From 802b4edf4d59a04e903fc8ef5342e25b6a566dc6 Mon Sep 17 00:00:00 2001 From: Christopher Odenbach Date: Mon, 3 Apr 2017 21:30:18 +0200 Subject: [PATCH 001/607] Fixed GSSAPI authentication. gssapi32.dll from MIT Kerberos as well as from Heimdal both load further DLLs from their installation directories. [SGT: I polished the original patch a bit, in particular replacing manual memory allocation with dup_mb_to_wc. This required a Recipe change to link miscucs.c and winucs.c into more of the tools.] --- Recipe | 6 +++--- windows/wingss.c | 51 +++++++++++++++++++++++++++++++++++++++++++--- windows/winmisc.c | 6 ++++-- windows/winstuff.h | 15 ++++++++++++++ 4 files changed, 70 insertions(+), 8 deletions(-) diff --git a/Recipe b/Recipe index e39faa1b..54e00636 100644 --- a/Recipe +++ b/Recipe @@ -235,8 +235,8 @@ TERMINAL = terminal wcwidth ldiscucs logging tree234 minibidi + config dialog conf # GUI front end and terminal emulator (putty, puttytel). -GUITERM = TERMINAL window windlg winctrls sizetip winucs winprint - + winutils wincfg sercfg winhelp winjump miscucs +GUITERM = TERMINAL window windlg winctrls sizetip winprint winutils + + wincfg sercfg winhelp winjump # Same thing on Unix. UXTERM = TERMINAL uxcfg sercfg uxucs uxprint timing callback miscucs @@ -262,7 +262,7 @@ SFTP = sftp int64 logging # Pageant or PuTTYgen). MISC = timing callback misc version settings tree234 proxy conf be_misc WINMISC = MISC winstore winnet winhandl cmdline windefs winmisc winproxy - + wintime winhsock errsock winsecur + + wintime winhsock errsock winsecur winucs miscucs UXMISC = MISC uxstore uxsel uxnet uxpeer cmdline uxmisc uxproxy time # import.c and dependencies, for PuTTYgen-like utilities that have to diff --git a/windows/wingss.c b/windows/wingss.c index 6aaa20cf..f7cc43eb 100644 --- a/windows/wingss.c +++ b/windows/wingss.c @@ -49,6 +49,9 @@ DECL_WINDOWS_FUNCTION(static, SECURITY_STATUS, DECL_WINDOWS_FUNCTION(static, SECURITY_STATUS, MakeSignature, (PCtxtHandle, ULONG, PSecBufferDesc, ULONG)); +DECL_WINDOWS_FUNCTION(static, DLL_DIRECTORY_COOKIE, + AddDllDirectory, + (PCWSTR)); typedef struct winSsh_gss_ctx { unsigned long maj_stat; @@ -72,6 +75,11 @@ struct ssh_gss_liblist *ssh_gss_setup(Conf *conf) HKEY regkey; struct ssh_gss_liblist *list = snew(struct ssh_gss_liblist); char *path; + static HMODULE kernel32_module; + if (!kernel32_module) { + kernel32_module = load_system32_dll("kernel32.dll"); + } + GET_WINDOWS_FUNCTION(kernel32_module, AddDllDirectory); list->libraries = snewn(3, struct ssh_gss_library); list->nlibraries = 0; @@ -93,8 +101,20 @@ struct ssh_gss_liblist *ssh_gss_setup(Conf *conf) ret = RegQueryValueEx(regkey, "InstallDir", NULL, &type, (LPBYTE)buffer, &size); if (ret == ERROR_SUCCESS && type == REG_SZ) { - strcat(buffer, "\\bin\\gssapi32.dll"); - module = LoadLibrary(buffer); + strcat (buffer, "\\bin"); + if(p_AddDllDirectory) { + /* Add MIT Kerberos' path to the DLL search path, + * it loads its own DLLs further down the road */ + wchar_t *dllPath = + dup_mb_to_wc(DEFAULT_CODEPAGE, 0, buffer); + p_AddDllDirectory(dllPath); + sfree(dllPath); + } + strcat (buffer, "\\gssapi32.dll"); + module = LoadLibraryEx (buffer, NULL, + LOAD_LIBRARY_SEARCH_SYSTEM32 | + LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | + LOAD_LIBRARY_SEARCH_USER_DIRS); } sfree(buffer); } @@ -152,7 +172,32 @@ struct ssh_gss_liblist *ssh_gss_setup(Conf *conf) module = NULL; path = conf_get_filename(conf, CONF_ssh_gss_custom)->path; if (*path) { - module = LoadLibrary(path); + if(p_AddDllDirectory) { + /* Add the custom directory as well in case it chainloads + * some other DLLs (e.g a non-installed MIT Kerberos + * instance) */ + int pathlen = strlen(path); + + while (pathlen > 0 && path[pathlen-1] != ':' && + path[pathlen-1] != '\\') + pathlen--; + + if (pathlen > 0 && path[pathlen-1] != '\\') + pathlen--; + + if (pathlen > 0) { + char *dirpath = dupprintf("%.*s", pathlen, path); + wchar_t *dllPath = dup_mb_to_wc(DEFAULT_CODEPAGE, 0, dirpath); + p_AddDllDirectory(dllPath); + sfree(dllPath); + sfree(dirpath); + } + } + + module = LoadLibraryEx(path, NULL, + LOAD_LIBRARY_SEARCH_SYSTEM32 | + LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | + LOAD_LIBRARY_SEARCH_USER_DIRS); } if (module) { struct ssh_gss_library *lib = diff --git a/windows/winmisc.c b/windows/winmisc.c index 11e2ca0f..384dc5ee 100644 --- a/windows/winmisc.c +++ b/windows/winmisc.c @@ -176,8 +176,10 @@ void dll_hijacking_protection(void) } if (p_SetDefaultDllDirectories) { - /* LOAD_LIBRARY_SEARCH_SYSTEM32 only */ - p_SetDefaultDllDirectories(0x800); + /* LOAD_LIBRARY_SEARCH_SYSTEM32 and explicitly specified + * directories only */ + p_SetDefaultDllDirectories(LOAD_LIBRARY_SEARCH_SYSTEM32 | + LOAD_LIBRARY_SEARCH_USER_DIRS); } } diff --git a/windows/winstuff.h b/windows/winstuff.h index c1918d4a..87706f32 100644 --- a/windows/winstuff.h +++ b/windows/winstuff.h @@ -512,6 +512,21 @@ const char *win_strerror(int error); void restrict_process_acl(void); GLOBAL int restricted_acl; +/* A few pieces of up-to-date Windows API definition needed for older + * compilers. */ +#ifndef LOAD_LIBRARY_SEARCH_SYSTEM32 +#define LOAD_LIBRARY_SEARCH_SYSTEM32 0x00000800 +#endif +#ifndef LOAD_LIBRARY_SEARCH_USER_DIRS +#define LOAD_LIBRARY_SEARCH_USER_DIRS 0x00000400 +#endif +#ifndef LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR +#define LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR 0x00000100 +#endif +#if _MSC_VER < 1400 +typedef PVOID DLL_DIRECTORY_COOKIE; +#endif + /* * Exports from sizetip.c. */ From 3ff3be38822d9735f065bc0fb41fecc72721e78c Mon Sep 17 00:00:00 2001 From: Christopher Odenbach Date: Tue, 11 Apr 2017 14:04:00 +0200 Subject: [PATCH 002/607] Fix loading of SSPICLI.DLL by SECUR32.DLL. If MIT Kerberos is installed, then using GetProcAddress to extract GetUserNameExA() from secur32.dll causes Windows to implicitly load sspicli.dll in turn - and it does it in a search-path-unclean way. If we load it in our own way before that happens, then Windows doesn't need to load it again and won't do so wrongly. [SGT: tidied up commit message from original patch] --- windows/winmisc.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/windows/winmisc.c b/windows/winmisc.c index 384dc5ee..308f0ea5 100644 --- a/windows/winmisc.c +++ b/windows/winmisc.c @@ -101,6 +101,11 @@ char *get_username(void) if (!tried_usernameex) { /* Not available on Win9x, so load dynamically */ HMODULE secur32 = load_system32_dll("secur32.dll"); + /* If MIT Kerberos is installed, the following call to + GET_WINDOWS_FUNCTION makes Windows implicitly load + sspicli.dll WITHOUT proper path sanitizing, so better + load it properly before */ + HMODULE sspicli = load_system32_dll("sspicli.dll"); GET_WINDOWS_FUNCTION(secur32, GetUserNameExA); tried_usernameex = TRUE; } From 49fb598b0e78d09d6a2a42679ee0649df482090e Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Tue, 11 Apr 2017 18:56:55 +0100 Subject: [PATCH 003/607] Add automatic type-checking to GET_WINDOWS_FUNCTION. This gives me an extra safety-check against having mistyped one of the function prototypes that we load at run time from DLLs: we verify that the typedef we defined based on the prototype in our source code matches the type of the real function as declared in the Windows headers. This was an idea I had while adding a pile of further functions using this mechanism. It didn't catch any errors (either in the new functions or in the existing collection), but that's no reason not to keep it anyway now that I've thought of it! In VS2015, this automated type-check works for most functions, but a couple manage to break it. SetCurrentProcessExplicitAppUserModelID in winjump.c can't be type-checked, because including where that function is declared would also bring in a load of other stuff that conflicts with the painful manual COM declarations in winjump.c. (That stuff could probably be removed now we're on an up-to-date Visual Studio, on the other hand, but that's a separate chore.) And gai_strerror, used in winnet.c, does _have_ an implementation in a DLL, but the header files like to provide an inline version with a different calling convention, which defeats this error-checking trick. And in the older VS2003 that we still precautionarily build with, several more type-checks have to be #ifdeffed out because the functions they check against just aren't there at all. --- windows/wingss.c | 5 +++++ windows/winhsock.c | 10 +++++++++- windows/winjump.c | 8 +++++++- windows/winmisc.c | 7 +++++++ windows/winnet.c | 14 ++++++++++++-- windows/winstuff.h | 21 +++++++++++++++------ 6 files changed, 55 insertions(+), 10 deletions(-) diff --git a/windows/wingss.c b/windows/wingss.c index f7cc43eb..ef056167 100644 --- a/windows/wingss.c +++ b/windows/wingss.c @@ -79,7 +79,12 @@ struct ssh_gss_liblist *ssh_gss_setup(Conf *conf) if (!kernel32_module) { kernel32_module = load_system32_dll("kernel32.dll"); } +#if defined _MSC_VER && _MSC_VER < 1900 + /* Omit the type-check because older MSVCs don't have this function */ + GET_WINDOWS_FUNCTION_NO_TYPECHECK(kernel32_module, AddDllDirectory); +#else GET_WINDOWS_FUNCTION(kernel32_module, AddDllDirectory); +#endif list->libraries = snewn(3, struct ssh_gss_library); list->nlibraries = 0; diff --git a/windows/winhsock.c b/windows/winhsock.c index 1a4ee4d7..e5f0fa4f 100644 --- a/windows/winhsock.c +++ b/windows/winhsock.c @@ -282,7 +282,15 @@ static char *sk_handle_peer_info(Socket s) if (!kernel32_module) { kernel32_module = load_system32_dll("kernel32.dll"); - GET_WINDOWS_FUNCTION(kernel32_module, GetNamedPipeClientProcessId); +#if defined _MSC_VER && _MSC_VER < 1900 + /* For older Visual Studio, this function isn't available in + * the header files to type-check */ + GET_WINDOWS_FUNCTION_NO_TYPECHECK( + kernel32_module, GetNamedPipeClientProcessId); +#else + GET_WINDOWS_FUNCTION( + kernel32_module, GetNamedPipeClientProcessId); +#endif } /* diff --git a/windows/winjump.c b/windows/winjump.c index 85963a32..d0dea863 100644 --- a/windows/winjump.c +++ b/windows/winjump.c @@ -728,7 +728,13 @@ BOOL set_explicit_app_user_model_id() if (!shell32_module) { shell32_module = load_system32_dll("Shell32.dll"); - GET_WINDOWS_FUNCTION(shell32_module, SetCurrentProcessExplicitAppUserModelID); + /* + * We can't typecheck this function here, because it's defined + * in , which we're not including due to clashes + * with all the manual-COM machinery above. + */ + GET_WINDOWS_FUNCTION_NO_TYPECHECK( + shell32_module, SetCurrentProcessExplicitAppUserModelID); } if (p_SetCurrentProcessExplicitAppUserModelID) diff --git a/windows/winmisc.c b/windows/winmisc.c index 308f0ea5..85fa3c95 100644 --- a/windows/winmisc.c +++ b/windows/winmisc.c @@ -177,7 +177,14 @@ void dll_hijacking_protection(void) if (!kernel32_module) { kernel32_module = load_system32_dll("kernel32.dll"); +#if defined _MSC_VER && _MSC_VER < 1900 + /* For older Visual Studio, this function isn't available in + * the header files to type-check */ + GET_WINDOWS_FUNCTION_NO_TYPECHECK( + kernel32_module, SetDefaultDllDirectories); +#else GET_WINDOWS_FUNCTION(kernel32_module, SetDefaultDllDirectories); +#endif } if (p_SetDefaultDllDirectories) { diff --git a/windows/winnet.c b/windows/winnet.c index 98753237..7ceca486 100644 --- a/windows/winnet.c +++ b/windows/winnet.c @@ -268,7 +268,10 @@ void sk_init(void) GET_WINDOWS_FUNCTION(winsock_module, getaddrinfo); GET_WINDOWS_FUNCTION(winsock_module, freeaddrinfo); GET_WINDOWS_FUNCTION(winsock_module, getnameinfo); - GET_WINDOWS_FUNCTION(winsock_module, gai_strerror); + /* This function would fail its type-check if we did one, + * because the VS header file provides an inline definition + * which is __cdecl instead of WINAPI. */ + GET_WINDOWS_FUNCTION_NO_TYPECHECK(winsock_module, gai_strerror); } else { /* Fall back to wship6.dll for Windows 2000 */ wship6_module = load_system32_dll("wship6.dll"); @@ -279,7 +282,8 @@ void sk_init(void) GET_WINDOWS_FUNCTION(wship6_module, getaddrinfo); GET_WINDOWS_FUNCTION(wship6_module, freeaddrinfo); GET_WINDOWS_FUNCTION(wship6_module, getnameinfo); - GET_WINDOWS_FUNCTION(wship6_module, gai_strerror); + /* See comment above about type check */ + GET_WINDOWS_FUNCTION_NO_TYPECHECK(winsock_module, gai_strerror); } else { #ifdef NET_SETUP_DIAGNOSTICS logevent(NULL, "No IPv6 support detected"); @@ -310,7 +314,13 @@ void sk_init(void) GET_WINDOWS_FUNCTION(winsock_module, getservbyname); GET_WINDOWS_FUNCTION(winsock_module, inet_addr); GET_WINDOWS_FUNCTION(winsock_module, inet_ntoa); +#if defined _MSC_VER && _MSC_VER < 1900 + /* Older Visual Studio doesn't know about this function at all, so + * can't type-check it */ + GET_WINDOWS_FUNCTION_NO_TYPECHECK(winsock_module, inet_ntop); +#else GET_WINDOWS_FUNCTION(winsock_module, inet_ntop); +#endif GET_WINDOWS_FUNCTION(winsock_module, connect); GET_WINDOWS_FUNCTION(winsock_module, bind); GET_WINDOWS_FUNCTION(winsock_module, setsockopt); diff --git a/windows/winstuff.h b/windows/winstuff.h index 87706f32..007889e4 100644 --- a/windows/winstuff.h +++ b/windows/winstuff.h @@ -128,15 +128,24 @@ struct FontSpec *fontspec_new(const char *name, * * (DECL_WINDOWS_FUNCTION works with both these variants.) */ -#define DECL_WINDOWS_FUNCTION(linkage, rettype, name, params) \ - typedef rettype (WINAPI *t_##name) params; \ +#define TYPECHECK(to_check, to_return) \ + (sizeof(to_check) ? to_return : to_return) +#define DECL_WINDOWS_FUNCTION(linkage, rettype, name, params) \ + typedef rettype (WINAPI *t_##name) params; \ linkage t_##name p_##name #define STR1(x) #x #define STR(x) STR1(x) -#define GET_WINDOWS_FUNCTION_PP(module, name) \ - (p_##name = module ? (t_##name) GetProcAddress(module, STR(name)) : NULL) -#define GET_WINDOWS_FUNCTION(module, name) \ - (p_##name = module ? (t_##name) GetProcAddress(module, #name) : NULL) +#define GET_WINDOWS_FUNCTION_PP(module, name) \ + TYPECHECK((t_##name)NULL == name, \ + (p_##name = module ? \ + (t_##name) GetProcAddress(module, STR(name)) : NULL)) +#define GET_WINDOWS_FUNCTION(module, name) \ + TYPECHECK((t_##name)NULL == name, \ + (p_##name = module ? \ + (t_##name) GetProcAddress(module, #name) : NULL)) +#define GET_WINDOWS_FUNCTION_NO_TYPECHECK(module, name) \ + (p_##name = module ? \ + (t_##name) GetProcAddress(module, #name) : NULL) /* * Global variables. Most modules declare these `extern', but From 89fff90de738025d338fa5d06b6ff3b589c33c9c Mon Sep 17 00:00:00 2001 From: klemens Date: Sat, 15 Apr 2017 10:06:22 +0200 Subject: [PATCH 004/607] Spelling fixes (just in comments). As found by a bot ( http://www.misfix.org, https://github.com/ka7/misspell_fixer ). --- doc/config.but | 2 +- minibidi.c | 4 ++-- mkfiles.pl | 2 +- pageant.c | 2 +- settings.c | 2 +- terminal.c | 2 +- windows/window.c | 4 ++-- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/doc/config.but b/doc/config.but index eb96fc17..269dbdc1 100644 --- a/doc/config.but +++ b/doc/config.but @@ -2507,7 +2507,7 @@ used: Disabling data-based rekeys entirely is a bad idea. The \i{integrity}, and to a lesser extent, \i{confidentiality} of the SSH-2 protocol depend -in part on rekeys occuring before a 32-bit packet sequence number +in part on rekeys occurring before a 32-bit packet sequence number wraps around. Unlike time-based rekeys, data-based rekeys won't occur when the SSH connection is idle, so they shouldn't cause the same problems. The SSH-1 protocol, incidentally, has even weaker integrity diff --git a/minibidi.c b/minibidi.c index 6c062116..8d78594d 100644 --- a/minibidi.c +++ b/minibidi.c @@ -3,7 +3,7 @@ * ------------ * Description: * ------------ - * This is an implemention of Unicode's Bidirectional Algorithm + * This is an implementation of Unicode's Bidirectional Algorithm * (known as UAX #9). * * http://www.unicode.org/reports/tr9/ @@ -89,7 +89,7 @@ enum { /* Shaping Types */ enum { - SL, /* Left-Joining, doesnt exist in U+0600 - U+06FF */ + SL, /* Left-Joining, doesn't exist in U+0600 - U+06FF */ SR, /* Right-Joining, ie has Isolated, Final */ SD, /* Dual-Joining, ie has Isolated, Final, Initial, Medial */ SU, /* Non-Joining */ diff --git a/mkfiles.pl b/mkfiles.pl index ae15ac48..a19cec5d 100755 --- a/mkfiles.pl +++ b/mkfiles.pl @@ -1966,7 +1966,7 @@ sub manpages { "# ** DO NOT EDIT **\r\n". "\r\n". # No difference between DEBUG and RELEASE here as in 'vcproj', because - # Dev-C++ does not support mutiple compilation profiles in one single project. + # Dev-C++ does not support multiple compilation profiles in one single project. # (At least I can say this for Dev-C++ 5 Beta) "[Project]\r\n". "FileName=$windows_project.dev\r\n". diff --git a/pageant.c b/pageant.c index 2d9a7402..36671725 100644 --- a/pageant.c +++ b/pageant.c @@ -1469,7 +1469,7 @@ int pageant_add_keyfile(Filename *filename, const char *passphrase, } /* - * If we get here, we've succesfully loaded the key into + * If we get here, we've successfully loaded the key into * rkey/skey, but not yet added it to the agent. */ diff --git a/settings.c b/settings.c index f810d3f9..00c01c54 100644 --- a/settings.c +++ b/settings.c @@ -892,7 +892,7 @@ void load_open_settings(void *sesskey, Conf *conf) { /* SSH-2 only by default */ int sshprot = gppi_raw(sesskey, "SshProt", 3); - /* Old sessions may contain the values correponding to the fallbacks + /* Old sessions may contain the values corresponding to the fallbacks * we used to allow; migrate them */ if (sshprot == 1) sshprot = 0; /* => "SSH-1 only" */ else if (sshprot == 2) sshprot = 3; /* => "SSH-2 only" */ diff --git a/terminal.c b/terminal.c index c79944cd..f47fe1bd 100644 --- a/terminal.c +++ b/terminal.c @@ -2437,7 +2437,7 @@ static void erase_lots(Terminal *term, /* After an erase of lines from the top of the screen, we shouldn't * bring the lines back again if the terminal enlarges (since the user or - * application has explictly thrown them away). */ + * application has explicitly thrown them away). */ if (erasing_lines_from_top && !(term->alt_which)) term->tempsblines = 0; } diff --git a/windows/window.c b/windows/window.c index 004eb4f8..38c0e3cd 100644 --- a/windows/window.c +++ b/windows/window.c @@ -1700,7 +1700,7 @@ void request_resize(void *frontend, int w, int h) { int width, height; - /* If the window is maximized supress resizing attempts */ + /* If the window is maximized suppress resizing attempts */ if (IsZoomed(hwnd)) { if (conf_get_int(conf, CONF_resize_action) == RESIZE_TERM) return; @@ -4777,7 +4777,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, return p - output; } - /* If we're definitly not building up an ALT-54321 then clear it */ + /* If we're definitely not building up an ALT-54321 then clear it */ if (!left_alt) keys_unicode[0] = 0; /* If we will be using alt_sum fix the 256s */ From b189df947d2625499cf508fd1fae7e18b03b9247 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 15 Apr 2017 18:13:47 +0100 Subject: [PATCH 005/607] Condition out some API type-checks in the MinGW build. A couple of the functions for which I was already turning off the type check for old Visual Studio turn out to also need it turning off for MinGW. --- windows/winhsock.c | 7 ++++--- windows/winnet.c | 6 +++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/windows/winhsock.c b/windows/winhsock.c index e5f0fa4f..c8cb46f6 100644 --- a/windows/winhsock.c +++ b/windows/winhsock.c @@ -282,9 +282,10 @@ static char *sk_handle_peer_info(Socket s) if (!kernel32_module) { kernel32_module = load_system32_dll("kernel32.dll"); -#if defined _MSC_VER && _MSC_VER < 1900 - /* For older Visual Studio, this function isn't available in - * the header files to type-check */ +#if (defined _MSC_VER && _MSC_VER < 1900) || defined __MINGW32__ + /* For older Visual Studio, and MinGW too (at least as of + * Ubuntu 16.04), this function isn't available in the header + * files to type-check */ GET_WINDOWS_FUNCTION_NO_TYPECHECK( kernel32_module, GetNamedPipeClientProcessId); #else diff --git a/windows/winnet.c b/windows/winnet.c index 7ceca486..fc26c3e5 100644 --- a/windows/winnet.c +++ b/windows/winnet.c @@ -314,9 +314,9 @@ void sk_init(void) GET_WINDOWS_FUNCTION(winsock_module, getservbyname); GET_WINDOWS_FUNCTION(winsock_module, inet_addr); GET_WINDOWS_FUNCTION(winsock_module, inet_ntoa); -#if defined _MSC_VER && _MSC_VER < 1900 - /* Older Visual Studio doesn't know about this function at all, so - * can't type-check it */ +#if (defined _MSC_VER && _MSC_VER < 1900) || defined __MINGW32__ + /* Older Visual Studio, and MinGW as of Ubuntu 16.04, don't know + * about this function at all, so can't type-check it */ GET_WINDOWS_FUNCTION_NO_TYPECHECK(winsock_module, inet_ntop); #else GET_WINDOWS_FUNCTION(winsock_module, inet_ntop); From 73039b7831aa863fabba1e6ff06471643303ae09 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Mon, 13 Mar 2017 21:24:06 +0000 Subject: [PATCH 006/607] Load winmm.dll (for PlaySound()) at run time. It's not on the default list of important system 'known DLLs' stored at HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs (see https://isc.sans.edu/forums/diary/DLL+hijacking+vulnerabilities/9445/ ) which apparently makes it exempt from Windows's standard DLL hijacking defence, i.e. if an executable links against it in the normal way then that executable will be vulnerable to DLL hijacking from a file called winmm.dll in the same directory as it. The solution is to load it dynamically _after_ we've locked down our DLL search path, which fortunately PuTTY's code base is well used to doing already for other DLLs. --- Recipe | 2 +- windows/window.c | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Recipe b/Recipe index 54e00636..e2cce9ae 100644 --- a/Recipe +++ b/Recipe @@ -274,7 +274,7 @@ CHARSET = sbcsdat slookup sbcs utf8 toucs fromucs xenc mimeenc macenc localenc # Standard libraries. LIBS = advapi32.lib user32.lib gdi32.lib comctl32.lib comdlg32.lib - + shell32.lib winmm.lib imm32.lib winspool.lib ole32.lib + + shell32.lib imm32.lib winspool.lib ole32.lib # Network backend sets. This also brings in the relevant attachment # to proxy.c depending on whether we're crypto-avoidant or not. diff --git a/windows/window.c b/windows/window.c index 38c0e3cd..cb42addf 100644 --- a/windows/window.c +++ b/windows/window.c @@ -3949,12 +3949,14 @@ int char_width(Context ctx, int uc) { DECL_WINDOWS_FUNCTION(static, BOOL, FlashWindowEx, (PFLASHWINFO)); DECL_WINDOWS_FUNCTION(static, BOOL, ToUnicodeEx, (UINT, UINT, const BYTE *, LPWSTR, int, UINT, HKL)); +DECL_WINDOWS_FUNCTION(static, BOOL, PlaySound, (LPCTSTR, HMODULE, DWORD)); static void init_winfuncs(void) { HMODULE user32_module = load_system32_dll("user32.dll"); + HMODULE winmm_module = load_system32_dll("winmm.dll"); GET_WINDOWS_FUNCTION(user32_module, FlashWindowEx); - GET_WINDOWS_FUNCTION(user32_module, ToUnicodeEx); + GET_WINDOWS_FUNCTION_PP(winmm_module, PlaySound); } /* @@ -5540,8 +5542,8 @@ void do_beep(void *frontend, int mode) lastbeep = GetTickCount(); } else if (mode == BELL_WAVEFILE) { Filename *bell_wavefile = conf_get_filename(conf, CONF_bell_wavefile); - if (!PlaySound(bell_wavefile->path, NULL, - SND_ASYNC | SND_FILENAME)) { + if (!p_PlaySound || !p_PlaySound(bell_wavefile->path, NULL, + SND_ASYNC | SND_FILENAME)) { char buf[sizeof(bell_wavefile->path) + 80]; char otherbuf[100]; sprintf(buf, "Unable to play sound file\n%s\n" From 793ac872757667a87df4636b5b3eed61302dd837 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Mon, 13 Mar 2017 21:28:36 +0000 Subject: [PATCH 007/607] Load the Windows printing subsystem at run time. The printing functions are split between winspool.drv and spoolss.dll in a really weird way (who would have guessed that OpenPrinter and ClosePrinter don't live in the same dynamic library?!), but _neither_ of those counts as a system 'known DLL', so linking against either one of these at load time is again a potential DLL hijacking vector. --- Recipe | 2 +- windows/winprint.c | 65 ++++++++++++++++++++++++++++++++++++---------- 2 files changed, 52 insertions(+), 15 deletions(-) diff --git a/Recipe b/Recipe index e2cce9ae..0fb7bbb7 100644 --- a/Recipe +++ b/Recipe @@ -274,7 +274,7 @@ CHARSET = sbcsdat slookup sbcs utf8 toucs fromucs xenc mimeenc macenc localenc # Standard libraries. LIBS = advapi32.lib user32.lib gdi32.lib comctl32.lib comdlg32.lib - + shell32.lib imm32.lib winspool.lib ole32.lib + + shell32.lib imm32.lib ole32.lib # Network backend sets. This also brings in the relevant attachment # to proxy.c depending on whether we're crypto-avoidant or not. diff --git a/windows/winprint.c b/windows/winprint.c index c190e5fb..11587273 100644 --- a/windows/winprint.c +++ b/windows/winprint.c @@ -18,11 +18,46 @@ struct printer_job_tag { HANDLE hprinter; }; +DECL_WINDOWS_FUNCTION(static, BOOL, EnumPrinters, + (DWORD, LPTSTR, DWORD, LPBYTE, DWORD, LPDWORD, LPDWORD)); +DECL_WINDOWS_FUNCTION(static, BOOL, OpenPrinter, + (LPTSTR, LPHANDLE, LPPRINTER_DEFAULTS)); +DECL_WINDOWS_FUNCTION(static, BOOL, ClosePrinter, (HANDLE)); +DECL_WINDOWS_FUNCTION(static, BOOL, StartDocPrinter, (HANDLE, DWORD, LPBYTE)); +DECL_WINDOWS_FUNCTION(static, BOOL, EndDocPrinter, (HANDLE)); +DECL_WINDOWS_FUNCTION(static, BOOL, StartPagePrinter, (HANDLE)); +DECL_WINDOWS_FUNCTION(static, BOOL, EndPagePrinter, (HANDLE)); +DECL_WINDOWS_FUNCTION(static, BOOL, WritePrinter, + (HANDLE, LPVOID, DWORD, LPDWORD)); + +static void init_winfuncs(void) +{ + static int initialised = FALSE; + char buf[4096]; + if (initialised) + return; + { + HMODULE winspool_module = load_system32_dll("winspool.drv"); + HMODULE spoolss_module = load_system32_dll("spoolss.dll"); + GET_WINDOWS_FUNCTION_PP(winspool_module, EnumPrinters); + GET_WINDOWS_FUNCTION_PP(winspool_module, OpenPrinter); + GET_WINDOWS_FUNCTION_PP(spoolss_module, ClosePrinter); + GET_WINDOWS_FUNCTION_PP(winspool_module, StartDocPrinter); + GET_WINDOWS_FUNCTION_PP(spoolss_module, EndDocPrinter); + GET_WINDOWS_FUNCTION_PP(spoolss_module, StartPagePrinter); + GET_WINDOWS_FUNCTION_PP(spoolss_module, EndPagePrinter); + GET_WINDOWS_FUNCTION_PP(spoolss_module, WritePrinter); + } + initialised = TRUE; +} + static int printer_add_enum(int param, DWORD level, char **buffer, int offset, int *nprinters_ptr) { DWORD needed = 0, nprinters = 0; + init_winfuncs(); + *buffer = sresize(*buffer, offset+512, char); /* @@ -30,16 +65,16 @@ static int printer_add_enum(int param, DWORD level, char **buffer, * we'll need for the output. Discard the return value since it * will almost certainly be a failure due to lack of space. */ - EnumPrinters(param, NULL, level, (LPBYTE)((*buffer)+offset), 512, - &needed, &nprinters); + p_EnumPrinters(param, NULL, level, (LPBYTE)((*buffer)+offset), 512, + &needed, &nprinters); if (needed < 512) needed = 512; *buffer = sresize(*buffer, offset+needed, char); - if (EnumPrinters(param, NULL, level, (LPBYTE)((*buffer)+offset), - needed, &needed, &nprinters) == 0) + if (p_EnumPrinters(param, NULL, level, (LPBYTE)((*buffer)+offset), + needed, &needed, &nprinters) == 0) return FALSE; *nprinters_ptr += nprinters; @@ -131,19 +166,21 @@ printer_job *printer_start_job(char *printer) DOC_INFO_1 docinfo; int jobstarted = 0, pagestarted = 0; + init_winfuncs(); + ret->hprinter = NULL; - if (!OpenPrinter(printer, &ret->hprinter, NULL)) + if (!p_OpenPrinter(printer, &ret->hprinter, NULL)) goto error; docinfo.pDocName = "PuTTY remote printer output"; docinfo.pOutputFile = NULL; docinfo.pDatatype = "RAW"; - if (!StartDocPrinter(ret->hprinter, 1, (LPBYTE)&docinfo)) + if (!p_StartDocPrinter(ret->hprinter, 1, (LPBYTE)&docinfo)) goto error; jobstarted = 1; - if (!StartPagePrinter(ret->hprinter)) + if (!p_StartPagePrinter(ret->hprinter)) goto error; pagestarted = 1; @@ -151,11 +188,11 @@ printer_job *printer_start_job(char *printer) error: if (pagestarted) - EndPagePrinter(ret->hprinter); + p_EndPagePrinter(ret->hprinter); if (jobstarted) - EndDocPrinter(ret->hprinter); + p_EndDocPrinter(ret->hprinter); if (ret->hprinter) - ClosePrinter(ret->hprinter); + p_ClosePrinter(ret->hprinter); sfree(ret); return NULL; } @@ -167,7 +204,7 @@ void printer_job_data(printer_job *pj, void *data, int len) if (!pj) return; - WritePrinter(pj->hprinter, data, len, &written); + p_WritePrinter(pj->hprinter, data, len, &written); } void printer_finish_job(printer_job *pj) @@ -175,8 +212,8 @@ void printer_finish_job(printer_job *pj) if (!pj) return; - EndPagePrinter(pj->hprinter); - EndDocPrinter(pj->hprinter); - ClosePrinter(pj->hprinter); + p_EndPagePrinter(pj->hprinter); + p_EndDocPrinter(pj->hprinter); + p_ClosePrinter(pj->hprinter); sfree(pj); } From f77ee39e8cae2eaaea3a8fdd1eaffaf484cada08 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Mon, 13 Mar 2017 21:42:44 +0000 Subject: [PATCH 008/607] Load comctl32.dll (for drag lists) at run time. This too is not in the list of known DLLs on Windows 10. I don't know of any actual viable hijacking attack based on it, which according to my reading of MSDN (specifically, a rather vague hint in https://msdn.microsoft.com/library/ff919712) _may_ be because we mention the common controls assembly in our application manifest; but better safe than sorry. Now the entire list of remaining DLLs that PuTTY links against at load time is a subset of the Win10 known DLLs list, so that _should_ mean that everything we load before we've deployed our own defence (SetDefaultDllDirectories) is defended against for us by Windows itself. --- Recipe | 2 +- windows/winctrls.c | 33 ++++++++++++++++++++++++--------- windows/window.c | 2 +- windows/winpgen.c | 2 +- windows/winstuff.h | 1 + 5 files changed, 28 insertions(+), 12 deletions(-) diff --git a/Recipe b/Recipe index 0fb7bbb7..f5458122 100644 --- a/Recipe +++ b/Recipe @@ -273,7 +273,7 @@ IMPORT = import sshbcrypt sshblowf CHARSET = sbcsdat slookup sbcs utf8 toucs fromucs xenc mimeenc macenc localenc # Standard libraries. -LIBS = advapi32.lib user32.lib gdi32.lib comctl32.lib comdlg32.lib +LIBS = advapi32.lib user32.lib gdi32.lib comdlg32.lib + shell32.lib imm32.lib ole32.lib # Network backend sets. This also brings in the relevant attachment diff --git a/windows/winctrls.c b/windows/winctrls.c index a03967e6..737018e4 100644 --- a/windows/winctrls.c +++ b/windows/winctrls.c @@ -38,6 +38,21 @@ #define PUSHBTNHEIGHT 14 #define PROGBARHEIGHT 14 +DECL_WINDOWS_FUNCTION(static, void, InitCommonControls, (void)); +DECL_WINDOWS_FUNCTION(static, BOOL, MakeDragList, (HWND)); +DECL_WINDOWS_FUNCTION(static, int, LBItemFromPt, (HWND, POINT, BOOL)); +DECL_WINDOWS_FUNCTION(static, int, DrawInsert, (HWND, HWND, int)); + +void init_common_controls(void) +{ + HMODULE comctl32_module = load_system32_dll("comctl32.dll"); + GET_WINDOWS_FUNCTION(comctl32_module, InitCommonControls); + GET_WINDOWS_FUNCTION(comctl32_module, MakeDragList); + GET_WINDOWS_FUNCTION(comctl32_module, LBItemFromPt); + GET_WINDOWS_FUNCTION(comctl32_module, DrawInsert); + p_InitCommonControls(); +} + void ctlposinit(struct ctlpos *cp, HWND hwnd, int leftborder, int rightborder, int topborder) { @@ -921,7 +936,7 @@ void prefslist(struct prefslist *hdl, struct ctlpos *cp, int lines, WS_VSCROLL | LBS_HASSTRINGS | LBS_USETABSTOPS, WS_EX_CLIENTEDGE, "", listid); - MakeDragList(ctl); + p_MakeDragList(ctl); } break; @@ -996,17 +1011,17 @@ int pl_itemfrompt(HWND hwnd, POINT cursor, BOOL scroll) * current item if the upper edge is closer than * the lower edge, or _below_ it if vice versa. */ - ret = LBItemFromPt(hwnd, cursor, scroll); + ret = p_LBItemFromPt(hwnd, cursor, scroll); if (ret == -1) return ret; - ret = LBItemFromPt(hwnd, cursor, FALSE); + ret = p_LBItemFromPt(hwnd, cursor, FALSE); updist = downdist = 0; for (i = 1; i < 4096 && (!updist || !downdist); i++) { uppoint = downpoint = cursor; uppoint.y -= i; downpoint.y += i; - upitem = LBItemFromPt(hwnd, uppoint, FALSE); - downitem = LBItemFromPt(hwnd, downpoint, FALSE); + upitem = p_LBItemFromPt(hwnd, uppoint, FALSE); + downitem = p_LBItemFromPt(hwnd, downpoint, FALSE); if (!updist && upitem != ret) updist = i; if (!downdist && downitem != ret) @@ -1047,13 +1062,13 @@ int handle_prefslist(struct prefslist *hdl, SendDlgItemMessage(hwnd, hdl->listid, LB_ADDSTRING, 0, (LPARAM) ""); - hdl->srcitem = LBItemFromPt(dlm->hWnd, dlm->ptCursor, TRUE); + hdl->srcitem = p_LBItemFromPt(dlm->hWnd, dlm->ptCursor, TRUE); hdl->dragging = 0; /* XXX hack Q183115 */ SetWindowLongPtr(hwnd, DWLP_MSGRESULT, TRUE); ret |= 1; break; case DL_CANCELDRAG: - DrawInsert(hwnd, dlm->hWnd, -1); /* Clear arrow */ + p_DrawInsert(hwnd, dlm->hWnd, -1); /* Clear arrow */ SendDlgItemMessage(hwnd, hdl->listid, LB_DELETESTRING, hdl->dummyitem, 0); hdl->dragging = 0; @@ -1062,7 +1077,7 @@ int handle_prefslist(struct prefslist *hdl, hdl->dragging = 1; dest = pl_itemfrompt(dlm->hWnd, dlm->ptCursor, TRUE); if (dest > hdl->dummyitem) dest = hdl->dummyitem; - DrawInsert (hwnd, dlm->hWnd, dest); + p_DrawInsert (hwnd, dlm->hWnd, dest); if (dest >= 0) SetWindowLongPtr(hwnd, DWLP_MSGRESULT, DL_MOVECURSOR); else @@ -1072,7 +1087,7 @@ int handle_prefslist(struct prefslist *hdl, if (hdl->dragging) { dest = pl_itemfrompt(dlm->hWnd, dlm->ptCursor, TRUE); if (dest > hdl->dummyitem) dest = hdl->dummyitem; - DrawInsert (hwnd, dlm->hWnd, -1); + p_DrawInsert (hwnd, dlm->hWnd, -1); } SendDlgItemMessage(hwnd, hdl->listid, LB_DELETESTRING, hdl->dummyitem, 0); diff --git a/windows/window.c b/windows/window.c index cb42addf..e01a3c32 100644 --- a/windows/window.c +++ b/windows/window.c @@ -359,7 +359,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) sk_init(); - InitCommonControls(); + init_common_controls(); /* Set Explicit App User Model Id so that jump lists don't cause PuTTY to hang on to removable media. */ diff --git a/windows/winpgen.c b/windows/winpgen.c index c4f4de45..2507d37e 100644 --- a/windows/winpgen.c +++ b/windows/winpgen.c @@ -1529,7 +1529,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) dll_hijacking_protection(); - InitCommonControls(); + init_common_controls(); hinst = inst; hwnd = NULL; diff --git a/windows/winstuff.h b/windows/winstuff.h index 007889e4..f8c4243f 100644 --- a/windows/winstuff.h +++ b/windows/winstuff.h @@ -329,6 +329,7 @@ struct ctlpos { int boxystart, boxid; char *boxtext; }; +void init_common_controls(void); /* also does some DLL-loading */ /* * Exports from winutils.c. From b1829b81b5c0d12dcc91f6b50b0b4d83c3df6a8e Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Mon, 24 Apr 2017 14:45:52 +0100 Subject: [PATCH 009/607] Update version number for 0.69 release. --- Buildscr | 2 +- LATEST.VER | 2 +- doc/plink.but | 2 +- doc/pscp.but | 2 +- windows/putty.iss | 8 ++++---- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Buildscr b/Buildscr index 7ca4eb7f..086800ac 100644 --- a/Buildscr +++ b/Buildscr @@ -35,7 +35,7 @@ module putty ifeq "$(RELEASE)" "" set Ndate $(!builddate) ifneq "$(Ndate)" "" in . do echo $(Ndate) | perl -pe 's/(....)(..)(..)/$$1-$$2-$$3/' > date ifneq "$(Ndate)" "" read Date date -set Epoch 16214 # update this at every release +set Epoch 16280 # update this at every release ifneq "$(Ndate)" "" in . do echo $(Ndate) | perl -ne 'use Time::Local; /(....)(..)(..)/ and print timegm(0,0,0,$$3,$$2-1,$$1) / 86400 - $(Epoch)' > days ifneq "$(Ndate)" "" read Days days diff --git a/LATEST.VER b/LATEST.VER index db1ed30c..b04c6474 100644 --- a/LATEST.VER +++ b/LATEST.VER @@ -1 +1 @@ -0.68 +0.69 diff --git a/doc/plink.but b/doc/plink.but index 351e13ea..153982e0 100644 --- a/doc/plink.but +++ b/doc/plink.but @@ -41,7 +41,7 @@ use Plink: \c Z:\sysosd>plink \c Plink: command-line connection utility -\c Release 0.68 +\c Release 0.69 \c Usage: plink [options] [user@]host [command] \c ("host" can also be a PuTTY saved session name) \c Options: diff --git a/doc/pscp.but b/doc/pscp.but index 27643a46..30a47f83 100644 --- a/doc/pscp.but +++ b/doc/pscp.but @@ -39,7 +39,7 @@ use PSCP: \c Z:\owendadmin>pscp \c PuTTY Secure Copy client -\c Release 0.68 +\c Release 0.69 \c Usage: pscp [options] [user@]host:source target \c pscp [options] source [source...] [user@]host:target \c pscp [options] -ls [user@]host:filespec diff --git a/windows/putty.iss b/windows/putty.iss index dda68f63..b3deb76c 100644 --- a/windows/putty.iss +++ b/windows/putty.iss @@ -14,10 +14,10 @@ [Setup] AppName=PuTTY -AppVerName=PuTTY version 0.68 -VersionInfoTextVersion=Release 0.68 -AppVersion=0.68 -VersionInfoVersion=0.68.0.0 +AppVerName=PuTTY version 0.69 +VersionInfoTextVersion=Release 0.69 +AppVersion=0.69 +VersionInfoVersion=0.69.0.0 AppPublisher=Simon Tatham AppPublisherURL=http://www.chiark.greenend.org.uk/~sgtatham/putty/ AppReadmeFile={app}\README.txt From d6d10932ac1f9333b06ee8027dcfad231f17ed04 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 29 Apr 2017 10:23:31 +0100 Subject: [PATCH 010/607] Release checklist update: no @releases array! The rewritten bugs2html.py in the wishlist repository no longer needs me to manually maintain a mapping between releases and version control - and the one thing I forgot was to remove the reminder in the release checklist telling me to keep that mapping up to date :-) --- CHECKLST.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/CHECKLST.txt b/CHECKLST.txt index 0499d780..8d55ac41 100644 --- a/CHECKLST.txt +++ b/CHECKLST.txt @@ -96,7 +96,6 @@ for it: branch (so that the wishlist mechanism can't automatically mark them as fixed in the new release), add appropriate Fixed-in headers for those. - * Add an entry to the @releases array in control/bugs2html. - Make a release-candidate build from the release tag, and put the build.out and build.log dfiles somewhere safe. Normally I store From 5a576e0c891ddc745ea1f67bcca10f1386ff1849 Mon Sep 17 00:00:00 2001 From: Jacob Nevins Date: Sat, 29 Apr 2017 12:07:37 +0100 Subject: [PATCH 011/607] Reinstate use of ToUnicodeEx(). This was accidentally disabled by 73039b783, causing a regression in ability to type characters outside of the current Windows code page. --- windows/window.c | 1 + 1 file changed, 1 insertion(+) diff --git a/windows/window.c b/windows/window.c index e01a3c32..89ddb863 100644 --- a/windows/window.c +++ b/windows/window.c @@ -3956,6 +3956,7 @@ static void init_winfuncs(void) HMODULE user32_module = load_system32_dll("user32.dll"); HMODULE winmm_module = load_system32_dll("winmm.dll"); GET_WINDOWS_FUNCTION(user32_module, FlashWindowEx); + GET_WINDOWS_FUNCTION(user32_module, ToUnicodeEx); GET_WINDOWS_FUNCTION_PP(winmm_module, PlaySound); } From ed600ab23f87fd1785d100937e992e244ba82ed5 Mon Sep 17 00:00:00 2001 From: Jacob Nevins Date: Sat, 29 Apr 2017 14:24:17 +0100 Subject: [PATCH 012/607] Fix double negative in TTY mode docs. --- doc/config.but | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/config.but b/doc/config.but index 269dbdc1..a7d45689 100644 --- a/doc/config.but +++ b/doc/config.but @@ -2959,7 +2959,7 @@ modes from the local terminal, if any. } -\b If \q{Nothing} is selected, no value for the mode will not be +\b If \q{Nothing} is selected, no value for the mode will be specified to the server under any circumstances. \b If a value is specified, it will be sent to the server under all From fb023da0fdcbfca104b39c2315a79186d7254c99 Mon Sep 17 00:00:00 2001 From: Jacob Nevins Date: Sun, 30 Apr 2017 10:42:02 +0100 Subject: [PATCH 013/607] Be less vague in the description of IUTF8. --- doc/config.but | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/doc/config.but b/doc/config.but index a7d45689..bb18b794 100644 --- a/doc/config.but +++ b/doc/config.but @@ -3006,18 +3006,19 @@ PuTTY in a variety of ways, such as \cw{true}/\cw{false}, \cw{no} is different from not sending the mode at all.) \b The boolean mode \I{IUTF8 terminal mode}\cw{IUTF8} signals to the -server whether the terminal character set is \i{UTF-8} or not. -If this is set incorrectly, keys like backspace may do the wrong thing -in some circumstances. However, setting this is not usually -sufficient to cause servers to expect the terminal to be in UTF-8 mode; -POSIX servers will generally require the locale to be set (by some -server-dependent means), although many default to UTF-8. Also, -since this mode was added to the SSH protocol much later than the -others, \#{circa 2016} many servers (particularly older servers) do -not honour this mode sent over SSH; indeed, a few poorly-written -servers object to its mere presence, so you may find you need to set -it to not be sent at all. When set to \q{Auto}, this follows the local -configured character set (see \k{config-charset}). +server whether the terminal character set is \i{UTF-8} or not, for +purposes such as basic line editing; if this is set incorrectly, +the backspace key may erase the wrong amount of text, for instance. +However, simply setting this is not usually sufficient for the server +to use UTF-8; POSIX servers will generally also require the locale to +be set (by some server-dependent means), although many newer +installations default to UTF-8. Also, since this mode was added to the +SSH protocol much later than the others, \#{circa 2016} many servers +(particularly older servers) do not honour this mode sent over SSH; +indeed, a few poorly-written servers object to its mere presence, so +you may find you need to set it to not be sent at all. When set to +\q{Auto}, this follows the local configured character set (see +\k{config-charset}). \b Terminal speeds are configured elsewhere; see \k{config-termspeed}. From 230f7d56284a703c65c4fecf7e6f23b791043f81 Mon Sep 17 00:00:00 2001 From: Zero King Date: Sun, 30 Apr 2017 11:01:13 +0100 Subject: [PATCH 014/607] Fix thinko introduced in 8833634f4. This prevented compilation with Gtk 2. --- unix/gtkwin.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/unix/gtkwin.c b/unix/gtkwin.c index 69e33509..bca6daa4 100644 --- a/unix/gtkwin.c +++ b/unix/gtkwin.c @@ -2188,11 +2188,11 @@ void set_gtk_widget_background(GtkWidget *widget, const GdkColor *col) free(data); free(col_css); #else - if (gtk_widget_get_window(win)) { + if (gtk_widget_get_window(widget)) { /* For GTK1, which doesn't have a 'const' on * gdk_window_set_background's second parameter type. */ GdkColor col_mutable = *col; - gdk_window_set_background(gtk_widget_get_window(win), &col_mutable); + gdk_window_set_background(gtk_widget_get_window(widget), &col_mutable); } #endif } From b566c5f125efb9933303a61303ab17e2af0a859b Mon Sep 17 00:00:00 2001 From: Jacob Nevins Date: Sun, 30 Apr 2017 11:39:07 +0100 Subject: [PATCH 015/607] Add a cast to fix a warning. This fixes compilation with Gtk 2 with -Werror. Problem introduced by 64221972c. --- unix/gtkwin.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unix/gtkwin.c b/unix/gtkwin.c index bca6daa4..67cfcac3 100644 --- a/unix/gtkwin.c +++ b/unix/gtkwin.c @@ -1935,7 +1935,7 @@ gboolean scroll_event(GtkWidget *widget, GdkEventScroll *event, gpointer data) event_button->x_root = event->x_root; event_button->y_root = event->y_root; ret = button_internal(inst, event_button); - gdk_event_free(event_button); + gdk_event_free((GdkEvent *)event_button); return ret; #endif } From ad694a494158d44ff3dce86d20f4f2afb1dc142e Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Mon, 1 May 2017 06:53:06 +0100 Subject: [PATCH 016/607] mkfiles.pl: fix regex syntax error. Thanks to Brian K. White for spotting this straight-up syntax error of a missing ), in the regex handling the special case of &splitlines when it findss a word in its input string too long to fit in the specified output line width. Apparently in all my own uses of &splitline I'd never exercised that special-case code path before. --- mkfiles.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkfiles.pl b/mkfiles.pl index a19cec5d..8a63c65d 100755 --- a/mkfiles.pl +++ b/mkfiles.pl @@ -364,7 +364,7 @@ sub splitline { $len = (defined $width ? $width : 76); $splitchar = (defined $splitchar ? $splitchar : '\\'); while (length $line > $len) { - $line =~ /^(.{0,$len})\s(.*)$/ or $line =~ /^(.{$len,}?\s(.*)$/; + $line =~ /^(.{0,$len})\s(.*)$/ or $line =~ /^(.{$len,})?\s(.*)$/; $result .= $1; $result .= " ${splitchar}\n\t\t" if $2 ne ''; $line = $2; From 6ea9d36ae94736493216591fb18d20efe79b5216 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 7 May 2017 16:29:01 +0100 Subject: [PATCH 017/607] Switch chiark URLs to https. --- Buildscr | 4 ++-- README | 4 ++-- contrib/cygtermd/README | 2 +- doc/blurb.but | 2 +- doc/faq.but | 18 +++++++++--------- doc/feedback.but | 18 +++++++++--------- doc/man-pl.but | 2 +- doc/man-pscp.but | 2 +- doc/man-psft.but | 2 +- doc/man-ptel.but | 2 +- doc/man-putt.but | 2 +- doc/pgpkeys.but | 20 ++++++++++---------- doc/udp.but | 2 +- ssh.c | 2 +- windows/README-msi.txt | 2 +- windows/README.txt | 2 +- windows/putty.iss | 2 +- windows/website.url | Bin 103 -> 104 bytes windows/windlg.c | 2 +- windows/winpgen.c | 2 +- windows/winpgnt.c | 2 +- 21 files changed, 47 insertions(+), 47 deletions(-) diff --git a/Buildscr b/Buildscr index 086800ac..afcc2766 100644 --- a/Buildscr +++ b/Buildscr @@ -172,7 +172,7 @@ delegate windows # provide a 'more info' URL, and an optional -n option to provide a # program name, and that it can take multiple .exe filename # arguments and sign them all in place. - ifneq "$(winsigncode)" "" in putty/windows do $(winsigncode) -i http://www.chiark.greenend.org.uk/~sgtatham/putty/ build*/*.exe + ifneq "$(winsigncode)" "" in putty/windows do $(winsigncode) -i https://www.chiark.greenend.org.uk/~sgtatham/putty/ build*/*.exe # Ignore exit code from hhc, in favour of seeing whether the .chm # file was created. (Yuck; but hhc appears to return non-zero @@ -187,7 +187,7 @@ delegate windows in putty/windows with innosetup do/win iscc putty.iss # Sign the installers. - ifneq "$(winsigncode)" "" in putty/windows do $(winsigncode) -i http://www.chiark.greenend.org.uk/~sgtatham/putty/ -n "PuTTY Installer" installer32.msi installer64.msi Output/installer.exe + ifneq "$(winsigncode)" "" in putty/windows do $(winsigncode) -i https://www.chiark.greenend.org.uk/~sgtatham/putty/ -n "PuTTY Installer" installer32.msi installer64.msi Output/installer.exe # Finished Windows builds. return putty/windows/buildold/*.exe diff --git a/README b/README index ef931dd1..4d73a995 100644 --- a/README +++ b/README @@ -127,11 +127,11 @@ Documentation (in various formats including Windows Help and Unix `man' pages) is built from the Halibut (`.but') files in the `doc' subdirectory using `doc/Makefile'. If you aren't using one of our source snapshots, you'll need to do this yourself. Halibut can be -found at . +found at . The PuTTY home web site is - http://www.chiark.greenend.org.uk/~sgtatham/putty/ + https://www.chiark.greenend.org.uk/~sgtatham/putty/ If you want to send bug reports or feature requests, please read the Feedback section of the web site before doing so. Sending one-line diff --git a/contrib/cygtermd/README b/contrib/cygtermd/README index ebfdfdd7..a722fe10 100644 --- a/contrib/cygtermd/README +++ b/contrib/cygtermd/README @@ -8,4 +8,4 @@ install it in Cygwin's /bin, and configure PuTTY to use it as a local proxy process. For detailed instructions, see the PuTTY Wishlist page at -http://www.chiark.greenend.org.uk/~sgtatham/putty/wishlist/cygwin-terminal-window.html +https://www.chiark.greenend.org.uk/~sgtatham/putty/wishlist/cygwin-terminal-window.html diff --git a/doc/blurb.but b/doc/blurb.but index 227300f4..64e8ab74 100644 --- a/doc/blurb.but +++ b/doc/blurb.but @@ -7,7 +7,7 @@ \cfg{xhtml-leaf-contains-contents}{true} \cfg{xhtml-body-end}{

If you want to provide feedback on this manual or on the PuTTY tools themselves, see the -Feedback +Feedback page.

} \cfg{html-template-fragment}{%k}{%b} diff --git a/doc/faq.but b/doc/faq.but index 42f965b2..80cf9d63 100644 --- a/doc/faq.but +++ b/doc/faq.but @@ -27,18 +27,18 @@ else. \I{supported features}In general, if you want to know if PuTTY supports a particular feature, you should look for it on the -\W{http://www.chiark.greenend.org.uk/~sgtatham/putty/}{PuTTY web site}. +\W{https://www.chiark.greenend.org.uk/~sgtatham/putty/}{PuTTY web site}. In particular: \b try the -\W{http://www.chiark.greenend.org.uk/~sgtatham/putty/changes.html}{changes +\W{https://www.chiark.greenend.org.uk/~sgtatham/putty/changes.html}{changes page}, and see if you can find the feature on there. If a feature is listed there, it's been implemented. If it's listed as a change made \e{since} the latest version, it should be available in the development snapshots, in which case testing will be very welcome. \b try the -\W{http://www.chiark.greenend.org.uk/~sgtatham/putty/wishlist/}{Wishlist +\W{https://www.chiark.greenend.org.uk/~sgtatham/putty/wishlist/}{Wishlist page}, and see if you can find the feature there. If it's on there, and not in the \q{Recently fixed} section, it probably \e{hasn't} been implemented. @@ -54,7 +54,7 @@ version 0.52. \cw{ssh.com} SSH-2 private key files? PuTTY doesn't support this natively (see -\W{http://www.chiark.greenend.org.uk/~sgtatham/putty/wishlist/key-formats-natively.html}{the wishlist entry} +\W{https://www.chiark.greenend.org.uk/~sgtatham/putty/wishlist/key-formats-natively.html}{the wishlist entry} for reasons why not), but as of 0.53 PuTTYgen can convert both OpenSSH and \cw{ssh.com} private key files into PuTTY's format. @@ -236,7 +236,7 @@ port, or any other port of PuTTY, they were mistaken. We don't. There are some third-party ports to various platforms, mentioned on the -\W{http://www.chiark.greenend.org.uk/~sgtatham/putty/links.html}{Links page of our website}. +\W{https://www.chiark.greenend.org.uk/~sgtatham/putty/links.html}{Links page of our website}. \S{faq-unix}{Question} \I{Unix version}Is there a port to Unix? @@ -323,7 +323,7 @@ for, it might be a long time before any of us get round to learning a new system and doing the port for that. However, some of the work has been done by other people; see the -\W{http://www.chiark.greenend.org.uk/~sgtatham/putty/links.html}{Links page of our website} +\W{https://www.chiark.greenend.org.uk/~sgtatham/putty/links.html}{Links page of our website} for various third-party ports. \S{faq-iphone}{Question} Will there be a port to the iPhone? @@ -351,7 +351,7 @@ Most of the code cleanup work would be a good thing to happen in general, so if anyone feels like helping, we wouldn't say no. See also -\W{http://www.chiark.greenend.org.uk/~sgtatham/putty/wishlist/dll-frontend.html}{the wishlist entry}. +\W{https://www.chiark.greenend.org.uk/~sgtatham/putty/wishlist/dll-frontend.html}{the wishlist entry}. \S{faq-vb}{Question} Is the SSH or Telnet code available as a Visual Basic component? @@ -891,7 +891,7 @@ us \q{I wanted the F1 key to send \c{^[[11~}, but instead it's sending \c{^[OP}, can this be done?}, or something similar. You should still read the -\W{http://www.chiark.greenend.org.uk/~sgtatham/putty/feedback.html}{Feedback +\W{https://www.chiark.greenend.org.uk/~sgtatham/putty/feedback.html}{Feedback page} on the PuTTY website (also provided as \k{feedback} in the manual), and follow the guidelines contained in that. @@ -1060,7 +1060,7 @@ still. We do not recommend it.) This is caused by a bug in certain versions of \i{Windows XP} which is triggered by PuTTY 0.58. This was fixed in 0.59. The -\W{http://www.chiark.greenend.org.uk/~sgtatham/putty/wishlist/xp-wont-run}{\q{xp-wont-run}} +\W{https://www.chiark.greenend.org.uk/~sgtatham/putty/wishlist/xp-wont-run}{\q{xp-wont-run}} entry in PuTTY's wishlist has more details. \S{faq-system32}{Question} When I put 32-bit PuTTY in diff --git a/doc/feedback.but b/doc/feedback.but index e0854fc5..b8428e41 100644 --- a/doc/feedback.but +++ b/doc/feedback.but @@ -112,7 +112,7 @@ If you think you have found a bug in PuTTY, your first steps should be: \b Check the -\W{http://www.chiark.greenend.org.uk/~sgtatham/putty/wishlist/}{Wishlist +\W{https://www.chiark.greenend.org.uk/~sgtatham/putty/wishlist/}{Wishlist page} on the PuTTY website, and see if we already know about the problem. If we do, it is almost certainly not necessary to mail us about it, unless you think you have extra information that might be @@ -121,12 +121,12 @@ specific extra information about a particular bug, the Wishlist page will say so.) \b Check the -\W{http://www.chiark.greenend.org.uk/~sgtatham/putty/changes.html}{Change +\W{https://www.chiark.greenend.org.uk/~sgtatham/putty/changes.html}{Change Log} on the PuTTY website, and see if we have already fixed the bug in the \i{development snapshots}. \b Check the -\W{http://www.chiark.greenend.org.uk/~sgtatham/putty/faq.html}{FAQ} +\W{https://www.chiark.greenend.org.uk/~sgtatham/putty/faq.html}{FAQ} on the PuTTY website (also provided as \k{faq} in the manual), and see if it answers your question. The FAQ lists the most common things which people think are bugs, but which aren't bugs. @@ -188,7 +188,7 @@ you haven't supplied us with full information about the actual bug, then we won't be able to find a better solution. \b -\W{http://www.chiark.greenend.org.uk/~sgtatham/bugs.html}\cw{http://www.chiark.greenend.org.uk/~sgtatham/bugs.html} +\W{https://www.chiark.greenend.org.uk/~sgtatham/bugs.html}\cw{https://www.chiark.greenend.org.uk/~sgtatham/bugs.html} is an article on how to report bugs effectively in general. If your bug report is \e{particularly} unclear, we may ask you to go away, read this article, and then report the bug again. @@ -224,14 +224,14 @@ If you want to request a new feature in PuTTY, the very first things you should do are: \b Check the -\W{http://www.chiark.greenend.org.uk/~sgtatham/putty/wishlist/}{Wishlist +\W{https://www.chiark.greenend.org.uk/~sgtatham/putty/wishlist/}{Wishlist page} on the PuTTY website, and see if your feature is already on the list. If it is, it probably won't achieve very much to repeat the request. (But see \k{feedback-feature-priority} if you want to persuade us to give your particular feature higher priority.) \b Check the Wishlist and -\W{http://www.chiark.greenend.org.uk/~sgtatham/putty/changes.html}{Change +\W{https://www.chiark.greenend.org.uk/~sgtatham/putty/changes.html}{Change Log} on the PuTTY website, and see if we have already added your feature in the development snapshots. If it isn't clear, download the latest development snapshot and see if the feature is present. @@ -350,7 +350,7 @@ Of course, if the web site has some other error (Connection Refused, If you want to report a problem with our web site, check that you're looking at our \e{real} web site and not a mirror. The real web site is at -\W{http://www.chiark.greenend.org.uk/~sgtatham/putty/}\c{http://www.chiark.greenend.org.uk/~sgtatham/putty/}; +\W{https://www.chiark.greenend.org.uk/~sgtatham/putty/}\c{https://www.chiark.greenend.org.uk/~sgtatham/putty/}; if that's not where you're reading this, then don't report the problem to us until you've checked that it's really a problem with the main site. If it's only a problem with the mirror, you should @@ -399,7 +399,7 @@ setting up a mirror. You already have permission. If the mirror is in a country where we don't already have plenty of mirrors, we may be willing to add it to the list on our -\W{http://www.chiark.greenend.org.uk/~sgtatham/putty/mirrors.html}{mirrors +\W{https://www.chiark.greenend.org.uk/~sgtatham/putty/mirrors.html}{mirrors page}. Read the guidelines on that page, make sure your mirror works, and email us the information listed at the bottom of the page. @@ -414,7 +414,7 @@ to be a cheap way to gain search rankings. If you have technical questions about the process of mirroring, then you might want to mail us before setting up the mirror (see also the -\W{http://www.chiark.greenend.org.uk/~sgtatham/putty/mirrors.html#guidelines}{guidelines on the Mirrors page}); +\W{https://www.chiark.greenend.org.uk/~sgtatham/putty/mirrors.html#guidelines}{guidelines on the Mirrors page}); but if you just want to ask for permission, you don't need to. You already have permission. diff --git a/doc/man-pl.but b/doc/man-pl.but index a46e6a19..9f411871 100644 --- a/doc/man-pl.but +++ b/doc/man-pl.but @@ -260,7 +260,7 @@ exists, nonzero otherwise. For more information on plink, it's probably best to go and look at the manual on the PuTTY web page: -\W{http://www.chiark.greenend.org.uk/~sgtatham/putty/}\cw{http://www.chiark.greenend.org.uk/~sgtatham/putty/} +\W{https://www.chiark.greenend.org.uk/~sgtatham/putty/}\cw{https://www.chiark.greenend.org.uk/~sgtatham/putty/} \S{plink-manpage-bugs} BUGS diff --git a/doc/man-pscp.but b/doc/man-pscp.but index 05e5a23c..6c703e13 100644 --- a/doc/man-pscp.but +++ b/doc/man-pscp.but @@ -174,7 +174,7 @@ encrypted packet data. For more information on \cw{pscp} it's probably best to go and look at the manual on the PuTTY web page: -\W{http://www.chiark.greenend.org.uk/~sgtatham/putty/}\cw{http://www.chiark.greenend.org.uk/~sgtatham/putty/} +\W{https://www.chiark.greenend.org.uk/~sgtatham/putty/}\cw{https://www.chiark.greenend.org.uk/~sgtatham/putty/} \S{pscp-manpage-bugs} BUGS diff --git a/doc/man-psft.but b/doc/man-psft.but index 80d86ecf..51f30d3a 100644 --- a/doc/man-psft.but +++ b/doc/man-psft.but @@ -159,7 +159,7 @@ at the \cw{psftp>} prompt. For more information on \cw{psftp} it's probably best to go and look at the manual on the PuTTY web page: -\cw{http://www.chiark.greenend.org.uk/~sgtatham/putty/} +\cw{https://www.chiark.greenend.org.uk/~sgtatham/putty/} \S{psftp-manpage-bugs} BUGS diff --git a/doc/man-ptel.but b/doc/man-ptel.but index a3b79405..73b85ecc 100644 --- a/doc/man-ptel.but +++ b/doc/man-ptel.but @@ -208,7 +208,7 @@ your home directory. For more information on PuTTY and PuTTYtel, it's probably best to go and look at the manual on the web page: -\W{http://www.chiark.greenend.org.uk/~sgtatham/putty/}\cw{http://www.chiark.greenend.org.uk/~sgtatham/putty/} +\W{https://www.chiark.greenend.org.uk/~sgtatham/putty/}\cw{https://www.chiark.greenend.org.uk/~sgtatham/putty/} \S{puttytel-manpage-bugs} BUGS diff --git a/doc/man-putt.but b/doc/man-putt.but index df7b9e1f..cb7cca47 100644 --- a/doc/man-putt.but +++ b/doc/man-putt.but @@ -321,7 +321,7 @@ your home directory. For more information on PuTTY, it's probably best to go and look at the manual on the web page: -\W{http://www.chiark.greenend.org.uk/~sgtatham/putty/}\cw{http://www.chiark.greenend.org.uk/~sgtatham/putty/} +\W{https://www.chiark.greenend.org.uk/~sgtatham/putty/}\cw{https://www.chiark.greenend.org.uk/~sgtatham/putty/} \S{putty-manpage-bugs} BUGS diff --git a/doc/pgpkeys.but b/doc/pgpkeys.but index 9ec90066..71143af2 100644 --- a/doc/pgpkeys.but +++ b/doc/pgpkeys.but @@ -53,19 +53,19 @@ The current issue of those keys are available for download from the PuTTY website, and are also available on PGP keyservers using the key IDs listed below. -\dt \W{http://www.chiark.greenend.org.uk/~sgtatham/putty/keys/master-2015.asc}{\s{Master Key}} +\dt \W{https://www.chiark.greenend.org.uk/~sgtatham/putty/keys/master-2015.asc}{\s{Master Key}} \dd RSA, 4096-bit. Key ID: \cw{4096R/04676F7C} (long version: \cw{4096R/AB585DC604676F7C}). Fingerprint: \cw{440D\_E3B5\_B7A1\_CA85\_B3CC\_\_1718\_AB58\_5DC6\_0467\_6F7C} -\dt \W{http://www.chiark.greenend.org.uk/~sgtatham/putty/keys/release-2015.asc}{\s{Release Key}} +\dt \W{https://www.chiark.greenend.org.uk/~sgtatham/putty/keys/release-2015.asc}{\s{Release Key}} \dd RSA, 2048-bit. Key ID: \cw{2048R/B43434E4} (long version: \cw{2048R/9DFE2648B43434E4}). Fingerprint: \cw{0054\_DDAA\_8ADA\_15D2\_768A\_\_6DE7\_9DFE\_2648\_B434\_34E4} -\dt \W{http://www.chiark.greenend.org.uk/~sgtatham/putty/keys/contact-2016.asc}{\s{Secure Contact Key}} +\dt \W{https://www.chiark.greenend.org.uk/~sgtatham/putty/keys/contact-2016.asc}{\s{Secure Contact Key}} \dd RSA, 2048-bit. Main key ID: \cw{2048R/8A0AF00B} (long version: \cw{2048R/C4FCAAD08A0AF00B}). Encryption subkey ID: @@ -73,7 +73,7 @@ IDs listed below. Fingerprint: \cw{8A26\_250E\_763F\_E359\_75F3\_\_118F\_C4FC\_AAD0\_8A0A\_F00B} -\dt \W{http://www.chiark.greenend.org.uk/~sgtatham/putty/keys/snapshot-2015.asc}{\s{Snapshot Key}} +\dt \W{https://www.chiark.greenend.org.uk/~sgtatham/putty/keys/snapshot-2015.asc}{\s{Snapshot Key}} \dd RSA, 2048-bit. Key ID: \cw{2048R/D15F7E8A} (long version: \cw{2048R/EEF20295D15F7E8A}). Fingerprint: @@ -179,37 +179,37 @@ Releases prior to the rollover are signed with the old Release Keys. For completeness, those old keys are given here: -\dt \W{http://www.chiark.greenend.org.uk/~sgtatham/putty/keys/master-rsa.asc}{\s{Master Key} (original RSA)} +\dt \W{https://www.chiark.greenend.org.uk/~sgtatham/putty/keys/master-rsa.asc}{\s{Master Key} (original RSA)} \dd RSA, 1024-bit. Key ID: \cw{1024R/1E34AC41} (long version: \cw{1024R/9D5877BF1E34AC41}). Fingerprint: \cw{8F\_15\_97\_DA\_25\_30\_AB\_0D\_\_88\_D1\_92\_54\_11\_CF\_0C\_4C} -\dt \W{http://www.chiark.greenend.org.uk/~sgtatham/putty/keys/master-dsa.asc}{\s{Master Key} (original DSA)} +\dt \W{https://www.chiark.greenend.org.uk/~sgtatham/putty/keys/master-dsa.asc}{\s{Master Key} (original DSA)} \dd DSA, 1024-bit. Key ID: \cw{1024D/6A93B34E} (long version: \cw{1024D/4F5E6DF56A93B34E}). Fingerprint: \cw{313C\_3E76\_4B74\_C2C5\_F2AE\_\_83A8\_4F5E\_6DF5\_6A93\_B34E} -\dt \W{http://www.chiark.greenend.org.uk/~sgtatham/putty/keys/release-rsa.asc}{\s{Release Key} (original RSA)} +\dt \W{https://www.chiark.greenend.org.uk/~sgtatham/putty/keys/release-rsa.asc}{\s{Release Key} (original RSA)} \dd RSA, 1024-bit. Key ID: \cw{1024R/B41CAE29} (long version: \cw{1024R/EF39CCC0B41CAE29}). Fingerprint: \cw{AE\_65\_D3\_F7\_85\_D3\_18\_E0\_\_3B\_0C\_9B\_02\_FF\_3A\_81\_FE} -\dt \W{http://www.chiark.greenend.org.uk/~sgtatham/putty/keys/release-dsa.asc}{\s{Release Key} (original DSA)} +\dt \W{https://www.chiark.greenend.org.uk/~sgtatham/putty/keys/release-dsa.asc}{\s{Release Key} (original DSA)} \dd DSA, 1024-bit. Key ID: \cw{1024D/08B0A90B} (long version: \cw{1024D/FECD6F3F08B0A90B}). Fingerprint: \cw{00B1\_1009\_38E6\_9800\_6518\_\_F0AB\_FECD\_6F3F\_08B0\_A90B} -\dt \W{http://www.chiark.greenend.org.uk/~sgtatham/putty/keys/snapshot-rsa.asc}{\s{Snapshot Key} (original RSA)} +\dt \W{https://www.chiark.greenend.org.uk/~sgtatham/putty/keys/snapshot-rsa.asc}{\s{Snapshot Key} (original RSA)} \dd RSA, 1024-bit. Key ID: \cw{1024R/32B903A9} (long version: \cw{1024R/FAAED21532B903A9}). Fingerprint: \cw{86\_8B\_1F\_79\_9C\_F4\_7F\_BD\_\_8B\_1B\_D7\_8E\_C6\_4E\_4C\_03} -\dt \W{http://www.chiark.greenend.org.uk/~sgtatham/putty/keys/snapshot-dsa.asc}{\s{Snapshot Key} (original DSA)} +\dt \W{https://www.chiark.greenend.org.uk/~sgtatham/putty/keys/snapshot-dsa.asc}{\s{Snapshot Key} (original DSA)} \dd DSA, 1024-bit. Key ID: \cw{1024D/7D3E4A00} (long version: \cw{1024D/165E56F77D3E4A00}). Fingerprint: diff --git a/doc/udp.but b/doc/udp.but index c50464ee..9ca8ed3f 100644 --- a/doc/udp.but +++ b/doc/udp.but @@ -331,7 +331,7 @@ local state structures \c{s} or \c{st} in each function, or the backend-wide structure \c{ssh}. See -\W{http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html}\c{http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html} +\W{https://www.chiark.greenend.org.uk/~sgtatham/coroutines.html}\c{https://www.chiark.greenend.org.uk/~sgtatham/coroutines.html} for a more in-depth discussion of what these macros are for and how they work. diff --git a/ssh.c b/ssh.c index 693f52d8..994e93ae 100644 --- a/ssh.c +++ b/ssh.c @@ -303,7 +303,7 @@ enum { * macros look impenetrable to you, you might find it helpful to * read * - * http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html + * https://www.chiark.greenend.org.uk/~sgtatham/coroutines.html * * which explains the theory behind these macros. * diff --git a/windows/README-msi.txt b/windows/README-msi.txt index a6c2707d..14aac092 100644 --- a/windows/README-msi.txt +++ b/windows/README-msi.txt @@ -35,7 +35,7 @@ What do I do if it doesn't work? The PuTTY home web site is - http://www.chiark.greenend.org.uk/~sgtatham/putty/ + https://www.chiark.greenend.org.uk/~sgtatham/putty/ Here you will find our list of known bugs and pending feature requests. If your problem is not listed in there, or in the FAQ, or diff --git a/windows/README.txt b/windows/README.txt index fa153c62..d929df90 100644 --- a/windows/README.txt +++ b/windows/README.txt @@ -29,7 +29,7 @@ What do I do if it doesn't work? The PuTTY home web site is - http://www.chiark.greenend.org.uk/~sgtatham/putty/ + https://www.chiark.greenend.org.uk/~sgtatham/putty/ Here you will find our list of known bugs and pending feature requests. If your problem is not listed in there, or in the FAQ, or diff --git a/windows/putty.iss b/windows/putty.iss index b3deb76c..3fadcb92 100644 --- a/windows/putty.iss +++ b/windows/putty.iss @@ -19,7 +19,7 @@ VersionInfoTextVersion=Release 0.69 AppVersion=0.69 VersionInfoVersion=0.69.0.0 AppPublisher=Simon Tatham -AppPublisherURL=http://www.chiark.greenend.org.uk/~sgtatham/putty/ +AppPublisherURL=https://www.chiark.greenend.org.uk/~sgtatham/putty/ AppReadmeFile={app}\README.txt DefaultDirName={pf}\PuTTY DefaultGroupName=PuTTY diff --git a/windows/website.url b/windows/website.url index 4b50369cec07713e189e28b5e0724a8dee278eba..4f6d47d1f7136fed66f8bd3d36f26e7315f5496a 100644 GIT binary patch delta 9 QcmYe#m>|tqJW<*Q01toy=Kufz delta 7 Ocmc~upCCO^#s>fjyaIFp diff --git a/windows/windlg.c b/windows/windlg.c index e29f1291..8bd02d85 100644 --- a/windows/windlg.c +++ b/windows/windlg.c @@ -227,7 +227,7 @@ static INT_PTR CALLBACK AboutProc(HWND hwnd, UINT msg, case IDA_WEB: /* Load web browser */ ShellExecute(hwnd, "open", - "http://www.chiark.greenend.org.uk/~sgtatham/putty/", + "https://www.chiark.greenend.org.uk/~sgtatham/putty/", 0, 0, SW_SHOWDEFAULT); return 0; } diff --git a/windows/winpgen.c b/windows/winpgen.c index 2507d37e..7903c1cf 100644 --- a/windows/winpgen.c +++ b/windows/winpgen.c @@ -322,7 +322,7 @@ static INT_PTR CALLBACK AboutProc(HWND hwnd, UINT msg, case 102: /* Load web browser */ ShellExecute(hwnd, "open", - "http://www.chiark.greenend.org.uk/~sgtatham/putty/", + "https://www.chiark.greenend.org.uk/~sgtatham/putty/", 0, 0, SW_SHOWDEFAULT); return 0; } diff --git a/windows/winpgnt.c b/windows/winpgnt.c index 70f3d2ca..ebb6c6ac 100644 --- a/windows/winpgnt.c +++ b/windows/winpgnt.c @@ -178,7 +178,7 @@ static INT_PTR CALLBACK AboutProc(HWND hwnd, UINT msg, case 102: /* Load web browser */ ShellExecute(hwnd, "open", - "http://www.chiark.greenend.org.uk/~sgtatham/putty/", + "https://www.chiark.greenend.org.uk/~sgtatham/putty/", 0, 0, SW_SHOWDEFAULT); return 0; } From ce050c5b72d17559ef79f07b2013b35e2dd22467 Mon Sep 17 00:00:00 2001 From: Ben Harris Date: Mon, 8 May 2017 21:33:03 +0100 Subject: [PATCH 018/607] Fix a luking mention of Win32 in README. --- README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README b/README index 4d73a995..50314ca6 100644 --- a/README +++ b/README @@ -1,4 +1,4 @@ -This is the README for the source archive of PuTTY, a free Win32 +This is the README for the source archive of PuTTY, a free Windows and Unix Telnet and SSH client. If you want to rebuild PuTTY from source, we provide a variety of From 93931b0a568c8f39801ffcb0c67cc001dac4f9b3 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 13 May 2017 17:10:36 +0100 Subject: [PATCH 019/607] Switch to using Halibut's new direct .CHM generation. This allows me to remove HTML Help Workshop completely from my build dependencies, and good riddance! --- Buildscr | 9 +-------- doc/Makefile | 10 ++++------ doc/blurb.but | 6 ++++++ doc/chm.but | 22 ---------------------- 4 files changed, 11 insertions(+), 36 deletions(-) delete mode 100644 doc/chm.but diff --git a/Buildscr b/Buildscr index afcc2766..de7f41b5 100644 --- a/Buildscr +++ b/Buildscr @@ -139,8 +139,7 @@ ifneq "$(MAKEARGS)" "" set Makeargs $(Makeargs) $(MAKEARGS) in putty do ./mksrcarc.sh in putty do ./mkunxarc.sh '$(Autoconfver)' '$(Uxarcsuffix)' $(Docmakever) in putty do perl mkfiles.pl -in putty/doc do make $(Docmakever) putty.hlp -in putty/doc do make $(Docmakever) chm +in putty/doc do make $(Docmakever) putty.hlp putty.chm # Munge the installer script locally so that it reports the version # we're really building. @@ -174,11 +173,6 @@ delegate windows # arguments and sign them all in place. ifneq "$(winsigncode)" "" in putty/windows do $(winsigncode) -i https://www.chiark.greenend.org.uk/~sgtatham/putty/ build*/*.exe - # Ignore exit code from hhc, in favour of seeing whether the .chm - # file was created. (Yuck; but hhc appears to return non-zero - # exit codes on whim.) - in putty/doc with htmlhelp do/win hhc putty.hhp & type putty.chm >nul - # Build a WiX MSI installer, for each of build32 and build64. in putty/windows with wix do/win candle -arch x86 -dWin64=no -dBuilddir=build32\ -dWinver="$(Winver)" -dPuttytextver="$(Puttytextver)" installer.wxs && light -ext WixUIExtension -ext WixUtilExtension -sval installer.wixobj -o installer32.msi in putty/windows with wix do/win candle -arch x64 -dWin64=yes -dBuilddir=build64\ -dWinver="$(Winver)" -dPuttytextver="$(Puttytextver)" installer.wxs && light -ext WixUIExtension -ext WixUtilExtension -sval installer.wixobj -o installer64.msi @@ -196,7 +190,6 @@ delegate windows return putty/windows/build32/*.map return putty/windows/build64/*.exe return putty/windows/build64/*.map - return putty/doc/putty.chm return putty/windows/installer32.msi return putty/windows/installer64.msi return putty/windows/Output/installer.exe diff --git a/doc/Makefile b/doc/Makefile index e7bf287e..cb079fb5 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -44,19 +44,17 @@ INPUTS = $(patsubst %,%.but,$(CHAPTERS)) HALIBUT = halibut index.html: $(INPUTS) - $(HALIBUT) --text --html --winhelp $(INPUTS) + $(HALIBUT) --text --html --winhelp --chm $(INPUTS) -# During formal builds it's useful to be able to build this one alone. +# During formal builds it's useful to be able to build these ones alone. putty.hlp: $(INPUTS) $(HALIBUT) --winhelp $(INPUTS) +putty.chm: $(INPUTS) + $(HALIBUT) --chm $(INPUTS) putty.info: $(INPUTS) $(HALIBUT) --info $(INPUTS) -chm: putty.hhp -putty.hhp: $(INPUTS) chm.but - $(HALIBUT) --html $(INPUTS) chm.but - MKMAN = $(HALIBUT) --man=$@ mancfg.but $< MANPAGES = putty.1 puttygen.1 plink.1 pscp.1 psftp.1 puttytel.1 pterm.1 \ pageant.1 diff --git a/doc/blurb.but b/doc/blurb.but index 64e8ab74..e5e03a60 100644 --- a/doc/blurb.but +++ b/doc/blurb.but @@ -14,10 +14,16 @@ page.

} \cfg{info-max-file-size}{0} +\cfg{chm-contents-filename}{index.html} +\cfg{chm-template-filename}{%k.html} +\cfg{chm-head-end}{} +\cfg{chm-extra-file}{chm.css} + \cfg{xhtml-contents-filename}{index.html} \cfg{text-filename}{puttydoc.txt} \cfg{winhelp-filename}{putty.hlp} \cfg{info-filename}{putty.info} +\cfg{chm-filename}{putty.chm} PuTTY is a free (MIT-licensed) Windows Telnet and SSH client. This manual documents PuTTY, and its companion utilities PSCP, PSFTP, diff --git a/doc/chm.but b/doc/chm.but deleted file mode 100644 index 44d1dca3..00000000 --- a/doc/chm.but +++ /dev/null @@ -1,22 +0,0 @@ -\# File containing the magic HTML configuration directives to create -\# an MS HTML Help project. We put this on the end of the PuTTY -\# docs build command line to build the HHP and friends. - -\cfg{html-leaf-level}{infinite} -\cfg{html-leaf-contains-contents}{false} -\cfg{html-suppress-navlinks}{true} -\cfg{html-suppress-address}{true} - -\cfg{html-contents-filename}{index.html} -\cfg{html-template-filename}{%k.html} -\cfg{html-template-fragment}{%k} - -\cfg{html-mshtmlhelp-chm}{putty.chm} -\cfg{html-mshtmlhelp-project}{putty.hhp} -\cfg{html-mshtmlhelp-contents}{putty.hhc} -\cfg{html-mshtmlhelp-index}{putty.hhk} - -\cfg{html-body-end}{} - -\cfg{html-head-end}{} - From 95f81227a29a79eeafb6395db159c376cafd6bc2 Mon Sep 17 00:00:00 2001 From: Ben Harris Date: Mon, 30 May 2016 20:40:29 +0100 Subject: [PATCH 020/607] uxplink: remove the "connopen" variable. It had the constant value 1 everywhere that it was read. --- unix/uxplink.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/unix/uxplink.c b/unix/uxplink.c index 2d4259b9..e891d66a 100644 --- a/unix/uxplink.c +++ b/unix/uxplink.c @@ -616,7 +616,6 @@ int main(int argc, char **argv) int *fdlist; int fd; int i, fdcount, fdsize, fdstate; - int connopen; int exitcode; int errors; int use_subsystem = 0; @@ -1027,7 +1026,6 @@ int main(int argc, char **argv) ldisc_create(conf, NULL, back, backhandle, NULL); sfree(realhost); } - connopen = 1; /* * Set up the initial console mode. We don't care if this call @@ -1054,7 +1052,7 @@ int main(int argc, char **argv) FD_SET_MAX(signalpipe[0], maxfd, rset); - if (connopen && !sending && + if (!sending && back->connected(backhandle) && back->sendok(backhandle) && back->sendbuffer(backhandle) < MAX_STDIN_BACKLOG) { @@ -1165,7 +1163,7 @@ int main(int argc, char **argv) char buf[4096]; int ret; - if (connopen && back->connected(backhandle)) { + if (back->connected(backhandle)) { ret = read(STDIN_FILENO, buf, sizeof(buf)); if (ret < 0) { perror("stdin: read"); @@ -1192,7 +1190,7 @@ int main(int argc, char **argv) run_toplevel_callbacks(); - if ((!connopen || !back->connected(backhandle)) && + if (!back->connected(backhandle) && bufchain_size(&stdout_data) == 0 && bufchain_size(&stderr_data) == 0) break; /* we closed the connection */ From 30cdaa7ca8bfa03d90e170c2260d71a5819996b2 Mon Sep 17 00:00:00 2001 From: Ben Harris Date: Mon, 30 May 2016 22:37:32 +0100 Subject: [PATCH 021/607] unix: make select_result() return void. Nothing was using its return value anyway. --- unix/unix.h | 2 +- unix/uxsel.c | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/unix/unix.h b/unix/unix.h index 7ab2ca24..68f749ac 100644 --- a/unix/unix.h +++ b/unix/unix.h @@ -183,7 +183,7 @@ void uxsel_init(void); typedef int (*uxsel_callback_fn)(int fd, int event); void uxsel_set(int fd, int rwx, uxsel_callback_fn callback); void uxsel_del(int fd); -int select_result(int fd, int event); +void select_result(int fd, int event); int first_fd(int *state, int *rwx); int next_fd(int *state, int *rwx); /* The following are expected to be provided _to_ uxsel.c by the frontend */ diff --git a/unix/uxsel.c b/unix/uxsel.c index ef25cdb5..52f346a4 100644 --- a/unix/uxsel.c +++ b/unix/uxsel.c @@ -111,7 +111,7 @@ int first_fd(int *state, int *rwx) return next_fd(state, rwx); } -int select_result(int fd, int event) +void select_result(int fd, int event) { struct fd *fdstruct = find234(fds, &fd, uxsel_fd_findcmp); /* @@ -120,7 +120,5 @@ int select_result(int fd, int event) * fd I've stopped being interested in. Sigh. */ if (fdstruct) - return fdstruct->callback(fd, event); - else - return 1; + fdstruct->callback(fd, event); } From d56496c31c85767b805f261f01fc87cc8a468dec Mon Sep 17 00:00:00 2001 From: Ben Harris Date: Mon, 30 May 2016 22:52:30 +0100 Subject: [PATCH 022/607] unix: make uxsel callback functions return void. Nothing used their return values anyway. At least, not after the previous commit. --- unix/unix.h | 2 +- unix/uxagentc.c | 7 +++---- unix/uxnet.c | 24 +++++++++++------------- unix/uxproxy.c | 15 ++++++--------- unix/uxpty.c | 13 ++++--------- unix/uxser.c | 12 +++++------- 6 files changed, 30 insertions(+), 43 deletions(-) diff --git a/unix/unix.h b/unix/unix.h index 68f749ac..f21d23ff 100644 --- a/unix/unix.h +++ b/unix/unix.h @@ -180,7 +180,7 @@ void postmsg(struct termios *); /* The interface used by uxsel.c */ typedef struct uxsel_id uxsel_id; void uxsel_init(void); -typedef int (*uxsel_callback_fn)(int fd, int event); +typedef void (*uxsel_callback_fn)(int fd, int event); void uxsel_set(int fd, int rwx, uxsel_callback_fn callback); void uxsel_del(int fd); void select_result(int fd, int event); diff --git a/unix/uxagentc.c b/unix/uxagentc.c index ffc5879c..51f9a1eb 100644 --- a/unix/uxagentc.c +++ b/unix/uxagentc.c @@ -98,7 +98,7 @@ void agent_cancel_query(agent_pending_query *conn) sfree(conn); } -static int agent_select_result(int fd, int event) +static void agent_select_result(int fd, int event) { agent_pending_query *conn; @@ -107,11 +107,11 @@ static int agent_select_result(int fd, int event) conn = find234(agent_pending_queries, &fd, agent_connfind); if (!conn) { uxsel_del(fd); - return 1; + return; } if (!agent_try_read(conn)) - return 0; /* more data to come */ + return; /* more data to come */ /* * We have now completed the agent query. Do the callback, and @@ -120,7 +120,6 @@ static int agent_select_result(int fd, int event) */ conn->callback(conn->callback_ctx, conn->retbuf, conn->retlen); agent_cancel_query(conn); - return 0; } agent_pending_query *agent_query( diff --git a/unix/uxnet.c b/unix/uxnet.c index 79f4fbce..ddcd9228 100644 --- a/unix/uxnet.c +++ b/unix/uxnet.c @@ -1266,7 +1266,7 @@ static void sk_tcp_write_eof(Socket sock) uxsel_tell(s); } -static int net_select_result(int fd, int event) +static void net_select_result(int fd, int event) { int ret; char buf[20480]; /* nice big buffer for plenty of speed */ @@ -1276,7 +1276,7 @@ static int net_select_result(int fd, int event) /* Find the Socket structure */ s = find234(sktree, &fd, cmpforsearch); if (!s) - return 1; /* boggle */ + return; /* boggle */ noise_ultralight(event); @@ -1292,9 +1292,9 @@ static int net_select_result(int fd, int event) ret = recv(s->s, buf, sizeof(buf), MSG_OOB); noise_ultralight(ret); if (ret <= 0) { - return plug_closing(s->plug, - ret == 0 ? "Internal networking trouble" : - strerror(errno), errno, 0); + plug_closing(s->plug, + ret == 0 ? "Internal networking trouble" : + strerror(errno), errno, 0); } else { /* * Receiving actual data on a socket means we can @@ -1305,7 +1305,7 @@ static int net_select_result(int fd, int event) sk_addr_free(s->addr); s->addr = NULL; } - return plug_receive(s->plug, 2, buf, ret); + plug_receive(s->plug, 2, buf, ret); } break; } @@ -1377,11 +1377,11 @@ static int net_select_result(int fd, int event) } } if (ret < 0) { - return plug_closing(s->plug, strerror(errno), errno, 0); + plug_closing(s->plug, strerror(errno), errno, 0); } else if (0 == ret) { s->incomingeof = TRUE; /* stop trying to read now */ uxsel_tell(s); - return plug_closing(s->plug, NULL, 0, 0); + plug_closing(s->plug, NULL, 0, 0); } else { /* * Receiving actual data on a socket means we can @@ -1392,7 +1392,7 @@ static int net_select_result(int fd, int event) sk_addr_free(s->addr); s->addr = NULL; } - return plug_receive(s->plug, atmark ? 0 : 1, buf, ret); + plug_receive(s->plug, atmark ? 0 : 1, buf, ret); } break; case 2: /* writable */ @@ -1430,9 +1430,9 @@ static int net_select_result(int fd, int event) err = try_connect(s); } if (err) - return plug_closing(s->plug, strerror(err), err, 0); + plug_closing(s->plug, strerror(err), err, 0); if (!s->connected) - return 0; /* another async attempt in progress */ + return; /* another async attempt in progress */ } } @@ -1456,8 +1456,6 @@ static int net_select_result(int fd, int event) } break; } - - return 1; } /* diff --git a/unix/uxproxy.c b/unix/uxproxy.c index 3df4cebe..d3a82fa4 100644 --- a/unix/uxproxy.c +++ b/unix/uxproxy.c @@ -33,7 +33,7 @@ struct Socket_localproxy_tag { enum { EOF_NO, EOF_PENDING, EOF_SENT } outgoingeof; }; -static int localproxy_select_result(int fd, int event); +static void localproxy_select_result(int fd, int event); /* * Trees to look up the pipe fds in. @@ -229,7 +229,7 @@ static const char * sk_localproxy_socket_error (Socket s) return ps->error; } -static int localproxy_select_result(int fd, int event) +static void localproxy_select_result(int fd, int event) { Local_Proxy_Socket s; char buf[20480]; @@ -238,7 +238,7 @@ static int localproxy_select_result(int fd, int event) if (!(s = find234(localproxy_by_fromfd, &fd, localproxy_fromfd_find)) && !(s = find234(localproxy_by_fromfd, &fd, localproxy_errfd_find)) && !(s = find234(localproxy_by_tofd, &fd, localproxy_tofd_find)) ) - return 1; /* boggle */ + return; /* boggle */ if (event == 1) { if (fd == s->cmd_err) { @@ -249,21 +249,18 @@ static int localproxy_select_result(int fd, int event) assert(fd == s->from_cmd); ret = read(fd, buf, sizeof(buf)); if (ret < 0) { - return plug_closing(s->plug, strerror(errno), errno, 0); + plug_closing(s->plug, strerror(errno), errno, 0); } else if (ret == 0) { - return plug_closing(s->plug, NULL, 0, 0); + plug_closing(s->plug, NULL, 0, 0); } else { - return plug_receive(s->plug, 0, buf, ret); + plug_receive(s->plug, 0, buf, ret); } } } else if (event == 2) { assert(fd == s->to_cmd); if (localproxy_try_send(s)) plug_sent(s->plug, bufchain_size(&s->pending_output_data)); - return 1; } - - return 1; } Socket platform_new_connection(SockAddr addr, const char *hostname, diff --git a/unix/uxpty.c b/unix/uxpty.c index 39f96f12..618fe9bd 100644 --- a/unix/uxpty.c +++ b/unix/uxpty.c @@ -572,7 +572,7 @@ void pty_pre_init(void) } -int pty_real_select_result(Pty pty, int event, int status) +void pty_real_select_result(Pty pty, int event, int status) { char buf[4096]; int ret; @@ -672,13 +672,10 @@ int pty_real_select_result(Pty pty, int event, int status) notify_remote_exit(pty->frontend); } - - return !finished; } -int pty_select_result(int fd, int event) +void pty_select_result(int fd, int event) { - int ret = TRUE; Pty pty; if (fd == pty_signal_pipe[0]) { @@ -696,16 +693,14 @@ int pty_select_result(int fd, int event) pty = find234(ptys_by_pid, &pid, pty_find_by_pid); if (pty) - ret = ret && pty_real_select_result(pty, -1, status); + pty_real_select_result(pty, -1, status); } while (pid > 0); } else { pty = find234(ptys_by_fd, &fd, pty_find_by_fd); if (pty) - ret = ret && pty_real_select_result(pty, event, 0); + pty_real_select_result(pty, event, 0); } - - return ret; } static void pty_uxsel_setup(Pty pty) diff --git a/unix/uxser.c b/unix/uxser.c index 41beaf0e..e77f797a 100644 --- a/unix/uxser.c +++ b/unix/uxser.c @@ -56,7 +56,7 @@ static int serial_find_by_fd(void *av, void *bv) static tree234 *serial_by_fd = NULL; -static int serial_select_result(int fd, int event); +static void serial_select_result(int fd, int event); static void serial_uxsel_setup(Serial serial); static void serial_try_write(Serial serial); @@ -366,7 +366,7 @@ static void serial_reconfig(void *handle, Conf *conf) serial_configure(serial, conf); } -static int serial_select_result(int fd, int event) +static void serial_select_result(int fd, int event) { Serial serial; char buf[4096]; @@ -376,7 +376,7 @@ static int serial_select_result(int fd, int event) serial = find234(serial_by_fd, &fd, serial_find_by_fd); if (!serial) - return 1; /* spurious event; keep going */ + return; /* spurious event; keep going */ if (event == 1) { ret = read(serial->fd, buf, sizeof(buf)); @@ -391,11 +391,11 @@ static int serial_select_result(int fd, int event) } else if (ret < 0) { #ifdef EAGAIN if (errno == EAGAIN) - return 1; /* spurious */ + return; /* spurious */ #endif #ifdef EWOULDBLOCK if (errno == EWOULDBLOCK) - return 1; /* spurious */ + return; /* spurious */ #endif perror("read serial port"); exit(1); @@ -417,8 +417,6 @@ static int serial_select_result(int fd, int event) notify_remote_exit(serial->frontend); } - - return !finished; } static void serial_uxsel_setup(Serial serial) From f65c31667e0dee8d416df41dac66198a80c3314b Mon Sep 17 00:00:00 2001 From: Ben Harris Date: Mon, 30 May 2016 20:47:04 +0100 Subject: [PATCH 023/607] winplink: remove "connopen" variable. It's redundant with back->connected(): only the SSH backend has a receive function that can ever return 0, and whenever ssh_receive returns 0 it has called ssh_do_close, which will cause future calls to ssh_connected also to return 0. Similarly, all backend closing functions ensure that future calls to their connected function will return 0. --- windows/winplink.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/windows/winplink.c b/windows/winplink.c index 47470777..a1a8dda0 100644 --- a/windows/winplink.c +++ b/windows/winplink.c @@ -87,7 +87,6 @@ void cmdline_error(const char *p, ...) HANDLE inhandle, outhandle, errhandle; struct handle *stdin_handle, *stdout_handle, *stderr_handle; DWORD orig_console_mode; -int connopen; WSAEVENT netevent; @@ -267,7 +266,7 @@ int stdin_gotdata(struct handle *h, void *data, int len) cleanup_exit(0); } noise_ultralight(len); - if (connopen && back->connected(backhandle)) { + if (back->connected(backhandle)) { if (len > 0) { return back->send(backhandle, data, len); } else { @@ -294,7 +293,7 @@ void stdouterr_sent(struct handle *h, int new_backlog) (h == stdout_handle ? "output" : "error"), buf); cleanup_exit(0); } - if (connopen && back->connected(backhandle)) { + if (back->connected(backhandle)) { back->unthrottle(backhandle, (handle_backlog(stdout_handle) + handle_backlog(stderr_handle))); } @@ -662,7 +661,6 @@ int main(int argc, char **argv) back->provide_logctx(backhandle, logctx); sfree(realhost); } - connopen = 1; inhandle = GetStdHandle(STD_INPUT_HANDLE); outhandle = GetStdHandle(STD_OUTPUT_HANDLE); @@ -782,7 +780,7 @@ int main(int argc, char **argv) LPARAM lp; int err = things.iErrorCode[eventtypes[e].bit]; lp = WSAMAKESELECTREPLY(eventtypes[e].mask, err); - connopen &= select_result(wp, lp); + select_result(wp, lp); } } } @@ -810,7 +808,7 @@ int main(int argc, char **argv) if (sending) handle_unthrottle(stdin_handle, back->sendbuffer(backhandle)); - if ((!connopen || !back->connected(backhandle)) && + if (!back->connected(backhandle) && handle_backlog(stdout_handle) + handle_backlog(stderr_handle) == 0) break; /* we closed the connection */ } From 70e2e140f054f5cd894d0fd7f2c31a23cd7f7377 Mon Sep 17 00:00:00 2001 From: Ben Harris Date: Thu, 2 Jun 2016 22:37:36 +0100 Subject: [PATCH 024/607] windows: Remove spurious redeclarations of select_result(). --- windows/winplink.c | 1 - windows/winsftp.c | 2 -- 2 files changed, 3 deletions(-) diff --git a/windows/winplink.c b/windows/winplink.c index a1a8dda0..ea417501 100644 --- a/windows/winplink.c +++ b/windows/winplink.c @@ -727,7 +727,6 @@ int main(int argc, char **argv) WSANETWORKEVENTS things; SOCKET socket; extern SOCKET first_socket(int *), next_socket(int *); - extern int select_result(WPARAM, LPARAM); int i, socketstate; /* diff --git a/windows/winsftp.c b/windows/winsftp.c index e25d7e06..4558e5a9 100644 --- a/windows/winsftp.c +++ b/windows/winsftp.c @@ -498,7 +498,6 @@ char *do_select(SOCKET skt, int startup) } return NULL; } -extern int select_result(WPARAM, LPARAM); int do_eventsel_loop(HANDLE other_event) { @@ -547,7 +546,6 @@ int do_eventsel_loop(HANDLE other_event) WSANETWORKEVENTS things; SOCKET socket; extern SOCKET first_socket(int *), next_socket(int *); - extern int select_result(WPARAM, LPARAM); int i, socketstate; /* From a2fb1d96ef4660f94c2bed6cad1749c10013d351 Mon Sep 17 00:00:00 2001 From: Ben Harris Date: Thu, 2 Jun 2016 22:38:36 +0100 Subject: [PATCH 025/607] windows: Make select_result() return void. Nothing now uses its return value anyway. --- windows/winnet.c | 33 +++++++++++++-------------------- windows/winstuff.h | 2 +- 2 files changed, 14 insertions(+), 21 deletions(-) diff --git a/windows/winnet.c b/windows/winnet.c index fc26c3e5..0ec64a55 100644 --- a/windows/winnet.c +++ b/windows/winnet.c @@ -1625,9 +1625,9 @@ static void sk_tcp_write_eof(Socket sock) try_send(s); } -int select_result(WPARAM wParam, LPARAM lParam) +void select_result(WPARAM wParam, LPARAM lParam) { - int ret, open; + int ret; DWORD err; char buf[20480]; /* nice big buffer for plenty of speed */ Actual_Socket s; @@ -1636,11 +1636,11 @@ int select_result(WPARAM wParam, LPARAM lParam) /* wParam is the socket itself */ if (wParam == 0) - return 1; /* boggle */ + return; /* boggle */ s = find234(sktree, (void *) wParam, cmpforsearch); if (!s) - return 1; /* boggle */ + return; /* boggle */ if ((err = WSAGETSELECTERROR(lParam)) != 0) { /* @@ -1657,9 +1657,8 @@ int select_result(WPARAM wParam, LPARAM lParam) } } if (err != 0) - return plug_closing(s->plug, winsock_error_string(err), err, 0); - else - return 1; + plug_closing(s->plug, winsock_error_string(err), err, 0); + return; } noise_ultralight(lParam); @@ -1712,12 +1711,11 @@ int select_result(WPARAM wParam, LPARAM lParam) } } if (ret < 0) { - return plug_closing(s->plug, winsock_error_string(err), err, - 0); + plug_closing(s->plug, winsock_error_string(err), err, 0); } else if (0 == ret) { - return plug_closing(s->plug, NULL, 0, 0); + plug_closing(s->plug, NULL, 0, 0); } else { - return plug_receive(s->plug, atmark ? 0 : 1, buf, ret); + plug_receive(s->plug, atmark ? 0 : 1, buf, ret); } break; case FD_OOB: @@ -1737,7 +1735,7 @@ int select_result(WPARAM wParam, LPARAM lParam) logevent(NULL, str); fatalbox("%s", str); } else { - return plug_receive(s->plug, 2, buf, ret); + plug_receive(s->plug, 2, buf, ret); } break; case FD_WRITE: @@ -1753,23 +1751,20 @@ int select_result(WPARAM wParam, LPARAM lParam) break; case FD_CLOSE: /* Signal a close on the socket. First read any outstanding data. */ - open = 1; do { ret = p_recv(s->s, buf, sizeof(buf), 0); if (ret < 0) { err = p_WSAGetLastError(); if (err == WSAEWOULDBLOCK) break; - return plug_closing(s->plug, winsock_error_string(err), - err, 0); + plug_closing(s->plug, winsock_error_string(err), err, 0); } else { if (ret) - open &= plug_receive(s->plug, 0, buf, ret); + plug_receive(s->plug, 0, buf, ret); else - open &= plug_closing(s->plug, NULL, 0, 0); + plug_closing(s->plug, NULL, 0, 0); } } while (ret > 0); - return open; case FD_ACCEPT: { #ifdef NO_IPV6 @@ -1807,8 +1802,6 @@ int select_result(WPARAM wParam, LPARAM lParam) } } } - - return 1; } /* diff --git a/windows/winstuff.h b/windows/winstuff.h index f8c4243f..dfa032f4 100644 --- a/windows/winstuff.h +++ b/windows/winstuff.h @@ -284,7 +284,7 @@ GLOBAL void *logctx; /* * Exports from winnet.c. */ -extern int select_result(WPARAM, LPARAM); +extern void select_result(WPARAM, LPARAM); /* * winnet.c dynamically loads WinSock 2 or WinSock 1 depending on From 0d9c7d82e8506d9b6da557cfaf8a08bc3bfeb299 Mon Sep 17 00:00:00 2001 From: Ben Harris Date: Sat, 4 Jun 2016 15:42:06 +0100 Subject: [PATCH 026/607] Don't treat plug_closing() and plug_receive() as returning backlog. plug_receive() and plug_closing() return 0 or 1 depending on whether they think the main connection has closed. It is not appropriate, as handle_gotdata and handle_socket_unfreeze did, to treat them as returning a backlog. In fact, plugs are unusual in PuTTY in not reporting a backlog, but just calling into the socket to freeze and unfreeze it as required. --- windows/winhsock.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/windows/winhsock.c b/windows/winhsock.c index c8cb46f6..799fd28d 100644 --- a/windows/winhsock.c +++ b/windows/winhsock.c @@ -54,10 +54,11 @@ static int handle_gotdata(struct handle *h, void *data, int len) Handle_Socket ps = (Handle_Socket) handle_get_privdata(h); if (len < 0) { - return plug_closing(ps->plug, "Read error from handle", - 0, 0); + plug_closing(ps->plug, "Read error from handle", 0, 0); + return 0; } else if (len == 0) { - return plug_closing(ps->plug, NULL, 0, 0); + plug_closing(ps->plug, NULL, 0, 0); + return 0; } else { assert(ps->frozen != FROZEN && ps->frozen != THAWING); if (ps->frozen == FREEZING) { @@ -76,7 +77,8 @@ static int handle_gotdata(struct handle *h, void *data, int len) */ return INT_MAX; } else { - return plug_receive(ps->plug, 0, data, len); + plug_receive(ps->plug, 0, data, len); + return 0; } } } @@ -168,7 +170,7 @@ static void handle_socket_unfreeze(void *psv) { Handle_Socket ps = (Handle_Socket) psv; void *data; - int len, new_backlog; + int len; /* * If we've been put into a state other than THAWING since the @@ -188,7 +190,7 @@ static void handle_socket_unfreeze(void *psv) * have the effect of trying to close this socket. */ ps->defer_close = TRUE; - new_backlog = plug_receive(ps->plug, 0, data, len); + plug_receive(ps->plug, 0, data, len); bufchain_consume(&ps->inputdata, len); ps->defer_close = FALSE; if (ps->deferred_close) { @@ -207,7 +209,7 @@ static void handle_socket_unfreeze(void *psv) * Otherwise, we've successfully thawed! */ ps->frozen = UNFROZEN; - handle_unthrottle(ps->recv_h, new_backlog); + handle_unthrottle(ps->recv_h, 0); } } From 0d57b8a4d9c8f487c6a8806384cb2c485161d19c Mon Sep 17 00:00:00 2001 From: Ben Harris Date: Thu, 2 Jun 2016 23:03:24 +0100 Subject: [PATCH 027/607] Make plug receive and closing functions return void instead of int. Nothing was paying attention to their return values any more anyway. --- network.h | 4 ++-- pageant.c | 18 ++++++++---------- portfwd.c | 25 ++++++++++--------------- proxy.c | 41 +++++++++++++++++++++-------------------- raw.c | 8 +++----- rlogin.c | 8 +++----- ssh.c | 9 +++------ sshshare.c | 25 +++++++++++-------------- telnet.c | 8 +++----- unix/uxpgnt.c | 7 +++---- x11fwd.c | 18 ++++++------------ 11 files changed, 73 insertions(+), 98 deletions(-) diff --git a/network.h b/network.h index d58635b6..0941f721 100644 --- a/network.h +++ b/network.h @@ -64,12 +64,12 @@ struct plug_function_table { * proxy command, so the receiver should probably prefix it to * indicate this. */ - int (*closing) + void (*closing) (Plug p, const char *error_msg, int error_code, int calling_back); /* error_msg is NULL iff it is not an error (ie it closed normally) */ /* calling_back != 0 iff there is a Plug function */ /* currently running (would cure the fixme in try_send()) */ - int (*receive) (Plug p, int urgent, char *data, int len); + void (*receive) (Plug p, int urgent, char *data, int len); /* * - urgent==0. `data' points to `len' bytes of perfectly * ordinary data. diff --git a/pageant.c b/pageant.c index 36671725..a168e522 100644 --- a/pageant.c +++ b/pageant.c @@ -964,11 +964,11 @@ int pageant_delete_ssh2_key(struct ssh2_userkey *skey) * Coroutine macros similar to, but simplified from, those in ssh.c. */ #define crBegin(v) { int *crLine = &v; switch(v) { case 0:; -#define crFinish(z) } *crLine = 0; return (z); } +#define crFinishV } *crLine = 0; return; } #define crGetChar(c) do \ { \ while (len == 0) { \ - *crLine =__LINE__; return 1; case __LINE__:; \ + *crLine =__LINE__; return; case __LINE__:; \ } \ len--; \ (c) = (unsigned char)*data++; \ @@ -987,8 +987,8 @@ struct pageant_conn_state { int crLine; /* for coroutine in pageant_conn_receive */ }; -static int pageant_conn_closing(Plug plug, const char *error_msg, - int error_code, int calling_back) +static void pageant_conn_closing(Plug plug, const char *error_msg, + int error_code, int calling_back) { struct pageant_conn_state *pc = (struct pageant_conn_state *)plug; if (error_msg) @@ -997,7 +997,6 @@ static int pageant_conn_closing(Plug plug, const char *error_msg, plog(pc->logctx, pc->logfn, "%p: connection closed", pc); sk_close(pc->connsock); sfree(pc); - return 1; } static void pageant_conn_sent(Plug plug, int bufsize) @@ -1021,7 +1020,7 @@ static void pageant_conn_log(void *logctx, const char *fmt, va_list ap) sfree(formatted); } -static int pageant_conn_receive(Plug plug, int urgent, char *data, int len) +static void pageant_conn_receive(Plug plug, int urgent, char *data, int len) { struct pageant_conn_state *pc = (struct pageant_conn_state *)plug; char c; @@ -1065,7 +1064,7 @@ static int pageant_conn_receive(Plug plug, int urgent, char *data, int len) } } - crFinish(1); + crFinishV; } struct pageant_listen_state { @@ -1077,15 +1076,14 @@ struct pageant_listen_state { pageant_logfn_t logfn; }; -static int pageant_listen_closing(Plug plug, const char *error_msg, - int error_code, int calling_back) +static void pageant_listen_closing(Plug plug, const char *error_msg, + int error_code, int calling_back) { struct pageant_listen_state *pl = (struct pageant_listen_state *)plug; if (error_msg) plog(pl->logctx, pl->logfn, "listening socket: error: %s", error_msg); sk_close(pl->listensock); pl->listensock = NULL; - return 1; } static int pageant_listen_accepting(Plug plug, diff --git a/portfwd.c b/portfwd.c index 8a73a182..febd8af9 100644 --- a/portfwd.c +++ b/portfwd.c @@ -117,8 +117,8 @@ static void pfl_log(Plug plug, int type, SockAddr addr, int port, /* we have to dump these since we have no interface to logging.c */ } -static int pfd_closing(Plug plug, const char *error_msg, int error_code, - int calling_back) +static void pfd_closing(Plug plug, const char *error_msg, int error_code, + int calling_back) { struct PortForwarding *pf = (struct PortForwarding *) plug; @@ -145,16 +145,13 @@ static int pfd_closing(Plug plug, const char *error_msg, int error_code, if (pf->c) sshfwd_write_eof(pf->c); } - - return 1; } -static int pfl_closing(Plug plug, const char *error_msg, int error_code, - int calling_back) +static void pfl_closing(Plug plug, const char *error_msg, int error_code, + int calling_back) { struct PortListener *pl = (struct PortListener *) plug; pfl_terminate(pl); - return 1; } static void wrap_send_port_open(void *channel, const char *hostname, int port, @@ -172,7 +169,7 @@ static void wrap_send_port_open(void *channel, const char *hostname, int port, sfree(description); } -static int pfd_receive(Plug plug, int urgent, char *data, int len) +static void pfd_receive(Plug plug, int urgent, char *data, int len) { struct PortForwarding *pf = (struct PortForwarding *) plug; if (pf->dynamic) { @@ -204,7 +201,7 @@ static int pfd_receive(Plug plug, int urgent, char *data, int len) data[1] = 91; /* generic `request rejected' */ sk_write(pf->s, data, 8); pfd_close(pf); - return 1; + return; } if (pf->sockslen <= 8) continue; /* haven't started user/hostname */ @@ -320,7 +317,7 @@ static int pfd_receive(Plug plug, int urgent, char *data, int len) reply[1] = 1; /* generic failure */ sk_write(pf->s, (char *) reply, lenof(reply)); pfd_close(pf); - return 1; + return; } /* * Now we have a viable connect request. Switch @@ -350,7 +347,7 @@ static int pfd_receive(Plug plug, int urgent, char *data, int len) reply[1] = 8; /* atype not supported */ sk_write(pf->s, (char *) reply, lenof(reply)); pfd_close(pf); - return 1; + return; } } } @@ -362,9 +359,8 @@ static int pfd_receive(Plug plug, int urgent, char *data, int len) * close the connection rudely. */ pfd_close(pf); - return 1; } - return 1; + return; /* * We come here when we're ready to make an actual @@ -383,7 +379,7 @@ static int pfd_receive(Plug plug, int urgent, char *data, int len) pf->c = new_sock_channel(pf->backhandle, pf); if (pf->c == NULL) { pfd_close(pf); - return 1; + return; } else { /* asks to forward to the specified host/port for this */ wrap_send_port_open(pf->c, pf->hostname, pf->port, pf->s); @@ -406,7 +402,6 @@ static int pfd_receive(Plug plug, int urgent, char *data, int len) sk_set_frozen(pf->s, 1); } } - return 1; } static void pfd_sent(Plug plug, int bufsize) diff --git a/proxy.c b/proxy.c index 52006794..68b7e9a0 100644 --- a/proxy.c +++ b/proxy.c @@ -201,8 +201,8 @@ static void plug_proxy_log(Plug plug, int type, SockAddr addr, int port, plug_log(ps->plug, type, addr, port, error_msg, error_code); } -static int plug_proxy_closing (Plug p, const char *error_msg, - int error_code, int calling_back) +static void plug_proxy_closing (Plug p, const char *error_msg, + int error_code, int calling_back) { Proxy_Plug pp = (Proxy_Plug) p; Proxy_Socket ps = pp->proxy_socket; @@ -211,13 +211,13 @@ static int plug_proxy_closing (Plug p, const char *error_msg, ps->closing_error_msg = error_msg; ps->closing_error_code = error_code; ps->closing_calling_back = calling_back; - return ps->negotiate(ps, PROXY_CHANGE_CLOSING); + ps->negotiate(ps, PROXY_CHANGE_CLOSING); + } else { + plug_closing(ps->plug, error_msg, error_code, calling_back); } - return plug_closing(ps->plug, error_msg, - error_code, calling_back); } -static int plug_proxy_receive (Plug p, int urgent, char *data, int len) +static void plug_proxy_receive (Plug p, int urgent, char *data, int len) { Proxy_Plug pp = (Proxy_Plug) p; Proxy_Socket ps = pp->proxy_socket; @@ -231,9 +231,10 @@ static int plug_proxy_receive (Plug p, int urgent, char *data, int len) ps->receive_urgent = urgent; ps->receive_data = data; ps->receive_len = len; - return ps->negotiate(ps, PROXY_CHANGE_RECEIVE); + ps->negotiate(ps, PROXY_CHANGE_RECEIVE); + } else { + plug_receive(ps->plug, urgent, data, len); } - return plug_receive(ps->plug, urgent, data, len); } static void plug_proxy_sent (Plug p, int bufsize) @@ -644,9 +645,9 @@ int proxy_http_negotiate (Proxy_Socket p, int change) * a socket close, then some error must have occurred. we'll * just pass those errors up to the backend. */ - return plug_closing(p->plug, p->closing_error_msg, - p->closing_error_code, - p->closing_calling_back); + plug_closing(p->plug, p->closing_error_msg, p->closing_error_code, + p->closing_calling_back); + return 0; /* ignored */ } if (change == PROXY_CHANGE_SENT) { @@ -847,9 +848,9 @@ int proxy_socks4_negotiate (Proxy_Socket p, int change) * a socket close, then some error must have occurred. we'll * just pass those errors up to the backend. */ - return plug_closing(p->plug, p->closing_error_msg, - p->closing_error_code, - p->closing_calling_back); + plug_closing(p->plug, p->closing_error_msg, p->closing_error_code, + p->closing_calling_back); + return 0; /* ignored */ } if (change == PROXY_CHANGE_SENT) { @@ -987,9 +988,9 @@ int proxy_socks5_negotiate (Proxy_Socket p, int change) * a socket close, then some error must have occurred. we'll * just pass those errors up to the backend. */ - return plug_closing(p->plug, p->closing_error_msg, - p->closing_error_code, - p->closing_calling_back); + plug_closing(p->plug, p->closing_error_msg, p->closing_error_code, + p->closing_calling_back); + return 0; /* ignored */ } if (change == PROXY_CHANGE_SENT) { @@ -1561,9 +1562,9 @@ int proxy_telnet_negotiate (Proxy_Socket p, int change) * a socket close, then some error must have occurred. we'll * just pass those errors up to the backend. */ - return plug_closing(p->plug, p->closing_error_msg, - p->closing_error_code, - p->closing_calling_back); + plug_closing(p->plug, p->closing_error_msg, p->closing_error_code, + p->closing_calling_back); + return 0; /* ignored */ } if (change == PROXY_CHANGE_SENT) { diff --git a/raw.c b/raw.c index 0c5445ad..fbc9018d 100644 --- a/raw.c +++ b/raw.c @@ -61,8 +61,8 @@ static void raw_check_close(Raw raw) } } -static int raw_closing(Plug plug, const char *error_msg, int error_code, - int calling_back) +static void raw_closing(Plug plug, const char *error_msg, int error_code, + int calling_back) { Raw raw = (Raw) plug; @@ -92,17 +92,15 @@ static int raw_closing(Plug plug, const char *error_msg, int error_code, raw->sent_console_eof = TRUE; raw_check_close(raw); } - return 0; } -static int raw_receive(Plug plug, int urgent, char *data, int len) +static void raw_receive(Plug plug, int urgent, char *data, int len) { Raw raw = (Raw) plug; c_write(raw, data, len); /* We count 'session start', for proxy logging purposes, as being * when data is received from the network and printed. */ raw->session_started = TRUE; - return 1; } static void raw_sent(Plug plug, int bufsize) diff --git a/rlogin.c b/rlogin.c index eba468da..ff2c0a8f 100644 --- a/rlogin.c +++ b/rlogin.c @@ -53,8 +53,8 @@ static void rlogin_log(Plug plug, int type, SockAddr addr, int port, rlogin->conf, !rlogin->firstbyte); } -static int rlogin_closing(Plug plug, const char *error_msg, int error_code, - int calling_back) +static void rlogin_closing(Plug plug, const char *error_msg, int error_code, + int calling_back) { Rlogin rlogin = (Rlogin) plug; @@ -76,10 +76,9 @@ static int rlogin_closing(Plug plug, const char *error_msg, int error_code, logevent(rlogin->frontend, error_msg); connection_fatal(rlogin->frontend, "%s", error_msg); } /* Otherwise, the remote side closed the connection normally. */ - return 0; } -static int rlogin_receive(Plug plug, int urgent, char *data, int len) +static void rlogin_receive(Plug plug, int urgent, char *data, int len) { Rlogin rlogin = (Rlogin) plug; if (urgent == 2) { @@ -113,7 +112,6 @@ static int rlogin_receive(Plug plug, int urgent, char *data, int len) if (len > 0) c_write(rlogin, data, len); } - return 1; } static void rlogin_sent(Plug plug, int bufsize) diff --git a/ssh.c b/ssh.c index 994e93ae..b6298b03 100644 --- a/ssh.c +++ b/ssh.c @@ -3560,8 +3560,8 @@ void ssh_connshare_log(Ssh ssh, int event, const char *logtext, } } -static int ssh_closing(Plug plug, const char *error_msg, int error_code, - int calling_back) +static void ssh_closing(Plug plug, const char *error_msg, int error_code, + int calling_back) { Ssh ssh = (Ssh) plug; int need_notify = ssh_do_close(ssh, FALSE); @@ -3583,18 +3583,15 @@ static int ssh_closing(Plug plug, const char *error_msg, int error_code, logevent(error_msg); if (!ssh->close_expected || !ssh->clean_exit) connection_fatal(ssh->frontend, "%s", error_msg); - return 0; } -static int ssh_receive(Plug plug, int urgent, char *data, int len) +static void ssh_receive(Plug plug, int urgent, char *data, int len) { Ssh ssh = (Ssh) plug; ssh_gotdata(ssh, (unsigned char *)data, len); if (ssh->state == SSH_STATE_CLOSED) { ssh_do_close(ssh, TRUE); - return 0; } - return 1; } static void ssh_sent(Plug plug, int bufsize) diff --git a/sshshare.c b/sshshare.c index 82c4bd31..59cdad45 100644 --- a/sshshare.c +++ b/sshshare.c @@ -911,8 +911,8 @@ static void share_disconnect(struct ssh_sharing_connstate *cs, share_begin_cleanup(cs); } -static int share_closing(Plug plug, const char *error_msg, int error_code, - int calling_back) +static void share_closing(Plug plug, const char *error_msg, int error_code, + int calling_back) { struct ssh_sharing_connstate *cs = (struct ssh_sharing_connstate *)plug; @@ -935,7 +935,6 @@ static int share_closing(Plug plug, const char *error_msg, int error_code, "Socket error: %s", error_msg); } share_begin_cleanup(cs); - return 1; } static int getstring_inner(const void *vdata, int datalen, @@ -1775,17 +1774,17 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs, * Coroutine macros similar to, but simplified from, those in ssh.c. */ #define crBegin(v) { int *crLine = &v; switch(v) { case 0:; -#define crFinish(z) } *crLine = 0; return (z); } +#define crFinishV } *crLine = 0; return; } #define crGetChar(c) do \ { \ while (len == 0) { \ - *crLine =__LINE__; return 1; case __LINE__:; \ + *crLine =__LINE__; return; case __LINE__:; \ } \ len--; \ (c) = (unsigned char)*data++; \ } while (0) -static int share_receive(Plug plug, int urgent, char *data, int len) +static void share_receive(Plug plug, int urgent, char *data, int len) { struct ssh_sharing_connstate *cs = (struct ssh_sharing_connstate *)plug; static const char expected_verstring_prefix[] = @@ -1858,7 +1857,7 @@ static int share_receive(Plug plug, int urgent, char *data, int len) } dead:; - crFinish(1); + crFinishV; } static void share_sent(Plug plug, int bufsize) @@ -1875,8 +1874,8 @@ static void share_sent(Plug plug, int bufsize) */ } -static int share_listen_closing(Plug plug, const char *error_msg, - int error_code, int calling_back) +static void share_listen_closing(Plug plug, const char *error_msg, + int error_code, int calling_back) { struct ssh_sharing_state *sharestate = (struct ssh_sharing_state *)plug; if (error_msg) @@ -1884,7 +1883,6 @@ static int share_listen_closing(Plug plug, const char *error_msg, "listening socket: %s", error_msg); sk_close(sharestate->listensock); sharestate->listensock = NULL; - return 1; } static void share_send_verstring(struct ssh_sharing_connstate *cs) @@ -2047,10 +2045,9 @@ char *ssh_share_sockname(const char *host, int port, Conf *conf) static void nullplug_socket_log(Plug plug, int type, SockAddr addr, int port, const char *error_msg, int error_code) {} -static int nullplug_closing(Plug plug, const char *error_msg, int error_code, - int calling_back) { return 0; } -static int nullplug_receive(Plug plug, int urgent, char *data, - int len) { return 0; } +static void nullplug_closing(Plug plug, const char *error_msg, int error_code, + int calling_back) {} +static void nullplug_receive(Plug plug, int urgent, char *data, int len) {} static void nullplug_sent(Plug plug, int bufsize) {} int ssh_share_test_for_upstream(const char *host, int port, Conf *conf) diff --git a/telnet.c b/telnet.c index c4b04132..8d03cb7b 100644 --- a/telnet.c +++ b/telnet.c @@ -658,8 +658,8 @@ static void telnet_log(Plug plug, int type, SockAddr addr, int port, telnet->session_started); } -static int telnet_closing(Plug plug, const char *error_msg, int error_code, - int calling_back) +static void telnet_closing(Plug plug, const char *error_msg, int error_code, + int calling_back) { Telnet telnet = (Telnet) plug; @@ -681,17 +681,15 @@ static int telnet_closing(Plug plug, const char *error_msg, int error_code, connection_fatal(telnet->frontend, "%s", error_msg); } /* Otherwise, the remote side closed the connection normally. */ - return 0; } -static int telnet_receive(Plug plug, int urgent, char *data, int len) +static void telnet_receive(Plug plug, int urgent, char *data, int len) { Telnet telnet = (Telnet) plug; if (urgent) telnet->in_synch = TRUE; telnet->session_started = TRUE; do_telnet_read(telnet, data, len); - return 1; } static void telnet_sent(Plug plug, int bufsize) diff --git a/unix/uxpgnt.c b/unix/uxpgnt.c index 41efcbc2..cb85b160 100644 --- a/unix/uxpgnt.c +++ b/unix/uxpgnt.c @@ -183,13 +183,12 @@ void sshfwd_x11_is_local(struct ssh_channel *c) {} */ static void x11_log(Plug p, int type, SockAddr addr, int port, const char *error_msg, int error_code) {} -static int x11_receive(Plug plug, int urgent, char *data, int len) {return 0;} +static void x11_receive(Plug plug, int urgent, char *data, int len) {} static void x11_sent(Plug plug, int bufsize) {} -static int x11_closing(Plug plug, const char *error_msg, int error_code, - int calling_back) +static void x11_closing(Plug plug, const char *error_msg, int error_code, + int calling_back) { time_to_die = TRUE; - return 1; } struct X11Connection { const struct plug_function_table *fn; diff --git a/x11fwd.c b/x11fwd.c index 584116aa..9d0a58de 100644 --- a/x11fwd.c +++ b/x11fwd.c @@ -58,11 +58,9 @@ static int xdmseen_cmp(void *a, void *b) * independent network.c or something */ static void dummy_plug_log(Plug p, int type, SockAddr addr, int port, const char *error_msg, int error_code) { } -static int dummy_plug_closing - (Plug p, const char *error_msg, int error_code, int calling_back) -{ return 1; } -static int dummy_plug_receive(Plug p, int urgent, char *data, int len) -{ return 1; } +static void dummy_plug_closing + (Plug p, const char *error_msg, int error_code, int calling_back) { } +static void dummy_plug_receive(Plug p, int urgent, char *data, int len) { } static void dummy_plug_sent(Plug p, int bufsize) { } static int dummy_plug_accepting(Plug p, accept_fn_t constructor, accept_ctx_t ctx) { return 1; } static const struct plug_function_table dummy_plug = { @@ -616,8 +614,8 @@ static void x11_log(Plug p, int type, SockAddr addr, int port, static void x11_send_init_error(struct X11Connection *conn, const char *err_message); -static int x11_closing(Plug plug, const char *error_msg, int error_code, - int calling_back) +static void x11_closing(Plug plug, const char *error_msg, int error_code, + int calling_back) { struct X11Connection *xconn = (struct X11Connection *) plug; @@ -646,11 +644,9 @@ static int x11_closing(Plug plug, const char *error_msg, int error_code, if (xconn->c) sshfwd_write_eof(xconn->c); } - - return 1; } -static int x11_receive(Plug plug, int urgent, char *data, int len) +static void x11_receive(Plug plug, int urgent, char *data, int len) { struct X11Connection *xconn = (struct X11Connection *) plug; @@ -659,8 +655,6 @@ static int x11_receive(Plug plug, int urgent, char *data, int len) xconn->no_data_sent_to_x_client = FALSE; sk_set_frozen(xconn->s, 1); } - - return 1; } static void x11_sent(Plug plug, int bufsize) From c7b9f846d9d4062dea9eeaca7b15c0a8caf0c73d Mon Sep 17 00:00:00 2001 From: Ben Harris Date: Wed, 17 May 2017 23:02:14 +0100 Subject: [PATCH 028/607] windows: Fix control-flow error in select_result(). When making select_result() return void (a2fb1d9), I removed a "return" at the end of the FD_CLOSE case, causing a fallthrough into FD_ACCEPT with hilarious (segfaulting) consequences. Re-instate the "return". --- windows/winnet.c | 1 + 1 file changed, 1 insertion(+) diff --git a/windows/winnet.c b/windows/winnet.c index 0ec64a55..ea950bba 100644 --- a/windows/winnet.c +++ b/windows/winnet.c @@ -1765,6 +1765,7 @@ void select_result(WPARAM wParam, LPARAM lParam) plug_closing(s->plug, NULL, 0, 0); } } while (ret > 0); + return; case FD_ACCEPT: { #ifdef NO_IPV6 From 12bd5a6c722152aa27f24598785593e72b3284ea Mon Sep 17 00:00:00 2001 From: Jacob Nevins Date: Sat, 20 May 2017 12:44:56 +0100 Subject: [PATCH 029/607] Stop Gtk2 builds exploding on scroll wheel events. More fallout from 64221972c. --- unix/gtkwin.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/unix/gtkwin.c b/unix/gtkwin.c index 67cfcac3..f54289a3 100644 --- a/unix/gtkwin.c +++ b/unix/gtkwin.c @@ -1923,7 +1923,7 @@ gboolean scroll_event(GtkWidget *widget, GdkEventScroll *event, gpointer data) return FALSE; event_button = (GdkEventButton *)gdk_event_new(GDK_BUTTON_PRESS); - event_button->window = event->window; + event_button->window = g_object_ref(event->window); event_button->send_event = event->send_event; event_button->time = event->time; event_button->x = event->x; @@ -1931,7 +1931,7 @@ gboolean scroll_event(GtkWidget *widget, GdkEventScroll *event, gpointer data) event_button->axes = NULL; event_button->state = event->state; event_button->button = button; - event_button->device = event->device; + event_button->device = g_object_ref(event->device); event_button->x_root = event->x_root; event_button->y_root = event->y_root; ret = button_internal(inst, event_button); From 22cf2823d1c5615c259eadf8a3ebb199aba6f2d6 Mon Sep 17 00:00:00 2001 From: Jacob Nevins Date: Tue, 23 May 2017 23:13:17 +0100 Subject: [PATCH 030/607] Remove some ancient cruft from the FAQ. - I haven't heard of OpenSSH/OpenSSL mismatches being a common problem for a long time. Specific advice about OpenSSH 3.1/3.4 seems unlikely to be useful these days. - "Incorrect MAC received on packet" doesn't seem to be a common problem these days, and if anyone encounters it, the words in the "Errors" bit of the docs seem adequate without a FAQ entry as well. --- doc/errors.but | 18 +++++++-------- doc/faq.but | 63 -------------------------------------------------- 2 files changed, 9 insertions(+), 72 deletions(-) diff --git a/doc/errors.but b/doc/errors.but index fdbdd861..8e353fb9 100644 --- a/doc/errors.but +++ b/doc/errors.but @@ -122,9 +122,7 @@ ridiculous amount of memory, and will terminate with an \q{Out of memory} error. This can happen in SSH-2, if PuTTY and the server have not enabled -encryption in the same way (see \k{faq-outofmem} in the FAQ). Some -versions of \i{OpenSSH} have a known problem with this: see -\k{faq-openssh-bad-openssl}. +encryption in the same way (see \k{faq-outofmem} in the FAQ). This can also happen in PSCP or PSFTP, if your \i{login scripts} on the server generate output: the client program will be expecting an SFTP @@ -233,8 +231,13 @@ protection (such as HTTP) will manifest in more subtle failures (such as misdisplayed text or images in a web browser) which may not be noticed. -A known server problem which can cause this error is described in -\k{faq-openssh-bad-openssl} in the FAQ. +Occasionally this has been caused by server bugs. An example is the +bug described at \k{config-ssh-bug-hmac2}, although you're very +unlikely to encounter that one these days. + +In this context MAC stands for \ii{Message Authentication Code}. It's a +cryptographic term, and it has nothing at all to do with Ethernet +MAC (Media Access Control) addresses, or with the Apple computer. \H{errors-garbled} \q{Incoming packet was garbled on decryption} @@ -247,10 +250,7 @@ in the server, or in between. If you get this error, one thing you could try would be to fiddle with the setting of \q{Miscomputes SSH-2 encryption keys} (see \k{config-ssh-bug-derivekey2}) or \q{Ignores SSH-2 maximum packet -size} (see \k{config-ssh-bug-maxpkt2}) on the Bugs panel . - -Another known server problem which can cause this error is described -in \k{faq-openssh-bad-openssl} in the FAQ. +size} (see \k{config-ssh-bug-maxpkt2}) on the Bugs panel. \H{errors-x11-proxy} \q{PuTTY X11 proxy: \e{various errors}} diff --git a/doc/faq.but b/doc/faq.but index 80cf9d63..dbc3fcc9 100644 --- a/doc/faq.but +++ b/doc/faq.but @@ -601,34 +601,6 @@ documentation.) \H{faq-trouble} Troubleshooting -\S{faq-incorrect-mac}{Question} Why do I see \q{Incorrect MAC -received on packet}? - -One possible cause of this that used to be common is a bug in old -SSH-2 servers distributed by \cw{ssh.com}. (This is not the only -possible cause; see \k{errors-crc} in the documentation.) -Version 2.3.0 and below of their SSH-2 server -constructs Message Authentication Codes in the wrong way, and -expects the client to construct them in the same wrong way. PuTTY -constructs the MACs correctly by default, and hence these old -servers will fail to work with it. - -If you are using PuTTY version 0.52 or better, this should work -automatically: PuTTY should detect the buggy servers from their -version number announcement, and automatically start to construct -its MACs in the same incorrect manner as they do, so it will be able -to work with them. - -If you are using PuTTY version 0.51 or below, you can enable the -workaround by going to the SSH panel and ticking the box labelled -\q{Imitate SSH2 MAC bug}. It's possible that you might have to do -this with 0.52 as well, if a buggy server exists that PuTTY doesn't -know about. - -In this context MAC stands for \ii{Message Authentication Code}. It's a -cryptographic term, and it has nothing at all to do with Ethernet -MAC (Media Access Control) addresses. - \S{faq-pscp-protocol}{Question} Why do I see \q{Fatal: Protocol error: Expected control record} in PSCP? @@ -895,41 +867,6 @@ You should still read the page} on the PuTTY website (also provided as \k{feedback} in the manual), and follow the guidelines contained in that. -\S{faq-openssh-bad-openssl}{Question} Since my SSH server was upgraded -to \i{OpenSSH} 3.1p1/3.4p1, I can no longer connect with PuTTY. - -There is a known problem when OpenSSH has been built against an -incorrect version of OpenSSL; the quick workaround is to configure -PuTTY to use SSH protocol 2 and the Blowfish cipher. - -For more details and OpenSSH patches, see -\W{http://bugzilla.mindrot.org/show_bug.cgi?id=138}{bug 138} in the -OpenSSH BTS. - -This is not a PuTTY-specific problem; if you try to connect with -another client you'll likely have similar problems. (Although PuTTY's -default cipher differs from many other clients.) - -\e{OpenSSH 3.1p1:} configurations known to be broken (and symptoms): - -\b SSH-2 with AES cipher (PuTTY says \q{Assertion failed! Expression: -(len & 15) == 0} in \cw{sshaes.c}, or \q{Out of memory}, or crashes) - -\b SSH-2 with 3DES (PuTTY says \q{Incorrect MAC received on packet}) - -\b SSH-1 with Blowfish (PuTTY says \q{Incorrect CRC received on -packet}) - -\b SSH-1 with 3DES - -\e{OpenSSH 3.4p1:} as of 3.4p1, only the problem with SSH-1 and -Blowfish remains. Rebuild your server, apply the patch linked to from -bug 138 above, or use another cipher (e.g., 3DES) instead. - -\e{Other versions:} we occasionally get reports of the same symptom -and workarounds with older versions of OpenSSH, although it's not -clear the underlying cause is the same. - \S{faq-ssh2key-ssh1conn}{Question} Why do I see \q{Couldn't load private key from ...}? Why can PuTTYgen load my key but not PuTTY? From e5dd1435e2f9446d7f131b4b0dd849dcec880aed Mon Sep 17 00:00:00 2001 From: Jacob Nevins Date: Tue, 23 May 2017 23:16:36 +0100 Subject: [PATCH 031/607] Remove FAQ about Plink on Win95. While it's still true, the link to Winsock 2 is dead, our standard release builds don't run on Win95 any more, and it's certainly not frequently asked. --- doc/faq.but | 15 --------------- doc/index.but | 3 --- 2 files changed, 18 deletions(-) diff --git a/doc/faq.but b/doc/faq.but index dbc3fcc9..cd3254a8 100644 --- a/doc/faq.but +++ b/doc/faq.but @@ -636,21 +636,6 @@ Clicking on \q{ANSI Green} won't turn your session green; it will only allow you to adjust the \e{shade} of green used when PuTTY is instructed by the server to display green text. -\S{faq-winsock2}{Question} Plink on \i{Windows 95} says it can't find -\i\cw{WS2_32.DLL}. - -Plink requires the extended Windows network library, WinSock version -2. This is installed as standard on Windows 98 and above, and on -Windows NT, and even on later versions of Windows 95; but early -Win95 installations don't have it. - -In order to use Plink on these systems, you will need to download -the -\W{http://www.microsoft.com/windows95/downloads/contents/wuadmintools/s_wunetworkingtools/w95sockets2/}{WinSock 2 upgrade}: - -\c http://www.microsoft.com/windows95/downloads/contents/ -\c wuadmintools/s_wunetworkingtools/w95sockets2/ - \S{faq-outofmem}{Question} After trying to establish an SSH-2 connection, PuTTY says \q{\ii{Out of memory}} and dies. diff --git a/doc/index.but b/doc/index.but index 1e71234f..30ebd784 100644 --- a/doc/index.but +++ b/doc/index.but @@ -829,9 +829,6 @@ saved sessions from \IM{login scripts}{startup scripts} login scripts \IM{login scripts}{startup scripts} startup scripts -\IM{WS2_32.DLL} \cw{WS2_32.DLL} -\IM{WS2_32.DLL} WinSock version 2 - \IM{Red Hat Linux} Red Hat Linux \IM{Red Hat Linux} Linux, Red Hat From 2e66a0d2601cd4275f039a7cc82c41e4add19f7f Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Wed, 24 May 2017 20:34:38 +0100 Subject: [PATCH 032/607] Fix a build failure under Visual Studio 2010. Patch due to Brian K. White; we now condition our own declaration of DLL_DIRECTORY_COOKIE on whether the toolchain's headers had #defined it already, rather than trying to guess the answer to that from version-number macros. (Apparently everything that defines DLL_DIRECTORY_COOKIE does it by does seem to work in all my tests.) --- windows/winstuff.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/windows/winstuff.h b/windows/winstuff.h index dfa032f4..10fcdaba 100644 --- a/windows/winstuff.h +++ b/windows/winstuff.h @@ -533,8 +533,9 @@ GLOBAL int restricted_acl; #ifndef LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR #define LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR 0x00000100 #endif -#if _MSC_VER < 1400 +#ifndef DLL_DIRECTORY_COOKIE typedef PVOID DLL_DIRECTORY_COOKIE; +DECLSPEC_IMPORT DLL_DIRECTORY_COOKIE WINAPI AddDllDirectory (PCWSTR NewDirectory); #endif /* From 8d2755c55f9d8b854ef9051937ececb23c5a4b23 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Thu, 25 May 2017 08:17:42 +0100 Subject: [PATCH 033/607] Under clang-cl, include stdint.h regardless of _MSC_VER. stdint.h is one of the set of standard C headers that has more to do with the compiler than the library, and hence, clang provides its own version of it, even when you're using it in clang-cl mode with Visual Studio headers, and even when those headers are old enough not to have a stdint.h of their own. So in clang builds, including stdint.h is always the right way to get uintptr_t defined. --- windows/winstuff.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/windows/winstuff.h b/windows/winstuff.h index 10fcdaba..546c273b 100644 --- a/windows/winstuff.h +++ b/windows/winstuff.h @@ -19,7 +19,7 @@ * stddef.h. So here we try to make sure _some_ standard header is * included which defines uintptr_t. */ #include -#if !defined _MSC_VER || _MSC_VER >= 1600 +#if !defined _MSC_VER || _MSC_VER >= 1600 || defined __clang__ #include #endif From f02587f7ac4f47982bf97674f5499dd3b6dede4b Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Thu, 25 May 2017 08:21:19 +0100 Subject: [PATCH 034/607] Makefile.clangcl: provide a way to tell lld-link about crt0.obj. I've been experimenting with using clang-cl with older versions of the Visual Studio libraries and headers, and found that the older VS libraries have a quirk which can cause link failure in a way that doesn't happen with the newer one. I assume the corresponding old VS linker must be doing some kind of special-case handling that lld isn't mimicking. The quirk arises because lld tries to pull in more than one of the *crt0.obj startup objects which set things up before calling main or WinMain (or whatever), and those objects define some of the same symbols as each other. The fix is to explicitly ask for the right one of those objects on the link command line, so that it's already been loaded _before_ the linker starts searching libraries for unresolved symbols; then the disputed symbols are never unresolved in the first place during the library search phase. But this means you have to pick your crt0 object differently depending on which subsystem you're compiling for. Accordingly, here's an extra feature in Makefile.clangcl to make that possible by means of the right definitions on the make command line. --- mkfiles.pl | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/mkfiles.pl b/mkfiles.pl index 8a63c65d..1d83912b 100755 --- a/mkfiles.pl +++ b/mkfiles.pl @@ -492,6 +492,31 @@ sub manpages { # paths in $LIB) it's reasonable to have the choice of # compilation target driven by another environment variable # set in parallel with that one. + # - for older versions of the VS libraries you may also have to + # set EXTRA_console and/or EXTRA_windows to the name of an + # object file manually extracted from one of those libraries. + # * This is because old VS seems to manage its startup code by + # having libcmt.lib contain lots of *crt0.obj objects, one + # for each possible user entry point (main, WinMain and the + # wide-char versions of both), of which the linker arranges + # to include the right one by special-case code. But lld + # only seems to mimic half of that code - it does include + # the right crt0 object, but it doesn't also deliberately + # _avoid_ including the _wrong_ ones, and since all those + # objects define a common set of global symbols for other + # parts of the library to use, lld may well select an + # arbitrary one of them the first time it sees a reference + # to one of those global symbols, and then later also select + # the _right_ one for the application's entry point, causing + # a multiple-definitions crash. + # * So the workaround is to explicitly include the right + # *crt0.obj file on the linker command line before lld even + # begins searching libraries. Hence, for a console + # application, you might extract crt0.obj from the library + # in question and set EXTRA_console=crt0.obj, and for a GUI + # application, do the same with wincrt0.obj. Then this + # makefile will include the right one of those objects + # alongside the matching /subsystem linker option. open OUT, ">$makefiles{'clangcl'}"; select OUT; print @@ -539,7 +564,8 @@ sub manpages { print &splitline("\t\$(LD) \$(LFLAGS) \$(XLFLAGS) ". "/out:\$(BUILDDIR)$prog.exe ". "/lldmap:\$(BUILDDIR)$prog.map ". - "/subsystem:$subsys\$(SUBSYSVER) $objstr")."\n\n"; + "/subsystem:$subsys\$(SUBSYSVER) ". + "\$(EXTRA_$subsys) $objstr")."\n\n"; } foreach $d (&deps("\$(BUILDDIR)X.obj", "\$(BUILDDIR)X.res.o", $dirpfx, "/", "vc")) { $extradeps = $forceobj{$d->{obj_orig}} ? ["*.c","*.h","*.rc"] : []; From eda5364eb476d4771e1f5a35ff81f50b4e309135 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Thu, 25 May 2017 08:22:22 +0100 Subject: [PATCH 035/607] Use / in pathnames in the Wix installer source. I've also been experimenting recently with running Wix on Linux under Mono, rather than running it on Windows in the obvious way. Wix under Mono insists on forward slashes in pathnames, and it turns out that Wix on Windows doesn't object to them either, so I can safely change them over unconditionally and then my installer source will work in both modes. --- windows/installer.wxs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/windows/installer.wxs b/windows/installer.wxs index 4a720e40..e3ed8c71 100644 --- a/windows/installer.wxs +++ b/windows/installer.wxs @@ -191,7 +191,7 @@ https://msdn.microsoft.com/en-us/library/windows/desktop/dd391569(v=vs.85).aspx + Source="../doc/putty.chm" KeyPath="yes"> @@ -209,7 +209,7 @@ https://msdn.microsoft.com/en-us/library/windows/desktop/dd391569(v=vs.85).aspx + Source="../LICENCE" KeyPath="yes" /> From bbdb527d4dc0eeabd083242d10faa1a2aad28e5d Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 27 May 2017 20:05:07 +0100 Subject: [PATCH 036/607] Turn off the Inno Setup installer build. We've been planning to do that for a while, and this installer-builder isn't going to work anyway in the build environment I'm about to move everything to, so this seems like the moment. --- Buildscr | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/Buildscr b/Buildscr index de7f41b5..8bd680df 100644 --- a/Buildscr +++ b/Buildscr @@ -177,11 +177,8 @@ delegate windows in putty/windows with wix do/win candle -arch x86 -dWin64=no -dBuilddir=build32\ -dWinver="$(Winver)" -dPuttytextver="$(Puttytextver)" installer.wxs && light -ext WixUIExtension -ext WixUtilExtension -sval installer.wixobj -o installer32.msi in putty/windows with wix do/win candle -arch x64 -dWin64=yes -dBuilddir=build64\ -dWinver="$(Winver)" -dPuttytextver="$(Puttytextver)" installer.wxs && light -ext WixUIExtension -ext WixUtilExtension -sval installer.wixobj -o installer64.msi - # Build the old Inno Setup installer, for 32-bit only. - in putty/windows with innosetup do/win iscc putty.iss - # Sign the installers. - ifneq "$(winsigncode)" "" in putty/windows do $(winsigncode) -i https://www.chiark.greenend.org.uk/~sgtatham/putty/ -n "PuTTY Installer" installer32.msi installer64.msi Output/installer.exe + ifneq "$(winsigncode)" "" in putty/windows do $(winsigncode) -i https://www.chiark.greenend.org.uk/~sgtatham/putty/ -n "PuTTY Installer" installer32.msi installer64.msi # Finished Windows builds. return putty/windows/buildold/*.exe @@ -192,7 +189,6 @@ delegate windows return putty/windows/build64/*.map return putty/windows/installer32.msi return putty/windows/installer64.msi - return putty/windows/Output/installer.exe enddelegate in putty/doc do make mostlyclean in putty/doc do make $(Docmakever) @@ -210,7 +206,6 @@ deliver putty/windows/build64/*.exe putty/w64/$@ deliver putty/windows/build64/putty.zip putty/w64/$@ deliver putty/windows/installer32.msi putty/w32/$(Ifilename32).msi deliver putty/windows/installer64.msi putty/w64/$(Ifilename64).msi -deliver putty/windows/Output/installer.exe putty/w32/$(Ifilename32).exe deliver putty/doc/puttydoc.zip putty/$@ deliver putty/doc/putty.chm putty/$@ deliver putty/doc/putty.hlp putty/$@ From 599ca6d726fa9c251fda6b45fd5161878a208c53 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 27 May 2017 20:06:11 +0100 Subject: [PATCH 037/607] Build using clang-cl instead of Visual Studio. This permits me to do the binary builds via cross-compilation on Linux, which is nice from a perspective of not having my build environment subject to the same potential pool of Windows malware that might be interested in infecting the resulting binaries. Also, it's quicker to build and the code generation is noticeably better. --- Buildscr | 51 ++++++++++++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/Buildscr b/Buildscr index 8bd680df..4cbf6c41 100644 --- a/Buildscr +++ b/Buildscr @@ -156,37 +156,42 @@ in putty/icons do make in putty do convert -size 164x312 'gradient:blue-white' -distort SRT -90 -swirl 180 \( -size 329x312 canvas:white \) +append \( icons/putty-48.png -geometry +28+24 \) -composite \( icons/pscp-48.png -geometry +88+96 \) -composite \( icons/puttygen-48.png -geometry +28+168 \) -composite \( icons/pageant-48.png -geometry +88+240 \) -composite windows/msidialog.bmp in putty do convert -size 493x58 canvas:white \( icons/putty-48.png -geometry +440+5 \) -composite windows/msibanner.bmp -delegate windows - # Build the original binaries. - in putty/windows with visualstudio do/win mkdir buildold && nmake -f Makefile.vc BUILDDIR=buildold\ $(Makeargs) all cleantestprogs - - # Build the VS2015 binaries. For the 32-bit ones, we set a subsystem - # version of 5.01, which allows the resulting files to still run on - # Windows XP. - in putty/windows with visualstudio2015_32bit do/win mkdir build32 && nmake -f Makefile.vc BUILDDIR=build32\ SUBSYSVER=,5.01 $(Makeargs) all cleantestprogs - in putty/windows with visualstudio2015_64bit do/win mkdir build64 && nmake -f Makefile.vc BUILDDIR=build64\ $(Makeargs) all cleantestprogs - - # Code-sign the binaries, if the local bob config provides a script - # to do so. We assume here that the script accepts an -i option to - # provide a 'more info' URL, and an optional -n option to provide a - # program name, and that it can take multiple .exe filename - # arguments and sign them all in place. - ifneq "$(winsigncode)" "" in putty/windows do $(winsigncode) -i https://www.chiark.greenend.org.uk/~sgtatham/putty/ build*/*.exe +# Build the standard binaries, in both 32- and 64-bit flavours. +# +# For the 32-bit ones, we set a subsystem version of 5.01, which +# allows the resulting files to still run on Windows XP. +in putty/windows with clangcl32 do mkdir build32 && Platform=x86 make -f Makefile.clangcl BUILDDIR=build32/ SUBSYSVER=,5.01 $(Makeargs) all cleantestprogs +in putty/windows with clangcl64 do mkdir build64 && Platform=x64 make -f Makefile.clangcl BUILDDIR=build64/ $(Makeargs) all cleantestprogs + +# Build the 'old' binaries, which should still run on all 32-bit +# versions of Windows back to Win95 (but not Win32s). These link +# against Visual Studio 2003 libraries (the more modern versions +# assume excessively modern Win32 API calls to be available), specify +# a subsystem version of 4.0, and compile with /arch:IA32 to prevent +# the use of modern CPU features like MMX which older machines also +# might not have. +in putty/windows with clangcl32_2003 do mkdir buildold && Platform=x86 make -f Makefile.clangcl BUILDDIR=buildold/ $(Makeargs) CCTARGET=i386-pc-windows-msvc13.0.0 SUBSYSVER=,4.0 EXTRA_windows=wincrt0.obj EXTRA_console=crt0.obj XFLAGS=/arch:IA32 all cleantestprogs + +# Code-sign the Windows binaries, if the local bob config provides a +# script to do so in a cross-compiling way. We assume here that the +# script accepts an -i option to provide a 'more info' URL, an +# optional -n option to provide a program name, and an -N option to +# take the program name from an .exe's version resource, and that it +# can accept multiple .exe or .msi filename arguments and sign them +# all in place. +ifneq "$(cross_winsigncode)" "" in putty/windows do $(cross_winsigncode) -N -i https://www.chiark.greenend.org.uk/~sgtatham/putty/ build*/*.exe +delegate windows # Build a WiX MSI installer, for each of build32 and build64. in putty/windows with wix do/win candle -arch x86 -dWin64=no -dBuilddir=build32\ -dWinver="$(Winver)" -dPuttytextver="$(Puttytextver)" installer.wxs && light -ext WixUIExtension -ext WixUtilExtension -sval installer.wixobj -o installer32.msi in putty/windows with wix do/win candle -arch x64 -dWin64=yes -dBuilddir=build64\ -dWinver="$(Winver)" -dPuttytextver="$(Puttytextver)" installer.wxs && light -ext WixUIExtension -ext WixUtilExtension -sval installer.wixobj -o installer64.msi - # Sign the installers. + # Sign the installers, if the local bob config provides + # $(winsigncode) that can run in a Windows delegation and behaves + # the same as $(cross_winsigncode) used above. ifneq "$(winsigncode)" "" in putty/windows do $(winsigncode) -i https://www.chiark.greenend.org.uk/~sgtatham/putty/ -n "PuTTY Installer" installer32.msi installer64.msi # Finished Windows builds. - return putty/windows/buildold/*.exe - return putty/windows/buildold/*.map - return putty/windows/build32/*.exe - return putty/windows/build32/*.map - return putty/windows/build64/*.exe - return putty/windows/build64/*.map return putty/windows/installer32.msi return putty/windows/installer64.msi enddelegate From fd6898b5865b3f7fcccfe57c6ee272984f52a34f Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 27 May 2017 20:07:00 +0100 Subject: [PATCH 038/607] Build the MSI using Wix run on Linux via Mono. I have a grubby method of getting this to work without Wine, which I intend to get round to publishing just as soon as I finish deciding what its best shape is. But I don't want to wait for that before starting to actually use it, because this eliminates the last trace of Windows in the PuTTY Windows builds. --- Buildscr | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/Buildscr b/Buildscr index 4cbf6c41..ab94ea92 100644 --- a/Buildscr +++ b/Buildscr @@ -181,20 +181,13 @@ in putty/windows with clangcl32_2003 do mkdir buildold && Platform=x86 make -f M # all in place. ifneq "$(cross_winsigncode)" "" in putty/windows do $(cross_winsigncode) -N -i https://www.chiark.greenend.org.uk/~sgtatham/putty/ build*/*.exe -delegate windows - # Build a WiX MSI installer, for each of build32 and build64. - in putty/windows with wix do/win candle -arch x86 -dWin64=no -dBuilddir=build32\ -dWinver="$(Winver)" -dPuttytextver="$(Puttytextver)" installer.wxs && light -ext WixUIExtension -ext WixUtilExtension -sval installer.wixobj -o installer32.msi - in putty/windows with wix do/win candle -arch x64 -dWin64=yes -dBuilddir=build64\ -dWinver="$(Winver)" -dPuttytextver="$(Puttytextver)" installer.wxs && light -ext WixUIExtension -ext WixUtilExtension -sval installer.wixobj -o installer64.msi - - # Sign the installers, if the local bob config provides - # $(winsigncode) that can run in a Windows delegation and behaves - # the same as $(cross_winsigncode) used above. - ifneq "$(winsigncode)" "" in putty/windows do $(winsigncode) -i https://www.chiark.greenend.org.uk/~sgtatham/putty/ -n "PuTTY Installer" installer32.msi installer64.msi - - # Finished Windows builds. - return putty/windows/installer32.msi - return putty/windows/installer64.msi -enddelegate +# Build a WiX MSI installer, for each of build32 and build64. +in putty/windows with wixonlinux do candle -arch x86 -dWin64=no -dBuilddir=build32/ -dWinver="$(Winver)" -dPuttytextver="$(Puttytextver)" installer.wxs && light -ext WixUIExtension -ext WixUtilExtension -sval installer.wixobj -o installer32.msi -spdb +in putty/windows with wixonlinux do candle -arch x64 -dWin64=yes -dBuilddir=build64/ -dWinver="$(Winver)" -dPuttytextver="$(Puttytextver)" installer.wxs && light -ext WixUIExtension -ext WixUtilExtension -sval installer.wixobj -o installer64.msi -spdb + +# Sign the Windows installers. +ifneq "$(cross_winsigncode)" "" in putty/windows do $(cross_winsigncode) -i https://www.chiark.greenend.org.uk/~sgtatham/putty/ -n "PuTTY Installer" installer32.msi installer64.msi + in putty/doc do make mostlyclean in putty/doc do make $(Docmakever) in putty/windows/buildold do zip -k -j putty.zip `ls *.exe | grep -v puttytel` ../../doc/putty.chm ../../doc/putty.hlp ../../doc/putty.cnt From 1da3c71474aab3296a99ae0ed40e4fa1aa425185 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Tue, 30 May 2017 22:49:25 +0100 Subject: [PATCH 039/607] Have clang-cl builds announce their _MSC_VER. In particular, this means the w32 and w32old builds have distinguishable buildinfo text, which should protect us against at least one source of confusion when receiving bug reports. --- misc.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/misc.c b/misc.c index 9aff234b..734ea8b1 100644 --- a/misc.c +++ b/misc.c @@ -1165,11 +1165,21 @@ char *buildinfo(const char *newline) BUILDINFO_PLATFORM); #ifdef __clang_version__ +#define FOUND_COMPILER strbuf_catf(buf, "%sCompiler: clang %s", newline, __clang_version__); #elif defined __GNUC__ && defined __VERSION__ +#define FOUND_COMPILER strbuf_catf(buf, "%sCompiler: gcc %s", newline, __VERSION__); -#elif defined _MSC_VER - strbuf_catf(buf, "%sCompiler: Visual Studio", newline); +#endif + +#if defined _MSC_VER +#ifndef FOUND_COMPILER +#define FOUND_COMPILER + strbuf_catf(buf, "%sCompiler: ", newline); +#else + strbuf_catf(buf, ", emulating "); +#endif + strbuf_catf(buf, "Visual Studio", newline); #if _MSC_VER == 1900 strbuf_catf(buf, " 2015 / MSVC++ 14.0"); #elif _MSC_VER == 1800 @@ -1178,12 +1188,14 @@ char *buildinfo(const char *newline) strbuf_catf(buf, " 2012 / MSVC++ 11.0"); #elif _MSC_VER == 1600 strbuf_catf(buf, " 2010 / MSVC++ 10.0"); -#elif _MSC_VER == 1500 +#elif _MSC_VER == 1500 strbuf_catf(buf, " 2008 / MSVC++ 9.0"); -#elif _MSC_VER == 1400 +#elif _MSC_VER == 1400 strbuf_catf(buf, " 2005 / MSVC++ 8.0"); -#elif _MSC_VER == 1310 +#elif _MSC_VER == 1310 strbuf_catf(buf, " 2003 / MSVC++ 7.1"); +#elif _MSC_VER == 1300 + strbuf_catf(buf, " 2003 / MSVC++ 7.0"); #else strbuf_catf(buf, ", unrecognised version"); #endif From 05f499e55f19b82c773559ee4465ba11c898c9eb Mon Sep 17 00:00:00 2001 From: Jacob Nevins Date: Tue, 6 Jun 2017 09:34:21 +0100 Subject: [PATCH 040/607] Add 'passthrough printing' as an index term. --- doc/config.but | 4 ++-- doc/index.but | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/doc/config.but b/doc/config.but index bb18b794..bd12efb2 100644 --- a/doc/config.but +++ b/doc/config.but @@ -499,8 +499,8 @@ instead of relying on the automatic detection. \cfg{winhelp-topic}{terminal.printing} A lot of VT100-compatible terminals support printing under control -of the remote server. PuTTY supports this feature as well, but it is -turned off by default. +of the remote server (sometimes called \q{passthrough printing}). +PuTTY supports this feature as well, but it is turned off by default. To enable remote-controlled printing, choose a printer from the \q{Printer to send ANSI printer output to} drop-down list box. This diff --git a/doc/index.but b/doc/index.but index 30ebd784..0877ee90 100644 --- a/doc/index.but +++ b/doc/index.but @@ -340,6 +340,7 @@ saved sessions from \IM{remote-controlled printing} ANSI printing \IM{remote-controlled printing} remote-controlled printing \IM{remote-controlled printing} printing, remote-controlled +\IM{remote-controlled printing} passthrough printing \IM{Home and End keys} Home key \IM{Home and End keys} End key From 6aac4b9cefbaa651639ef0495ebf9d098e67481c Mon Sep 17 00:00:00 2001 From: Jacob Nevins Date: Wed, 7 Jun 2017 22:02:28 +0100 Subject: [PATCH 041/607] StartDocPrinter returns DWORD, not BOOL. (Introduced in 793ac8727.) --- windows/winprint.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/windows/winprint.c b/windows/winprint.c index 11587273..a17166e6 100644 --- a/windows/winprint.c +++ b/windows/winprint.c @@ -23,7 +23,7 @@ DECL_WINDOWS_FUNCTION(static, BOOL, EnumPrinters, DECL_WINDOWS_FUNCTION(static, BOOL, OpenPrinter, (LPTSTR, LPHANDLE, LPPRINTER_DEFAULTS)); DECL_WINDOWS_FUNCTION(static, BOOL, ClosePrinter, (HANDLE)); -DECL_WINDOWS_FUNCTION(static, BOOL, StartDocPrinter, (HANDLE, DWORD, LPBYTE)); +DECL_WINDOWS_FUNCTION(static, DWORD, StartDocPrinter, (HANDLE, DWORD, LPBYTE)); DECL_WINDOWS_FUNCTION(static, BOOL, EndDocPrinter, (HANDLE)); DECL_WINDOWS_FUNCTION(static, BOOL, StartPagePrinter, (HANDLE)); DECL_WINDOWS_FUNCTION(static, BOOL, EndPagePrinter, (HANDLE)); From f31a72ba09d20e076f62e39e0f59404511bf6c86 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 10 Jun 2017 11:29:21 +0100 Subject: [PATCH 042/607] Unix: use conf_dest() in 'unable to open connection' error box. Alamy Liu points out that asking for CONF_host will display the wrong part of the configuration in the case where serial port setup fails. The Windows front end's analogous message already got this right, but I must have forgotten to change this one too when I introduced conf_dest. --- unix/gtkwin.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unix/gtkwin.c b/unix/gtkwin.c index f54289a3..9e73181e 100644 --- a/unix/gtkwin.c +++ b/unix/gtkwin.c @@ -4274,7 +4274,7 @@ static void start_backend(struct gui_data *inst) if (error) { char *msg = dupprintf("Unable to open connection to %s:\n%s", - conf_get_str(inst->conf, CONF_host), error); + conf_dest(inst->conf), error); inst->exited = TRUE; fatal_message_box(inst->window, msg); sfree(msg); From a9e1053c8ae29c80cf0827c346e7dac976fb949b Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Thu, 15 Jun 2017 18:58:01 +0100 Subject: [PATCH 043/607] Log the server's diagnostics if main channel open fails. This has been a FIXME in the code for ages, because back when the main channel was always a pty session or a program run in a pipe, there weren't that many circumstances in which the actual CHANNEL_OPEN could return failure, so it never seemed like a priority to get round to pulling the error information out of the CHANNEL_OPEN_FAILURE response message and including it in PuTTY or Plink's local error message. However, 'plink -nc' is the real reason why this is actually important; if you tell the SSH server to make a direct-tcpip network connection as its main channel, then that can fail for all the usual network-unreliability reasons, and you actually do want to know which (did you misspell the hostname, or is the target server refusing connections, or has network connectivity failed?). This actually bit me today when I had such a network failure, and had to debug it by pulling that information manually out of a packet log. Time to eliminate that FIXME. So I've pulled the error-extracting code out of the previous handler for OPEN_FAILURE on non-main channels into a separate function, and arranged to call that function if the main channel open fails too. In the process I've made a couple of minor tweaks, e.g. if the server sends back a reason code we haven't heard of, we say _what_ that reason code was, and also we at least make a token effort to spot if we see a packet other than OPEN_{CONFIRMATION,FAILURE} reaching the main loop in response to the main channel-open. --- ssh.c | 61 ++++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 42 insertions(+), 19 deletions(-) diff --git a/ssh.c b/ssh.c index b6298b03..1d80e919 100644 --- a/ssh.c +++ b/ssh.c @@ -8496,18 +8496,37 @@ static void ssh2_msg_channel_open_confirmation(Ssh ssh, struct Packet *pktin) ssh_channel_try_eof(c); /* in case we had a pending EOF */ } -static void ssh2_msg_channel_open_failure(Ssh ssh, struct Packet *pktin) +static char *ssh2_channel_open_failure_error_text(struct Packet *pktin) { static const char *const reasons[] = { - "", - "Administratively prohibited", - "Connect failed", - "Unknown channel type", - "Resource shortage", + NULL, + "Administratively prohibited", + "Connect failed", + "Unknown channel type", + "Resource shortage", }; unsigned reason_code; + const char *reason_code_string; + char reason_code_buf[256]; char *reason_string; int reason_length; + + reason_code = ssh_pkt_getuint32(pktin); + if (reason_code < lenof(reasons) && reasons[reason_code]) { + reason_code_string = reasons[reason_code]; + } else { + reason_code_string = reason_code_buf; + sprintf(reason_code_buf, "unknown reason code %#x", reason_code); + } + + ssh_pkt_getstring(pktin, &reason_string, &reason_length); + + return dupprintf("%s [%.*s]", reason_code_string, + reason_length, NULLTOEMPTY(reason_string)); +} + +static void ssh2_msg_channel_open_failure(Ssh ssh, struct Packet *pktin) +{ struct ssh_channel *c; c = ssh_channel_msg(ssh, pktin); @@ -8516,14 +8535,9 @@ static void ssh2_msg_channel_open_failure(Ssh ssh, struct Packet *pktin) assert(c->halfopen); /* ssh_channel_msg will have enforced this */ if (c->type == CHAN_SOCKDATA) { - reason_code = ssh_pkt_getuint32(pktin); - if (reason_code >= lenof(reasons)) - reason_code = 0; /* ensure reasons[reason_code] in range */ - ssh_pkt_getstring(pktin, &reason_string, &reason_length); - logeventf(ssh, "Forwarded connection refused by server: %s [%.*s]", - reasons[reason_code], reason_length, - NULLTOEMPTY(reason_string)); - + char *errtext = ssh2_channel_open_failure_error_text(pktin); + logeventf(ssh, "Forwarded connection refused by server: %s", errtext); + sfree(errtext); pfd_close(c->u.pfd.pf); } else if (c->type == CHAN_ZOMBIE) { /* @@ -10727,15 +10741,24 @@ static void do_ssh2_authconn(Ssh ssh, const unsigned char *in, int inlen, ssh->ncmode = FALSE; } crWaitUntilV(pktin); - if (pktin->type != SSH2_MSG_CHANNEL_OPEN_CONFIRMATION) { - bombout(("Server refused to open channel")); + if (pktin->type != SSH2_MSG_CHANNEL_OPEN_CONFIRMATION && + pktin->type != SSH2_MSG_CHANNEL_OPEN_FAILURE) { + bombout(("Server sent strange packet %d in response to main " + "channel open request", pktin->type)); crStopV; - /* FIXME: error data comes back in FAILURE packet */ - } + } if (ssh_pkt_getuint32(pktin) != ssh->mainchan->localid) { - bombout(("Server's channel confirmation cited wrong channel")); + bombout(("Server's response to main channel open cited wrong" + " channel number")); + crStopV; + } + if (pktin->type == SSH2_MSG_CHANNEL_OPEN_FAILURE) { + char *errtext = ssh2_channel_open_failure_error_text(pktin); + bombout(("Server refused to open main channel: %s", errtext)); + sfree(errtext); crStopV; } + ssh->mainchan->remoteid = ssh_pkt_getuint32(pktin); ssh->mainchan->halfopen = FALSE; ssh->mainchan->type = CHAN_MAINSESSION; From 892d4a0188ffd8aa60dc11b4bace30dfb0f9d50e Mon Sep 17 00:00:00 2001 From: Jacob Nevins Date: Thu, 15 Jun 2017 23:33:57 +0100 Subject: [PATCH 044/607] Seek all Windows print functions in winspool.drv. Rather than loading some from spoolss.dll, which some MSDN documentation suggests, but which doesn't work very well in practice. (Also, remove an unused variable.) --- windows/winprint.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/windows/winprint.c b/windows/winprint.c index a17166e6..6a1a74c2 100644 --- a/windows/winprint.c +++ b/windows/winprint.c @@ -33,20 +33,25 @@ DECL_WINDOWS_FUNCTION(static, BOOL, WritePrinter, static void init_winfuncs(void) { static int initialised = FALSE; - char buf[4096]; if (initialised) return; { HMODULE winspool_module = load_system32_dll("winspool.drv"); - HMODULE spoolss_module = load_system32_dll("spoolss.dll"); + /* Some MSDN documentation claims that some of the below functions + * should be loaded from spoolss.dll, but this doesn't seem to + * be reliable in practice. + * Nevertheless, we load spoolss.dll ourselves using our safe + * loading method, against the possibility that winspool.drv + * later loads it unsafely. */ + (void) load_system32_dll("spoolss.dll"); GET_WINDOWS_FUNCTION_PP(winspool_module, EnumPrinters); GET_WINDOWS_FUNCTION_PP(winspool_module, OpenPrinter); - GET_WINDOWS_FUNCTION_PP(spoolss_module, ClosePrinter); + GET_WINDOWS_FUNCTION_PP(winspool_module, ClosePrinter); GET_WINDOWS_FUNCTION_PP(winspool_module, StartDocPrinter); - GET_WINDOWS_FUNCTION_PP(spoolss_module, EndDocPrinter); - GET_WINDOWS_FUNCTION_PP(spoolss_module, StartPagePrinter); - GET_WINDOWS_FUNCTION_PP(spoolss_module, EndPagePrinter); - GET_WINDOWS_FUNCTION_PP(spoolss_module, WritePrinter); + GET_WINDOWS_FUNCTION_PP(winspool_module, EndDocPrinter); + GET_WINDOWS_FUNCTION_PP(winspool_module, StartPagePrinter); + GET_WINDOWS_FUNCTION_PP(winspool_module, EndPagePrinter); + GET_WINDOWS_FUNCTION_PP(winspool_module, WritePrinter); } initialised = TRUE; } From 4387b5f1617bf0222fc64e3ec73d14e252465309 Mon Sep 17 00:00:00 2001 From: Ilya Shipitsin Date: Mon, 19 Jun 2017 20:57:28 +0500 Subject: [PATCH 045/607] resolve an issue found by cppcheck: [unix/osxlaunch.c:133] -> [unix/osxlaunch.c:134]: (warning) Either the condition '!qhead' is redundant or there is possible null pointer dereference: qhead. --- unix/osxlaunch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unix/osxlaunch.c b/unix/osxlaunch.c index 2627c642..28516185 100644 --- a/unix/osxlaunch.c +++ b/unix/osxlaunch.c @@ -130,11 +130,11 @@ char *get_unused_env_prefix(void) char **e; qhead = (struct bucket *)malloc(sizeof(struct bucket)); - qhead->prefixlen = 0; if (!qhead) { fprintf(stderr, "out of memory\n"); exit(1); } + qhead->prefixlen = 0; for (e = environ; *e; e++) qhead->first_node = new_node(qhead->first_node, *e, strcspn(*e, "=")); From 5efee183569ede0a4155f8195e1b1be58e954b95 Mon Sep 17 00:00:00 2001 From: Ilya Shipitsin Date: Mon, 19 Jun 2017 21:39:32 +0500 Subject: [PATCH 046/607] resolve couple of issues found by cppcheck: [psftp.c:1135] -> [psftp.c:1134]: (warning) Either the condition '!dir' is redundant or there is possible null pointer dereference: dir. [psftp.c:1420] -> [psftp.c:1419]: (warning) Either the condition '!dir' is redundant or there is possible null pointer dereference: dir. --- psftp.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/psftp.c b/psftp.c index 5394c1fb..aa397181 100644 --- a/psftp.c +++ b/psftp.c @@ -1128,12 +1128,12 @@ int sftp_cmd_cd(struct sftp_command *cmd) if (cmd->nwords < 2) dir = dupstr(homedir); - else + else { dir = canonify(cmd->words[1]); - - if (!dir) { - printf("%s: canonify: %s\n", dir, fxp_error()); - return 0; + if (!dir) { + printf("%s: canonify: %s\n", cmd->words[1], fxp_error()); + return 0; + } } req = fxp_opendir_send(dir); @@ -1417,7 +1417,7 @@ int sftp_cmd_mkdir(struct sftp_command *cmd) for (i = 1; i < cmd->nwords; i++) { dir = canonify(cmd->words[i]); if (!dir) { - printf("%s: canonify: %s\n", dir, fxp_error()); + printf("%s: canonify: %s\n", cmd->words[i], fxp_error()); return 0; } From 3f2df8cc9dc6ae19c6513091eb009999f4406a60 Mon Sep 17 00:00:00 2001 From: Ilya Shipitsin Date: Mon, 19 Jun 2017 21:42:16 +0500 Subject: [PATCH 047/607] resolve (no real impact) issue found by cppcheck: [unix/osxlaunch.c:411]: (error) Memory leak: macos [unix/osxlaunch.c:411]: (error) Memory leak: contents [unix/osxlaunch.c:411]: (error) Memory leak: new_argv --- unix/osxlaunch.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/unix/osxlaunch.c b/unix/osxlaunch.c index 28516185..8082f2de 100644 --- a/unix/osxlaunch.c +++ b/unix/osxlaunch.c @@ -408,6 +408,9 @@ int main(int argc, char **argv) execv(realbin, new_argv); perror("execv"); + free(new_argv); + free(contents); + free(macos); return 127; } From 02043ec5ace4985fc35fef8b5d6543a871ccab3c Mon Sep 17 00:00:00 2001 From: Ilya Shipitsin Date: Tue, 20 Jun 2017 09:36:07 +0500 Subject: [PATCH 048/607] resolve (no real impact) issue found by cppcheck: [windows/winnet.c:589]: (error) Uninitialized variable: err --- windows/winnet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/windows/winnet.c b/windows/winnet.c index ea950bba..e2edc87a 100644 --- a/windows/winnet.c +++ b/windows/winnet.c @@ -548,7 +548,7 @@ SockAddr sk_namelookup(const char *host, char **canonicalname, if ((a = p_inet_addr(host)) == (unsigned long) INADDR_NONE) { struct hostent *h = NULL; - int err; + int err = 0; #ifndef NO_IPV6 /* * Use getaddrinfo when it's available From 20e36ae4a24e06f86ce533a24c5f61f00e2ab91c Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Tue, 20 Jun 2017 07:05:39 +0100 Subject: [PATCH 049/607] Fix a collection of type / format string mismatches. Ilya Shipitsin sent me a list of errors reported by a tool 'cppcheck', which I hadn't seen before, together with some fixes for things already taken off that list. This change picks out all the things from the remaining list that I could quickly identify as actual errors, which it turns out are all format-string goofs along the lines of using a %d with an unsigned int, or a %u with a signed int, or (in the cases in charset/utf8.c) an actual _size_ mismatch which could in principle have caused trouble on a big-endian target. --- charset/utf8.c | 4 ++-- import.c | 3 ++- minibidi.c | 2 +- misc.c | 3 ++- pscp.c | 2 +- terminal.c | 2 +- windows/window.c | 4 ++-- 7 files changed, 11 insertions(+), 9 deletions(-) diff --git a/charset/utf8.c b/charset/utf8.c index 3c777292..fe46cf98 100644 --- a/charset/utf8.c +++ b/charset/utf8.c @@ -267,7 +267,7 @@ void utf8_read_test(int line, char *input, int inlen, ...) } if (l != str[i]) { printf("%d: char %d came out as %08x, should be %08x\n", - line, i, str[i], l); + line, i, str[i], (unsigned)l); total_errs++; } } @@ -306,7 +306,7 @@ void utf8_write_test(int line, const long *input, int inlen, ...) } if (l != str[i]) { printf("%d: char %d came out as %08x, should be %08x\n", - line, i, str[i], l); + line, i, str[i], (unsigned)l); total_errs++; } } diff --git a/import.c b/import.c index adf68777..88589a71 100644 --- a/import.c +++ b/import.c @@ -445,7 +445,7 @@ static struct openssh_pem_key *load_openssh_pem_key(const Filename *filename, if (!strcmp(p, "ENCRYPTED")) ret->encrypted = TRUE; } else if (!strcmp(line, "DEK-Info")) { - int i, j, ivlen; + int i, ivlen; if (!strncmp(p, "DES-EDE3-CBC,", 13)) { ret->encryption = OP_E_3DES; @@ -459,6 +459,7 @@ static struct openssh_pem_key *load_openssh_pem_key(const Filename *filename, } p = strchr(p, ',') + 1;/* always non-NULL, by above checks */ for (i = 0; i < ivlen; i++) { + unsigned j; if (1 != sscanf(p, "%2x", &j)) { errmsg = "expected more iv data in DEK-Info"; goto error; diff --git a/minibidi.c b/minibidi.c index 8d78594d..2bdf4deb 100644 --- a/minibidi.c +++ b/minibidi.c @@ -2014,7 +2014,7 @@ int main(int argc, char **argv) unsigned long chr = strtoul(argv[i], NULL, 0); int type = getType(chr); assert(typetoname[type].type == type); - printf("U+%04x: %s\n", chr, typetoname[type].name); + printf("U+%04x: %s\n", (unsigned)chr, typetoname[type].name); } return 0; diff --git a/misc.c b/misc.c index 734ea8b1..469e4aeb 100644 --- a/misc.c +++ b/misc.c @@ -157,7 +157,8 @@ int main(void) passes++; \ } else { \ printf("fail: %s(%s,%s)%s = %u, expected %u\n", \ - #func, #string, #arg2, #suffix, ret, result); \ + #func, #string, #arg2, #suffix, ret, \ + (unsigned)result); \ fails++; \ } \ } while (0) diff --git a/pscp.c b/pscp.c index 454ec084..210362df 100644 --- a/pscp.c +++ b/pscp.c @@ -1476,7 +1476,7 @@ int scp_get_sink_action(struct scp_sink_action *act) act->action = SCP_SINK_ENDDIR; return 0; case 'T': - if (sscanf(act->buf, "%ld %*d %ld %*d", + if (sscanf(act->buf, "%lu %*d %lu %*d", &act->mtime, &act->atime) == 2) { act->settime = 1; back->send(backhandle, "", 1); diff --git a/terminal.c b/terminal.c index f47fe1bd..ba9dd617 100644 --- a/terminal.c +++ b/terminal.c @@ -4327,7 +4327,7 @@ static void term_out(Terminal *term) for (i = 1; i < term->esc_nargs; i++) { if (i != 1) strcat(term->id_string, ";"); - sprintf(lbuf, "%d", term->esc_args[i]); + sprintf(lbuf, "%u", term->esc_args[i]); strcat(term->id_string, lbuf); } strcat(term->id_string, "c"); diff --git a/windows/window.c b/windows/window.c index 89ddb863..96600311 100644 --- a/windows/window.c +++ b/windows/window.c @@ -5199,8 +5199,8 @@ void write_clip(void *frontend, wchar_t * data, int *attr, int len, int must_des multilen = WideCharToMultiByte(CP_ACP, 0, unitab+uindex, 1, NULL, 0, NULL, NULL); if (multilen != 1) { - blen = sprintf(before, "{\\uc%d\\u%d", multilen, - udata[uindex]); + blen = sprintf(before, "{\\uc%d\\u%d", (int)multilen, + (int)udata[uindex]); alen = 1; strcpy(after, "}"); } else { blen = sprintf(before, "\\u%d", udata[uindex]); From 98cbe6963b8126659cf16c622302cbd872026936 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Tue, 20 Jun 2017 19:02:13 +0100 Subject: [PATCH 050/607] Another format-string fix. Oops - I found this in an editor autosave file after pushing the previous commit. I meant it to be part of the previous commit. Oh well, better late than never. --- tree234.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tree234.c b/tree234.c index f1c0c2ed..d3c5293d 100644 --- a/tree234.c +++ b/tree234.c @@ -681,7 +681,7 @@ static void *delpos234_internal(tree234 * t, int index) LOG((" moving to subtree %d\n", ki)); sub = n->kids[ki]; if (!sub->elems[1]) { - LOG((" subtree has only one element!\n", ki)); + LOG((" subtree has only one element!\n")); if (ki > 0 && n->kids[ki - 1]->elems[1]) { /* * Case 3a, left-handed variant. Child ki has From 4696f4a40bd38386dac5bc0f8331ca9c4e579bd6 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Tue, 20 Jun 2017 19:02:48 +0100 Subject: [PATCH 051/607] Coverity build fixes. Like every other toolchain I've tried, my Coverity scanning build has its share of random objections to parts of my Windows API type- checking system. I do wonder if that bright idea was worth the hassle - but it would probably cost all the annoyance all over again to back out now... --- windows/wincapi.c | 9 ++++++++- windows/winhsock.c | 5 +++-- windows/winmisc.c | 8 +++++--- windows/winnet.c | 10 ++++++++++ 4 files changed, 26 insertions(+), 6 deletions(-) diff --git a/windows/wincapi.c b/windows/wincapi.c index 2550b6de..2bd03470 100644 --- a/windows/wincapi.c +++ b/windows/wincapi.c @@ -19,7 +19,14 @@ int got_crypt(void) attempted = TRUE; crypt = load_system32_dll("crypt32.dll"); successful = crypt && - GET_WINDOWS_FUNCTION(crypt, CryptProtectMemory); +#ifdef COVERITY + /* The build toolchain I use with Coverity doesn't know + * about this function, so can't type-check it */ + GET_WINDOWS_FUNCTION_NO_TYPECHECK(crypt, CryptProtectMemory) +#else + GET_WINDOWS_FUNCTION(crypt, CryptProtectMemory) +#endif + ; } return successful; } diff --git a/windows/winhsock.c b/windows/winhsock.c index 799fd28d..7c8b0ba6 100644 --- a/windows/winhsock.c +++ b/windows/winhsock.c @@ -284,10 +284,11 @@ static char *sk_handle_peer_info(Socket s) if (!kernel32_module) { kernel32_module = load_system32_dll("kernel32.dll"); -#if (defined _MSC_VER && _MSC_VER < 1900) || defined __MINGW32__ +#if (defined _MSC_VER && _MSC_VER < 1900) || defined __MINGW32__ || defined COVERITY /* For older Visual Studio, and MinGW too (at least as of * Ubuntu 16.04), this function isn't available in the header - * files to type-check */ + * files to type-check. Ditto the toolchain I use for + * Coveritying the Windows code. */ GET_WINDOWS_FUNCTION_NO_TYPECHECK( kernel32_module, GetNamedPipeClientProcessId); #else diff --git a/windows/winmisc.c b/windows/winmisc.c index 85fa3c95..59d64312 100644 --- a/windows/winmisc.c +++ b/windows/winmisc.c @@ -177,9 +177,11 @@ void dll_hijacking_protection(void) if (!kernel32_module) { kernel32_module = load_system32_dll("kernel32.dll"); -#if defined _MSC_VER && _MSC_VER < 1900 - /* For older Visual Studio, this function isn't available in - * the header files to type-check */ +#if (defined _MSC_VER && _MSC_VER < 1900) || defined COVERITY + /* For older Visual Studio, and also for the system I + * currently use for Coveritying the Windows code, this + * function isn't available in the header files to + * type-check */ GET_WINDOWS_FUNCTION_NO_TYPECHECK( kernel32_module, SetDefaultDllDirectories); #else diff --git a/windows/winnet.c b/windows/winnet.c index e2edc87a..86f7735f 100644 --- a/windows/winnet.c +++ b/windows/winnet.c @@ -305,11 +305,21 @@ void sk_init(void) GET_WINDOWS_FUNCTION(winsock_module, WSAStartup); GET_WINDOWS_FUNCTION(winsock_module, WSACleanup); GET_WINDOWS_FUNCTION(winsock_module, closesocket); +#ifndef COVERITY GET_WINDOWS_FUNCTION(winsock_module, ntohl); GET_WINDOWS_FUNCTION(winsock_module, htonl); GET_WINDOWS_FUNCTION(winsock_module, htons); GET_WINDOWS_FUNCTION(winsock_module, ntohs); GET_WINDOWS_FUNCTION(winsock_module, gethostname); +#else + /* The toolchain I use for Windows Coverity builds doesn't know + * the type signatures of these */ + GET_WINDOWS_FUNCTION_NO_TYPECHECK(winsock_module, ntohl); + GET_WINDOWS_FUNCTION_NO_TYPECHECK(winsock_module, htonl); + GET_WINDOWS_FUNCTION_NO_TYPECHECK(winsock_module, htons); + GET_WINDOWS_FUNCTION_NO_TYPECHECK(winsock_module, ntohs); + GET_WINDOWS_FUNCTION_NO_TYPECHECK(winsock_module, gethostname); +#endif GET_WINDOWS_FUNCTION(winsock_module, gethostbyname); GET_WINDOWS_FUNCTION(winsock_module, getservbyname); GET_WINDOWS_FUNCTION(winsock_module, inet_addr); From d61897414cae6e40dc39da6aac84ab48c6cdf149 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Tue, 20 Jun 2017 21:17:43 +0100 Subject: [PATCH 052/607] Fixes spotted by Coverity. A lenof() being applied to a non-array, a couple of missing frees on an error path, and a case in pfd_receive() where we could have gone round a loop again after freeing the port forwarding structure it was working on. --- config.c | 2 +- portfwd.c | 1 + psftp.c | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/config.c b/config.c index 220c1aa8..efe1ff1e 100644 --- a/config.c +++ b/config.c @@ -1005,7 +1005,7 @@ static void ttymodes_handler(union control *ctrl, void *dlg, char type; { - const char *types = "ANV"; + const char types[] = {'A', 'N', 'V'}; int button = dlg_radiobutton_get(td->valradio, dlg); assert(button >= 0 && button < lenof(types)); type = types[button]; diff --git a/portfwd.c b/portfwd.c index febd8af9..b68e4bb8 100644 --- a/portfwd.c +++ b/portfwd.c @@ -359,6 +359,7 @@ static void pfd_receive(Plug plug, int urgent, char *data, int len) * close the connection rudely. */ pfd_close(pf); + break; } return; diff --git a/psftp.c b/psftp.c index aa397181..e4e77c3a 100644 --- a/psftp.c +++ b/psftp.c @@ -1050,6 +1050,8 @@ int sftp_cmd_ls(struct sftp_command *cmd) if (dirh == NULL) { printf("Unable to open %s: %s\n", dir, fxp_error()); + sfree(cdir); + sfree(unwcdir); return 0; } else { nnames = namesize = 0; From 4241734dde44caea5a9c73a79db9c6d4cae50861 Mon Sep 17 00:00:00 2001 From: David Taylor Date: Sat, 1 Jul 2017 23:25:49 +0100 Subject: [PATCH 053/607] Update wcwidth.c with Unicode 9.0.0 data In order to maintain compatibility with screen[1], update wcwidth functions to use Unicode 9.0.0 character database. Updated intervals extracted from output of [2] from ucd files[3]. The comments at the head of [2] state that the output is unrestricted. Therefore it is not subject to the GPL as applies to the script itself. [1] See: https://savannah.gnu.org/bugs/?func=detailitem&item_id=50044 [2] https://raw.githubusercontent.com/GNOME/glib/37d4c2941bd0326b8b6e6bb22c81bd424fcc040b/glib/gen-unicode-tables.pl [3] http://www.unicode.org/Public/9.0.0/ucd/ --- wcwidth.c | 373 ++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 305 insertions(+), 68 deletions(-) diff --git a/wcwidth.c b/wcwidth.c index ec0fb2ba..25372a79 100644 --- a/wcwidth.c +++ b/wcwidth.c @@ -176,6 +176,120 @@ int mk_wcwidth(unsigned int ucs) { 0xE0100, 0xE01EF } }; + /* A sorted list of intervals of double-width characters generated by: + * https://raw.githubusercontent.com/GNOME/glib/37d4c2941bd0326b8b6e6bb22c81bd424fcc040b/glib/gen-unicode-tables.pl + * from the Unicode 9.0.0 data files available at: + * http://www.unicode.org/Public/9.0.0/ucd/ + */ + static const struct interval wide[] = { + {0x1100, 0x115F}, + {0x231A, 0x231B}, + {0x2329, 0x232A}, + {0x23E9, 0x23EC}, + {0x23F0, 0x23F0}, + {0x23F3, 0x23F3}, + {0x25FD, 0x25FE}, + {0x2614, 0x2615}, + {0x2648, 0x2653}, + {0x267F, 0x267F}, + {0x2693, 0x2693}, + {0x26A1, 0x26A1}, + {0x26AA, 0x26AB}, + {0x26BD, 0x26BE}, + {0x26C4, 0x26C5}, + {0x26CE, 0x26CE}, + {0x26D4, 0x26D4}, + {0x26EA, 0x26EA}, + {0x26F2, 0x26F3}, + {0x26F5, 0x26F5}, + {0x26FA, 0x26FA}, + {0x26FD, 0x26FD}, + {0x2705, 0x2705}, + {0x270A, 0x270B}, + {0x2728, 0x2728}, + {0x274C, 0x274C}, + {0x274E, 0x274E}, + {0x2753, 0x2755}, + {0x2757, 0x2757}, + {0x2795, 0x2797}, + {0x27B0, 0x27B0}, + {0x27BF, 0x27BF}, + {0x2B1B, 0x2B1C}, + {0x2B50, 0x2B50}, + {0x2B55, 0x2B55}, + {0x2E80, 0x2E99}, + {0x2E9B, 0x2EF3}, + {0x2F00, 0x2FD5}, + {0x2FF0, 0x2FFB}, + {0x3000, 0x303E}, + {0x3041, 0x3096}, + {0x3099, 0x30FF}, + {0x3105, 0x312D}, + {0x3131, 0x318E}, + {0x3190, 0x31BA}, + {0x31C0, 0x31E3}, + {0x31F0, 0x321E}, + {0x3220, 0x3247}, + {0x3250, 0x32FE}, + {0x3300, 0x4DBF}, + {0x4E00, 0xA48C}, + {0xA490, 0xA4C6}, + {0xA960, 0xA97C}, + {0xAC00, 0xD7A3}, + {0xF900, 0xFAFF}, + {0xFE10, 0xFE19}, + {0xFE30, 0xFE52}, + {0xFE54, 0xFE66}, + {0xFE68, 0xFE6B}, + {0xFF01, 0xFF60}, + {0xFFE0, 0xFFE6}, + {0x16FE0, 0x16FE0}, + {0x17000, 0x187EC}, + {0x18800, 0x18AF2}, + {0x1B000, 0x1B001}, + {0x1F004, 0x1F004}, + {0x1F0CF, 0x1F0CF}, + {0x1F18E, 0x1F18E}, + {0x1F191, 0x1F19A}, + {0x1F200, 0x1F202}, + {0x1F210, 0x1F23B}, + {0x1F240, 0x1F248}, + {0x1F250, 0x1F251}, + {0x1F300, 0x1F320}, + {0x1F32D, 0x1F335}, + {0x1F337, 0x1F37C}, + {0x1F37E, 0x1F393}, + {0x1F3A0, 0x1F3CA}, + {0x1F3CF, 0x1F3D3}, + {0x1F3E0, 0x1F3F0}, + {0x1F3F4, 0x1F3F4}, + {0x1F3F8, 0x1F43E}, + {0x1F440, 0x1F440}, + {0x1F442, 0x1F4FC}, + {0x1F4FF, 0x1F53D}, + {0x1F54B, 0x1F54E}, + {0x1F550, 0x1F567}, + {0x1F57A, 0x1F57A}, + {0x1F595, 0x1F596}, + {0x1F5A4, 0x1F5A4}, + {0x1F5FB, 0x1F64F}, + {0x1F680, 0x1F6C5}, + {0x1F6CC, 0x1F6CC}, + {0x1F6D0, 0x1F6D2}, + {0x1F6EB, 0x1F6EC}, + {0x1F6F4, 0x1F6F6}, + {0x1F910, 0x1F91E}, + {0x1F920, 0x1F927}, + {0x1F930, 0x1F930}, + {0x1F933, 0x1F93E}, + {0x1F940, 0x1F94B}, + {0x1F950, 0x1F95E}, + {0x1F980, 0x1F991}, + {0x1F9C0, 0x1F9C0}, + {0x20000, 0x2FFFD}, + {0x30000, 0x3FFFD}, + }; + /* test for 8-bit control characters */ if (ucs == 0) return 0; @@ -189,20 +303,13 @@ int mk_wcwidth(unsigned int ucs) /* if we arrive here, ucs is not a combining or C0/C1 control character */ - return 1 + - (ucs >= 0x1100 && - (ucs <= 0x115f || /* Hangul Jamo init. consonants */ - ucs == 0x2329 || ucs == 0x232a || - (ucs >= 0x2e80 && ucs <= 0xa4cf && - ucs != 0x303f) || /* CJK ... Yi */ - (ucs >= 0xac00 && ucs <= 0xd7a3) || /* Hangul Syllables */ - (ucs >= 0xf900 && ucs <= 0xfaff) || /* CJK Compatibility Ideographs */ - (ucs >= 0xfe10 && ucs <= 0xfe19) || /* Vertical forms */ - (ucs >= 0xfe30 && ucs <= 0xfe6f) || /* CJK Compatibility Forms */ - (ucs >= 0xff00 && ucs <= 0xff60) || /* Fullwidth Forms */ - (ucs >= 0xffe0 && ucs <= 0xffe6) || - (ucs >= 0x20000 && ucs <= 0x2fffd) || - (ucs >= 0x30000 && ucs <= 0x3fffd))); + /* binary search in table of double-width characters */ + if (bisearch(ucs, wide, + sizeof(wide) / sizeof(struct interval) - 1)) + return 2; + + /* normal width character */ + return 1; } @@ -231,61 +338,191 @@ int mk_wcswidth(const unsigned int *pwcs, size_t n) */ int mk_wcwidth_cjk(unsigned int ucs) { - /* sorted list of non-overlapping intervals of East Asian Ambiguous - * characters, generated by "uniset +WIDTH-A -cat=Me -cat=Mn -cat=Cf c" */ + /* A sorted list of intervals of ambiguous width characters generated by: + * https://raw.githubusercontent.com/GNOME/glib/37d4c2941bd0326b8b6e6bb22c81bd424fcc040b/glib/gen-unicode-tables.pl + * from the Unicode 9.0.0 data files available at: + * http://www.unicode.org/Public/9.0.0/ucd/ + */ static const struct interval ambiguous[] = { - { 0x00A1, 0x00A1 }, { 0x00A4, 0x00A4 }, { 0x00A7, 0x00A8 }, - { 0x00AA, 0x00AA }, { 0x00AE, 0x00AE }, { 0x00B0, 0x00B4 }, - { 0x00B6, 0x00BA }, { 0x00BC, 0x00BF }, { 0x00C6, 0x00C6 }, - { 0x00D0, 0x00D0 }, { 0x00D7, 0x00D8 }, { 0x00DE, 0x00E1 }, - { 0x00E6, 0x00E6 }, { 0x00E8, 0x00EA }, { 0x00EC, 0x00ED }, - { 0x00F0, 0x00F0 }, { 0x00F2, 0x00F3 }, { 0x00F7, 0x00FA }, - { 0x00FC, 0x00FC }, { 0x00FE, 0x00FE }, { 0x0101, 0x0101 }, - { 0x0111, 0x0111 }, { 0x0113, 0x0113 }, { 0x011B, 0x011B }, - { 0x0126, 0x0127 }, { 0x012B, 0x012B }, { 0x0131, 0x0133 }, - { 0x0138, 0x0138 }, { 0x013F, 0x0142 }, { 0x0144, 0x0144 }, - { 0x0148, 0x014B }, { 0x014D, 0x014D }, { 0x0152, 0x0153 }, - { 0x0166, 0x0167 }, { 0x016B, 0x016B }, { 0x01CE, 0x01CE }, - { 0x01D0, 0x01D0 }, { 0x01D2, 0x01D2 }, { 0x01D4, 0x01D4 }, - { 0x01D6, 0x01D6 }, { 0x01D8, 0x01D8 }, { 0x01DA, 0x01DA }, - { 0x01DC, 0x01DC }, { 0x0251, 0x0251 }, { 0x0261, 0x0261 }, - { 0x02C4, 0x02C4 }, { 0x02C7, 0x02C7 }, { 0x02C9, 0x02CB }, - { 0x02CD, 0x02CD }, { 0x02D0, 0x02D0 }, { 0x02D8, 0x02DB }, - { 0x02DD, 0x02DD }, { 0x02DF, 0x02DF }, { 0x0391, 0x03A1 }, - { 0x03A3, 0x03A9 }, { 0x03B1, 0x03C1 }, { 0x03C3, 0x03C9 }, - { 0x0401, 0x0401 }, { 0x0410, 0x044F }, { 0x0451, 0x0451 }, - { 0x2010, 0x2010 }, { 0x2013, 0x2016 }, { 0x2018, 0x2019 }, - { 0x201C, 0x201D }, { 0x2020, 0x2022 }, { 0x2024, 0x2027 }, - { 0x2030, 0x2030 }, { 0x2032, 0x2033 }, { 0x2035, 0x2035 }, - { 0x203B, 0x203B }, { 0x203E, 0x203E }, { 0x2074, 0x2074 }, - { 0x207F, 0x207F }, { 0x2081, 0x2084 }, { 0x20AC, 0x20AC }, - { 0x2103, 0x2103 }, { 0x2105, 0x2105 }, { 0x2109, 0x2109 }, - { 0x2113, 0x2113 }, { 0x2116, 0x2116 }, { 0x2121, 0x2122 }, - { 0x2126, 0x2126 }, { 0x212B, 0x212B }, { 0x2153, 0x2154 }, - { 0x215B, 0x215E }, { 0x2160, 0x216B }, { 0x2170, 0x2179 }, - { 0x2190, 0x2199 }, { 0x21B8, 0x21B9 }, { 0x21D2, 0x21D2 }, - { 0x21D4, 0x21D4 }, { 0x21E7, 0x21E7 }, { 0x2200, 0x2200 }, - { 0x2202, 0x2203 }, { 0x2207, 0x2208 }, { 0x220B, 0x220B }, - { 0x220F, 0x220F }, { 0x2211, 0x2211 }, { 0x2215, 0x2215 }, - { 0x221A, 0x221A }, { 0x221D, 0x2220 }, { 0x2223, 0x2223 }, - { 0x2225, 0x2225 }, { 0x2227, 0x222C }, { 0x222E, 0x222E }, - { 0x2234, 0x2237 }, { 0x223C, 0x223D }, { 0x2248, 0x2248 }, - { 0x224C, 0x224C }, { 0x2252, 0x2252 }, { 0x2260, 0x2261 }, - { 0x2264, 0x2267 }, { 0x226A, 0x226B }, { 0x226E, 0x226F }, - { 0x2282, 0x2283 }, { 0x2286, 0x2287 }, { 0x2295, 0x2295 }, - { 0x2299, 0x2299 }, { 0x22A5, 0x22A5 }, { 0x22BF, 0x22BF }, - { 0x2312, 0x2312 }, { 0x2460, 0x24E9 }, { 0x24EB, 0x254B }, - { 0x2550, 0x2573 }, { 0x2580, 0x258F }, { 0x2592, 0x2595 }, - { 0x25A0, 0x25A1 }, { 0x25A3, 0x25A9 }, { 0x25B2, 0x25B3 }, - { 0x25B6, 0x25B7 }, { 0x25BC, 0x25BD }, { 0x25C0, 0x25C1 }, - { 0x25C6, 0x25C8 }, { 0x25CB, 0x25CB }, { 0x25CE, 0x25D1 }, - { 0x25E2, 0x25E5 }, { 0x25EF, 0x25EF }, { 0x2605, 0x2606 }, - { 0x2609, 0x2609 }, { 0x260E, 0x260F }, { 0x2614, 0x2615 }, - { 0x261C, 0x261C }, { 0x261E, 0x261E }, { 0x2640, 0x2640 }, - { 0x2642, 0x2642 }, { 0x2660, 0x2661 }, { 0x2663, 0x2665 }, - { 0x2667, 0x266A }, { 0x266C, 0x266D }, { 0x266F, 0x266F }, - { 0x273D, 0x273D }, { 0x2776, 0x277F }, { 0xE000, 0xF8FF }, - { 0xFFFD, 0xFFFD }, { 0xF0000, 0xFFFFD }, { 0x100000, 0x10FFFD } + {0x00A1, 0x00A1}, + {0x00A4, 0x00A4}, + {0x00A7, 0x00A8}, + {0x00AA, 0x00AA}, + {0x00AD, 0x00AE}, + {0x00B0, 0x00B4}, + {0x00B6, 0x00BA}, + {0x00BC, 0x00BF}, + {0x00C6, 0x00C6}, + {0x00D0, 0x00D0}, + {0x00D7, 0x00D8}, + {0x00DE, 0x00E1}, + {0x00E6, 0x00E6}, + {0x00E8, 0x00EA}, + {0x00EC, 0x00ED}, + {0x00F0, 0x00F0}, + {0x00F2, 0x00F3}, + {0x00F7, 0x00FA}, + {0x00FC, 0x00FC}, + {0x00FE, 0x00FE}, + {0x0101, 0x0101}, + {0x0111, 0x0111}, + {0x0113, 0x0113}, + {0x011B, 0x011B}, + {0x0126, 0x0127}, + {0x012B, 0x012B}, + {0x0131, 0x0133}, + {0x0138, 0x0138}, + {0x013F, 0x0142}, + {0x0144, 0x0144}, + {0x0148, 0x014B}, + {0x014D, 0x014D}, + {0x0152, 0x0153}, + {0x0166, 0x0167}, + {0x016B, 0x016B}, + {0x01CE, 0x01CE}, + {0x01D0, 0x01D0}, + {0x01D2, 0x01D2}, + {0x01D4, 0x01D4}, + {0x01D6, 0x01D6}, + {0x01D8, 0x01D8}, + {0x01DA, 0x01DA}, + {0x01DC, 0x01DC}, + {0x0251, 0x0251}, + {0x0261, 0x0261}, + {0x02C4, 0x02C4}, + {0x02C7, 0x02C7}, + {0x02C9, 0x02CB}, + {0x02CD, 0x02CD}, + {0x02D0, 0x02D0}, + {0x02D8, 0x02DB}, + {0x02DD, 0x02DD}, + {0x02DF, 0x02DF}, + {0x0300, 0x036F}, + {0x0391, 0x03A1}, + {0x03A3, 0x03A9}, + {0x03B1, 0x03C1}, + {0x03C3, 0x03C9}, + {0x0401, 0x0401}, + {0x0410, 0x044F}, + {0x0451, 0x0451}, + {0x2010, 0x2010}, + {0x2013, 0x2016}, + {0x2018, 0x2019}, + {0x201C, 0x201D}, + {0x2020, 0x2022}, + {0x2024, 0x2027}, + {0x2030, 0x2030}, + {0x2032, 0x2033}, + {0x2035, 0x2035}, + {0x203B, 0x203B}, + {0x203E, 0x203E}, + {0x2074, 0x2074}, + {0x207F, 0x207F}, + {0x2081, 0x2084}, + {0x20AC, 0x20AC}, + {0x2103, 0x2103}, + {0x2105, 0x2105}, + {0x2109, 0x2109}, + {0x2113, 0x2113}, + {0x2116, 0x2116}, + {0x2121, 0x2122}, + {0x2126, 0x2126}, + {0x212B, 0x212B}, + {0x2153, 0x2154}, + {0x215B, 0x215E}, + {0x2160, 0x216B}, + {0x2170, 0x2179}, + {0x2189, 0x2189}, + {0x2190, 0x2199}, + {0x21B8, 0x21B9}, + {0x21D2, 0x21D2}, + {0x21D4, 0x21D4}, + {0x21E7, 0x21E7}, + {0x2200, 0x2200}, + {0x2202, 0x2203}, + {0x2207, 0x2208}, + {0x220B, 0x220B}, + {0x220F, 0x220F}, + {0x2211, 0x2211}, + {0x2215, 0x2215}, + {0x221A, 0x221A}, + {0x221D, 0x2220}, + {0x2223, 0x2223}, + {0x2225, 0x2225}, + {0x2227, 0x222C}, + {0x222E, 0x222E}, + {0x2234, 0x2237}, + {0x223C, 0x223D}, + {0x2248, 0x2248}, + {0x224C, 0x224C}, + {0x2252, 0x2252}, + {0x2260, 0x2261}, + {0x2264, 0x2267}, + {0x226A, 0x226B}, + {0x226E, 0x226F}, + {0x2282, 0x2283}, + {0x2286, 0x2287}, + {0x2295, 0x2295}, + {0x2299, 0x2299}, + {0x22A5, 0x22A5}, + {0x22BF, 0x22BF}, + {0x2312, 0x2312}, + {0x2460, 0x24E9}, + {0x24EB, 0x254B}, + {0x2550, 0x2573}, + {0x2580, 0x258F}, + {0x2592, 0x2595}, + {0x25A0, 0x25A1}, + {0x25A3, 0x25A9}, + {0x25B2, 0x25B3}, + {0x25B6, 0x25B7}, + {0x25BC, 0x25BD}, + {0x25C0, 0x25C1}, + {0x25C6, 0x25C8}, + {0x25CB, 0x25CB}, + {0x25CE, 0x25D1}, + {0x25E2, 0x25E5}, + {0x25EF, 0x25EF}, + {0x2605, 0x2606}, + {0x2609, 0x2609}, + {0x260E, 0x260F}, + {0x261C, 0x261C}, + {0x261E, 0x261E}, + {0x2640, 0x2640}, + {0x2642, 0x2642}, + {0x2660, 0x2661}, + {0x2663, 0x2665}, + {0x2667, 0x266A}, + {0x266C, 0x266D}, + {0x266F, 0x266F}, + {0x269E, 0x269F}, + {0x26BF, 0x26BF}, + {0x26C6, 0x26CD}, + {0x26CF, 0x26D3}, + {0x26D5, 0x26E1}, + {0x26E3, 0x26E3}, + {0x26E8, 0x26E9}, + {0x26EB, 0x26F1}, + {0x26F4, 0x26F4}, + {0x26F6, 0x26F9}, + {0x26FB, 0x26FC}, + {0x26FE, 0x26FF}, + {0x273D, 0x273D}, + {0x2776, 0x277F}, + {0x2B56, 0x2B59}, + {0x3248, 0x324F}, + {0xE000, 0xF8FF}, + {0xFE00, 0xFE0F}, + {0xFFFD, 0xFFFD}, + {0x1F100, 0x1F10A}, + {0x1F110, 0x1F12D}, + {0x1F130, 0x1F169}, + {0x1F170, 0x1F18D}, + {0x1F18F, 0x1F190}, + {0x1F19B, 0x1F1AC}, + {0xE0100, 0xE01EF}, + {0xF0000, 0xFFFFD}, + {0x100000, 0x10FFFD}, }; /* binary search in table of non-spacing characters */ From 4624115b76903b0b9ad97bee713afafcbd70a31c Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Mon, 3 Jul 2017 07:27:05 +0100 Subject: [PATCH 054/607] Make -DMINEFIELD show up in Windows buildinfo. I listed a lot of other build options, but not that one. The release checklist still recommends doing test builds with it, so it seems sensible to arrange that you can tell if a build _is_ one of those or not. --- misc.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/misc.c b/misc.c index 469e4aeb..fc5b149d 100644 --- a/misc.c +++ b/misc.c @@ -1214,6 +1214,9 @@ char *buildinfo(const char *newline) } #endif +#if defined _WINDOWS && defined MINEFIELD + strbuf_catf(buf, "%sBuild option: MINEFIELD", newline); +#endif #ifdef NO_SECURITY strbuf_catf(buf, "%sBuild option: NO_SECURITY", newline); #endif From ea0ab1c8218f28957b6e20dd84f9d2a3f19313e6 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Mon, 3 Jul 2017 07:19:07 +0100 Subject: [PATCH 055/607] Simplify running of release.pl --setver. Previously, it demanded that your checkout was in a state where you had run autoconf but not configure; so if you previously did have a Makefile then you had to 'make distclean' to remove it, whereas if you previously had no generated files at all (e.g. starting from a completely clean checkout) then you had to run mkfiles.pl and mkauto.sh to generate 'configure'. This is obviously confusing, and moreover, the dependence on prior generated files is fragile and prone to them having been generated wrong. Adjusted the script so that it uses 'git archive' to get a clean directory containing only the version-controlled files, and then runs scripts itself to get that directory into the state it wants. --- CHECKLST.txt | 1 - release.pl | 7 +++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHECKLST.txt b/CHECKLST.txt index 8d55ac41..f757c5e0 100644 --- a/CHECKLST.txt +++ b/CHECKLST.txt @@ -52,7 +52,6 @@ for it: - Now update the version numbers and the transcripts in the docs, by checking out the release branch and running - make distclean ./release.pl --version=X.YZ --setver Then check that the resulting automated git commit has updated the diff --git a/release.pl b/release.pl index cf73d9eb..7c76c6ae 100755 --- a/release.pl +++ b/release.pl @@ -31,8 +31,11 @@ 0 == system "git", "diff-files", "--quiet" or die "working tree is dirty"; -f "Makefile" and die "run 'make distclean' first"; my $builddir = tempdir(DIR => ".", CLEANUP => 1); - 0 == system "./mkfiles.pl" or die; - 0 == system "cd $builddir && ../configure" or die; + 0 == system "git archive --format=tar HEAD | ( cd $builddir && tar xf - )" + or die; + 0 == system "cd $builddir && ./mkfiles.pl" or die; + 0 == system "cd $builddir && ./mkauto.sh" or die; + 0 == system "cd $builddir && ./configure" or die; 0 == system "cd $builddir && make pscp plink RELEASE=${version}" or die; our $pscp_transcript = `cd $builddir && ./pscp --help`; $pscp_transcript =~ s/^Unidentified build/Release ${version}/m or die; From 5cac6013b702b014a063ed98ad91128308bc1b48 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Mon, 3 Jul 2017 07:38:20 +0100 Subject: [PATCH 056/607] Rework the release checklist for current practice. In recent releases we've taken to making the actual release build (or rather, candidates for it) ahead of time so that we can do some slightly more thorough last-minute testing of the exact binaries that we're going to release to everyone. It's time I actually wrote that procedure down in the checklist, so that I remember what it is. In particular, we had the idea that we should not properly GPG-sign the release until the last moment, and use the presence of a set of full GPG signatures as a means of distinguishing the real release build from an RC that accidentally got out into the wild somehow. This checklist update formalises that too, and documents the method I used of ensuring the binaries weren't tampered with between RC building and release signing (by making a signature on just the sha512sums). I also include in this commit an extra command-line option to sign.sh to make that preliminary signature step more convenient. --- CHECKLST.txt | 104 +++++++++++++++++++++++++++++++-------------------- sign.sh | 43 ++++++++++++++++----- 2 files changed, 97 insertions(+), 50 deletions(-) diff --git a/CHECKLST.txt b/CHECKLST.txt index f757c5e0..21f38656 100644 --- a/CHECKLST.txt +++ b/CHECKLST.txt @@ -24,25 +24,28 @@ pre-releases on the website: add a news announcement in components/news. (Previous naming convention has been to name it in the form 'X.YZ-pre.mi'.) -Preparing to make a release ---------------------------- +Things to do during the branch-stabilisation period: -Now that PuTTY is in git, a lot of the release preparation can be done -in advance, in local checkouts, and not pushed until the actual -process of _releasing_ it. + - Go through the source (including the documentation), and the + website, and review anything tagged with a comment containing the + word XXX-REVIEW-BEFORE-RELEASE. (Any such comments should state + clearly what needs to be done.) -To begin with, before dropping the tag, make sure everything is ready -for it: + - Do some testing of the Windows version with Minefield (you can + build a Minefield version using 'bob . XFLAGS=-DMINEFIELD'), and of + the Unix version with valgrind. In particular, any headline + features for the release should get a workout with memory checking + enabled! - - First of all, go through the source (including the documentation), - and the website, and review anything tagged with a comment - containing the word XXX-REVIEW-BEFORE-RELEASE. - (Any such comments should state clearly what needs to be done.) +Making a release candidate build +-------------------------------- - - Also, do some testing of the Windows version with Minefield, and - of the Unix version with valgrind or efence or both. In - particular, any headline features for the release should get a - workout with memory checking enabled! + - Make a directory to hold all the release paraphernalia. I usually + call it ~/src/putty/X.YZ (where X.YZ will stand throughout for the + version number). In that directory, make a git clone of the PuTTY + repository, where you can make release-related commits and tags + tentatively, and keep them out of the way of any 'git push' you + might still be doing in other checkouts. - Double-check that we have removed anything tagged with a comment containing the words XXX-REMOVE-BEFORE-RELEASE or @@ -50,7 +53,8 @@ for it: hits in this file itself.) - Now update the version numbers and the transcripts in the docs, by - checking out the release branch and running + checking out the release branch in the release-specific checkout + and running ./release.pl --version=X.YZ --setver @@ -71,6 +75,42 @@ for it: - If the release is on a branch (which I expect it generally will be), merge that branch to master. + - Make a release-candidate build from the release tag, and put the + build.out and build.log dfiles somewhere safe. Normally I store + these in an adjacent directory, so I'll run a command like + bob -o ../X.YZ/build-X.YZ-rcN.out -l ../X.YZ/build-X.YZ-rcN.log -c X.YZ . RELEASE=X.YZ + This should generate a basically valid release directory as + `build-X.YZ-rcN.out/putty', and provide link maps and sign.sh + alongside that. + + - Double-check in build-X.YZ-rcN.log that the release was built from + the right git commit. + + - Make a preliminary gpg signature, but don't run the full release- + signing procedure. (We use the presence of a full set of GPG + signatures to distinguish _abandoned_ release candidates from the + one that ended up being the release.) In the 'build.X.YZ-rcN.out' + directory, run + sh sign.sh -r -p putty + and you should only have to enter the release key passphrase once, + which will generate a clearsigned file called + sha512sums-preliminary.gpg _outside_ the 'putty' subdirectory. + + - For my own safety, make the release candidate build read-only. + chmod -R a-w build-X.YZ-rcN.out build-X.YZ-rcN.log + + - Now do some checking of the release binaries, and pass them to the + rest of the team to do some as well. Do at least these things: + * make sure they basically work + * check they report the right version number + * if there's any easily observable behaviour difference between + the release branch and master, arrange to observe it + * test the Windows installer + * test the Unix source tarball. + +Preparing to make the release +----------------------------- + - Write a release announcement (basically a summary of the changes since the last release). Squirrel it away in thyestes:src/putty-local/announce- in case it's needed again @@ -96,31 +136,15 @@ for it: them as fixed in the new release), add appropriate Fixed-in headers for those. - - Make a release-candidate build from the release tag, and put the - build.out and build.log dfiles somewhere safe. Normally I store - these in an adjacent directory, so I'll run a command like - bob -o ../X.YZ/build-X.YZ-rcN.out -l ../X.YZ/build-X.YZ-rcN.log -c X.YZ . RELEASE=X.YZ - This should generate a basically valid release directory as - `build-X.YZ-rcN.out/putty', and provide link maps and sign.sh - alongside that. - - - Double-check in build-X.YZ-rcN.log that the release was built from - the right git commit. - - - Do a bit of checking of the release binaries: - * make sure they basically work - * check they report the right version number - * if there's any easily observable behaviour difference between - the release branch and master, arrange to observe it - * test the Windows installer - * test the Unix source tarball. - - - Sign the release: in the `build-X.YZ-rcN.out' directory, type + - Sign the release in full. In the `build-X.YZ-rcN.out' directory, + re-verify that the preliminary signed checksums file has a correct + signature on it and also matches the files you're about to sign for real: + gpg -d sha512sums-preliminary.gpg | (cd putty; sha512sum -c) + If the combined output of that pipeline reports both a good + signature (from the release key) and a successful verification of + all the sha512sums, then all is well, so now run sh sign.sh -r putty - and enter the passphrases a lot of times. - - - For my own safety, make the release candidate build read-only. - chmod -R a-w build-X.YZ-rcN.out build-X.YZ-rcN.log + and enter the release key passphrase a lot of times. The actual release procedure ---------------------------- diff --git a/sign.sh b/sign.sh index bdf6245f..8dbdb613 100755 --- a/sign.sh +++ b/sign.sh @@ -10,11 +10,27 @@ set -e keyname=EEF20295D15F7E8A +preliminary=false -if test "x$1" = "x-r"; then - shift - keyname=9DFE2648B43434E4 -fi +while :; do + case "$1" in + -r) + shift + keyname=9DFE2648B43434E4 + ;; + -p) + shift + preliminary=true + ;; + -*) + echo "Unknown option '$1'" >&2 + exit 1 + ;; + *) + break + ;; + esac +done sign() { # Check for the prior existence of the signature, so we can @@ -27,9 +43,16 @@ sign() { cd "$1" echo "===== Signing with key '$keyname'" -for i in putty*src.zip putty*.tar.gz w32/*.exe w32/*.zip w32/*.msi w64/*.exe w64/*.zip w64/*.msi w32old/*.exe w32old/*.zip; do - sign --detach-sign "$i" "$i.gpg" -done -for i in md5sums sha1sums sha256sums sha512sums; do - sign --clearsign "$i" "$i.gpg" -done +if $preliminary; then + sign --clearsign sha512sums ../sha512sums-preliminary.gpg +else + for i in putty*src.zip putty*.tar.gz \ + w32/*.exe w32/*.zip w32/*.msi \ + w64/*.exe w64/*.zip w64/*.msi \ + w32old/*.exe w32old/*.zip; do + sign --detach-sign "$i" "$i.gpg" + done + for i in md5sums sha1sums sha256sums sha512sums; do + sign --clearsign "$i" "$i.gpg" + done +fi From a2b040ee094fcd43b4d53e14121c8c2301fba303 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Tue, 4 Jul 2017 19:35:18 +0100 Subject: [PATCH 057/607] Expand the About box. It wasn't big enough to fit the full buildinfo text, when compiling with clang-cl which has a bulky compiler identification string. --- windows/win_res.rc2 | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/windows/win_res.rc2 b/windows/win_res.rc2 index 92d39cd5..0c486ce5 100644 --- a/windows/win_res.rc2 +++ b/windows/win_res.rc2 @@ -16,15 +16,15 @@ IDI_MAINICON ICON "putty.ico" IDI_CFGICON ICON "puttycfg.ico" /* Accelerators used: clw */ -IDD_ABOUTBOX DIALOG DISCARDABLE 140, 40, 270, 106 +IDD_ABOUTBOX DIALOG DISCARDABLE 140, 40, 270, 136 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "About PuTTY" FONT 8, "MS Shell Dlg" BEGIN - DEFPUSHBUTTON "&Close", IDOK, 216, 88, 48, 14 - PUSHBUTTON "View &Licence", IDA_LICENCE, 6, 88, 70, 14 - PUSHBUTTON "Visit &Web Site", IDA_WEB, 140, 88, 70, 14 - EDITTEXT IDA_TEXT, 10, 6, 250, 80, ES_READONLY | ES_MULTILINE | ES_CENTER, WS_EX_STATICEDGE + DEFPUSHBUTTON "&Close", IDOK, 216, 118, 48, 14 + PUSHBUTTON "View &Licence", IDA_LICENCE, 6, 118, 70, 14 + PUSHBUTTON "Visit &Web Site", IDA_WEB, 140, 118, 70, 14 + EDITTEXT IDA_TEXT, 10, 6, 250, 110, ES_READONLY | ES_MULTILINE | ES_CENTER, WS_EX_STATICEDGE END /* Accelerators used: aco */ From 3cd10509a51edf5a21cdc80aabf7e6a934522d47 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Tue, 4 Jul 2017 20:29:54 +0100 Subject: [PATCH 058/607] Update version number for 0.70 release. --- Buildscr | 2 +- LATEST.VER | 2 +- doc/plink.but | 2 +- doc/pscp.but | 2 +- windows/putty.iss | 8 ++++---- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Buildscr b/Buildscr index ab94ea92..8833a9c4 100644 --- a/Buildscr +++ b/Buildscr @@ -35,7 +35,7 @@ module putty ifeq "$(RELEASE)" "" set Ndate $(!builddate) ifneq "$(Ndate)" "" in . do echo $(Ndate) | perl -pe 's/(....)(..)(..)/$$1-$$2-$$3/' > date ifneq "$(Ndate)" "" read Date date -set Epoch 16280 # update this at every release +set Epoch 16351 # update this at every release ifneq "$(Ndate)" "" in . do echo $(Ndate) | perl -ne 'use Time::Local; /(....)(..)(..)/ and print timegm(0,0,0,$$3,$$2-1,$$1) / 86400 - $(Epoch)' > days ifneq "$(Ndate)" "" read Days days diff --git a/LATEST.VER b/LATEST.VER index b04c6474..ac37bbea 100644 --- a/LATEST.VER +++ b/LATEST.VER @@ -1 +1 @@ -0.69 +0.70 diff --git a/doc/plink.but b/doc/plink.but index 153982e0..459ceadf 100644 --- a/doc/plink.but +++ b/doc/plink.but @@ -41,7 +41,7 @@ use Plink: \c Z:\sysosd>plink \c Plink: command-line connection utility -\c Release 0.69 +\c Release 0.70 \c Usage: plink [options] [user@]host [command] \c ("host" can also be a PuTTY saved session name) \c Options: diff --git a/doc/pscp.but b/doc/pscp.but index 30a47f83..7b90810b 100644 --- a/doc/pscp.but +++ b/doc/pscp.but @@ -39,7 +39,7 @@ use PSCP: \c Z:\owendadmin>pscp \c PuTTY Secure Copy client -\c Release 0.69 +\c Release 0.70 \c Usage: pscp [options] [user@]host:source target \c pscp [options] source [source...] [user@]host:target \c pscp [options] -ls [user@]host:filespec diff --git a/windows/putty.iss b/windows/putty.iss index 3fadcb92..ae926310 100644 --- a/windows/putty.iss +++ b/windows/putty.iss @@ -14,10 +14,10 @@ [Setup] AppName=PuTTY -AppVerName=PuTTY version 0.69 -VersionInfoTextVersion=Release 0.69 -AppVersion=0.69 -VersionInfoVersion=0.69.0.0 +AppVerName=PuTTY version 0.70 +VersionInfoTextVersion=Release 0.70 +AppVersion=0.70 +VersionInfoVersion=0.70.0.0 AppPublisher=Simon Tatham AppPublisherURL=https://www.chiark.greenend.org.uk/~sgtatham/putty/ AppReadmeFile={app}\README.txt From 7470e3bdaffc64260c0f786908682128b58c38c7 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 8 Jul 2017 09:20:55 +0100 Subject: [PATCH 059/607] Stop release.pl --setver failing if Makefile exists. This should have been part of commit ea0ab1c82; it's part of the general revamp that we regenerate the autoconf files ourselves in a clean directory - so we don't depend on them being present, but we also don't depend on them being _absent_ either. But when I made that commit my immediate priority was to get --setver to work from a completely clean checkout, not from one already littered with cruft, so I didn't check quite as carefully that my changes fixed the problem in the latter case too :-) --- release.pl | 1 - 1 file changed, 1 deletion(-) diff --git a/release.pl b/release.pl index 7c76c6ae..da7d2a88 100755 --- a/release.pl +++ b/release.pl @@ -29,7 +29,6 @@ 0 == system "git", "diff-index", "--quiet", "--cached", "HEAD" or die "index is dirty"; 0 == system "git", "diff-files", "--quiet" or die "working tree is dirty"; - -f "Makefile" and die "run 'make distclean' first"; my $builddir = tempdir(DIR => ".", CLEANUP => 1); 0 == system "git archive --format=tar HEAD | ( cd $builddir && tar xf - )" or die; From 0e2955ffbff083212d2a8a0d7fd829716f283081 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 8 Jul 2017 09:23:51 +0100 Subject: [PATCH 060/607] Add a --no-ftp mode to the release.pl download checks. chiark's ftp server sometimes randomly refuses downloads. In the case where this happens at postcheck time, this isn't really release-blocking (all the files have been test-downloaded by precheck already, so the main aim at this stage is to check that the 'latest' symlink points to the right place, and even one or two successful downloads are good enough to confirm that in practice). So now I can add --no-ftp to the postcheck command line if that makes my life easier. --- release.pl | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/release.pl b/release.pl index da7d2a88..b5ad149c 100755 --- a/release.pl +++ b/release.pl @@ -15,11 +15,13 @@ my $upload = 0; my $precheck = 0; my $postcheck = 0; +my $skip_ftp = 0; GetOptions("version=s" => \$version, "setver" => \$setver, "upload" => \$upload, "precheck" => \$precheck, - "postcheck" => \$postcheck) + "postcheck" => \$postcheck, + "no-ftp" => \$skip_ftp) or &usage(); # --set-version: construct a local commit which updates the version @@ -163,11 +165,13 @@ } # Now test-download the files themselves. - my $ftpdata = `curl -s $ftp_uri`; - printf " got %d bytes via FTP", length $ftpdata; - die "FTP download for $ftp_uri did not match" - if $ftpdata ne $real_content; - print ", ok\n"; + unless ($skip_ftp) { + my $ftpdata = `curl -s $ftp_uri`; + printf " got %d bytes via FTP", length $ftpdata; + die "FTP download for $ftp_uri did not match" + if $ftpdata ne $real_content; + print ", ok\n"; + } my $ua = LWP::UserAgent->new; my $httpresponse = $ua->get($http_uri); From 309c3dfd95505f1bf1e4b4d488a5f03f0cf24b3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Thu, 6 Jul 2017 10:18:27 +0200 Subject: [PATCH 061/607] Add -share -noshare command line option to plink to share SSL connections. --- cmdline.c | 13 ++++++++++++- doc/man-pl.but | 9 +++++++++ doc/plink.but | 24 ++++++++++++++++++++++++ unix/uxplink.c | 2 ++ windows/winplink.c | 2 ++ 5 files changed, 49 insertions(+), 1 deletion(-) diff --git a/cmdline.c b/cmdline.c index f288ed62..d2a81592 100644 --- a/cmdline.c +++ b/cmdline.c @@ -403,7 +403,18 @@ int cmdline_process_param(const char *p, char *value, SAVEABLE(0); conf_set_int(conf, CONF_tryagent, FALSE); } - + if (!strcmp(p, "-share")) { + RETURN(1); + UNAVAILABLE_IN(TOOLTYPE_NONNETWORK); + SAVEABLE(0); + conf_set_int(conf, CONF_ssh_connection_sharing, TRUE); + } + if (!strcmp(p, "-noshare")) { + RETURN(1); + UNAVAILABLE_IN(TOOLTYPE_NONNETWORK); + SAVEABLE(0); + conf_set_int(conf, CONF_ssh_connection_sharing, FALSE); + } if (!strcmp(p, "-A")) { RETURN(1); UNAVAILABLE_IN(TOOLTYPE_FILETRANSFER | TOOLTYPE_NONNETWORK); diff --git a/doc/man-pl.but b/doc/man-pl.but index 9f411871..58ca7a28 100644 --- a/doc/man-pl.but +++ b/doc/man-pl.but @@ -182,6 +182,15 @@ which of the agent's keys to use. } \dd Allow use of an authentication agent. (This option is only necessary to override a setting in a saved session.) +\dt \cw{\-noshare} + +\dd Don't test and try to share an existing connection, always make +a new connection. + +\dt \cw{\-share} + +\dd Test and try to share an existing connection. + \dt \cw{\-hostkey} \e{key} \dd Specify an acceptable host public key. This option may be specified diff --git a/doc/plink.but b/doc/plink.but index 459ceadf..74da18a1 100644 --- a/doc/plink.but +++ b/doc/plink.but @@ -75,6 +75,8 @@ use Plink: \c -i key private key file for user authentication \c -noagent disable use of Pageant \c -agent enable use of Pageant +\c -noshare disable use of connection sharing +\c -share enable use of connection sharing \c -hostkey aa:bb:cc:... \c manually specify a host key (may be repeated) \c -m file read remote command(s) from file @@ -237,6 +239,28 @@ line. (This option is only meaningful with the SSH-2 protocol.) +\S2{plink-option-share} \I{-share-plink}\c{-share}: +Test and try to share an existing connection. + +This option tris to detect if an existing connection can be shared +(See \k{config-ssh-sharing} for more information about SSH connection +sharing.) and reuses that connection. + +A Plink invocation of the form: + +\c plink -share +\e iiiiiiiii + +will test whether there is currently a viable \q{upstream} for the +session in question, which can be specified using any syntax you'd +normally use with Plink to make an actual connection (a host/port +number, a bare saved session name, \c{-load}, etc). If no \q{upstream} +viable session is found and \c{-share} is specified, this connection +will be become the \q{upstream} connection for subsequent connection +sharing tries. + +(This option is only meaningful with the SSH-2 protocol.) + \S2{plink-option-shareexists} \I{-shareexists-plink}\c{-shareexists}: test for connection-sharing upstream diff --git a/unix/uxplink.c b/unix/uxplink.c index e891d66a..2a1926ef 100644 --- a/unix/uxplink.c +++ b/unix/uxplink.c @@ -579,6 +579,8 @@ static void usage(void) printf(" -i key private key file for user authentication\n"); printf(" -noagent disable use of Pageant\n"); printf(" -agent enable use of Pageant\n"); + printf(" -noshare disable use of connection sharing\n"); + printf(" -share enable use of connection sharing\n"); printf(" -hostkey aa:bb:cc:...\n"); printf(" manually specify a host key (may be repeated)\n"); printf(" -m file read remote command(s) from file\n"); diff --git a/windows/winplink.c b/windows/winplink.c index ea417501..84e47d6e 100644 --- a/windows/winplink.c +++ b/windows/winplink.c @@ -207,6 +207,8 @@ static void usage(void) printf(" -i key private key file for user authentication\n"); printf(" -noagent disable use of Pageant\n"); printf(" -agent enable use of Pageant\n"); + printf(" -noshare disable use of connection sharing\n"); + printf(" -share enable use of connection sharing\n"); printf(" -hostkey aa:bb:cc:...\n"); printf(" manually specify a host key (may be repeated)\n"); printf(" -m file read remote command(s) from file\n"); From 25683f0f3d5a654c1e2a8e1d43dca3778a77e7de Mon Sep 17 00:00:00 2001 From: Jacob Nevins Date: Wed, 12 Jul 2017 10:19:23 +0100 Subject: [PATCH 062/607] Add a FAQ about servers that don't like IUTF8. --- doc/faq.but | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/doc/faq.but b/doc/faq.but index cd3254a8..4d9e14a9 100644 --- a/doc/faq.but +++ b/doc/faq.but @@ -1002,6 +1002,26 @@ appropriate kind of binaries in \cw{SYSTEM32}. Thus, operations in the PuTTY suite that involve it accessing its own executables, such as \i{\q{New Session}} and \q{Duplicate Session}, will not work. +\S{faq-iutf8}{Question} After I upgraded PuTTY to 0.68, I can no longer +connect to my embedded device or appliance. + +If your SSH server has started unexpectedly closing SSH connections +after you enter your password, and it worked before 0.68, you may have +a buggy server that objects to certain SSH protocol extensions. + +The SSH protocol recently gained a new \q{terminal mode}, \cw{IUTF8}, +which PuTTY sends by default; see \k{config-ttymodes}. This is the +first new terminal mode since the SSH-2 protocol was defined. While +servers are supposed to ignore modes they don't know about, some buggy +servers will unceremoniously close the connection if they see anything +they don't recognise. SSH servers in embedded devices, network +appliances, and the like seem to disproportionately have this bug. + +If you think you have such a server, from 0.69 onwards you can disable +sending of the \cw{IUTF8} mode: on the SSH / TTY panel, select +\cw{IUTF8} on the list, select \q{Nothing}, and press \q{Set}. (It's +not possible to disable sending this mode in 0.68.) + \H{faq-secure} Security questions \S{faq-publicpc}{Question} Is it safe for me to download PuTTY and From f0126dd198358f2ae351bc49e8edf056c3ce2c6e Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Mon, 17 Jul 2017 20:57:07 +0100 Subject: [PATCH 063/607] Set ssh->mainchan->type earlier. A user reported a nonsensical assertion failure (claiming that ssh->version != 2) which suggested that a channel had somehow outlived its parent Ssh in the situation where the opening of the main session channel is rejected by the server. Checking with valgrind suggested that things start to go wrong at the point where we free the half-set- up ssh->mainchan before having filled in its type field, so that the switch in ssh_channel_close_local() picks an arbitrary wrong action. I haven't reproduced the same failure the user reported, but with this change, Unix plink is now valgrind-clean in that failure situation. --- ssh.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssh.c b/ssh.c index 1d80e919..89041f48 100644 --- a/ssh.c +++ b/ssh.c @@ -10722,6 +10722,7 @@ static void do_ssh2_authconn(Ssh ssh, const unsigned char *in, int inlen, } else { ssh->mainchan = snew(struct ssh_channel); ssh->mainchan->ssh = ssh; + ssh->mainchan->type = CHAN_MAINSESSION; ssh_channel_init(ssh->mainchan); if (*conf_get_str(ssh->conf, CONF_ssh_nc_host)) { @@ -10761,7 +10762,6 @@ static void do_ssh2_authconn(Ssh ssh, const unsigned char *in, int inlen, ssh->mainchan->remoteid = ssh_pkt_getuint32(pktin); ssh->mainchan->halfopen = FALSE; - ssh->mainchan->type = CHAN_MAINSESSION; ssh->mainchan->v.v2.remwindow = ssh_pkt_getuint32(pktin); ssh->mainchan->v.v2.remmaxpkt = ssh_pkt_getuint32(pktin); update_specials_menu(ssh->frontend); From 0a93b5d9bc6131c0cd84395f4aa88cac0cb40f23 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Wed, 19 Jul 2017 07:22:03 +0100 Subject: [PATCH 064/607] Stop ssh2_msg_channel_response using a stale ssh_channel. When it calls through ocr->handler() to process the response to a channel request, sometimes that call ends up back in the main SSH-2 authconn coroutine, and sometimes _that_ will call bomb_out(), which closes the whole SSH connection and frees all the channels - so that when control returns back up the call stack to ssh2_msg_channel_response itself which continues working with the channel it was passed, it's using freed memory and things go badly. This is the sort of thing I'd _like_ to fix using some kind of large-scale refactoring along the lines of moving all the actual free() calls out into top-level callbacks, so that _any_ function which is holding a pointer to something can rely on that pointer still being valid after it calls a subroutine. But I haven't worked out all the details of how that system should work, and doubtless it will turn out to have problems of its own once I do, so here's a point fix which simply checks if the whole SSH session has been closed (which is easy - much easier than checking if that _channel_ structure still exists) and fixes the immediate bug. (I think this is the real fix for the problem reported by the user I mention in commit f0126dd19, because I actually got the details wrong in the log message for that previous commit: the user's SSH server wasn't rejecting the _opening_ of the main session channel, it was rejecting the "shell" channel request, so this code path was the one being exercised. Still, the other bug was real too, so no harm done!) --- ssh.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ssh.c b/ssh.c index 89041f48..aa9fd5dd 100644 --- a/ssh.c +++ b/ssh.c @@ -8105,6 +8105,8 @@ static void ssh2_msg_channel_response(Ssh ssh, struct Packet *pktin) return; } ocr->handler(c, pktin, ocr->ctx); + if (ssh->state == SSH_STATE_CLOSED) + return; /* in case the handler called bomb_out(), which some can */ c->v.v2.chanreq_head = ocr->next; sfree(ocr); /* From 55efbc56a0f482d237b2315efac42c2f3301d986 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Fri, 4 Aug 2017 19:46:21 +0100 Subject: [PATCH 065/607] Fix filename of the 64-bit MIT Kerberos DLL. 64-bit PuTTY should be loading gssapi64.dll, not gssapi32.dll. (In contrast to the Windows system API DLLs, such as secur32.dll which is also mentioned in the same source file; those keep the "32" in their name whether we're in Win32 or Win64.) --- windows/wingss.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/windows/wingss.c b/windows/wingss.c index ef056167..54b1e477 100644 --- a/windows/wingss.c +++ b/windows/wingss.c @@ -13,9 +13,15 @@ /* Windows code to set up the GSSAPI library list. */ +#ifdef _WIN64 +#define MIT_KERB_SUFFIX "64" +#else +#define MIT_KERB_SUFFIX "32" +#endif + const int ngsslibs = 3; const char *const gsslibnames[3] = { - "MIT Kerberos GSSAPI32.DLL", + "MIT Kerberos GSSAPI"MIT_KERB_SUFFIX".DLL", "Microsoft SSPI SECUR32.DLL", "User-specified GSSAPI DLL", }; @@ -90,7 +96,6 @@ struct ssh_gss_liblist *ssh_gss_setup(Conf *conf) list->nlibraries = 0; /* MIT Kerberos GSSAPI implementation */ - /* TODO: For 64-bit builds, check for gssapi64.dll */ module = NULL; if (RegOpenKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\MIT\\Kerberos", ®key) == ERROR_SUCCESS) { @@ -115,7 +120,7 @@ struct ssh_gss_liblist *ssh_gss_setup(Conf *conf) p_AddDllDirectory(dllPath); sfree(dllPath); } - strcat (buffer, "\\gssapi32.dll"); + strcat (buffer, "\\gssapi"MIT_KERB_SUFFIX".dll"); module = LoadLibraryEx (buffer, NULL, LOAD_LIBRARY_SEARCH_SYSTEM32 | LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | @@ -130,7 +135,7 @@ struct ssh_gss_liblist *ssh_gss_setup(Conf *conf) &list->libraries[list->nlibraries++]; lib->id = 0; - lib->gsslogmsg = "Using GSSAPI from GSSAPI32.DLL"; + lib->gsslogmsg = "Using GSSAPI from GSSAPI"MIT_KERB_SUFFIX".DLL"; lib->handle = (void *)module; #define BIND_GSS_FN(name) \ From a459fc58e844a2152cedb068d5b552bd3aabd654 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 26 Aug 2017 15:23:56 +0100 Subject: [PATCH 066/607] Switch to producing .res files, not .res.o. I've just upgraded my build process to a version of lld-link that knows how to read .res, and I think it's a slightly more commonly found format, so less confusing to encounter. --- mkfiles.pl | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mkfiles.pl b/mkfiles.pl index 1d83912b..02421316 100755 --- a/mkfiles.pl +++ b/mkfiles.pl @@ -556,10 +556,10 @@ sub manpages { print "\n\n"; foreach $p (&prognames("G:C")) { ($prog, $type) = split ",", $p; - $objstr = &objects($p, "\$(BUILDDIR)X.obj", "\$(BUILDDIR)X.res.o", undef); + $objstr = &objects($p, "\$(BUILDDIR)X.obj", "\$(BUILDDIR)X.res", undef); print &splitline("\$(BUILDDIR)$prog.exe: " . $objstr), "\n"; - $objstr = &objects($p, "\$(BUILDDIR)X.obj", "\$(BUILDDIR)X.res.o", "X.lib"); + $objstr = &objects($p, "\$(BUILDDIR)X.obj", "\$(BUILDDIR)X.res", "X.lib"); $subsys = ($type eq "G") ? "windows" : "console"; print &splitline("\t\$(LD) \$(LFLAGS) \$(XLFLAGS) ". "/out:\$(BUILDDIR)$prog.exe ". @@ -567,11 +567,11 @@ sub manpages { "/subsystem:$subsys\$(SUBSYSVER) ". "\$(EXTRA_$subsys) $objstr")."\n\n"; } - foreach $d (&deps("\$(BUILDDIR)X.obj", "\$(BUILDDIR)X.res.o", $dirpfx, "/", "vc")) { + foreach $d (&deps("\$(BUILDDIR)X.obj", "\$(BUILDDIR)X.res", $dirpfx, "/", "vc")) { $extradeps = $forceobj{$d->{obj_orig}} ? ["*.c","*.h","*.rc"] : []; print &splitline(sprintf("%s: %s", $d->{obj}, join " ", @$extradeps, @{$d->{deps}})), "\n"; - if ($d->{obj} =~ /\.res\.o$/) { + if ($d->{obj} =~ /\.res$/) { print "\t\$(RC) \$(RCFLAGS) ".$d->{deps}->[0]." -o ".$d->{obj}."\n\n"; } else { print "\t\$(CC) /Fo\$(BUILDDIR) \$(COMPAT) \$(CFLAGS) \$(XFLAGS) /c \$<\n\n"; @@ -581,7 +581,7 @@ sub manpages { print &def($makefile_extra{'clangcl'}->{'end'}); print "\nclean:\n". &splitline("\trm -f \$(BUILDDIR)*.obj \$(BUILDDIR)*.exe ". - "\$(BUILDDIR)*.res.o \$(BUILDDIR)*.map ". + "\$(BUILDDIR)*.res \$(BUILDDIR)*.map ". "\$(BUILDDIR)*.exe.manifest")."\n"; select STDOUT; close OUT; } From 4634cd47f75e74a697840fb32f18edb7f1cf41da Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Tue, 5 Sep 2017 20:14:33 +0100 Subject: [PATCH 067/607] Avoid zero-length ldisc_send() in terminal.c. A user reports that a remote window title query, if the window title is empty or if the option to return it is disabled, fails the assertion in ldisc_send that I introduced as part of commit c269dd013 to catch any lingering uses of ldisc_send with length 0 that should have turned into ldisc_echoedit_update. Added a check for len > 0 guarding that ldisc_send call, and likewise at one or two others I noticed on my way here. (Probably at some point I should decide that the period of smoking out lingering old-style ldisc_send(0) calls is over, and declare it safe to remove that assertion again and get rid of all the cumbersome safety checks at call sites like these ones. But not quite yet.) --- terminal.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/terminal.c b/terminal.c index ba9dd617..f7bcbb95 100644 --- a/terminal.c +++ b/terminal.c @@ -3355,7 +3355,7 @@ static void term_out(Terminal *term) break; case 'Z': /* DECID: terminal type query */ compatibility(VT100); - if (term->ldisc) + if (term->ldisc && term->id_string[0]) ldisc_send(term->ldisc, term->id_string, strlen(term->id_string), 0); break; @@ -3662,7 +3662,7 @@ static void term_out(Terminal *term) case 'c': /* DA: terminal type query */ compatibility(VT100); /* This is the response for a VT102 */ - if (term->ldisc) + if (term->ldisc && term->id_string[0]) ldisc_send(term->ldisc, term->id_string, strlen(term->id_string), 0); break; @@ -4069,7 +4069,8 @@ static void term_out(Terminal *term) p = EMPTY_WINDOW_TITLE; len = strlen(p); ldisc_send(term->ldisc, "\033]L", 3, 0); - ldisc_send(term->ldisc, p, len, 0); + if (len > 0) + ldisc_send(term->ldisc, p, len, 0); ldisc_send(term->ldisc, "\033\\", 2, 0); } break; @@ -4082,7 +4083,8 @@ static void term_out(Terminal *term) p = EMPTY_WINDOW_TITLE; len = strlen(p); ldisc_send(term->ldisc, "\033]l", 3, 0); - ldisc_send(term->ldisc, p, len, 0); + if (len > 0) + ldisc_send(term->ldisc, p, len, 0); ldisc_send(term->ldisc, "\033\\", 2, 0); } break; From 4ec27919454102386f18d24df188cac3f663dbdc Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Wed, 13 Sep 2017 19:24:17 +0100 Subject: [PATCH 068/607] Remove Makefile.bor. After a conversation this week with a user who tried to use it, it's clear that Borland C can't build the up-to-date PuTTY without having to make too many compromises of functionality (unsupported API details, no 'long long' type), even above the issues that could be worked round with extra porting ifdefs. --- .gitignore | 2 - README | 4 -- Recipe | 1 - doc/udp.but | 6 +-- mkfiles.pl | 117 +--------------------------------------------- windows/rcstuff.h | 2 +- 6 files changed, 5 insertions(+), 127 deletions(-) diff --git a/.gitignore b/.gitignore index 15c253c2..c04f119b 100644 --- a/.gitignore +++ b/.gitignore @@ -19,7 +19,6 @@ /*.tds /*.td2 /*.map -/Makefile.bor /Makefile.mgw /Makefile.vc /Makefile.lcc @@ -128,7 +127,6 @@ /windows/*.td2 /windows/*.map /windows/Makefile.clangcl -/windows/Makefile.bor /windows/Makefile.mgw /windows/Makefile.vc /windows/Makefile.lcc diff --git a/README b/README index 50314ca6..de6eb9b0 100644 --- a/README +++ b/README @@ -34,10 +34,6 @@ For building on Windows: MSVC/putty/putty.dsp builds PuTTY itself, MSVC/plink/plink.dsp builds Plink, and so on. - - windows/Makefile.bor is for the Borland C compiler. Type `make -f - Makefile.bor' while in the `windows' subdirectory to build all - the PuTTY binaries. - - windows/Makefile.mgw is for MinGW / Cygwin installations. Type `make -f Makefile.mgw' while in the `windows' subdirectory to build all the PuTTY binaries. diff --git a/Recipe b/Recipe index f5458122..5715938b 100644 --- a/Recipe +++ b/Recipe @@ -16,7 +16,6 @@ !makefile vc windows/Makefile.vc !makefile vcproj windows/MSVC !makefile cygwin windows/Makefile.mgw -!makefile borland windows/Makefile.bor !makefile lcc windows/Makefile.lcc !makefile gtk unix/Makefile.gtk !makefile unix unix/Makefile.ux diff --git a/doc/udp.but b/doc/udp.but index 9ca8ed3f..b71688b7 100644 --- a/doc/udp.but +++ b/doc/udp.but @@ -138,9 +138,9 @@ construct. Use these wherever possible. \H{udp-multi-compiler} Independence of specific compiler -Windows PuTTY can currently be compiled with any of four Windows -compilers: MS Visual C, Borland's freely downloadable C compiler, -the Cygwin / \cw{mingw32} GNU tools, and \cw{lcc-win32}. +Windows PuTTY can currently be compiled with any of three Windows +compilers: MS Visual C, the Cygwin / \cw{mingw32} GNU tools, and +\cw{clang} (in MS compatibility mode). This is a really useful property of PuTTY, because it means people who want to contribute to the coding don't depend on having a diff --git a/mkfiles.pl b/mkfiles.pl index 02421316..6765f2a8 100755 --- a/mkfiles.pl +++ b/mkfiles.pl @@ -268,7 +268,7 @@ ($) # Returns true if the argument is a known makefile type. Otherwise, # prints a warning and returns false; if (grep { $type eq $_ } - ("vc","vcproj","cygwin","borland","lcc","devcppproj","gtk","unix", + ("vc","vcproj","cygwin","lcc","devcppproj","gtk","unix", "am","osx","vstudio10","vstudio12","clangcl")) { return 1; } @@ -659,121 +659,6 @@ sub manpages { } -##-- Borland makefile -if (defined $makefiles{'borland'}) { - $dirpfx = &dirpfx($makefiles{'borland'}, "\\"); - - %stdlibs = ( # Borland provides many Win32 API libraries intrinsically - "advapi32" => 1, - "comctl32" => 1, - "comdlg32" => 1, - "gdi32" => 1, - "imm32" => 1, - "shell32" => 1, - "user32" => 1, - "winmm" => 1, - "winspool" => 1, - "wsock32" => 1, - ); - open OUT, ">$makefiles{'borland'}"; select OUT; - print - "# Makefile for $project_name under Borland C.\n". - "#\n# This file was created by `mkfiles.pl' from the `Recipe' file.\n". - "# DO NOT EDIT THIS FILE DIRECTLY; edit Recipe or mkfiles.pl instead.\n"; - # bcc32 command line option is -D not /D - ($_ = $help) =~ s/([=" ])\/D/$1-D/gs; - print $_; - print - "\n". - "# If you rename this file to `Makefile', you should change this line,\n". - "# so that the .rsp files still depend on the correct makefile.\n". - "MAKEFILE = Makefile.bor\n". - "\n". - "# C compilation flags\n". - "CFLAGS = -D_WINDOWS -DWINVER=0x0500\n". - "# Resource compilation flags\n". - "RCFLAGS = -DNO_WINRESRC_H -DWIN32 -D_WIN32 -DWINVER=0x0401\n". - "\n". - "# Get include directory for resource compiler\n". - "!if !\$d(BCB)\n". - "BCB = \$(MAKEDIR)\\..\n". - "!endif\n". - "\n". - &def($makefile_extra{'borland'}->{'vars'}) . - "\n". - ".c.obj:\n". - &splitline("\tbcc32 -w-aus -w-ccc -w-par -w-pia \$(COMPAT)". - " \$(CFLAGS) \$(XFLAGS) ". - (join " ", map {"-I$dirpfx$_"} @srcdirs) . - " /c \$*.c",69)."\n". - ".rc.res:\n". - &splitline("\tbrcc32 \$(RCFL) -i \$(BCB)\\include -r". - " \$(RCFLAGS) \$*.rc",69)."\n". - "\n"; - print &splitline("all:" . join "", map { " $_.exe" } &progrealnames("G:C")); - print "\n\n"; - foreach $p (&prognames("G:C")) { - ($prog, $type) = split ",", $p; - $objstr = &objects($p, "X.obj", "X.res", undef); - print &splitline("$prog.exe: " . $objstr . " $prog.rsp"), "\n"; - my $ap = ($type eq "G") ? "-aa" : "-ap"; - print "\tilink32 $ap -Gn -L\$(BCB)\\lib \@$prog.rsp\n\n"; - } - foreach $p (&prognames("G:C")) { - ($prog, $type) = split ",", $p; - print $prog, ".rsp: \$(MAKEFILE)\n"; - $objstr = &objects($p, "X.obj", undef, undef); - @objlist = split " ", $objstr; - @objlines = (""); - foreach $i (@objlist) { - if (length($objlines[$#objlines] . " $i") > 50) { - push @objlines, ""; - } - $objlines[$#objlines] .= " $i"; - } - $c0w = ($type eq "G") ? "c0w32" : "c0x32"; - print "\techo $c0w + > $prog.rsp\n"; - for ($i=0; $i<=$#objlines; $i++) { - $plus = ($i < $#objlines ? " +" : ""); - print "\techo$objlines[$i]$plus >> $prog.rsp\n"; - } - print "\techo $prog.exe >> $prog.rsp\n"; - $objstr = &objects($p, "X.obj", "X.res", undef); - @libs = split " ", &objects($p, undef, undef, "X"); - @libs = grep { !$stdlibs{$_} } @libs; - unshift @libs, "cw32", "import32"; - $libstr = join ' ', @libs; - print "\techo nul,$libstr, >> $prog.rsp\n"; - print "\techo " . &objects($p, undef, "X.res", undef) . " >> $prog.rsp\n"; - print "\n"; - } - foreach $d (&deps("X.obj", "X.res", $dirpfx, "\\", "borland")) { - if ($forceobj{$d->{obj_orig}}) { - printf("%s: FORCE\n", $d->{obj}); - } else { - print &splitline(sprintf("%s: %s", $d->{obj}, - join " ", @{$d->{deps}})), "\n"; - } - } - print "\n"; - print &def($makefile_extra{'borland'}->{'end'}); - print "\nclean:\n". - "\t-del *.obj\n". - "\t-del *.exe\n". - "\t-del *.res\n". - "\t-del *.pch\n". - "\t-del *.aps\n". - "\t-del *.il*\n". - "\t-del *.pdb\n". - "\t-del *.rsp\n". - "\t-del *.tds\n". - "\t-del *.\$\$\$\$\$\$\n". - "\n". - "FORCE:\n". - "\t-rem dummy command\n"; - select STDOUT; close OUT; -} - if (defined $makefiles{'vc'}) { $dirpfx = &dirpfx($makefiles{'vc'}, "\\"); diff --git a/windows/rcstuff.h b/windows/rcstuff.h index 22b22035..ee2c7696 100644 --- a/windows/rcstuff.h +++ b/windows/rcstuff.h @@ -9,7 +9,7 @@ #include #else -/* Some compilers, like Borland, don't have winresrc.h */ +/* Some compilers don't have winresrc.h */ #ifndef NO_WINRESRC_H #ifndef MSVC4 #include From ba4837dae819cffffe36fd6c0985d8df10d2873c Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Wed, 20 Sep 2017 18:04:37 +0100 Subject: [PATCH 069/607] Add a -restrict-putty-acl option to Windows Pageant. This causes PuTTY processes spawned from its system-tray menu to run with the -restrict-acl option (or rather, the synonymous &R prefix used by my auto-constructed command lines for easier parsing). The previous behaviour of Pageant was never to pass -restrict-acl to PuTTY, even when started with -restrict-acl itself; this is not actually a silly thing to want to do, because Pageant might well have more need of -restrict-acl than PuTTY (it stores longer-term and more powerful secrets) and conversely PuTTY might have more need to _not_ restrict its ACL than Pageant (in that among the things enabled by an unrestricted ACL are various kinds of accessibility software, which is more useful on the more user-facing PuTTY than on Pageant). But for those who want to lock everything down with every security option possible (even though -restrict-acl is only an ad-hoc precaution and cannot deliver any hard guarantees), this new option should fill in the UI gap. --- doc/using.but | 12 ++++++++++++ windows/winpgnt.c | 26 ++++++++++++++++++++------ 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/doc/using.but b/doc/using.but index 7d184b7c..f5e3b57b 100644 --- a/doc/using.but +++ b/doc/using.but @@ -1042,3 +1042,15 @@ any processes started with Duplicate Session, New Session etc. (However, if you're invoking PuTTY tools explicitly, for instance as a proxy command, you'll need to arrange to pass them the \c{-restrict-acl} option yourself, if that's what you want.) + +If Pageant is started with the \c{-restrict-acl} option, and you use +it to launch a PuTTY session from its System Tray submenu, then +Pageant will \e{not} default to starting the PuTTY subprocess with a +restricted ACL. This is because PuTTY is more likely to suffer reduced +functionality as a result of restricted ACLs (e.g. screen reader +software will have a greater need to interact with it), whereas +Pageant stores the more critical information (hence benefits more from +the extra protection), so it's reasonable to want to run Pageant but +not PuTTY with the ACL restrictions. You can force Pageant to start +subsidiary PuTTY processes with a restricted ACL if you also pass the +\c{-restrict-putty-acl} option. diff --git a/windows/winpgnt.c b/windows/winpgnt.c index ebb6c6ac..1919a9b8 100644 --- a/windows/winpgnt.c +++ b/windows/winpgnt.c @@ -57,6 +57,7 @@ static HMENU systray_menu, session_menu; static int already_running; static char *putty_path; +static int restrict_putty_acl = FALSE; /* CWD for "add key" file requester. */ static filereq *keypath = NULL; @@ -847,11 +848,18 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, case WM_SYSCOMMAND: switch (wParam & ~0xF) { /* low 4 bits reserved to Windows */ case IDM_PUTTY: - if((INT_PTR)ShellExecute(hwnd, NULL, putty_path, _T(""), _T(""), - SW_SHOW) <= 32) { - MessageBox(NULL, "Unable to execute PuTTY!", - "Error", MB_OK | MB_ICONERROR); - } + { + TCHAR cmdline[10]; + cmdline[0] = '\0'; + if (restrict_putty_acl) + strcat(cmdline, "&R"); + + if((INT_PTR)ShellExecute(hwnd, NULL, putty_path, cmdline, + _T(""), SW_SHOW) <= 32) { + MessageBox(NULL, "Unable to execute PuTTY!", + "Error", MB_OK | MB_ICONERROR); + } + } break; case IDM_CLOSE: if (passphrase_box) @@ -912,7 +920,10 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, mii.cch = MAX_PATH; mii.dwTypeData = buf; GetMenuItemInfo(session_menu, wParam, FALSE, &mii); - strcpy(param, "@"); + param[0] = '\0'; + if (restrict_putty_acl) + strcat(param, "&R"); + strcat(param, "@"); strcat(param, mii.dwTypeData); if((INT_PTR)ShellExecute(hwnd, NULL, putty_path, param, _T(""), SW_SHOW) <= 32) { @@ -1169,6 +1180,9 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) !strcmp(argv[i], "-restrict_acl") || !strcmp(argv[i], "-restrictacl")) { restrict_process_acl(); + } else if (!strcmp(argv[i], "-restrict-putty-acl") || + !strcmp(argv[i], "-restrict_putty_acl")) { + restrict_putty_acl = TRUE; } else if (!strcmp(argv[i], "-c")) { /* * If we see `-c', then the rest of the From 581dd7071ea5131408420654808388ca7c42b3a2 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 30 Sep 2017 17:30:11 +0100 Subject: [PATCH 070/607] Squash the 256-colour test text into fewer lines. I'm about to want to add more stuff to that file, and it would be nice to have it still fit on a screen after I do. --- testdata/colours.txt | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/testdata/colours.txt b/testdata/colours.txt index 33709d23..2311eb83 100644 --- a/testdata/colours.txt +++ b/testdata/colours.txt @@ -4,19 +4,11 @@ Normal text and bold; reverse video and bold ANSI plus bold: 0 bold 1 bold 2 bold 3 bold 4 bold 5 bold 6 bold 7 bold xterm bright: fg0 bg0 fg1 bg1 fg2 bg2 fg3 bg3 fg4 bg4 fg5 bg5 fg6 bg6 fg7 bg7 xterm 256: greys                      reds   greens blues  yellow magent cyans  - 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 - 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 - 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 - 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 - 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 - 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 - 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 - 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 - 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 - 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 - 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 - 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 - 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 - 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 - 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 - 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 +0001020304050607 08090a0b0c0d0e0f 1011121314151617 18191a1b1c1d1e1f +2021222324252627 28292a2b2c2d2e2f 3031323334353637 38393a3b3c3d3e3f +4041424344454647 48494a4b4c4d4e4f 5051525354555657 58595a5b5c5d5e5f +6061626364656667 68696a6b6c6d6e6f 7071727374757677 78797a7b7c7d7e7f +8081828384858687 88898a8b8c8d8e8f 9091929394959697 98999a9b9c9d9e9f +a0a1a2a3a4a5a6a7 a8a9aaabacadaeaf b0b1b2b3b4b5b6b7 b8b9babbbcbdbebf +c0c1c2c3c4c5c6c7 c8c9cacbcccdcecf d0d1d2d3d4d5d6d7 d8d9dadbdcdddedf +e0e1e2e3e4e5e6e7 e8e9eaebecedeeef f0f1f2f3f4f5f6f7 f8f9fafbfcfdfeff From a4cbd3dfdb71d258e83bbf5b03a874c06d0b3106 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 30 Sep 2017 17:32:32 +0100 Subject: [PATCH 071/607] Support ESC[38;2;R;G;Bm for 24-bit true colour. This is a heavily rewritten version of a patch originally by Lorenz Diener; it was tidied up somewhat by Christian Brabandt, and then tidied up more by me. The basic idea is to add to the termchar structure a pair of small structs encoding 24-bit RGB values, each with a flag indicating whether it's turned on; if it is, it overrides any other specification of fg or bg colour for that character cell. I've added a test line to colours.txt containing a few example colours from /usr/share/X11/rgb.txt. In fact it makes quite a good demo to run the whole of rgb.txt through this treatment, with a command such as perl -pe 's!^\s*(\d+)\s+(\d+)\s+(\d+).*$!\e[38;2;$1;$2;$3m$&\e[m!' rgb.txt --- LICENCE | 3 +- fuzzterm.c | 4 +- putty.h | 28 +++++++++- terminal.c | 129 ++++++++++++++++++++++++++++++++++++++++--- terminal.h | 2 + testdata/colours.txt | 1 + unix/gtkwin.c | 38 ++++++++++--- windows/window.c | 33 ++++++----- 8 files changed, 204 insertions(+), 34 deletions(-) diff --git a/LICENCE b/LICENCE index 7c49ceb3..30b1fe2b 100644 --- a/LICENCE +++ b/LICENCE @@ -3,7 +3,8 @@ PuTTY is copyright 1997-2017 Simon Tatham. Portions copyright Robert de Bath, Joris van Rantwijk, Delian Delchev, Andreas Schultz, Jeroen Massar, Wez Furlong, Nicolas Barry, Justin Bradford, Ben Harris, Malcolm Smith, Ahmad Khalifa, Markus -Kuhn, Colin Watson, Christopher Staite, and CORE SDI S.A. +Kuhn, Colin Watson, Christopher Staite, Lorenz Diener, Christian +Brabandt, and CORE SDI S.A. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files diff --git a/fuzzterm.c b/fuzzterm.c index 15b5d635..480dca37 100644 --- a/fuzzterm.c +++ b/fuzzterm.c @@ -45,7 +45,7 @@ int from_backend(void *frontend, int is_stderr, const char *data, int len) void request_resize(void *frontend, int x, int y) { } void do_text(Context ctx, int x, int y, wchar_t * text, int len, - unsigned long attr, int lattr) + unsigned long attr, int lattr, truecolour tc) { int i; @@ -56,7 +56,7 @@ void do_text(Context ctx, int x, int y, wchar_t * text, int len, printf("\n"); } void do_cursor(Context ctx, int x, int y, wchar_t * text, int len, - unsigned long attr, int lattr) + unsigned long attr, int lattr, truecolour tc) { int i; diff --git a/putty.h b/putty.h index fd2d0250..61d6278d 100644 --- a/putty.h +++ b/putty.h @@ -592,12 +592,36 @@ void prompt_ensure_result_size(prompt_t *pr, int len); /* Burn the evidence. (Assumes _all_ strings want free()ing.) */ void free_prompts(prompts_t *p); +/* + * Data type definitions for true-colour terminal display. + * 'optionalrgb' describes a single RGB colour, which overrides the + * other colour settings if 'enabled' is nonzero, and is ignored + * otherwise. 'truecolour' contains a pair of those for foreground and + * background. + */ +typedef struct optionalrgb { + unsigned char enabled; + unsigned char r, g, b; +} optionalrgb; +extern const optionalrgb optionalrgb_none; +typedef struct truecolour { + optionalrgb fg, bg; +} truecolour; +#define optionalrgb_equal(r1,r2) ( \ + (r1).enabled==(r2).enabled && \ + (r1).r==(r2).r && (r1).g==(r2).g && (r1).b==(r2).b) +#define truecolour_equal(c1,c2) ( \ + optionalrgb_equal((c1).fg, (c2).fg) && \ + optionalrgb_equal((c1).bg, (c2).bg)) + /* * Exports from the front end. */ void request_resize(void *frontend, int, int); -void do_text(Context, int, int, wchar_t *, int, unsigned long, int); -void do_cursor(Context, int, int, wchar_t *, int, unsigned long, int); +void do_text(Context, int, int, wchar_t *, int, unsigned long, int, + truecolour); +void do_cursor(Context, int, int, wchar_t *, int, unsigned long, int, + truecolour); int char_width(Context ctx, int uc); #ifdef OPTIMISE_SCROLL void do_scroll(Context, int, int, int); diff --git a/terminal.c b/terminal.c index f7bcbb95..e597d472 100644 --- a/terminal.c +++ b/terminal.c @@ -108,6 +108,7 @@ static void update_sbar(Terminal *); static void deselect(Terminal *); static void term_print_finish(Terminal *); static void scroll(Terminal *, int, int, int, int); +static void parse_optionalrgb(optionalrgb *out, unsigned *values); #ifdef OPTIMISE_SCROLL static void scroll_display(Terminal *, int, int, int); #endif /* OPTIMISE_SCROLL */ @@ -283,6 +284,8 @@ static int termchars_equal_override(termchar *a, termchar *b, unsigned long bchr, unsigned long battr) { /* FULL-TERMCHAR */ + if (!truecolour_equal(a->truecolour, b->truecolour)) + return FALSE; if (a->chr != bchr) return FALSE; if ((a->attr &~ DATTR_MASK) != (battr &~ DATTR_MASK)) @@ -607,6 +610,24 @@ static void makeliteral_attr(struct buf *b, termchar *c, unsigned long *state) add(b, (unsigned char)(attr & 0xFF)); } } +static void makeliteral_truecolour(struct buf *b, termchar *c, unsigned long *state) +{ + /* + * Put the used parts of the colour info into the buffer. + */ + add(b, ((c->truecolour.fg.enabled ? 1 : 0) | + (c->truecolour.bg.enabled ? 2 : 0))); + if (c->truecolour.fg.enabled) { + add(b, c->truecolour.fg.r); + add(b, c->truecolour.fg.g); + add(b, c->truecolour.fg.b); + } + if (c->truecolour.bg.enabled) { + add(b, c->truecolour.bg.r); + add(b, c->truecolour.bg.g); + add(b, c->truecolour.bg.b); + } +} static void makeliteral_cc(struct buf *b, termchar *c, unsigned long *state) { /* @@ -681,6 +702,7 @@ static unsigned char *compressline(termline *ldata) */ makerle(b, ldata, makeliteral_chr); makerle(b, ldata, makeliteral_attr); + makerle(b, ldata, makeliteral_truecolour); makerle(b, ldata, makeliteral_cc); /* @@ -826,6 +848,29 @@ static void readliteral_attr(struct buf *b, termchar *c, termline *ldata, c->attr = attr; } +static void readliteral_truecolour(struct buf *b, termchar *c, termline *ldata, + unsigned long *state) +{ + int flags = get(b); + + if (flags & 1) { + c->truecolour.fg.enabled = TRUE; + c->truecolour.fg.r = get(b); + c->truecolour.fg.g = get(b); + c->truecolour.fg.b = get(b); + } else { + c->truecolour.fg = optionalrgb_none; + } + + if (flags & 2) { + c->truecolour.bg.enabled = TRUE; + c->truecolour.bg.r = get(b); + c->truecolour.bg.g = get(b); + c->truecolour.bg.b = get(b); + } else { + c->truecolour.bg = optionalrgb_none; + } +} static void readliteral_cc(struct buf *b, termchar *c, termline *ldata, unsigned long *state) { @@ -899,6 +944,7 @@ static termline *decompressline(unsigned char *data, int *bytes_used) */ readrle(b, ldata, readliteral_chr); readrle(b, ldata, readliteral_attr); + readrle(b, ldata, readliteral_truecolour); readrle(b, ldata, readliteral_cc); /* Return the number of bytes read, for diagnostic purposes. */ @@ -1570,6 +1616,8 @@ void term_clrsb(Terminal *term) update_sbar(term); } +const optionalrgb optionalrgb_none = {0, 0, 0, 0}; + /* * Initialise the terminal. */ @@ -1646,6 +1694,8 @@ Terminal *term_init(Conf *myconf, struct unicode_data *ucsdata, term->basic_erase_char.chr = CSET_ASCII | ' '; term->basic_erase_char.attr = ATTR_DEFAULT; term->basic_erase_char.cc_next = 0; + term->basic_erase_char.truecolour.fg = optionalrgb_none; + term->basic_erase_char.truecolour.bg = optionalrgb_none; term->erase_char = term->basic_erase_char; return term; @@ -3212,6 +3262,8 @@ static void term_out(Terminal *term) clear_cc(cline, term->curs.x); cline->chars[term->curs.x].chr = c; cline->chars[term->curs.x].attr = term->curr_attr; + cline->chars[term->curs.x].truecolour = + term->curr_truecolour; term->curs.x++; @@ -3219,6 +3271,8 @@ static void term_out(Terminal *term) clear_cc(cline, term->curs.x); cline->chars[term->curs.x].chr = UCSWIDE; cline->chars[term->curs.x].attr = term->curr_attr; + cline->chars[term->curs.x].truecolour = + term->curr_truecolour; break; case 1: @@ -3229,6 +3283,8 @@ static void term_out(Terminal *term) clear_cc(cline, term->curs.x); cline->chars[term->curs.x].chr = c; cline->chars[term->curs.x].attr = term->curr_attr; + cline->chars[term->curs.x].truecolour = + term->curr_truecolour; break; case 0: @@ -3799,6 +3855,8 @@ static void term_out(Terminal *term) switch (def(term->esc_args[i], 0)) { case 0: /* restore defaults */ term->curr_attr = term->default_attr; + term->curr_truecolour = + term->basic_erase_char.truecolour; break; case 1: /* enable bold */ compatibility(VT100AVO); @@ -3860,6 +3918,7 @@ static void term_out(Terminal *term) case 36: case 37: /* foreground */ + term->curr_truecolour.fg.enabled = FALSE; term->curr_attr &= ~ATTR_FGMASK; term->curr_attr |= (term->esc_args[i] - 30)<curr_truecolour.fg.enabled = FALSE; term->curr_attr &= ~ATTR_FGMASK; term->curr_attr |= ((term->esc_args[i] - 90 + 8) << ATTR_FGSHIFT); break; case 39: /* default-foreground */ + term->curr_truecolour.fg.enabled = FALSE; term->curr_attr &= ~ATTR_FGMASK; term->curr_attr |= ATTR_DEFFG; break; @@ -3891,6 +3952,7 @@ static void term_out(Terminal *term) case 46: case 47: /* background */ + term->curr_truecolour.bg.enabled = FALSE; term->curr_attr &= ~ATTR_BGMASK; term->curr_attr |= (term->esc_args[i] - 40)<curr_truecolour.bg.enabled = FALSE; term->curr_attr &= ~ATTR_BGMASK; term->curr_attr |= ((term->esc_args[i] - 100 + 8) << ATTR_BGSHIFT); break; case 49: /* default-background */ + term->curr_truecolour.bg.enabled = FALSE; term->curr_attr &= ~ATTR_BGMASK; term->curr_attr |= ATTR_DEFBG; break; - case 38: /* xterm 256-colour mode */ + + /* + * 256-colour and true-colour + * sequences. A 256-colour + * foreground is selected by a + * sequence of 3 arguments in the + * form 38;5;n, where n is in the + * range 0-255. A true-colour RGB + * triple is selected by 5 args of + * the form 38;2;r;g;b. Replacing + * the initial 38 with 48 in both + * cases selects the same colour + * as the background. + */ + case 38: if (i+2 < term->esc_nargs && term->esc_args[i+1] == 5) { term->curr_attr &= ~ATTR_FGMASK; @@ -3921,9 +3999,16 @@ static void term_out(Terminal *term) ((term->esc_args[i+2] & 0xFF) << ATTR_FGSHIFT); i += 2; + } + if (i + 4 < term->esc_nargs && + term->esc_args[i + 1] == 2) { + parse_optionalrgb( + &term->curr_truecolour.fg, + term->esc_args + (i+2)); + i += 4; } break; - case 48: /* xterm 256-colour mode */ + case 48: if (i+2 < term->esc_nargs && term->esc_args[i+1] == 5) { term->curr_attr &= ~ATTR_BGMASK; @@ -3932,6 +4017,13 @@ static void term_out(Terminal *term) << ATTR_BGSHIFT); i += 2; } + if (i + 4 < term->esc_nargs && + term->esc_args[i+1] == 2) { + parse_optionalrgb( + &term->curr_truecolour.bg, + term->esc_args + (i+2)); + i += 4; + } break; } } @@ -4733,6 +4825,19 @@ static void term_out(Terminal *term) logflush(term->logctx); } +/* + * Small subroutine to parse three consecutive escape-sequence + * arguments representing a true-colour RGB triple into an + * optionalrgb. + */ +static void parse_optionalrgb(optionalrgb *out, unsigned *values) +{ + out->enabled = TRUE; + out->r = values[0] < 256 ? values[0] : 0; + out->g = values[1] < 256 ? values[1] : 0; + out->b = values[2] < 256 ? values[2] : 0; +} + /* * To prevent having to run the reasonably tricky bidi algorithm * too many times, we maintain a cache of the last lineful of data @@ -5035,6 +5140,7 @@ static void do_paint(Terminal *term, Context ctx, int may_optimise) int last_run_dirty = 0; int laststart, dirtyrect; int *backward; + truecolour tc; scrpos.y = i + term->disptop; ldata = lineptr(scrpos.y); @@ -5064,6 +5170,7 @@ static void do_paint(Terminal *term, Context ctx, int may_optimise) tattr = (tattr & ~(ATTR_FGMASK | ATTR_BGMASK)) | ATTR_DEFFG | ATTR_DEFBG; + tc = d->truecolour; if (!term->xterm_256_colour) { int colour; colour = (tattr & ATTR_FGMASK) >> ATTR_FGSHIFT; @@ -5131,6 +5238,7 @@ static void do_paint(Terminal *term, Context ctx, int may_optimise) /* FULL-TERMCHAR */ newline[j].attr = tattr; newline[j].chr = tchar; + newline[j].truecolour = tc; /* Combining characters are still read from lchars */ newline[j].cc_next = 0; } @@ -5181,6 +5289,7 @@ static void do_paint(Terminal *term, Context ctx, int may_optimise) term->disptext[i]->lattr); term->disptext[i]->lattr = ldata->lattr; + tc = term->erase_char.truecolour; for (j = 0; j < term->cols; j++) { unsigned long tattr, tchar; int break_run, do_copy; @@ -5194,6 +5303,9 @@ static void do_paint(Terminal *term, Context ctx, int may_optimise) break_run = ((tattr ^ attr) & term->attr_mask) != 0; + if (!truecolour_equal(newline[j].truecolour, tc)) + break_run = TRUE; + #ifdef USES_VTLINE_HACK /* Special hack for VT100 Linedraw glyphs */ if ((tchar >= 0x23BA && tchar <= 0x23BD) || @@ -5226,15 +5338,15 @@ static void do_paint(Terminal *term, Context ctx, int may_optimise) if (break_run) { if ((dirty_run || last_run_dirty) && ccount > 0) { - do_text(ctx, start, i, ch, ccount, attr, - ldata->lattr); + do_text(ctx, start, i, ch, ccount, attr, ldata->lattr, tc); if (attr & (TATTR_ACTCURS | TATTR_PASCURS)) do_cursor(ctx, start, i, ch, ccount, attr, - ldata->lattr); + ldata->lattr, tc); } start = j; ccount = 0; attr = tattr; + tc = newline[j].truecolour; cset = CSET_OF(tchar); if (term->ucsdata->dbcs_screenfont) last_run_dirty = dirty_run; @@ -5303,6 +5415,7 @@ static void do_paint(Terminal *term, Context ctx, int may_optimise) copy_termchar(term->disptext[i], j, d); term->disptext[i]->chars[j].chr = tchar; term->disptext[i]->chars[j].attr = tattr; + term->disptext[i]->chars[j].truecolour = tc; if (start == j) term->disptext[i]->chars[j].attr |= DATTR_STARTRUN; } @@ -5324,11 +5437,9 @@ static void do_paint(Terminal *term, Context ctx, int may_optimise) } } if (dirty_run && ccount > 0) { - do_text(ctx, start, i, ch, ccount, attr, - ldata->lattr); + do_text(ctx, start, i, ch, ccount, attr, ldata->lattr, tc); if (attr & (TATTR_ACTCURS | TATTR_PASCURS)) - do_cursor(ctx, start, i, ch, ccount, attr, - ldata->lattr); + do_cursor(ctx, start, i, ch, ccount, attr, ldata->lattr, tc); } unlineptr(ldata); diff --git a/terminal.h b/terminal.h index 2ed9e6ef..21b8774a 100644 --- a/terminal.h +++ b/terminal.h @@ -40,6 +40,7 @@ struct termchar { */ unsigned long chr; unsigned long attr; + truecolour truecolour; /* * The cc_next field is used to link multiple termchars @@ -102,6 +103,7 @@ struct terminal_tag { #endif /* OPTIMISE_SCROLL */ int default_attr, curr_attr, save_attr; + truecolour curr_truecolour; termchar basic_erase_char, erase_char; bufchain inbuf; /* terminal input buffer */ diff --git a/testdata/colours.txt b/testdata/colours.txt index 2311eb83..34dff8a5 100644 --- a/testdata/colours.txt +++ b/testdata/colours.txt @@ -12,3 +12,4 @@ xterm 256: greys[48;5;236 a0a1a2a3a4a5a6a7 a8a9aaabacadaeaf b0b1b2b3b4b5b6b7 b8b9babbbcbdbebf c0c1c2c3c4c5c6c7 c8c9cacbcccdcecf d0d1d2d3d4d5d6d7 d8d9dadbdcdddedf e0e1e2e3e4e5e6e7 e8e9eaebecedeeef f0f1f2f3f4f5f6f7 f8f9fafbfcfdfeff +24-bit colour: SlateGrey OliveDrab goldenrod SaddleBrown DarkViolet (bg) diff --git a/unix/gtkwin.c b/unix/gtkwin.c index 9e73181e..f49f92af 100644 --- a/unix/gtkwin.c +++ b/unix/gtkwin.c @@ -3029,6 +3029,24 @@ static void draw_set_colour(struct draw_ctx *dctx, int col) #endif } +static void draw_set_colour_rgb(struct draw_ctx *dctx, optionalrgb orgb) +{ +#ifdef DRAW_TEXT_GDK + if (dctx->uctx.type == DRAWTYPE_GDK) { + GdkColor color; + color.red = orgb.r * 256; + color.green = orgb.g * 256; + color.blue = orgb.b * 256; + gdk_gc_set_rgb_fg_color(dctx->uctx.u.gdk.gc, &color); + } +#endif +#ifdef DRAW_TEXT_CAIRO + if (dctx->uctx.type == DRAWTYPE_CAIRO) + cairo_set_source_rgb(dctx->uctx.u.cairo.cr, + orgb.r / 255.0, orgb.g / 255.0, orgb.b / 255.0); +#endif +} + static void draw_rectangle(struct draw_ctx *dctx, int filled, int x, int y, int w, int h) { @@ -3222,7 +3240,7 @@ static void draw_backing_rect(struct gui_data *inst) * We are allowed to fiddle with the contents of `text'. */ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, - unsigned long attr, int lattr) + unsigned long attr, int lattr, truecolour truecolour) { struct draw_ctx *dctx = (struct draw_ctx *)ctx; struct gui_data *inst = dctx->inst; @@ -3316,13 +3334,19 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, ((lattr & LATTR_MODE) == LATTR_BOT)); } - draw_set_colour(dctx, nbg); + if (truecolour.bg.enabled) + draw_set_colour_rgb(dctx, truecolour.bg); + else + draw_set_colour(dctx, nbg); draw_rectangle(dctx, TRUE, x*inst->font_width+inst->window_border, y*inst->font_height+inst->window_border, rlen*widefactor*inst->font_width, inst->font_height); - draw_set_colour(dctx, nfg); + if (truecolour.fg.enabled) + draw_set_colour_rgb(dctx, truecolour.fg); + else + draw_set_colour(dctx, nfg); if (ncombining > 1) { assert(len == 1); unifont_draw_combining(&dctx->uctx, inst->fonts[fontid], @@ -3362,13 +3386,13 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, } void do_text(Context ctx, int x, int y, wchar_t *text, int len, - unsigned long attr, int lattr) + unsigned long attr, int lattr, truecolour truecolour) { struct draw_ctx *dctx = (struct draw_ctx *)ctx; struct gui_data *inst = dctx->inst; int widefactor; - do_text_internal(ctx, x, y, text, len, attr, lattr); + do_text_internal(ctx, x, y, text, len, attr, lattr, truecolour); if (attr & ATTR_WIDE) { widefactor = 2; @@ -3392,7 +3416,7 @@ void do_text(Context ctx, int x, int y, wchar_t *text, int len, } void do_cursor(Context ctx, int x, int y, wchar_t *text, int len, - unsigned long attr, int lattr) + unsigned long attr, int lattr, truecolour truecolour) { struct draw_ctx *dctx = (struct draw_ctx *)ctx; struct gui_data *inst = dctx->inst; @@ -3409,7 +3433,7 @@ void do_cursor(Context ctx, int x, int y, wchar_t *text, int len, active = 1; } else active = 0; - do_text_internal(ctx, x, y, text, len, attr, lattr); + do_text_internal(ctx, x, y, text, len, attr, lattr, truecolour); if (attr & TATTR_COMBINING) len = 1; diff --git a/windows/window.c b/windows/window.c index 96600311..452eb771 100644 --- a/windows/window.c +++ b/windows/window.c @@ -3395,7 +3395,7 @@ static void sys_cursor_update(void) * We are allowed to fiddle with the contents of `text'. */ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, - unsigned long attr, int lattr) + unsigned long attr, int lattr, truecolour truecolour) { COLORREF fg, bg, t; int nfg, nbg, nfont; @@ -3522,8 +3522,16 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, if (nbg < 16) nbg |= 8; else if (nbg >= 256) nbg |= 1; } - fg = colours[nfg]; - bg = colours[nbg]; + if (truecolour.fg.enabled) + fg = RGB(truecolour.fg.r, truecolour.fg.g, truecolour.fg.b); + else + fg = colours[nfg]; + + if (truecolour.bg.enabled) + bg = RGB(truecolour.bg.r, truecolour.bg.g, truecolour.bg.b); + else + bg = colours[nbg]; + SelectObject(hdc, fonts[nfont]); SetTextColor(hdc, fg); SetBkColor(hdc, bg); @@ -3768,7 +3776,7 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, * Wrapper that handles combining characters. */ void do_text(Context ctx, int x, int y, wchar_t *text, int len, - unsigned long attr, int lattr) + unsigned long attr, int lattr, truecolour truecolour) { if (attr & TATTR_COMBINING) { unsigned long a = 0; @@ -3778,13 +3786,13 @@ void do_text(Context ctx, int x, int y, wchar_t *text, int len, len0 = 2; if (len-len0 >= 1 && IS_LOW_VARSEL(text[len0])) { attr &= ~TATTR_COMBINING; - do_text_internal(ctx, x, y, text, len0+1, attr, lattr); + do_text_internal(ctx, x, y, text, len0+1, attr, lattr, truecolour); text += len0+1; len -= len0+1; a = TATTR_COMBINING; } else if (len-len0 >= 2 && IS_HIGH_VARSEL(text[len0], text[len0+1])) { attr &= ~TATTR_COMBINING; - do_text_internal(ctx, x, y, text, len0+2, attr, lattr); + do_text_internal(ctx, x, y, text, len0+2, attr, lattr, truecolour); text += len0+2; len -= len0+2; a = TATTR_COMBINING; @@ -3794,22 +3802,21 @@ void do_text(Context ctx, int x, int y, wchar_t *text, int len, while (len--) { if (len >= 1 && IS_SURROGATE_PAIR(text[0], text[1])) { - do_text_internal(ctx, x, y, text, 2, attr | a, lattr); + do_text_internal(ctx, x, y, text, 2, attr | a, lattr, truecolour); len--; text++; - } else { - do_text_internal(ctx, x, y, text, 1, attr | a, lattr); - } + } else + do_text_internal(ctx, x, y, text, 1, attr | a, lattr, truecolour); text++; a = TATTR_COMBINING; } } else - do_text_internal(ctx, x, y, text, len, attr, lattr); + do_text_internal(ctx, x, y, text, len, attr, lattr, truecolour); } void do_cursor(Context ctx, int x, int y, wchar_t *text, int len, - unsigned long attr, int lattr) + unsigned long attr, int lattr, truecolour truecolour) { int fnt_width; @@ -3821,7 +3828,7 @@ void do_cursor(Context ctx, int x, int y, wchar_t *text, int len, if ((attr & TATTR_ACTCURS) && (ctype == 0 || term->big_cursor)) { if (*text != UCSWIDE) { - do_text(ctx, x, y, text, len, attr, lattr); + do_text(ctx, x, y, text, len, attr, lattr, truecolour); return; } ctype = 2; From 16214ea0f5de7023c7e08fba57e7a49c2d518583 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 1 Oct 2017 20:59:00 +0100 Subject: [PATCH 072/607] Initialise term->curr_truecolour at startup. Somehow I managed to miss _that_ really obvious bug in the true- colour patch. --- terminal.c | 1 + 1 file changed, 1 insertion(+) diff --git a/terminal.c b/terminal.c index e597d472..0eb1a9a6 100644 --- a/terminal.c +++ b/terminal.c @@ -1296,6 +1296,7 @@ static void power_on(Terminal *term, int clear) term->big_cursor = 0; term->default_attr = term->save_attr = term->alt_save_attr = term->curr_attr = ATTR_DEFAULT; + term->curr_truecolour.fg = term->curr_truecolour.bg = optionalrgb_none; term->term_editing = term->term_echoing = FALSE; term->app_cursor_keys = conf_get_int(term->conf, CONF_app_cursor); term->app_keypad_keys = conf_get_int(term->conf, CONF_app_keypad); From f813e9f937b5b6198659c8c64b3090dc3902b930 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 1 Oct 2017 21:05:25 +0100 Subject: [PATCH 073/607] uxnet.c: don't close a socket's fd if it is -1. This is harmless in principle (you just get EBADF back from close(2) and ignore it), but it leads to warnings in valgrind. --- unix/uxnet.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/unix/uxnet.c b/unix/uxnet.c index ddcd9228..f3498527 100644 --- a/unix/uxnet.c +++ b/unix/uxnet.c @@ -1023,9 +1023,11 @@ static void sk_tcp_close(Socket sock) if (s->child) sk_tcp_close((Socket)s->child); - uxsel_del(s->s); del234(sktree, s); - close(s->s); + if (s->s >= 0) { + uxsel_del(s->s); + close(s->s); + } if (s->addr) sk_addr_free(s->addr); sfree(s); From 6b824713d56bf105cede71daa186593aa9906718 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 1 Oct 2017 21:53:32 +0100 Subject: [PATCH 074/607] term_mouse: make special treatment of x < 0 more selective. A mouse drag which manages to reach x < 0 (via SetCapture or equivalent) was treated as having the coordinates of (x_max, y-1). This is intended to be useful when the mouse drag is part of ordinary raster-ordered selection. But we were leaving that treatment enabled even for mouse actions that went to xterm mouse tracking mode - thanks to Markus Gans for reporting that - and when I investigated, I realised that this isn't a sensible transformation in _rectangular_ selection mode either. Fixed both. --- terminal.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/terminal.c b/terminal.c index 0eb1a9a6..433b3fa5 100644 --- a/terminal.c +++ b/terminal.c @@ -6088,7 +6088,18 @@ void term_mouse(Terminal *term, Mouse_Button braw, Mouse_Button bcooked, term_scroll(term, 0, +1); } if (x < 0) { - if (y > 0) { + if (y > 0 && !raw_mouse && term->seltype != RECTANGULAR) { + /* + * When we're using the mouse for normal raster-based + * selection, dragging off the left edge of a terminal row + * is treated the same as the right-hand end of the + * previous row, in that it's considered to identify a + * point _before_ the first character on row y. + * + * But if the mouse action is going to be used for + * anything else - rectangular selection, or xterm mouse + * tracking - then we disable this special treatment. + */ x = term->cols - 1; y--; } else From 2f9738a282c9b738b135198d34c61f7d81aa69c1 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Thu, 5 Oct 2017 20:27:27 +0100 Subject: [PATCH 075/607] Make terminal true-colour mode configurable. I know some users don't like any colour _at all_, and we have a separate option to turn off xterm-style 256-colour sequences, so it seems remiss not to have an option to disable true colour as well. --- config.c | 3 +++ doc/config.but | 9 +++++++++ putty.h | 1 + settings.c | 2 ++ terminal.c | 8 +++++++- terminal.h | 1 + windows/winhelp.h | 1 + 7 files changed, 24 insertions(+), 1 deletion(-) diff --git a/config.c b/config.c index efe1ff1e..cc5e726b 100644 --- a/config.c +++ b/config.c @@ -1898,6 +1898,9 @@ void setup_config_box(struct controlbox *b, int midsession, ctrl_checkbox(s, "Allow terminal to use xterm 256-colour mode", '2', HELPCTX(colours_xterm256), conf_checkbox_handler, I(CONF_xterm_256_colour)); + ctrl_checkbox(s, "Allow terminal to use 24-bit colours", '4', + HELPCTX(colours_truecolour), conf_checkbox_handler, + I(CONF_true_colour)); ctrl_radiobuttons(s, "Indicate bolded text by changing:", 'b', 3, HELPCTX(colours_bold), conf_radiobutton_handler, I(CONF_bold_style), diff --git a/doc/config.but b/doc/config.but index bd12efb2..7ad5e282 100644 --- a/doc/config.but +++ b/doc/config.but @@ -1549,6 +1549,15 @@ If you do not see \cq{colors#256} in the output, you may need to change your terminal setting. On modern Linux machines, you could try \cq{xterm-256color}. +\S{config-truecolour} \q{Allow terminal to use 24-bit colour} + +\cfg{winhelp-topic}{colours.truecolour} + +This option is enabled by default. If it is disabled, PuTTY will +ignore any control sequences sent by the server which use the control +sequences supported by modern terminals to specify arbitrary 24-bit +RGB colour value. + \S{config-boldcolour} \q{Indicate bolded text by changing...} \cfg{winhelp-topic}{colours.bold} diff --git a/putty.h b/putty.h index 61d6278d..8a8b5425 100644 --- a/putty.h +++ b/putty.h @@ -859,6 +859,7 @@ void cleanup_exit(int); /* Colour options */ \ X(INT, NONE, ansi_colour) \ X(INT, NONE, xterm_256_colour) \ + X(INT, NONE, true_colour) \ X(INT, NONE, system_colour) \ X(INT, NONE, try_palette) \ X(INT, NONE, bold_style) \ diff --git a/settings.c b/settings.c index 00c01c54..47e5b9f7 100644 --- a/settings.c +++ b/settings.c @@ -609,6 +609,7 @@ void save_open_settings(void *sesskey, Conf *conf) write_setting_i(sesskey, "TryPalette", conf_get_int(conf, CONF_try_palette)); write_setting_i(sesskey, "ANSIColour", conf_get_int(conf, CONF_ansi_colour)); write_setting_i(sesskey, "Xterm256Colour", conf_get_int(conf, CONF_xterm_256_colour)); + write_setting_i(sesskey, "TrueColour", conf_get_int(conf, CONF_true_colour)); write_setting_i(sesskey, "BoldAsColour", conf_get_int(conf, CONF_bold_style)-1); for (i = 0; i < 22; i++) { @@ -1005,6 +1006,7 @@ void load_open_settings(void *sesskey, Conf *conf) gppi(sesskey, "TryPalette", 0, conf, CONF_try_palette); gppi(sesskey, "ANSIColour", 1, conf, CONF_ansi_colour); gppi(sesskey, "Xterm256Colour", 1, conf, CONF_xterm_256_colour); + gppi(sesskey, "TrueColour", 1, conf, CONF_true_colour); i = gppi_raw(sesskey, "BoldAsColour", 1); conf_set_int(conf, CONF_bold_style, i+1); for (i = 0; i < 22; i++) { diff --git a/terminal.c b/terminal.c index 433b3fa5..5102db12 100644 --- a/terminal.c +++ b/terminal.c @@ -1458,6 +1458,7 @@ void term_copy_stuff_from_conf(Terminal *term) term->scroll_on_disp = conf_get_int(term->conf, CONF_scroll_on_disp); term->scroll_on_key = conf_get_int(term->conf, CONF_scroll_on_key); term->xterm_256_colour = conf_get_int(term->conf, CONF_xterm_256_colour); + term->true_colour = conf_get_int(term->conf, CONF_true_colour); /* * Parse the control-character escapes in the configured @@ -5171,7 +5172,6 @@ static void do_paint(Terminal *term, Context ctx, int may_optimise) tattr = (tattr & ~(ATTR_FGMASK | ATTR_BGMASK)) | ATTR_DEFFG | ATTR_DEFBG; - tc = d->truecolour; if (!term->xterm_256_colour) { int colour; colour = (tattr & ATTR_FGMASK) >> ATTR_FGSHIFT; @@ -5182,6 +5182,12 @@ static void do_paint(Terminal *term, Context ctx, int may_optimise) tattr = (tattr &~ ATTR_BGMASK) | ATTR_DEFBG; } + if (term->true_colour) { + tc = d->truecolour; + } else { + tc.fg = tc.bg = optionalrgb_none; + } + switch (tchar & CSET_MASK) { case CSET_ASCII: tchar = term->ucsdata->unitab_line[tchar & 0xFF]; diff --git a/terminal.h b/terminal.h index 21b8774a..4a205a77 100644 --- a/terminal.h +++ b/terminal.h @@ -325,6 +325,7 @@ struct terminal_tag { int scroll_on_disp; int scroll_on_key; int xterm_256_colour; + int true_colour; }; #define in_utf(term) ((term)->utf || (term)->ucsdata->line_codepage==CP_UTF8) diff --git a/windows/winhelp.h b/windows/winhelp.h index 761c8c76..dbe32c91 100644 --- a/windows/winhelp.h +++ b/windows/winhelp.h @@ -125,6 +125,7 @@ #define WINHELP_CTX_selection_rtf "selection.rtf:config-rtfpaste" #define WINHELP_CTX_colours_ansi "colours.ansi:config-ansicolour" #define WINHELP_CTX_colours_xterm256 "colours.xterm256:config-xtermcolour" +#define WINHELP_CTX_colours_truecolour "colours.truecolour:config-truecolour" #define WINHELP_CTX_colours_bold "colours.bold:config-boldcolour" #define WINHELP_CTX_colours_system "colours.system:config-syscolour" #define WINHELP_CTX_colours_logpal "colours.logpal:config-logpalette" From 1adf211d70e162b50b18ede5a9c6ba6ae73ac8b2 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Thu, 5 Oct 2017 20:30:09 +0100 Subject: [PATCH 076/607] Disable true colour on monochrome or paletted displays. I'm not sure if any X11 monochrome visuals or Windows paletted display modes are still around, but just in case they are, we shouldn't attempt true colour on either kind of display. --- unix/gtkwin.c | 3 +++ windows/window.c | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/unix/gtkwin.c b/unix/gtkwin.c index f49f92af..94ba4069 100644 --- a/unix/gtkwin.c +++ b/unix/gtkwin.c @@ -3255,6 +3255,9 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, } else ncombining = 1; + if (monochrome) + truecolour.fg = truecolour.bg = optionalrgb_none; + nfg = ((monochrome ? ATTR_DEFFG : (attr & ATTR_FGMASK)) >> ATTR_FGSHIFT); nbg = ((monochrome ? ATTR_DEFBG : (attr & ATTR_BGMASK)) >> ATTR_BGSHIFT); if (!!(attr & ATTR_REVERSE) ^ (monochrome && (attr & TATTR_ACTCURS))) { diff --git a/windows/window.c b/windows/window.c index 452eb771..79738ff9 100644 --- a/windows/window.c +++ b/windows/window.c @@ -3522,12 +3522,12 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, if (nbg < 16) nbg |= 8; else if (nbg >= 256) nbg |= 1; } - if (truecolour.fg.enabled) + if (!pal && truecolour.fg.enabled) fg = RGB(truecolour.fg.r, truecolour.fg.g, truecolour.fg.b); else fg = colours[nfg]; - if (truecolour.bg.enabled) + if (!pal && truecolour.bg.enabled) bg = RGB(truecolour.bg.r, truecolour.bg.g, truecolour.bg.b); else bg = colours[nbg]; From 262376a054719f0c248032df97be66142f0208e3 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Thu, 5 Oct 2017 20:30:04 +0100 Subject: [PATCH 077/607] Make the cursor colour override true colour. Otherwise, moving the cursor (at least in active, filled-cell mode) on to a true-coloured character cell causes it to vanish completely because the cell's colours override the thing that differentiates the cursor. --- unix/gtkwin.c | 1 + windows/window.c | 1 + 2 files changed, 2 insertions(+) diff --git a/unix/gtkwin.c b/unix/gtkwin.c index 94ba4069..dcff614f 100644 --- a/unix/gtkwin.c +++ b/unix/gtkwin.c @@ -3274,6 +3274,7 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, else if (nbg >= 256) nbg |= 1; } if ((attr & TATTR_ACTCURS) && !monochrome) { + truecolour.fg = truecolour.bg = optionalrgb_none; nfg = 260; nbg = 261; } diff --git a/windows/window.c b/windows/window.c index 79738ff9..97c4d462 100644 --- a/windows/window.c +++ b/windows/window.c @@ -3429,6 +3429,7 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, y += offset_height; if ((attr & TATTR_ACTCURS) && (cursor_type == 0 || term->big_cursor)) { + truecolour.fg = truecolour.bg = optionalrgb_none; attr &= ~(ATTR_REVERSE|ATTR_BLINK|ATTR_COLOURS); /* cursor fg and bg */ attr |= (260 << ATTR_FGSHIFT) | (261 << ATTR_BGSHIFT); From 4743798400e3eeae2902c4540da905a565f05c47 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Thu, 5 Oct 2017 20:43:02 +0100 Subject: [PATCH 078/607] Support OSC 4 terminal colour-palette queries. Markus Gans points out that some applications which (not at all unreasonably) don't trust $TERM to tell them the full capabilities of their terminal will use the sequence "OSC 4 ; nn ; ? BEL" to ask for the colour-palette value in position nn, and they may not particularly care _what_ the results are but they will use them to decide whether the right number of colour palette entries even exist. --- fuzzterm.c | 1 + putty.h | 1 + terminal.c | 66 +++++++++++++++++++++++++++++++++++------------- unix/gtkwin.c | 11 ++++++++ windows/window.c | 52 +++++++++++++++++++++++++------------- 5 files changed, 96 insertions(+), 35 deletions(-) diff --git a/fuzzterm.c b/fuzzterm.c index 480dca37..c57412c4 100644 --- a/fuzzterm.c +++ b/fuzzterm.c @@ -81,6 +81,7 @@ Context get_ctx(void *frontend) { void free_ctx(Context ctx) { } void palette_set(void *frontend, int a, int b, int c, int d) { } void palette_reset(void *frontend) { } +int palette_get(void *frontend, int n, int *r, int *g, int *b) {return FALSE;} void write_clip(void *frontend, wchar_t *a, int *b, int c, int d) { } void get_clip(void *frontend, wchar_t **w, int *i) { } void set_raw_mouse_mode(void *frontend, int m) { } diff --git a/putty.h b/putty.h index 8a8b5425..f89d0709 100644 --- a/putty.h +++ b/putty.h @@ -633,6 +633,7 @@ Context get_ctx(void *frontend); void free_ctx(Context); void palette_set(void *frontend, int, int, int, int); void palette_reset(void *frontend); +int palette_get(void *frontend, int n, int *r, int *g, int *b); void write_aclip(void *frontend, char *, int, int); void write_clip(void *frontend, wchar_t *, int *, int, int); void get_clip(void *frontend, wchar_t **, int *); diff --git a/terminal.c b/terminal.c index 5102db12..0fa52e17 100644 --- a/terminal.c +++ b/terminal.c @@ -2727,6 +2727,22 @@ static void do_osc(Terminal *term) if (!term->no_remote_wintitle) set_title(term->frontend, term->osc_string); break; + case 4: + if (term->ldisc && !strcmp(term->osc_string, "?")) { + int r, g, b; + if (palette_get(term->frontend, toint(term->esc_args[1]), + &r, &g, &b)) { + char *reply_buf = dupprintf( + "\033]4;%u;rgb:%04x/%04x/%04x\007", + term->esc_args[1], + (unsigned)r * 0x0101, + (unsigned)g * 0x0101, + (unsigned)b * 0x0101); + ldisc_send(term->ldisc, reply_buf, strlen(reply_buf), 0); + sfree(reply_buf); + } + } + break; } } } @@ -3365,6 +3381,7 @@ static void term_out(Terminal *term) compatibility(OTHER); term->termstate = SEEN_OSC; term->esc_args[0] = 0; + term->esc_nargs = 1; break; case '7': /* DECSC: save cursor */ compatibility(VT100); @@ -4470,25 +4487,40 @@ static void term_out(Terminal *term) case '7': case '8': case '9': - if (term->esc_args[0] <= UINT_MAX / 10 && - term->esc_args[0] * 10 <= UINT_MAX - c - '0') - term->esc_args[0] = 10 * term->esc_args[0] + c - '0'; + if (term->esc_args[term->esc_nargs-1] <= UINT_MAX / 10 && + term->esc_args[term->esc_nargs-1] * 10 <= UINT_MAX - c - '0') + term->esc_args[term->esc_nargs-1] = + 10 * term->esc_args[term->esc_nargs-1] + c - '0'; else - term->esc_args[0] = UINT_MAX; + term->esc_args[term->esc_nargs-1] = UINT_MAX; break; - case 'L': - /* - * Grotty hack to support xterm and DECterm title - * sequences concurrently. - */ - if (term->esc_args[0] == 2) { - term->esc_args[0] = 1; - break; - } - /* else fall through */ - default: - term->termstate = OSC_STRING; - term->osc_strlen = 0; + default: + /* + * _Most_ other characters here terminate the + * immediate parsing of the OSC sequence and go + * into OSC_STRING state, but we deal with a + * couple of exceptions first. + */ + if (c == 'L' && term->esc_args[0] == 2) { + /* + * Grotty hack to support xterm and DECterm title + * sequences concurrently. + */ + term->esc_args[0] = 1; + } else if (c == ';' && term->esc_nargs == 1 && + term->esc_args[0] == 4) { + /* + * xterm's OSC 4 sequence to query the current + * RGB value of a colour takes a second + * numeric argument which is easiest to parse + * using the existing system rather than in + * do_osc. + */ + term->esc_args[term->esc_nargs++] = 0; + } else { + term->termstate = OSC_STRING; + term->osc_strlen = 0; + } } break; case OSC_STRING: diff --git a/unix/gtkwin.c b/unix/gtkwin.c index dcff614f..969c42ff 100644 --- a/unix/gtkwin.c +++ b/unix/gtkwin.c @@ -2222,6 +2222,17 @@ void palette_set(void *frontend, int n, int r, int g, int b) } } +int palette_get(void *frontend, int n, int *r, int *g, int *b) +{ + struct gui_data *inst = (struct gui_data *)frontend; + if (n < 0 || n >= NALLCOLOURS) + return FALSE; + *r = inst->cols[n].red >> 8; + *g = inst->cols[n].green >> 8; + *b = inst->cols[n].blue >> 8; + return TRUE; +} + void palette_reset(void *frontend) { struct gui_data *inst = (struct gui_data *)frontend; diff --git a/windows/window.c b/windows/window.c index 97c4d462..aa96a578 100644 --- a/windows/window.c +++ b/windows/window.c @@ -198,6 +198,9 @@ static int descent; #define NEXTCOLOURS 240 #define NALLCOLOURS (NCFGCOLOURS + NEXTCOLOURS) static COLORREF colours[NALLCOLOURS]; +struct rgb { + int r, g, b; +} colours_rgb[NALLCOLOURS]; static HPALETTE pal; static LPLOGPALETTE logpal; static RGBTRIPLE defpal[NALLCOLOURS]; @@ -1264,6 +1267,19 @@ static void systopalette(void) } } +static void internal_set_colour(int i, int r, int g, int b) +{ + assert(i >= 0); + assert(i < NALLCOLOURS); + if (pal) + colours[i] = PALETTERGB(r, g, b); + else + colours[i] = RGB(r, g, b); + colours_rgb[i].r = r; + colours_rgb[i].g = g; + colours_rgb[i].b = b; +} + /* * Set up the colour palette. */ @@ -1298,15 +1314,9 @@ static void init_palette(void) } ReleaseDC(hwnd, hdc); } - if (pal) - for (i = 0; i < NALLCOLOURS; i++) - colours[i] = PALETTERGB(defpal[i].rgbtRed, - defpal[i].rgbtGreen, - defpal[i].rgbtBlue); - else - for (i = 0; i < NALLCOLOURS; i++) - colours[i] = RGB(defpal[i].rgbtRed, - defpal[i].rgbtGreen, defpal[i].rgbtBlue); + for (i = 0; i < NALLCOLOURS; i++) + internal_set_colour(i, defpal[i].rgbtRed, + defpal[i].rgbtGreen, defpal[i].rgbtBlue); } /* @@ -4865,15 +4875,24 @@ void free_ctx(Context ctx) static void real_palette_set(int n, int r, int g, int b) { + internal_set_colour(n, r, g, b); if (pal) { logpal->palPalEntry[n].peRed = r; logpal->palPalEntry[n].peGreen = g; logpal->palPalEntry[n].peBlue = b; logpal->palPalEntry[n].peFlags = PC_NOCOLLAPSE; - colours[n] = PALETTERGB(r, g, b); SetPaletteEntries(pal, 0, NALLCOLOURS, logpal->palPalEntry); - } else - colours[n] = RGB(r, g, b); + } +} + +int palette_get(void *frontend, int n, int *r, int *g, int *b) +{ + if (n < 0 || n >= NALLCOLOURS) + return FALSE; + *r = colours_rgb[n].r; + *g = colours_rgb[n].g; + *b = colours_rgb[n].b; + return TRUE; } void palette_set(void *frontend, int n, int r, int g, int b) @@ -4903,17 +4922,14 @@ void palette_reset(void *frontend) /* And this */ for (i = 0; i < NALLCOLOURS; i++) { + internal_set_colour(i, defpal[i].rgbtRed, + defpal[i].rgbtGreen, defpal[i].rgbtBlue); if (pal) { logpal->palPalEntry[i].peRed = defpal[i].rgbtRed; logpal->palPalEntry[i].peGreen = defpal[i].rgbtGreen; logpal->palPalEntry[i].peBlue = defpal[i].rgbtBlue; logpal->palPalEntry[i].peFlags = 0; - colours[i] = PALETTERGB(defpal[i].rgbtRed, - defpal[i].rgbtGreen, - defpal[i].rgbtBlue); - } else - colours[i] = RGB(defpal[i].rgbtRed, - defpal[i].rgbtGreen, defpal[i].rgbtBlue); + } } if (pal) { From 1a718403d40ccb88a1436eff98c82bf92268ef96 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Thu, 5 Oct 2017 21:02:56 +0100 Subject: [PATCH 079/607] Support SGR 2 to dim the foreground colour. I've done this on a 'where possible' basis: in Windows paletted mode (in case anyone is still using an old enough graphics card to need that!) I simply haven't bothered, and will completely ignore the dim flag. --- putty.h | 19 ++++++++------- terminal.c | 8 +++++-- unix/gtkwin.c | 61 ++++++++++++++++++++++++++++++++++-------------- windows/window.c | 8 ++++++- 4 files changed, 67 insertions(+), 29 deletions(-) diff --git a/putty.h b/putty.h index f89d0709..a9433fa7 100644 --- a/putty.h +++ b/putty.h @@ -104,15 +104,16 @@ typedef struct terminal_tag Terminal; */ #define UCSWIDE 0xDFFF -#define ATTR_NARROW 0x800000U -#define ATTR_WIDE 0x400000U -#define ATTR_BOLD 0x040000U -#define ATTR_UNDER 0x080000U -#define ATTR_REVERSE 0x100000U -#define ATTR_BLINK 0x200000U -#define ATTR_FGMASK 0x0001FFU -#define ATTR_BGMASK 0x03FE00U -#define ATTR_COLOURS 0x03FFFFU +#define ATTR_NARROW 0x0800000U +#define ATTR_WIDE 0x0400000U +#define ATTR_BOLD 0x0040000U +#define ATTR_UNDER 0x0080000U +#define ATTR_REVERSE 0x0100000U +#define ATTR_BLINK 0x0200000U +#define ATTR_FGMASK 0x00001FFU +#define ATTR_BGMASK 0x003FE00U +#define ATTR_COLOURS 0x003FFFFU +#define ATTR_DIM 0x1000000U #define ATTR_FGSHIFT 0 #define ATTR_BGSHIFT 9 diff --git a/terminal.c b/terminal.c index 0fa52e17..de5748e9 100644 --- a/terminal.c +++ b/terminal.c @@ -3881,6 +3881,10 @@ static void term_out(Terminal *term) compatibility(VT100AVO); term->curr_attr |= ATTR_BOLD; break; + case 2: /* enable dim */ + compatibility(OTHER); + term->curr_attr |= ATTR_DIM; + break; case 21: /* (enable double underline) */ compatibility(OTHER); case 4: /* enable underline */ @@ -3912,9 +3916,9 @@ static void term_out(Terminal *term) compatibility(SCOANSI); if (term->no_remote_charset) break; term->sco_acs = 2; break; - case 22: /* disable bold */ + case 22: /* disable bold and dim */ compatibility2(OTHER, VT220); - term->curr_attr &= ~ATTR_BOLD; + term->curr_attr &= ~(ATTR_BOLD | ATTR_DIM); break; case 24: /* disable underline */ compatibility2(OTHER, VT220); diff --git a/unix/gtkwin.c b/unix/gtkwin.c index 969c42ff..5c629519 100644 --- a/unix/gtkwin.c +++ b/unix/gtkwin.c @@ -3023,24 +3023,44 @@ static void draw_update(struct draw_ctx *dctx, int x, int y, int w, int h) gtk_widget_queue_draw_area(dctx->inst->area, x, y, w, h); } -static void draw_set_colour(struct draw_ctx *dctx, int col) +#ifdef DRAW_TEXT_CAIRO +static void cairo_set_source_rgb_dim(cairo_t *cr, double r, double g, double b, + int dim) +{ + if (dim) + cairo_set_source_rgb(cr, r * 2 / 3, g * 2 / 3, b * 2 / 3); + else + cairo_set_source_rgb(cr, r, g, b); +} +#endif + +static void draw_set_colour(struct draw_ctx *dctx, int col, int dim) { #ifdef DRAW_TEXT_GDK if (dctx->uctx.type == DRAWTYPE_GDK) { - gdk_gc_set_foreground(dctx->uctx.u.gdk.gc, &dctx->inst->cols[col]); + if (dim) { + GdkColor color; + color.red = dctx->inst->cols[col].red * 2 / 3; + color.green = dctx->inst->cols[col].green * 2 / 3; + color.blue = dctx->inst->cols[col].blue * 2 / 3; + gdk_gc_set_rgb_fg_color(dctx->uctx.u.gdk.gc, &color); + } else { + gdk_gc_set_foreground(dctx->uctx.u.gdk.gc, &dctx->inst->cols[col]); + } } #endif #ifdef DRAW_TEXT_CAIRO if (dctx->uctx.type == DRAWTYPE_CAIRO) { - cairo_set_source_rgb(dctx->uctx.u.cairo.cr, - dctx->inst->cols[col].red / 65535.0, - dctx->inst->cols[col].green / 65535.0, - dctx->inst->cols[col].blue / 65535.0); + cairo_set_source_rgb_dim(dctx->uctx.u.cairo.cr, + dctx->inst->cols[col].red / 65535.0, + dctx->inst->cols[col].green / 65535.0, + dctx->inst->cols[col].blue / 65535.0, dim); } #endif } -static void draw_set_colour_rgb(struct draw_ctx *dctx, optionalrgb orgb) +static void draw_set_colour_rgb(struct draw_ctx *dctx, optionalrgb orgb, + int dim) { #ifdef DRAW_TEXT_GDK if (dctx->uctx.type == DRAWTYPE_GDK) { @@ -3048,13 +3068,19 @@ static void draw_set_colour_rgb(struct draw_ctx *dctx, optionalrgb orgb) color.red = orgb.r * 256; color.green = orgb.g * 256; color.blue = orgb.b * 256; + if (dim) { + color.red = color.red * 2 / 3; + color.green = color.green * 2 / 3; + color.blue = color.blue * 2 / 3; + } gdk_gc_set_rgb_fg_color(dctx->uctx.u.gdk.gc, &color); } #endif #ifdef DRAW_TEXT_CAIRO - if (dctx->uctx.type == DRAWTYPE_CAIRO) - cairo_set_source_rgb(dctx->uctx.u.cairo.cr, - orgb.r / 255.0, orgb.g / 255.0, orgb.b / 255.0); + if (dctx->uctx.type == DRAWTYPE_CAIRO) { + cairo_set_source_rgb_dim(dctx->uctx.u.cairo.cr, orgb.r / 255.0, + orgb.g / 255.0, orgb.b / 255.0, dim); + } #endif } @@ -3238,7 +3264,7 @@ static void draw_backing_rect(struct gui_data *inst) struct draw_ctx *dctx = get_ctx(inst); int w = inst->width * inst->font_width + 2*inst->window_border; int h = inst->height * inst->font_height + 2*inst->window_border; - draw_set_colour(dctx, 258); + draw_set_colour(dctx, 258, FALSE); draw_rectangle(dctx, 1, 0, 0, w, h); draw_update(dctx, 0, 0, w, h); free_ctx(dctx); @@ -3288,6 +3314,7 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, truecolour.fg = truecolour.bg = optionalrgb_none; nfg = 260; nbg = 261; + attr &= ~ATTR_DIM; /* don't dim the cursor */ } fontid = shadow = 0; @@ -3350,18 +3377,18 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, } if (truecolour.bg.enabled) - draw_set_colour_rgb(dctx, truecolour.bg); + draw_set_colour_rgb(dctx, truecolour.bg, attr & ATTR_DIM); else - draw_set_colour(dctx, nbg); + draw_set_colour(dctx, nbg, attr & ATTR_DIM); draw_rectangle(dctx, TRUE, x*inst->font_width+inst->window_border, y*inst->font_height+inst->window_border, rlen*widefactor*inst->font_width, inst->font_height); if (truecolour.fg.enabled) - draw_set_colour_rgb(dctx, truecolour.fg); + draw_set_colour_rgb(dctx, truecolour.fg, attr & ATTR_DIM); else - draw_set_colour(dctx, nfg); + draw_set_colour(dctx, nfg, attr & ATTR_DIM); if (ncombining > 1) { assert(len == 1); unifont_draw_combining(&dctx->uctx, inst->fonts[fontid], @@ -3475,7 +3502,7 @@ void do_cursor(Context ctx, int x, int y, wchar_t *text, int len, * if it's passive. */ if (passive) { - draw_set_colour(dctx, 261); + draw_set_colour(dctx, 261, FALSE); draw_rectangle(dctx, FALSE, x*inst->font_width+inst->window_border, y*inst->font_height+inst->window_border, @@ -3514,7 +3541,7 @@ void do_cursor(Context ctx, int x, int y, wchar_t *text, int len, length = inst->font_height; } - draw_set_colour(dctx, 261); + draw_set_colour(dctx, 261, FALSE); if (passive) { for (i = 0; i < length; i++) { if (i % 2 == 0) { diff --git a/windows/window.c b/windows/window.c index aa96a578..be7b4379 100644 --- a/windows/window.c +++ b/windows/window.c @@ -3440,7 +3440,7 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, if ((attr & TATTR_ACTCURS) && (cursor_type == 0 || term->big_cursor)) { truecolour.fg = truecolour.bg = optionalrgb_none; - attr &= ~(ATTR_REVERSE|ATTR_BLINK|ATTR_COLOURS); + attr &= ~(ATTR_REVERSE|ATTR_BLINK|ATTR_COLOURS|ATTR_DIM); /* cursor fg and bg */ attr |= (260 << ATTR_FGSHIFT) | (261 << ATTR_BGSHIFT); is_cursor = TRUE; @@ -3543,6 +3543,12 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, else bg = colours[nbg]; + if (!pal && (attr & ATTR_DIM)) { + fg = RGB(GetRValue(fg) * 2 / 3, + GetGValue(fg) * 2 / 3, + GetBValue(fg) * 2 / 3); + } + SelectObject(hdc, fonts[nfont]); SetTextColor(hdc, fg); SetBkColor(hdc, bg); From 96a088195fe86cb31347b42b1c262c1aa2ee0a2f Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 8 Oct 2017 13:43:27 +0100 Subject: [PATCH 080/607] Make true colour work with background-colour erase. Thanks to Markus Gans for reporting this bug. --- terminal.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/terminal.c b/terminal.c index de5748e9..8c44b906 100644 --- a/terminal.c +++ b/terminal.c @@ -1407,9 +1407,11 @@ void term_pwron(Terminal *term, int clear) static void set_erase_char(Terminal *term) { term->erase_char = term->basic_erase_char; - if (term->use_bce) + if (term->use_bce) { term->erase_char.attr = (term->curr_attr & (ATTR_FGMASK | ATTR_BGMASK)); + term->erase_char.truecolour.bg = term->curr_truecolour.bg; + } } /* From e3d92df936b97aef3cd51f1e85eb3c47409069c5 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 8 Oct 2017 13:45:08 +0100 Subject: [PATCH 081/607] Save and restore true-colour state with the cursor. I spotted this myself while looking through the code in search of the cause of the background-colour-erase bug: saving and restoring the cursor via ESC 7 / ESC 8 ought to also save and restore the current graphics rendition attributes including foreground and background colour settings, but it was not saving and restoring the new term->curr_truecolour along with term->curr_attr. So there's now a term->save_truecolour to keep that in, and also a term->alt_save_truecolour to take account of the fact that all the saved cursor state variables get swapped out _again_ when switching between the main and alternate screens. (However, there is not a term->alt_truecolour to complete the cross product, because the _active_ graphics rendition is carried over when switching between the terminal screens; it's only the _saved_ one from ESC 7 / ESC 8 that is saved separately. That's consistent with the behaviour we've had all along for ordinary fg/bg colour selection.) --- terminal.c | 8 ++++++++ terminal.h | 1 + 2 files changed, 9 insertions(+) diff --git a/terminal.c b/terminal.c index 8c44b906..7a7207a0 100644 --- a/terminal.c +++ b/terminal.c @@ -1297,6 +1297,7 @@ static void power_on(Terminal *term, int clear) term->default_attr = term->save_attr = term->alt_save_attr = term->curr_attr = ATTR_DEFAULT; term->curr_truecolour.fg = term->curr_truecolour.bg = optionalrgb_none; + term->save_truecolour = term->alt_save_truecolour = term->curr_truecolour; term->term_editing = term->term_echoing = FALSE; term->app_cursor_keys = conf_get_int(term->conf, CONF_app_cursor); term->app_keypad_keys = conf_get_int(term->conf, CONF_app_keypad); @@ -1987,6 +1988,7 @@ static void swap_screen(Terminal *term, int which, int reset, int keep_cur_pos) { int t; pos tp; + truecolour ttc; tree234 *ttr; if (!which) @@ -2051,6 +2053,10 @@ static void swap_screen(Terminal *term, int which, int reset, int keep_cur_pos) if (!reset && !keep_cur_pos) term->save_attr = term->alt_save_attr; term->alt_save_attr = t; + ttc = term->save_truecolour; + if (!reset && !keep_cur_pos) + term->save_truecolour = term->alt_save_truecolour; + term->alt_save_truecolour = ttc; t = term->save_utf; if (!reset && !keep_cur_pos) term->save_utf = term->alt_save_utf; @@ -2346,6 +2352,7 @@ static void save_cursor(Terminal *term, int save) if (save) { term->savecurs = term->curs; term->save_attr = term->curr_attr; + term->save_truecolour = term->curr_truecolour; term->save_cset = term->cset; term->save_utf = term->utf; term->save_wnext = term->wrapnext; @@ -2360,6 +2367,7 @@ static void save_cursor(Terminal *term, int save) term->curs.y = term->rows - 1; term->curr_attr = term->save_attr; + term->curr_truecolour = term->save_truecolour; term->cset = term->save_cset; term->utf = term->save_utf; term->wrapnext = term->save_wnext; diff --git a/terminal.h b/terminal.h index 4a205a77..fcb321c4 100644 --- a/terminal.h +++ b/terminal.h @@ -140,6 +140,7 @@ struct terminal_tag { /* ESC 7 saved state for the alternate screen */ pos alt_savecurs; int alt_save_attr; + truecolour alt_save_truecolour; int alt_save_cset, alt_save_csattr; int alt_save_utf, alt_save_wnext; int alt_save_sco_acs; From f353e2219e4371cda176bc37a11ddc4bb7e32516 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 8 Oct 2017 13:47:39 +0100 Subject: [PATCH 082/607] Turn off true colour on SCO and VT52 colour sequences. After fixing the previous two bugs, I thought it was probably a good idea to re-check _everywhere_ in terminal.c where curr_attr is used, to make sure that if curr_truecolour also needed updating at the same time then that was being done. --- terminal.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/terminal.c b/terminal.c index 7a7207a0..a55b6e6a 100644 --- a/terminal.c +++ b/terminal.c @@ -4370,6 +4370,7 @@ static void term_out(Terminal *term) ATTR_FGSHIFT; term->curr_attr &= ~ATTR_FGMASK; term->curr_attr |= colour; + term->curr_truecolour.fg = optionalrgb_none; term->default_attr &= ~ATTR_FGMASK; term->default_attr |= colour; set_erase_char(term); @@ -4384,6 +4385,7 @@ static void term_out(Terminal *term) ATTR_BGSHIFT; term->curr_attr &= ~ATTR_BGMASK; term->curr_attr |= colour; + term->curr_truecolour.bg = optionalrgb_none; term->default_attr &= ~ATTR_BGMASK; term->default_attr |= colour; set_erase_char(term); @@ -4811,6 +4813,8 @@ static void term_out(Terminal *term) /* compatibility(OTHER) */ term->vt52_bold = FALSE; term->curr_attr = ATTR_DEFAULT; + term->curr_truecolour.fg = optionalrgb_none; + term->curr_truecolour.bg = optionalrgb_none; set_erase_char(term); break; case 'S': From 916a2574d5fb40ee9ce899ac93e8d31738f5bed4 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 8 Oct 2017 13:49:54 +0100 Subject: [PATCH 083/607] Make reverse video interact correctly with true colour. ATTR_REVERSE was being handled in the front ends, and was causing the foreground and background colours to be switched. (I'm not completely sure why I made that design decision; it might be purely historical, but then again, it might also be because reverse video is one effect on the fg and bg colours that must still be performed even in unusual frontend-specific situations like display-driven monochrome mode.) This affected both explicit reverse video enabled using SGR 7, and also the transient reverse video arising from mouse selection. Thanks to Markus Gans for reporting the bug in the latter, which when I investigated it turned out to affect the former as well. --- terminal.h | 2 +- unix/gtkwin.c | 6 ++++++ windows/window.c | 6 ++++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/terminal.h b/terminal.h index fcb321c4..03659744 100644 --- a/terminal.h +++ b/terminal.h @@ -103,7 +103,7 @@ struct terminal_tag { #endif /* OPTIMISE_SCROLL */ int default_attr, curr_attr, save_attr; - truecolour curr_truecolour; + truecolour curr_truecolour, save_truecolour; termchar basic_erase_char, erase_char; bufchain inbuf; /* terminal input buffer */ diff --git a/unix/gtkwin.c b/unix/gtkwin.c index 5c629519..3e12a4ba 100644 --- a/unix/gtkwin.c +++ b/unix/gtkwin.c @@ -3298,9 +3298,15 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, nfg = ((monochrome ? ATTR_DEFFG : (attr & ATTR_FGMASK)) >> ATTR_FGSHIFT); nbg = ((monochrome ? ATTR_DEFBG : (attr & ATTR_BGMASK)) >> ATTR_BGSHIFT); if (!!(attr & ATTR_REVERSE) ^ (monochrome && (attr & TATTR_ACTCURS))) { + struct optionalrgb trgb; + t = nfg; nfg = nbg; nbg = t; + + trgb = truecolour.fg; + truecolour.fg = truecolour.bg; + truecolour.bg = trgb; } if ((inst->bold_style & 2) && (attr & ATTR_BOLD)) { if (nfg < 16) nfg |= 8; diff --git a/windows/window.c b/windows/window.c index be7b4379..73f0751c 100644 --- a/windows/window.c +++ b/windows/window.c @@ -3521,9 +3521,15 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, if (!fonts[nfont]) nfont = FONT_NORMAL; if (attr & ATTR_REVERSE) { + struct optionalrgb trgb; + t = nfg; nfg = nbg; nbg = t; + + trgb = truecolour.fg; + truecolour.fg = truecolour.bg; + truecolour.bg = trgb; } if (bold_colours && (attr & ATTR_BOLD) && !is_cursor) { if (nfg < 16) nfg |= 8; From 298b9fd4d40a86b192a23a6bceac1f06f89f9eaf Mon Sep 17 00:00:00 2001 From: Jeff Smith Date: Fri, 13 Oct 2017 22:49:25 -0500 Subject: [PATCH 084/607] Setting an 8-bit colour should cancel a 24-bit colour --- terminal.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/terminal.c b/terminal.c index a55b6e6a..2106d10a 100644 --- a/terminal.c +++ b/terminal.c @@ -4031,6 +4031,8 @@ static void term_out(Terminal *term) term->curr_attr |= ((term->esc_args[i+2] & 0xFF) << ATTR_FGSHIFT); + term->curr_truecolour.fg = + optionalrgb_none; i += 2; } if (i + 4 < term->esc_nargs && @@ -4048,6 +4050,8 @@ static void term_out(Terminal *term) term->curr_attr |= ((term->esc_args[i+2] & 0xFF) << ATTR_BGSHIFT); + term->curr_truecolour.bg = + optionalrgb_none; i += 2; } if (i + 4 < term->esc_nargs && From 7bdfdabb5e1c7418074ff43d9b436033c96aa00c Mon Sep 17 00:00:00 2001 From: Jeff Smith Date: Wed, 14 Jun 2017 08:11:05 -0500 Subject: [PATCH 085/607] Update clipping interface for true-colour --- fuzzterm.c | 2 +- putty.h | 2 +- terminal.c | 19 ++++++++++++++----- unix/gtkwin.c | 8 ++++---- windows/window.c | 3 ++- 5 files changed, 22 insertions(+), 12 deletions(-) diff --git a/fuzzterm.c b/fuzzterm.c index c57412c4..255fc6fb 100644 --- a/fuzzterm.c +++ b/fuzzterm.c @@ -82,7 +82,7 @@ void free_ctx(Context ctx) { } void palette_set(void *frontend, int a, int b, int c, int d) { } void palette_reset(void *frontend) { } int palette_get(void *frontend, int n, int *r, int *g, int *b) {return FALSE;} -void write_clip(void *frontend, wchar_t *a, int *b, int c, int d) { } +void write_clip(void *frontend, wchar_t *a, int *b, truecolour *c, int d, int e) { } void get_clip(void *frontend, wchar_t **w, int *i) { } void set_raw_mouse_mode(void *frontend, int m) { } void request_paste(void *frontend) { } diff --git a/putty.h b/putty.h index a9433fa7..ac35eb73 100644 --- a/putty.h +++ b/putty.h @@ -636,7 +636,7 @@ void palette_set(void *frontend, int, int, int, int); void palette_reset(void *frontend); int palette_get(void *frontend, int n, int *r, int *g, int *b); void write_aclip(void *frontend, char *, int, int); -void write_clip(void *frontend, wchar_t *, int *, int, int); +void write_clip(void *frontend, wchar_t *, int *, truecolour *, int, int); void get_clip(void *frontend, wchar_t **, int *); void optimised_move(void *frontend, int, int, int); void set_raw_mouse_mode(void *frontend, int); diff --git a/terminal.c b/terminal.c index 2106d10a..d32d4f42 100644 --- a/terminal.c +++ b/terminal.c @@ -5616,9 +5616,11 @@ typedef struct { wchar_t *textptr; /* = textbuf + bufpos (current insertion point) */ int *attrbuf; /* buffer for copied attributes */ int *attrptr; /* = attrbuf + bufpos */ + truecolour *tcbuf; /* buffer for copied colours */ + truecolour *tcptr; /* = tcbuf + bufpos */ } clip_workbuf; -static void clip_addchar(clip_workbuf *b, wchar_t chr, int attr) +static void clip_addchar(clip_workbuf *b, wchar_t chr, int attr, truecolour tc) { if (b->bufpos >= b->buflen) { b->buflen *= 2; @@ -5626,9 +5628,12 @@ static void clip_addchar(clip_workbuf *b, wchar_t chr, int attr) b->textptr = b->textbuf + b->bufpos; b->attrbuf = sresize(b->attrbuf, b->buflen, int); b->attrptr = b->attrbuf + b->bufpos; + b->tcbuf = sresize(b->tcbuf, b->buflen, truecolour); + b->tcptr = b->tcbuf + b->bufpos; } *b->textptr++ = chr; *b->attrptr++ = attr; + *b->tcptr++ = tc; b->bufpos++; } @@ -5637,11 +5642,13 @@ static void clipme(Terminal *term, pos top, pos bottom, int rect, int desel) clip_workbuf buf; int old_top_x; int attr; + truecolour tc; buf.buflen = 5120; buf.bufpos = 0; buf.textptr = buf.textbuf = snewn(buf.buflen, wchar_t); buf.attrptr = buf.attrbuf = snewn(buf.buflen, int); + buf.tcptr = buf.tcbuf = snewn(buf.buflen, truecolour); old_top_x = top.x; /* needed for rect==1 */ @@ -5707,6 +5714,7 @@ static void clipme(Terminal *term, pos top, pos bottom, int rect, int desel) while (1) { int uc = ldata->chars[x].chr; attr = ldata->chars[x].attr; + tc = ldata->chars[x].truecolour; switch (uc & CSET_MASK) { case CSET_LINEDRW: @@ -5767,7 +5775,7 @@ static void clipme(Terminal *term, pos top, pos bottom, int rect, int desel) #endif for (p = cbuf; *p; p++) - clip_addchar(&buf, *p, attr); + clip_addchar(&buf, *p, attr, tc); if (ldata->chars[x].cc_next) x += ldata->chars[x].cc_next; @@ -5779,7 +5787,7 @@ static void clipme(Terminal *term, pos top, pos bottom, int rect, int desel) if (nl) { int i; for (i = 0; i < sel_nl_sz; i++) - clip_addchar(&buf, sel_nl[i], 0); + clip_addchar(&buf, sel_nl[i], 0, term->basic_erase_char.truecolour); } top.y++; top.x = rect ? old_top_x : 0; @@ -5787,12 +5795,13 @@ static void clipme(Terminal *term, pos top, pos bottom, int rect, int desel) unlineptr(ldata); } #if SELECTION_NUL_TERMINATED - clip_addchar(&buf, 0, 0); + clip_addchar(&buf, 0, 0, term->basic_erase_char.truecolour); #endif /* Finally, transfer all that to the clipboard. */ - write_clip(term->frontend, buf.textbuf, buf.attrbuf, buf.bufpos, desel); + write_clip(term->frontend, buf.textbuf, buf.attrbuf, buf.tcbuf, buf.bufpos, desel); sfree(buf.textbuf); sfree(buf.attrbuf); + sfree(buf.tcbuf); } void term_copyall(Terminal *term) diff --git a/unix/gtkwin.c b/unix/gtkwin.c index 3e12a4ba..3a3c2a54 100644 --- a/unix/gtkwin.c +++ b/unix/gtkwin.c @@ -2360,8 +2360,8 @@ static void clipboard_clear(GtkClipboard *clipboard, gpointer data) sfree(cdi); } -void write_clip(void *frontend, wchar_t *data, int *attr, int len, - int must_deselect) +void write_clip(void *frontend, wchar_t *data, int *attr, truecolour *truecolour, + int len, int must_deselect) { struct gui_data *inst = (struct gui_data *)frontend; struct clipboard_data_instance *cdi; @@ -2488,8 +2488,8 @@ static char *retrieve_cutbuffer(int *nbytes) #endif } -void write_clip(void *frontend, wchar_t *data, int *attr, int len, - int must_deselect) +void write_clip(void *frontend, wchar_t *data, int *attr, truecolour *truecolour, + int len, int must_deselect) { struct gui_data *inst = (struct gui_data *)frontend; if (inst->pasteout_data) diff --git a/windows/window.c b/windows/window.c index 73f0751c..8faa57e9 100644 --- a/windows/window.c +++ b/windows/window.c @@ -4989,7 +4989,8 @@ void write_aclip(void *frontend, char *data, int len, int must_deselect) /* * Note: unlike write_aclip() this will not append a nul. */ -void write_clip(void *frontend, wchar_t * data, int *attr, int len, int must_deselect) +void write_clip(void *frontend, wchar_t *data, int *attr, truecolour *truecolour, + int len, int must_deselect) { HGLOBAL clipdata, clipdata2, clipdata3; int len2; From 891d909b3d7fb206e1055feaafbb25e771393ce2 Mon Sep 17 00:00:00 2001 From: Jeff Smith Date: Mon, 12 Jun 2017 23:55:57 -0500 Subject: [PATCH 086/607] Implement true-colour in write_clip for Windows This allows text copied from PuTTY to a rich-text program to retain the true-colour attribute. --- windows/window.c | 126 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 111 insertions(+), 15 deletions(-) diff --git a/windows/window.c b/windows/window.c index 8faa57e9..88a29dd4 100644 --- a/windows/window.c +++ b/windows/window.c @@ -24,6 +24,7 @@ #include "storage.h" #include "win_res.h" #include "winsecur.h" +#include "tree234.h" #ifndef NO_MULTIMON #include @@ -4986,6 +4987,18 @@ void write_aclip(void *frontend, char *data, int len, int must_deselect) SendMessage(hwnd, WM_IGNORE_CLIP, FALSE, 0); } +typedef struct _rgbindex { + int index; + COLORREF ref; +} rgbindex; + +int cmpCOLORREF(void *va, void *vb) +{ + COLORREF a = ((rgbindex *)va)->ref; + COLORREF b = ((rgbindex *)vb)->ref; + return (a < b) ? -1 : (a > b) ? +1 : 0; +} + /* * Note: unlike write_aclip() this will not append a nul. */ @@ -5033,12 +5046,15 @@ void write_clip(void *frontend, wchar_t *data, int *attr, truecolour *truecolour int rtfsize = 0; int multilen, blen, alen, totallen, i; char before[16], after[4]; - int fgcolour, lastfgcolour = 0; - int bgcolour, lastbgcolour = 0; + int fgcolour, lastfgcolour = -1; + int bgcolour, lastbgcolour = -1; + COLORREF fg, lastfg = -1; + COLORREF bg, lastbg = -1; int attrBold, lastAttrBold = 0; int attrUnder, lastAttrUnder = 0; int palette[NALLCOLOURS]; int numcolours; + tree234 *rgbtree = NULL; FontSpec *font = conf_get_fontspec(conf, CONF_font); get_unitab(CP_ACP, unitab, 0); @@ -5076,7 +5092,7 @@ void write_clip(void *frontend, wchar_t *data, int *attr, truecolour *truecolour fgcolour ++; } - if (attr[i] & ATTR_BLINK) { + if ((attr[i] & ATTR_BLINK)) { if (bgcolour < 8) /* ANSI colours */ bgcolour += 8; else if (bgcolour >= 256) /* Default colours */ @@ -5087,6 +5103,28 @@ void write_clip(void *frontend, wchar_t *data, int *attr, truecolour *truecolour palette[bgcolour]++; } + if (truecolour) { + rgbtree = newtree234(cmpCOLORREF); + for (i = 0; i < (len-1); i++) { + if (truecolour[i].fg.enabled) { + rgbindex *rgbp = snew(rgbindex); + rgbp->ref = RGB(truecolour[i].fg.r, + truecolour[i].fg.g, + truecolour[i].fg.b); + if (add234(rgbtree, rgbp) != rgbp) + sfree(rgbp); + } + if (truecolour[i].bg.enabled) { + rgbindex *rgbp = snew(rgbindex); + rgbp->ref = RGB(truecolour[i].bg.r, + truecolour[i].bg.g, + truecolour[i].bg.b); + if (add234(rgbtree, rgbp) != rgbp) + sfree(rgbp); + } + } + } + /* * Next - Create a reduced palette */ @@ -5096,6 +5134,12 @@ void write_clip(void *frontend, wchar_t *data, int *attr, truecolour *truecolour palette[i] = ++numcolours; } + if (rgbtree) { + rgbindex *rgbp; + for (i = 0; (rgbp = index234(rgbtree, i)) != NULL; i++) + rgbp->index = ++numcolours; + } + /* * Finally - Write the colour table */ @@ -5108,6 +5152,12 @@ void write_clip(void *frontend, wchar_t *data, int *attr, truecolour *truecolour rtflen += sprintf(&rtf[rtflen], "\\red%d\\green%d\\blue%d;", defpal[i].rgbtRed, defpal[i].rgbtGreen, defpal[i].rgbtBlue); } } + if (rgbtree) { + rgbindex *rgbp; + for (i = 0; (rgbp = index234(rgbtree, i)) != NULL; i++) + rtflen += sprintf(&rtf[rtflen], "\\red%d\\green%d\\blue%d;", + GetRValue(rgbp->ref), GetGValue(rgbp->ref), GetBValue(rgbp->ref)); + } strcpy(&rtf[rtflen], "}"); rtflen ++; } @@ -5151,23 +5201,44 @@ void write_clip(void *frontend, wchar_t *data, int *attr, truecolour *truecolour /* * Determine foreground and background colours */ - fgcolour = ((attr[tindex] & ATTR_FGMASK) >> ATTR_FGSHIFT); - bgcolour = ((attr[tindex] & ATTR_BGMASK) >> ATTR_BGSHIFT); + if (truecolour && truecolour[tindex].fg.enabled) { + fgcolour = -1; + fg = RGB(truecolour[tindex].fg.r, + truecolour[tindex].fg.g, + truecolour[tindex].fg.b); + } else { + fgcolour = ((attr[tindex] & ATTR_FGMASK) >> ATTR_FGSHIFT); + fg = -1; + } + + if (truecolour && truecolour[tindex].bg.enabled) { + bgcolour = -1; + bg = RGB(truecolour[tindex].bg.r, + truecolour[tindex].bg.g, + truecolour[tindex].bg.b); + } else { + bgcolour = ((attr[tindex] & ATTR_BGMASK) >> ATTR_BGSHIFT); + bg = -1; + } if (attr[tindex] & ATTR_REVERSE) { int tmpcolour = fgcolour; /* Swap foreground and background */ fgcolour = bgcolour; bgcolour = tmpcolour; + + COLORREF tmpref = fg; + fg = bg; + bg = tmpref; } - if (bold_colours && (attr[tindex] & ATTR_BOLD)) { + if (bold_colours && (attr[tindex] & ATTR_BOLD) && (fgcolour >= 0)) { if (fgcolour < 8) /* ANSI colours */ fgcolour += 8; else if (fgcolour >= 256) /* Default colours */ fgcolour ++; } - if (attr[tindex] & ATTR_BLINK) { + if ((attr[tindex] & ATTR_BLINK) && (bgcolour >= 0)) { if (bgcolour < 8) /* ANSI colours */ bgcolour += 8; else if (bgcolour >= 256) /* Default colours */ @@ -5206,15 +5277,33 @@ void write_clip(void *frontend, wchar_t *data, int *attr, truecolour *truecolour /* * Write RTF text attributes */ - if (lastfgcolour != fgcolour) { - lastfgcolour = fgcolour; - rtflen += sprintf(&rtf[rtflen], "\\cf%d ", (fgcolour >= 0) ? palette[fgcolour] : 0); - } + if ((lastfgcolour != fgcolour) || (lastfg != fg)) { + lastfgcolour = fgcolour; + lastfg = fg; + if (fg == -1) + rtflen += sprintf(&rtf[rtflen], "\\cf%d ", + (fgcolour >= 0) ? palette[fgcolour] : 0); + else { + rgbindex rgb, *rgbp; + rgb.ref = fg; + if ((rgbp = find234(rgbtree, &rgb, NULL)) != NULL) + rtflen += sprintf(&rtf[rtflen], "\\cf%d ", rgbp->index); + } + } - if (lastbgcolour != bgcolour) { - lastbgcolour = bgcolour; - rtflen += sprintf(&rtf[rtflen], "\\highlight%d ", (bgcolour >= 0) ? palette[bgcolour] : 0); - } + if ((lastbgcolour != bgcolour) || (lastbg != bg)) { + lastbgcolour = bgcolour; + lastbg = bg; + if (bg == -1) + rtflen += sprintf(&rtf[rtflen], "\\highlight%d ", + (bgcolour >= 0) ? palette[bgcolour] : 0); + else { + rgbindex rgb, *rgbp; + rgb.ref = bg; + if ((rgbp = find234(rgbtree, &rgb, NULL)) != NULL) + rtflen += sprintf(&rtf[rtflen], "\\highlight%d ", rgbp->index); + } + } if (lastAttrBold != attrBold) { lastAttrBold = attrBold; @@ -5295,6 +5384,13 @@ void write_clip(void *frontend, wchar_t *data, int *attr, truecolour *truecolour GlobalUnlock(clipdata3); } sfree(rtf); + + if (rgbtree) { + rgbindex *rgbp; + while ((rgbp = delpos234(rgbtree, 0)) != NULL) + sfree(rgbp); + freetree234(rgbtree); + } } else clipdata3 = NULL; From b4e5485caa1ba9286db3f51ba1b8a5498db52411 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Thu, 19 Oct 2017 18:27:03 +0100 Subject: [PATCH 087/607] Add Jeff Smith as a copyright holder. --- LICENCE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENCE b/LICENCE index 30b1fe2b..05fbb7d3 100644 --- a/LICENCE +++ b/LICENCE @@ -4,7 +4,7 @@ Portions copyright Robert de Bath, Joris van Rantwijk, Delian Delchev, Andreas Schultz, Jeroen Massar, Wez Furlong, Nicolas Barry, Justin Bradford, Ben Harris, Malcolm Smith, Ahmad Khalifa, Markus Kuhn, Colin Watson, Christopher Staite, Lorenz Diener, Christian -Brabandt, and CORE SDI S.A. +Brabandt, Jeff Smith, and CORE SDI S.A. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files From ea5425939297e0f41de4be3168fbb8d68854bb64 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Thu, 19 Oct 2017 18:55:22 +0100 Subject: [PATCH 088/607] sshaes.c: fix file name in header comment. Apparently I forgot to edit that when I originally imported this AES implementation into PuTTY's SSH code from the more generically named source file in which I'd originally developed it. --- sshaes.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sshaes.c b/sshaes.c index 904cbdb2..0368d6e9 100644 --- a/sshaes.c +++ b/sshaes.c @@ -1,5 +1,5 @@ /* - * aes.c - implementation of AES / Rijndael + * sshaes.c - implementation of AES / Rijndael * * AES is a flexible algorithm as regards endianness: it has no * inherent preference as to which way round you should form words From 4dfadcfb2643fe3b54bb29277ca73bc5ba647208 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Thu, 19 Oct 2017 19:13:02 +0100 Subject: [PATCH 089/607] sshaes.c: remove completely unused #define MAX_NK. --- sshaes.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sshaes.c b/sshaes.c index 0368d6e9..9be58dab 100644 --- a/sshaes.c +++ b/sshaes.c @@ -33,7 +33,6 @@ #include "ssh.h" #define MAX_NR 14 /* max no of rounds */ -#define MAX_NK 8 /* max no of words in input key */ #define MAX_NB 8 /* max no of words in cipher blk */ #define mulby2(x) ( ((x&0x7F) << 1) ^ (x & 0x80 ? 0x1B : 0) ) From 5592312636988869517026b6b8ead0a0dfd45266 Mon Sep 17 00:00:00 2001 From: "Pavel I. Kryukov" Date: Fri, 20 Oct 2017 19:13:21 +0100 Subject: [PATCH 090/607] AES: remove support for block sizes other than 128 bits. They're not really part of AES at all, in that they were part of the Rijndael design but not part of the subset standardised by NIST. More relevantly, they're not used by any SSH cipher definition, so they're just adding complexity to the code which is about to get in the way of refactoring it. Removing them means there's only one pair of core encrypt/decrypt functions, so the 'encrypt' and 'decrypt' function pointer fields can be completely removed from AESContext. --- sshaes.c | 277 ++++++++----------------------------------------------- 1 file changed, 40 insertions(+), 237 deletions(-) diff --git a/sshaes.c b/sshaes.c index 9be58dab..48d0ca16 100644 --- a/sshaes.c +++ b/sshaes.c @@ -33,19 +33,17 @@ #include "ssh.h" #define MAX_NR 14 /* max no of rounds */ -#define MAX_NB 8 /* max no of words in cipher blk */ +#define NB 4 /* no of words in cipher blk */ #define mulby2(x) ( ((x&0x7F) << 1) ^ (x & 0x80 ? 0x1B : 0) ) typedef struct AESContext AESContext; struct AESContext { - word32 keysched[(MAX_NR + 1) * MAX_NB]; - word32 invkeysched[(MAX_NR + 1) * MAX_NB]; - void (*encrypt) (AESContext * ctx, word32 * block); - void (*decrypt) (AESContext * ctx, word32 * block); - word32 iv[MAX_NB]; - int Nb, Nr; + word32 keysched[(MAX_NR + 1) * NB]; + word32 invkeysched[(MAX_NR + 1) * NB]; + word32 iv[NB]; + int Nr; /* number of rounds */ }; static const unsigned char Sbox[256] = { @@ -652,36 +650,28 @@ static const word32 D3[256] = { */ #define ADD_ROUND_KEY_4 (block[0]^=*keysched++, block[1]^=*keysched++, \ block[2]^=*keysched++, block[3]^=*keysched++) -#define ADD_ROUND_KEY_6 (block[0]^=*keysched++, block[1]^=*keysched++, \ - block[2]^=*keysched++, block[3]^=*keysched++, \ - block[4]^=*keysched++, block[5]^=*keysched++) -#define ADD_ROUND_KEY_8 (block[0]^=*keysched++, block[1]^=*keysched++, \ - block[2]^=*keysched++, block[3]^=*keysched++, \ - block[4]^=*keysched++, block[5]^=*keysched++, \ - block[6]^=*keysched++, block[7]^=*keysched++) #define MOVEWORD(i) ( block[i] = newstate[i] ) /* - * Macros for the encryption routine. There are three encryption - * cores, for Nb=4,6,8. + * Macros for the encryption routine. */ #define MAKEWORD(i) ( newstate[i] = (E0[(block[i] >> 24) & 0xFF] ^ \ - E1[(block[(i+C1)%Nb] >> 16) & 0xFF] ^ \ - E2[(block[(i+C2)%Nb] >> 8) & 0xFF] ^ \ - E3[block[(i+C3)%Nb] & 0xFF]) ) + E1[(block[(i+C1)%NB] >> 16) & 0xFF] ^ \ + E2[(block[(i+C2)%NB] >> 8) & 0xFF] ^ \ + E3[block[(i+C3)%NB] & 0xFF]) ) #define LASTWORD(i) ( newstate[i] = (Sbox[(block[i] >> 24) & 0xFF] << 24) | \ - (Sbox[(block[(i+C1)%Nb] >> 16) & 0xFF] << 16) | \ - (Sbox[(block[(i+C2)%Nb] >> 8) & 0xFF] << 8) | \ - (Sbox[(block[(i+C3)%Nb] ) & 0xFF] ) ) + (Sbox[(block[(i+C1)%NB] >> 16) & 0xFF] << 16) | \ + (Sbox[(block[(i+C2)%NB] >> 8) & 0xFF] << 8) | \ + (Sbox[(block[(i+C3)%NB] ) & 0xFF] ) ) /* - * Core encrypt routines, expecting word32 inputs read big-endian + * Core encrypt routine, expecting word32 inputs read big-endian * from the byte-oriented input stream. */ -static void aes_encrypt_nb_4(AESContext * ctx, word32 * block) +static void aes_encrypt(AESContext * ctx, word32 * block) { int i; - static const int C1 = 1, C2 = 2, C3 = 3, Nb = 4; + static const int C1 = 1, C2 = 2, C3 = 3; word32 *keysched = ctx->keysched; word32 newstate[4]; for (i = 0; i < ctx->Nr - 1; i++) { @@ -706,111 +696,30 @@ static void aes_encrypt_nb_4(AESContext * ctx, word32 * block) MOVEWORD(3); ADD_ROUND_KEY_4; } -static void aes_encrypt_nb_6(AESContext * ctx, word32 * block) -{ - int i; - static const int C1 = 1, C2 = 2, C3 = 3, Nb = 6; - word32 *keysched = ctx->keysched; - word32 newstate[6]; - for (i = 0; i < ctx->Nr - 1; i++) { - ADD_ROUND_KEY_6; - MAKEWORD(0); - MAKEWORD(1); - MAKEWORD(2); - MAKEWORD(3); - MAKEWORD(4); - MAKEWORD(5); - MOVEWORD(0); - MOVEWORD(1); - MOVEWORD(2); - MOVEWORD(3); - MOVEWORD(4); - MOVEWORD(5); - } - ADD_ROUND_KEY_6; - LASTWORD(0); - LASTWORD(1); - LASTWORD(2); - LASTWORD(3); - LASTWORD(4); - LASTWORD(5); - MOVEWORD(0); - MOVEWORD(1); - MOVEWORD(2); - MOVEWORD(3); - MOVEWORD(4); - MOVEWORD(5); - ADD_ROUND_KEY_6; -} -static void aes_encrypt_nb_8(AESContext * ctx, word32 * block) -{ - int i; - static const int C1 = 1, C2 = 3, C3 = 4, Nb = 8; - word32 *keysched = ctx->keysched; - word32 newstate[8]; - for (i = 0; i < ctx->Nr - 1; i++) { - ADD_ROUND_KEY_8; - MAKEWORD(0); - MAKEWORD(1); - MAKEWORD(2); - MAKEWORD(3); - MAKEWORD(4); - MAKEWORD(5); - MAKEWORD(6); - MAKEWORD(7); - MOVEWORD(0); - MOVEWORD(1); - MOVEWORD(2); - MOVEWORD(3); - MOVEWORD(4); - MOVEWORD(5); - MOVEWORD(6); - MOVEWORD(7); - } - ADD_ROUND_KEY_8; - LASTWORD(0); - LASTWORD(1); - LASTWORD(2); - LASTWORD(3); - LASTWORD(4); - LASTWORD(5); - LASTWORD(6); - LASTWORD(7); - MOVEWORD(0); - MOVEWORD(1); - MOVEWORD(2); - MOVEWORD(3); - MOVEWORD(4); - MOVEWORD(5); - MOVEWORD(6); - MOVEWORD(7); - ADD_ROUND_KEY_8; -} #undef MAKEWORD #undef LASTWORD /* - * Macros for the decryption routine. There are three decryption - * cores, for Nb=4,6,8. + * Macros for the decryption routine. */ #define MAKEWORD(i) ( newstate[i] = (D0[(block[i] >> 24) & 0xFF] ^ \ - D1[(block[(i+C1)%Nb] >> 16) & 0xFF] ^ \ - D2[(block[(i+C2)%Nb] >> 8) & 0xFF] ^ \ - D3[block[(i+C3)%Nb] & 0xFF]) ) + D1[(block[(i+C1)%NB] >> 16) & 0xFF] ^ \ + D2[(block[(i+C2)%NB] >> 8) & 0xFF] ^ \ + D3[block[(i+C3)%NB] & 0xFF]) ) #define LASTWORD(i) (newstate[i] = (Sboxinv[(block[i] >> 24) & 0xFF] << 24) | \ - (Sboxinv[(block[(i+C1)%Nb] >> 16) & 0xFF] << 16) | \ - (Sboxinv[(block[(i+C2)%Nb] >> 8) & 0xFF] << 8) | \ - (Sboxinv[(block[(i+C3)%Nb] ) & 0xFF] ) ) + (Sboxinv[(block[(i+C1)%NB] >> 16) & 0xFF] << 16) | \ + (Sboxinv[(block[(i+C2)%NB] >> 8) & 0xFF] << 8) | \ + (Sboxinv[(block[(i+C3)%NB] ) & 0xFF] ) ) /* - * Core decrypt routines, expecting word32 inputs read big-endian + * Core decrypt routine, expecting word32 inputs read big-endian * from the byte-oriented input stream. */ -static void aes_decrypt_nb_4(AESContext * ctx, word32 * block) +static void aes_decrypt(AESContext * ctx, word32 * block) { int i; - static const int C1 = 4 - 1, C2 = 4 - 2, C3 = 4 - 3, Nb = 4; + static const int C1 = 4 - 1, C2 = 4 - 2, C3 = 4 - 3; word32 *keysched = ctx->invkeysched; word32 newstate[4]; for (i = 0; i < ctx->Nr - 1; i++) { @@ -835,126 +744,30 @@ static void aes_decrypt_nb_4(AESContext * ctx, word32 * block) MOVEWORD(3); ADD_ROUND_KEY_4; } -static void aes_decrypt_nb_6(AESContext * ctx, word32 * block) -{ - int i; - static const int C1 = 6 - 1, C2 = 6 - 2, C3 = 6 - 3, Nb = 6; - word32 *keysched = ctx->invkeysched; - word32 newstate[6]; - for (i = 0; i < ctx->Nr - 1; i++) { - ADD_ROUND_KEY_6; - MAKEWORD(0); - MAKEWORD(1); - MAKEWORD(2); - MAKEWORD(3); - MAKEWORD(4); - MAKEWORD(5); - MOVEWORD(0); - MOVEWORD(1); - MOVEWORD(2); - MOVEWORD(3); - MOVEWORD(4); - MOVEWORD(5); - } - ADD_ROUND_KEY_6; - LASTWORD(0); - LASTWORD(1); - LASTWORD(2); - LASTWORD(3); - LASTWORD(4); - LASTWORD(5); - MOVEWORD(0); - MOVEWORD(1); - MOVEWORD(2); - MOVEWORD(3); - MOVEWORD(4); - MOVEWORD(5); - ADD_ROUND_KEY_6; -} -static void aes_decrypt_nb_8(AESContext * ctx, word32 * block) -{ - int i; - static const int C1 = 8 - 1, C2 = 8 - 3, C3 = 8 - 4, Nb = 8; - word32 *keysched = ctx->invkeysched; - word32 newstate[8]; - for (i = 0; i < ctx->Nr - 1; i++) { - ADD_ROUND_KEY_8; - MAKEWORD(0); - MAKEWORD(1); - MAKEWORD(2); - MAKEWORD(3); - MAKEWORD(4); - MAKEWORD(5); - MAKEWORD(6); - MAKEWORD(7); - MOVEWORD(0); - MOVEWORD(1); - MOVEWORD(2); - MOVEWORD(3); - MOVEWORD(4); - MOVEWORD(5); - MOVEWORD(6); - MOVEWORD(7); - } - ADD_ROUND_KEY_8; - LASTWORD(0); - LASTWORD(1); - LASTWORD(2); - LASTWORD(3); - LASTWORD(4); - LASTWORD(5); - LASTWORD(6); - LASTWORD(7); - MOVEWORD(0); - MOVEWORD(1); - MOVEWORD(2); - MOVEWORD(3); - MOVEWORD(4); - MOVEWORD(5); - MOVEWORD(6); - MOVEWORD(7); - ADD_ROUND_KEY_8; -} #undef MAKEWORD #undef LASTWORD /* - * Set up an AESContext. `keylen' and `blocklen' are measured in - * bytes; each can be either 16 (128-bit), 24 (192-bit), or 32 + * Set up an AESContext. `keylen' is measured in + * bytes; it can be either 16 (128-bit), 24 (192-bit), or 32 * (256-bit). */ -static void aes_setup(AESContext * ctx, int blocklen, - unsigned char *key, int keylen) +static void aes_setup(AESContext * ctx, unsigned char *key, int keylen) { int i, j, Nk, rconst; - assert(blocklen == 16 || blocklen == 24 || blocklen == 32); - assert(keylen == 16 || keylen == 24 || keylen == 32); - - /* - * Basic parameters. Words per block, words in key, rounds. - */ - Nk = keylen / 4; - ctx->Nb = blocklen / 4; - ctx->Nr = 6 + (ctx->Nb > Nk ? ctx->Nb : Nk); + ctx->Nr = 6 + (keylen / 4); /* Number of rounds */ - /* - * Assign core-function pointers. - */ - if (ctx->Nb == 8) - ctx->encrypt = aes_encrypt_nb_8, ctx->decrypt = aes_decrypt_nb_8; - else if (ctx->Nb == 6) - ctx->encrypt = aes_encrypt_nb_6, ctx->decrypt = aes_decrypt_nb_6; - else if (ctx->Nb == 4) - ctx->encrypt = aes_encrypt_nb_4, ctx->decrypt = aes_decrypt_nb_4; + assert(keylen == 16 || keylen == 24 || keylen == 32); /* * Now do the key setup itself. */ + Nk = keylen / 4; rconst = 1; - for (i = 0; i < (ctx->Nr + 1) * ctx->Nb; i++) { + for (i = 0; i < (ctx->Nr + 1) * NB; i++) { if (i < Nk) ctx->keysched[i] = GET_32BIT_MSB_FIRST(key + 4 * i); else { @@ -989,9 +802,9 @@ static void aes_setup(AESContext * ctx, int blocklen, * Now prepare the modified keys for the inverse cipher. */ for (i = 0; i <= ctx->Nr; i++) { - for (j = 0; j < ctx->Nb; j++) { + for (j = 0; j < NB; j++) { word32 temp; - temp = ctx->keysched[(ctx->Nr - i) * ctx->Nb + j]; + temp = ctx->keysched[(ctx->Nr - i) * NB + j]; if (i != 0 && i != ctx->Nr) { /* * Perform the InvMixColumn operation on i. The D @@ -1009,21 +822,11 @@ static void aes_setup(AESContext * ctx, int blocklen, temp ^= D2[Sbox[c]]; temp ^= D3[Sbox[d]]; } - ctx->invkeysched[i * ctx->Nb + j] = temp; + ctx->invkeysched[i * NB + j] = temp; } } } -static void aes_encrypt(AESContext * ctx, word32 * block) -{ - ctx->encrypt(ctx, block); -} - -static void aes_decrypt(AESContext * ctx, word32 * block) -{ - ctx->decrypt(ctx, block); -} - static void aes_encrypt_cbc(unsigned char *blk, int len, AESContext * ctx) { word32 iv[4]; @@ -1109,19 +912,19 @@ void aes_free_context(void *handle) void aes128_key(void *handle, unsigned char *key) { AESContext *ctx = (AESContext *)handle; - aes_setup(ctx, 16, key, 16); + aes_setup(ctx, key, 16); } void aes192_key(void *handle, unsigned char *key) { AESContext *ctx = (AESContext *)handle; - aes_setup(ctx, 16, key, 24); + aes_setup(ctx, key, 24); } void aes256_key(void *handle, unsigned char *key) { AESContext *ctx = (AESContext *)handle; - aes_setup(ctx, 16, key, 32); + aes_setup(ctx, key, 32); } void aes_iv(void *handle, unsigned char *iv) @@ -1153,7 +956,7 @@ static void aes_ssh2_sdctr(void *handle, unsigned char *blk, int len) void aes256_encrypt_pubkey(unsigned char *key, unsigned char *blk, int len) { AESContext ctx; - aes_setup(&ctx, 16, key, 32); + aes_setup(&ctx, key, 32); memset(ctx.iv, 0, sizeof(ctx.iv)); aes_encrypt_cbc(blk, len, &ctx); smemclr(&ctx, sizeof(ctx)); @@ -1162,7 +965,7 @@ void aes256_encrypt_pubkey(unsigned char *key, unsigned char *blk, int len) void aes256_decrypt_pubkey(unsigned char *key, unsigned char *blk, int len) { AESContext ctx; - aes_setup(&ctx, 16, key, 32); + aes_setup(&ctx, key, 32); memset(ctx.iv, 0, sizeof(ctx.iv)); aes_decrypt_cbc(blk, len, &ctx); smemclr(&ctx, sizeof(ctx)); From 0816e2b1a019e97b37eb6007c34f0c58c257635c Mon Sep 17 00:00:00 2001 From: "Pavel I. Kryukov" Date: Fri, 20 Oct 2017 19:13:39 +0100 Subject: [PATCH 091/607] AES: fold the core and outer routines together. The outer routines are the ones which handle the CBC encrypt, CBC decrypt and SDCTR cipher modes. Previously each of those had to be able to dispatch to one of the per-block-size core routines, which made it worth dividing the system up into two layers. But now there's only one set of core routines, they may as well be inlined into the outer ones. Also as part of this commit, the nasty undef/redef of MAKEWORD and LASTWORD have been removed, and the different macro definitions now have different macro _names_, to make it clearer which one is used where. --- sshaes.c | 277 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 142 insertions(+), 135 deletions(-) diff --git a/sshaes.c b/sshaes.c index 48d0ca16..44303184 100644 --- a/sshaes.c +++ b/sshaes.c @@ -645,110 +645,6 @@ static const word32 D3[256] = { 0xcb84617b, 0x32b670d5, 0x6c5c7448, 0xb85742d0, }; -/* - * Common macros in both the encryption and decryption routines. - */ -#define ADD_ROUND_KEY_4 (block[0]^=*keysched++, block[1]^=*keysched++, \ - block[2]^=*keysched++, block[3]^=*keysched++) -#define MOVEWORD(i) ( block[i] = newstate[i] ) - -/* - * Macros for the encryption routine. - */ -#define MAKEWORD(i) ( newstate[i] = (E0[(block[i] >> 24) & 0xFF] ^ \ - E1[(block[(i+C1)%NB] >> 16) & 0xFF] ^ \ - E2[(block[(i+C2)%NB] >> 8) & 0xFF] ^ \ - E3[block[(i+C3)%NB] & 0xFF]) ) -#define LASTWORD(i) ( newstate[i] = (Sbox[(block[i] >> 24) & 0xFF] << 24) | \ - (Sbox[(block[(i+C1)%NB] >> 16) & 0xFF] << 16) | \ - (Sbox[(block[(i+C2)%NB] >> 8) & 0xFF] << 8) | \ - (Sbox[(block[(i+C3)%NB] ) & 0xFF] ) ) - -/* - * Core encrypt routine, expecting word32 inputs read big-endian - * from the byte-oriented input stream. - */ -static void aes_encrypt(AESContext * ctx, word32 * block) -{ - int i; - static const int C1 = 1, C2 = 2, C3 = 3; - word32 *keysched = ctx->keysched; - word32 newstate[4]; - for (i = 0; i < ctx->Nr - 1; i++) { - ADD_ROUND_KEY_4; - MAKEWORD(0); - MAKEWORD(1); - MAKEWORD(2); - MAKEWORD(3); - MOVEWORD(0); - MOVEWORD(1); - MOVEWORD(2); - MOVEWORD(3); - } - ADD_ROUND_KEY_4; - LASTWORD(0); - LASTWORD(1); - LASTWORD(2); - LASTWORD(3); - MOVEWORD(0); - MOVEWORD(1); - MOVEWORD(2); - MOVEWORD(3); - ADD_ROUND_KEY_4; -} - -#undef MAKEWORD -#undef LASTWORD - -/* - * Macros for the decryption routine. - */ -#define MAKEWORD(i) ( newstate[i] = (D0[(block[i] >> 24) & 0xFF] ^ \ - D1[(block[(i+C1)%NB] >> 16) & 0xFF] ^ \ - D2[(block[(i+C2)%NB] >> 8) & 0xFF] ^ \ - D3[block[(i+C3)%NB] & 0xFF]) ) -#define LASTWORD(i) (newstate[i] = (Sboxinv[(block[i] >> 24) & 0xFF] << 24) | \ - (Sboxinv[(block[(i+C1)%NB] >> 16) & 0xFF] << 16) | \ - (Sboxinv[(block[(i+C2)%NB] >> 8) & 0xFF] << 8) | \ - (Sboxinv[(block[(i+C3)%NB] ) & 0xFF] ) ) - -/* - * Core decrypt routine, expecting word32 inputs read big-endian - * from the byte-oriented input stream. - */ -static void aes_decrypt(AESContext * ctx, word32 * block) -{ - int i; - static const int C1 = 4 - 1, C2 = 4 - 2, C3 = 4 - 3; - word32 *keysched = ctx->invkeysched; - word32 newstate[4]; - for (i = 0; i < ctx->Nr - 1; i++) { - ADD_ROUND_KEY_4; - MAKEWORD(0); - MAKEWORD(1); - MAKEWORD(2); - MAKEWORD(3); - MOVEWORD(0); - MOVEWORD(1); - MOVEWORD(2); - MOVEWORD(3); - } - ADD_ROUND_KEY_4; - LASTWORD(0); - LASTWORD(1); - LASTWORD(2); - LASTWORD(3); - MOVEWORD(0); - MOVEWORD(1); - MOVEWORD(2); - MOVEWORD(3); - ADD_ROUND_KEY_4; -} - -#undef MAKEWORD -#undef LASTWORD - - /* * Set up an AESContext. `keylen' is measured in * bytes; it can be either 16 (128-bit), 24 (192-bit), or 32 @@ -762,9 +658,6 @@ static void aes_setup(AESContext * ctx, unsigned char *key, int keylen) assert(keylen == 16 || keylen == 24 || keylen == 32); - /* - * Now do the key setup itself. - */ Nk = keylen / 4; rconst = 1; for (i = 0; i < (ctx->Nr + 1) * NB; i++) { @@ -827,73 +720,187 @@ static void aes_setup(AESContext * ctx, unsigned char *key, int keylen) } } +/* + * Software encrypt/decrypt macros + */ +#define ADD_ROUND_KEY (block[0]^=*keysched++, \ + block[1]^=*keysched++, \ + block[2]^=*keysched++, \ + block[3]^=*keysched++) +#define MOVEWORD(i) ( block[i] = newstate[i] ) + +#define ENCWORD(i) ( newstate[i] = (E0[(block[i ] >> 24) & 0xFF] ^ \ + E1[(block[(i+1)%NB] >> 16) & 0xFF] ^ \ + E2[(block[(i+2)%NB] >> 8) & 0xFF] ^ \ + E3[ block[(i+3)%NB] & 0xFF]) ) +#define ENCROUND { ENCWORD(0); ENCWORD(1); ENCWORD(2); ENCWORD(3); \ + MOVEWORD(0); MOVEWORD(1); MOVEWORD(2); MOVEWORD(3); ADD_ROUND_KEY; } + +#define ENCLASTWORD(i) ( newstate[i] = \ + (Sbox[(block[i] >> 24) & 0xFF] << 24) | \ + (Sbox[(block[(i+1)%NB] >> 16) & 0xFF] << 16) | \ + (Sbox[(block[(i+2)%NB] >> 8) & 0xFF] << 8) | \ + (Sbox[(block[(i+3)%NB] ) & 0xFF] ) ) +#define ENCLASTROUND { ENCLASTWORD(0); ENCLASTWORD(1); ENCLASTWORD(2); ENCLASTWORD(3); \ + MOVEWORD(0); MOVEWORD(1); MOVEWORD(2); MOVEWORD(3); ADD_ROUND_KEY; } + +#define DECWORD(i) ( newstate[i] = (D0[(block[i] >> 24) & 0xFF] ^ \ + D1[(block[(i+3)%NB] >> 16) & 0xFF] ^ \ + D2[(block[(i+2)%NB] >> 8) & 0xFF] ^ \ + D3[ block[(i+1)%NB] & 0xFF]) ) +#define DECROUND { DECWORD(0); DECWORD(1); DECWORD(2); DECWORD(3); \ + MOVEWORD(0); MOVEWORD(1); MOVEWORD(2); MOVEWORD(3); ADD_ROUND_KEY; } + +#define DECLASTWORD(i) (newstate[i] = \ + (Sboxinv[(block[i] >> 24) & 0xFF] << 24) | \ + (Sboxinv[(block[(i+3)%NB] >> 16) & 0xFF] << 16) | \ + (Sboxinv[(block[(i+2)%NB] >> 8) & 0xFF] << 8) | \ + (Sboxinv[(block[(i+1)%NB] ) & 0xFF] ) ) +#define DECLASTROUND { DECLASTWORD(0); DECLASTWORD(1); DECLASTWORD(2); DECLASTWORD(3); \ + MOVEWORD(0); MOVEWORD(1); MOVEWORD(2); MOVEWORD(3); ADD_ROUND_KEY; } + +/* + * Software AES encrypt/decrypt core + */ static void aes_encrypt_cbc(unsigned char *blk, int len, AESContext * ctx) { - word32 iv[4]; + word32 block[4]; + unsigned char* finish = blk + len; int i; assert((len & 15) == 0); - memcpy(iv, ctx->iv, sizeof(iv)); + memcpy(block, ctx->iv, sizeof(block)); - while (len > 0) { + while (blk < finish) { + word32 *keysched = ctx->keysched; + word32 newstate[4]; for (i = 0; i < 4; i++) - iv[i] ^= GET_32BIT_MSB_FIRST(blk + 4 * i); - aes_encrypt(ctx, iv); + block[i] ^= GET_32BIT_MSB_FIRST(blk + 4 * i); + ADD_ROUND_KEY; + switch (ctx->Nr) { + case 14: + ENCROUND; + ENCROUND; + case 12: + ENCROUND; + ENCROUND; + case 10: + ENCROUND; + ENCROUND; + ENCROUND; + ENCROUND; + ENCROUND; + ENCROUND; + ENCROUND; + ENCROUND; + ENCROUND; + ENCLASTROUND; + break; + default: + assert(0); + } for (i = 0; i < 4; i++) - PUT_32BIT_MSB_FIRST(blk + 4 * i, iv[i]); + PUT_32BIT_MSB_FIRST(blk + 4 * i, block[i]); blk += 16; - len -= 16; } - memcpy(ctx->iv, iv, sizeof(iv)); + memcpy(ctx->iv, block, sizeof(block)); } -static void aes_decrypt_cbc(unsigned char *blk, int len, AESContext * ctx) +static void aes_sdctr(unsigned char *blk, int len, AESContext *ctx) { - word32 iv[4], x[4], ct[4]; + word32 iv[4]; + unsigned char* finish = blk + len; int i; assert((len & 15) == 0); memcpy(iv, ctx->iv, sizeof(iv)); - while (len > 0) { - for (i = 0; i < 4; i++) - x[i] = ct[i] = GET_32BIT_MSB_FIRST(blk + 4 * i); - aes_decrypt(ctx, x); + while (blk < finish) { + word32 *keysched = ctx->keysched; + word32 newstate[4], block[4], tmp; + memcpy(block, iv, sizeof(block)); + ADD_ROUND_KEY; + switch (ctx->Nr) { + case 14: + ENCROUND; + ENCROUND; + case 12: + ENCROUND; + ENCROUND; + case 10: + ENCROUND; + ENCROUND; + ENCROUND; + ENCROUND; + ENCROUND; + ENCROUND; + ENCROUND; + ENCROUND; + ENCROUND; + ENCLASTROUND; + break; + default: + assert(0); + } for (i = 0; i < 4; i++) { - PUT_32BIT_MSB_FIRST(blk + 4 * i, iv[i] ^ x[i]); - iv[i] = ct[i]; + tmp = GET_32BIT_MSB_FIRST(blk + 4 * i); + PUT_32BIT_MSB_FIRST(blk + 4 * i, tmp ^ block[i]); } + for (i = 3; i >= 0; i--) + if ((iv[i] = (iv[i] + 1) & 0xffffffff) != 0) + break; blk += 16; - len -= 16; } memcpy(ctx->iv, iv, sizeof(iv)); } -static void aes_sdctr(unsigned char *blk, int len, AESContext *ctx) +static void aes_decrypt_cbc(unsigned char *blk, int len, AESContext * ctx) { - word32 iv[4], b[4], tmp; + word32 iv[4]; + unsigned char* finish = blk + len; int i; assert((len & 15) == 0); memcpy(iv, ctx->iv, sizeof(iv)); - while (len > 0) { - memcpy(b, iv, sizeof(b)); - aes_encrypt(ctx, b); + while (blk < finish) { + word32 *keysched = ctx->invkeysched; + word32 newstate[4], ct[4], block[4]; + for (i = 0; i < 4; i++) + block[i] = ct[i] = GET_32BIT_MSB_FIRST(blk + 4 * i); + ADD_ROUND_KEY; + switch (ctx->Nr) { + case 14: + DECROUND; + DECROUND; + case 12: + DECROUND; + DECROUND; + case 10: + DECROUND; + DECROUND; + DECROUND; + DECROUND; + DECROUND; + DECROUND; + DECROUND; + DECROUND; + DECROUND; + DECLASTROUND; + break; + default: + assert(0); + } for (i = 0; i < 4; i++) { - tmp = GET_32BIT_MSB_FIRST(blk + 4 * i); - PUT_32BIT_MSB_FIRST(blk + 4 * i, tmp ^ b[i]); + PUT_32BIT_MSB_FIRST(blk + 4 * i, iv[i] ^ block[i]); + iv[i] = ct[i]; } - for (i = 3; i >= 0; i--) - if ((iv[i] = (iv[i] + 1) & 0xffffffff) != 0) - break; blk += 16; - len -= 16; } memcpy(ctx->iv, iv, sizeof(iv)); From e8be7ea98a4c21a839dcd4b75dc62688778bdde8 Mon Sep 17 00:00:00 2001 From: "Pavel I. Kryukov" Date: Fri, 20 Oct 2017 19:13:47 +0100 Subject: [PATCH 092/607] AES: 16-byte align the key schedule arrays. This is going to be important in the next commit, when we start accessing them using x86 SSE instructions. --- sshaes.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/sshaes.c b/sshaes.c index 44303184..488e32a3 100644 --- a/sshaes.c +++ b/sshaes.c @@ -40,8 +40,9 @@ typedef struct AESContext AESContext; struct AESContext { - word32 keysched[(MAX_NR + 1) * NB]; - word32 invkeysched[(MAX_NR + 1) * NB]; + word32 keysched_buf[(MAX_NR + 1) * NB + 3]; + word32 invkeysched_buf[(MAX_NR + 1) * NB + 3]; + word32 *keysched, *invkeysched; word32 iv[NB]; int Nr; /* number of rounds */ }; @@ -653,9 +654,20 @@ static const word32 D3[256] = { static void aes_setup(AESContext * ctx, unsigned char *key, int keylen) { int i, j, Nk, rconst; + size_t bufaddr; ctx->Nr = 6 + (keylen / 4); /* Number of rounds */ + /* Ensure the key schedule arrays are 16-byte aligned */ + bufaddr = (size_t)ctx->keysched_buf; + ctx->keysched = ctx->keysched_buf + + (0xF & -bufaddr) / sizeof(word32); + assert((size_t)ctx->keysched % 16 == 0); + bufaddr = (size_t)ctx->invkeysched_buf; + ctx->invkeysched = ctx->invkeysched_buf + + (0xF & -bufaddr) / sizeof(word32); + assert((size_t)ctx->invkeysched % 16 == 0); + assert(keylen == 16 || keylen == 24 || keylen == 32); Nk = keylen / 4; From 2d31305af9d3bf4096bb0c30e8a8336caaa70673 Mon Sep 17 00:00:00 2001 From: "Pavel I. Kryukov" Date: Fri, 20 Oct 2017 19:13:54 +0100 Subject: [PATCH 093/607] Alternative AES routines, using x86 hardware support. The new AES routines are compiled into the code on any platform where the compiler can be made to generate the necessary AES-NI and SSE instructions. But not every CPU will support those instructions, so the pure-software routines haven't gone away: both sets of functions sit side by side in the code, and at key setup time we check the CPUID bitmap to decide which set to select. (This reintroduces function pointers into AESContext, replacing the ones that we managed to remove a few commits ago.) --- sshaes.c | 667 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 661 insertions(+), 6 deletions(-) diff --git a/sshaes.c b/sshaes.c index 488e32a3..7ebeb5be 100644 --- a/sshaes.c +++ b/sshaes.c @@ -37,6 +37,17 @@ #define mulby2(x) ( ((x&0x7F) << 1) ^ (x & 0x80 ? 0x1B : 0) ) +/* + * Select appropriate inline keyword for the compiler + */ +#if defined __GNUC__ || defined __clang__ +# define INLINE __inline__ +#elif defined (_MSC_VER) +# define INLINE __forceinline +#else +# define INLINE +#endif + typedef struct AESContext AESContext; struct AESContext { @@ -45,8 +56,37 @@ struct AESContext { word32 *keysched, *invkeysched; word32 iv[NB]; int Nr; /* number of rounds */ + void (*encrypt_cbc)(unsigned char*, int, AESContext*); + void (*decrypt_cbc)(unsigned char*, int, AESContext*); + void (*sdctr)(unsigned char*, int, AESContext*); + int isNI; }; +static void aes_encrypt_cbc_sw(unsigned char*, int, AESContext*); +static void aes_decrypt_cbc_sw(unsigned char*, int, AESContext*); +static void aes_sdctr_sw(unsigned char*, int, AESContext*); + +INLINE static int supports_aes_ni(); +static void aes_setup_ni(AESContext * ctx, unsigned char *key, int keylen); + +INLINE static void aes_encrypt_cbc(unsigned char *blk, int len, AESContext * ctx) +{ + ctx->encrypt_cbc(blk, len, ctx); +} + +INLINE static void aes_decrypt_cbc(unsigned char *blk, int len, AESContext * ctx) +{ + ctx->decrypt_cbc(blk, len, ctx); +} + +INLINE static void aes_sdctr(unsigned char *blk, int len, AESContext * ctx) +{ + ctx->sdctr(blk, len, ctx); +} + +/* + * SW AES lookup tables + */ static const unsigned char Sbox[256] = { 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, @@ -668,8 +708,19 @@ static void aes_setup(AESContext * ctx, unsigned char *key, int keylen) (0xF & -bufaddr) / sizeof(word32); assert((size_t)ctx->invkeysched % 16 == 0); + ctx->isNI = supports_aes_ni(); + + if (ctx->isNI) { + aes_setup_ni(ctx, key, keylen); + return; + } + assert(keylen == 16 || keylen == 24 || keylen == 32); + ctx->encrypt_cbc = aes_encrypt_cbc_sw; + ctx->decrypt_cbc = aes_decrypt_cbc_sw; + ctx->sdctr = aes_sdctr_sw; + Nk = keylen / 4; rconst = 1; for (i = 0; i < (ctx->Nr + 1) * NB; i++) { @@ -774,7 +825,7 @@ static void aes_setup(AESContext * ctx, unsigned char *key, int keylen) /* * Software AES encrypt/decrypt core */ -static void aes_encrypt_cbc(unsigned char *blk, int len, AESContext * ctx) +static void aes_encrypt_cbc_sw(unsigned char *blk, int len, AESContext * ctx) { word32 block[4]; unsigned char* finish = blk + len; @@ -820,7 +871,7 @@ static void aes_encrypt_cbc(unsigned char *blk, int len, AESContext * ctx) memcpy(ctx->iv, block, sizeof(block)); } -static void aes_sdctr(unsigned char *blk, int len, AESContext *ctx) +static void aes_sdctr_sw(unsigned char *blk, int len, AESContext *ctx) { word32 iv[4]; unsigned char* finish = blk + len; @@ -870,7 +921,7 @@ static void aes_sdctr(unsigned char *blk, int len, AESContext *ctx) memcpy(ctx->iv, iv, sizeof(iv)); } -static void aes_decrypt_cbc(unsigned char *blk, int len, AESContext * ctx) +static void aes_decrypt_cbc_sw(unsigned char *blk, int len, AESContext * ctx) { word32 iv[4]; unsigned char* finish = blk + len; @@ -949,9 +1000,14 @@ void aes256_key(void *handle, unsigned char *key) void aes_iv(void *handle, unsigned char *iv) { AESContext *ctx = (AESContext *)handle; - int i; - for (i = 0; i < 4; i++) - ctx->iv[i] = GET_32BIT_MSB_FIRST(iv + 4 * i); + if (ctx->isNI) { + memcpy(ctx->iv, iv, sizeof(ctx->iv)); + } + else { + int i; + for (i = 0; i < 4; i++) + ctx->iv[i] = GET_32BIT_MSB_FIRST(iv + 4 * i); + } } void aes_ssh2_encrypt_blk(void *handle, unsigned char *blk, int len) @@ -1060,3 +1116,602 @@ const struct ssh2_ciphers ssh2_aes = { sizeof(aes_list) / sizeof(*aes_list), aes_list }; + +/* + * Implementation of AES for PuTTY using AES-NI + * instuction set expansion was made by: + * @author Pavel Kryukov + * @author Maxim Kuznetsov + * @author Svyatoslav Kuzmich + * + * For Putty AES NI project + * http://pavelkryukov.github.io/putty-aes-ni/ + */ + +/* + * Check of compiler version + */ +#ifdef _FORCE_AES_NI +# define COMPILER_SUPPORTS_AES_NI +#elif defined(__clang__) +# if (__clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 8)) && (defined(__x86_64__) || defined(__i386)) +# define COMPILER_SUPPORTS_AES_NI +# endif +#elif defined(__GNUC__) +# if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)) && (defined(__x86_64__) || defined(__i386)) +# define COMPILER_SUPPORTS_AES_NI +# endif +#elif defined (_MSC_VER) +# if (defined(_M_X64) || defined(_M_IX86)) && _MSC_FULL_VER >= 150030729 +# define COMPILER_SUPPORTS_AES_NI +# endif +#endif + +#ifdef _FORCE_SOFTWARE_AES +# undef COMPILER_SUPPORTS_AES_NI +#endif + +#ifdef COMPILER_SUPPORTS_AES_NI + +/* + * Set target architecture for Clang and GCC + */ +#if !defined(__clang__) && defined(__GNUC__) +# pragma GCC target("aes") +# pragma GCC target("sse4.1") +#endif + +#if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))) +# define FUNC_ISA __attribute__ ((target("sse4.1,aes"))) +#else +# define FUNC_ISA +#endif + +#include +#include + +/* + * Determinators of CPU type + */ +#if defined(__clang__) || defined(__GNUC__) + +#include +INLINE static int supports_aes_ni() +{ + unsigned int CPUInfo[4]; + __cpuid(1, CPUInfo[0], CPUInfo[1], CPUInfo[2], CPUInfo[3]); + return (CPUInfo[2] & (1 << 25)) && (CPUInfo[2] & (1 << 19)); /* Check AES and SSE4.1 */ +} + +#else /* defined(__clang__) || defined(__GNUC__) */ + +INLINE static int supports_aes_ni() +{ + unsigned int CPUInfo[4]; + __cpuid(CPUInfo, 1); + return (CPUInfo[2] & (1 << 25)) && (CPUInfo[2] & (1 << 19)); /* Check AES and SSE4.1 */ +} + +#endif /* defined(__clang__) || defined(__GNUC__) */ + +/* + * Wrapper of SHUFPD instruction for MSVC + */ +#ifdef _MSC_VER +INLINE static __m128i mm_shuffle_pd_i0(__m128i a, __m128i b) +{ + union { + __m128i i; + __m128d d; + } au, bu, ru; + au.i = a; + bu.i = b; + ru.d = _mm_shuffle_pd(au.d, bu.d, 0); + return ru.i; +} + +INLINE static __m128i mm_shuffle_pd_i1(__m128i a, __m128i b) +{ + union { + __m128i i; + __m128d d; + } au, bu, ru; + au.i = a; + bu.i = b; + ru.d = _mm_shuffle_pd(au.d, bu.d, 1); + return ru.i; +} +#else +#define mm_shuffle_pd_i0(a, b) ((__m128i)_mm_shuffle_pd((__m128d)a, (__m128d)b, 0)); +#define mm_shuffle_pd_i1(a, b) ((__m128i)_mm_shuffle_pd((__m128d)a, (__m128d)b, 1)); +#endif + +/* + * AES-NI key expansion assist functions + */ +FUNC_ISA +INLINE static __m128i AES_128_ASSIST (__m128i temp1, __m128i temp2) +{ + __m128i temp3; + temp2 = _mm_shuffle_epi32 (temp2 ,0xff); + temp3 = _mm_slli_si128 (temp1, 0x4); + temp1 = _mm_xor_si128 (temp1, temp3); + temp3 = _mm_slli_si128 (temp3, 0x4); + temp1 = _mm_xor_si128 (temp1, temp3); + temp3 = _mm_slli_si128 (temp3, 0x4); + temp1 = _mm_xor_si128 (temp1, temp3); + temp1 = _mm_xor_si128 (temp1, temp2); + return temp1; +} + +FUNC_ISA +INLINE static void KEY_192_ASSIST(__m128i* temp1, __m128i * temp2, __m128i * temp3) +{ + __m128i temp4; + *temp2 = _mm_shuffle_epi32 (*temp2, 0x55); + temp4 = _mm_slli_si128 (*temp1, 0x4); + *temp1 = _mm_xor_si128 (*temp1, temp4); + temp4 = _mm_slli_si128 (temp4, 0x4); + *temp1 = _mm_xor_si128 (*temp1, temp4); + temp4 = _mm_slli_si128 (temp4, 0x4); + *temp1 = _mm_xor_si128 (*temp1, temp4); + *temp1 = _mm_xor_si128 (*temp1, *temp2); + *temp2 = _mm_shuffle_epi32(*temp1, 0xff); + temp4 = _mm_slli_si128 (*temp3, 0x4); + *temp3 = _mm_xor_si128 (*temp3, temp4); + *temp3 = _mm_xor_si128 (*temp3, *temp2); +} + +FUNC_ISA +INLINE static void KEY_256_ASSIST_1(__m128i* temp1, __m128i * temp2) +{ + __m128i temp4; + *temp2 = _mm_shuffle_epi32(*temp2, 0xff); + temp4 = _mm_slli_si128 (*temp1, 0x4); + *temp1 = _mm_xor_si128 (*temp1, temp4); + temp4 = _mm_slli_si128 (temp4, 0x4); + *temp1 = _mm_xor_si128 (*temp1, temp4); + temp4 = _mm_slli_si128 (temp4, 0x4); + *temp1 = _mm_xor_si128 (*temp1, temp4); + *temp1 = _mm_xor_si128 (*temp1, *temp2); +} + +FUNC_ISA +INLINE static void KEY_256_ASSIST_2(__m128i* temp1, __m128i * temp3) +{ + __m128i temp2,temp4; + temp4 = _mm_aeskeygenassist_si128 (*temp1, 0x0); + temp2 = _mm_shuffle_epi32(temp4, 0xaa); + temp4 = _mm_slli_si128 (*temp3, 0x4); + *temp3 = _mm_xor_si128 (*temp3, temp4); + temp4 = _mm_slli_si128 (temp4, 0x4); + *temp3 = _mm_xor_si128 (*temp3, temp4); + temp4 = _mm_slli_si128 (temp4, 0x4); + *temp3 = _mm_xor_si128 (*temp3, temp4); + *temp3 = _mm_xor_si128 (*temp3, temp2); +} + +/* + * AES-NI key expansion core + */ +FUNC_ISA +static void AES_128_Key_Expansion (unsigned char *userkey, __m128i *key) +{ + __m128i temp1, temp2; + temp1 = _mm_loadu_si128((__m128i*)userkey); + key[0] = temp1; + temp2 = _mm_aeskeygenassist_si128 (temp1 ,0x1); + temp1 = AES_128_ASSIST(temp1, temp2); + key[1] = temp1; + temp2 = _mm_aeskeygenassist_si128 (temp1,0x2); + temp1 = AES_128_ASSIST(temp1, temp2); + key[2] = temp1; + temp2 = _mm_aeskeygenassist_si128 (temp1,0x4); + temp1 = AES_128_ASSIST(temp1, temp2); + key[3] = temp1; + temp2 = _mm_aeskeygenassist_si128 (temp1,0x8); + temp1 = AES_128_ASSIST(temp1, temp2); + key[4] = temp1; + temp2 = _mm_aeskeygenassist_si128 (temp1,0x10); + temp1 = AES_128_ASSIST(temp1, temp2); + key[5] = temp1; + temp2 = _mm_aeskeygenassist_si128 (temp1,0x20); + temp1 = AES_128_ASSIST(temp1, temp2); + key[6] = temp1; + temp2 = _mm_aeskeygenassist_si128 (temp1,0x40); + temp1 = AES_128_ASSIST(temp1, temp2); + key[7] = temp1; + temp2 = _mm_aeskeygenassist_si128 (temp1,0x80); + temp1 = AES_128_ASSIST(temp1, temp2); + key[8] = temp1; + temp2 = _mm_aeskeygenassist_si128 (temp1,0x1b); + temp1 = AES_128_ASSIST(temp1, temp2); + key[9] = temp1; + temp2 = _mm_aeskeygenassist_si128 (temp1,0x36); + temp1 = AES_128_ASSIST(temp1, temp2); + key[10] = temp1; +} + +FUNC_ISA +static void AES_192_Key_Expansion (unsigned char *userkey, __m128i *key) +{ + __m128i temp1, temp2, temp3; + temp1 = _mm_loadu_si128((__m128i*)userkey); + temp3 = _mm_loadu_si128((__m128i*)(userkey+16)); + key[0]=temp1; + key[1]=temp3; + temp2=_mm_aeskeygenassist_si128 (temp3,0x1); + KEY_192_ASSIST(&temp1, &temp2, &temp3); + key[1] = mm_shuffle_pd_i0(key[1], temp1); + key[2] = mm_shuffle_pd_i1(temp1, temp3); + temp2=_mm_aeskeygenassist_si128 (temp3,0x2); + KEY_192_ASSIST(&temp1, &temp2, &temp3); + key[3]=temp1; + key[4]=temp3; + temp2=_mm_aeskeygenassist_si128 (temp3,0x4); + KEY_192_ASSIST(&temp1, &temp2, &temp3); + key[4] = mm_shuffle_pd_i0(key[4], temp1); + key[5] = mm_shuffle_pd_i1(temp1, temp3); + temp2=_mm_aeskeygenassist_si128 (temp3,0x8); + KEY_192_ASSIST(&temp1, &temp2, &temp3); + key[6]=temp1; + key[7]=temp3; + temp2=_mm_aeskeygenassist_si128 (temp3,0x10); + KEY_192_ASSIST(&temp1, &temp2, &temp3); + key[7] = mm_shuffle_pd_i0(key[7], temp1); + key[8] = mm_shuffle_pd_i1(temp1, temp3); + temp2=_mm_aeskeygenassist_si128 (temp3,0x20); + KEY_192_ASSIST(&temp1, &temp2, &temp3); + key[9]=temp1; + key[10]=temp3; + temp2=_mm_aeskeygenassist_si128 (temp3,0x40); + KEY_192_ASSIST(&temp1, &temp2, &temp3); + key[10] = mm_shuffle_pd_i0(key[10], temp1); + key[11] = mm_shuffle_pd_i1(temp1, temp3); + temp2=_mm_aeskeygenassist_si128 (temp3,0x80); + KEY_192_ASSIST(&temp1, &temp2, &temp3); + key[12]=temp1; + key[13]=temp3; +} + +FUNC_ISA +static void AES_256_Key_Expansion (unsigned char *userkey, __m128i *key) +{ + __m128i temp1, temp2, temp3; + temp1 = _mm_loadu_si128((__m128i*)userkey); + temp3 = _mm_loadu_si128((__m128i*)(userkey+16)); + key[0] = temp1; + key[1] = temp3; + temp2 = _mm_aeskeygenassist_si128 (temp3,0x01); + KEY_256_ASSIST_1(&temp1, &temp2); + key[2]=temp1; + KEY_256_ASSIST_2(&temp1, &temp3); + key[3]=temp3; + temp2 = _mm_aeskeygenassist_si128 (temp3,0x02); + KEY_256_ASSIST_1(&temp1, &temp2); + key[4]=temp1; + KEY_256_ASSIST_2(&temp1, &temp3); + key[5]=temp3; + temp2 = _mm_aeskeygenassist_si128 (temp3,0x04); + KEY_256_ASSIST_1(&temp1, &temp2); + key[6]=temp1; + KEY_256_ASSIST_2(&temp1, &temp3); + key[7]=temp3; + temp2 = _mm_aeskeygenassist_si128 (temp3,0x08); + KEY_256_ASSIST_1(&temp1, &temp2); + key[8]=temp1; + KEY_256_ASSIST_2(&temp1, &temp3); + key[9]=temp3; + temp2 = _mm_aeskeygenassist_si128 (temp3,0x10); + KEY_256_ASSIST_1(&temp1, &temp2); + key[10]=temp1; + KEY_256_ASSIST_2(&temp1, &temp3); + key[11]=temp3; + temp2 = _mm_aeskeygenassist_si128 (temp3,0x20); + KEY_256_ASSIST_1(&temp1, &temp2); + key[12]=temp1; + KEY_256_ASSIST_2(&temp1, &temp3); + key[13]=temp3; + temp2 = _mm_aeskeygenassist_si128 (temp3,0x40); + KEY_256_ASSIST_1(&temp1, &temp2); + key[14]=temp1; +} + +/* + * AES-NI encrypt/decrypt core + */ +FUNC_ISA +static void aes_encrypt_cbc_ni(unsigned char *blk, int len, AESContext * ctx) +{ + __m128i enc; + __m128i* block = (__m128i*)blk; + const __m128i* finish = (__m128i*)(blk + len); + + assert((len & 15) == 0); + + /* Load IV */ + enc = _mm_loadu_si128((__m128i*)(ctx->iv)); + while (block < finish) { + /* Key schedule ptr */ + __m128i* keysched = (__m128i*)ctx->keysched; + + /* Xor data with IV */ + enc = _mm_xor_si128(_mm_loadu_si128(block), enc); + + /* Perform rounds */ + enc = _mm_xor_si128(enc, *keysched); + switch (ctx->Nr) { + case 14: + enc = _mm_aesenc_si128(enc, *(++keysched)); + enc = _mm_aesenc_si128(enc, *(++keysched)); + case 12: + enc = _mm_aesenc_si128(enc, *(++keysched)); + enc = _mm_aesenc_si128(enc, *(++keysched)); + case 10: + enc = _mm_aesenc_si128(enc, *(++keysched)); + enc = _mm_aesenc_si128(enc, *(++keysched)); + enc = _mm_aesenc_si128(enc, *(++keysched)); + enc = _mm_aesenc_si128(enc, *(++keysched)); + enc = _mm_aesenc_si128(enc, *(++keysched)); + enc = _mm_aesenc_si128(enc, *(++keysched)); + enc = _mm_aesenc_si128(enc, *(++keysched)); + enc = _mm_aesenc_si128(enc, *(++keysched)); + enc = _mm_aesenc_si128(enc, *(++keysched)); + enc = _mm_aesenclast_si128(enc, *(++keysched)); + break; + default: + assert(0); + } + + /* Store and go to next block */ + _mm_storeu_si128(block, enc); + ++block; + } + + /* Update IV */ + _mm_storeu_si128((__m128i*)(ctx->iv), enc); +} + +FUNC_ISA +static void aes_decrypt_cbc_ni(unsigned char *blk, int len, AESContext * ctx) +{ + __m128i dec = _mm_setzero_si128(); + __m128i last, iv; + __m128i* block = (__m128i*)blk; + const __m128i* finish = (__m128i*)(blk + len); + + assert((len & 15) == 0); + + /* Load IV */ + iv = _mm_loadu_si128((__m128i*)(ctx->iv)); + while (block < finish) { + /* Key schedule ptr */ + __m128i* keysched = (__m128i*)ctx->invkeysched; + last = _mm_loadu_si128(block); + dec = _mm_xor_si128(last, *keysched); + switch (ctx->Nr) { + case 14: + dec = _mm_aesdec_si128(dec, *(++keysched)); + dec = _mm_aesdec_si128(dec, *(++keysched)); + case 12: + dec = _mm_aesdec_si128(dec, *(++keysched)); + dec = _mm_aesdec_si128(dec, *(++keysched)); + case 10: + dec = _mm_aesdec_si128(dec, *(++keysched)); + dec = _mm_aesdec_si128(dec, *(++keysched)); + dec = _mm_aesdec_si128(dec, *(++keysched)); + dec = _mm_aesdec_si128(dec, *(++keysched)); + dec = _mm_aesdec_si128(dec, *(++keysched)); + dec = _mm_aesdec_si128(dec, *(++keysched)); + dec = _mm_aesdec_si128(dec, *(++keysched)); + dec = _mm_aesdec_si128(dec, *(++keysched)); + dec = _mm_aesdec_si128(dec, *(++keysched)); + dec = _mm_aesdeclast_si128(dec, *(++keysched)); + break; + default: + assert(0); + } + + /* Xor data with IV */ + dec = _mm_xor_si128(iv, dec); + + /* Store data */ + _mm_storeu_si128(block, dec); + iv = last; + + /* Go to next block */ + ++block; + } + + /* Update IV */ + _mm_storeu_si128((__m128i*)(ctx->iv), dec); +} + +FUNC_ISA +static void aes_sdctr_ni(unsigned char *blk, int len, AESContext *ctx) +{ + const __m128i BSWAP_EPI64 = _mm_setr_epi8(3,2,1,0,7,6,5,4,11,10,9,8,15,14,13,12); + const __m128i ONE = _mm_setr_epi32(0,0,0,1); + const __m128i ZERO = _mm_setzero_si128(); + __m128i iv; + __m128i* block = (__m128i*)blk; + const __m128i* finish = (__m128i*)(blk + len); + + assert((len & 15) == 0); + + iv = _mm_loadu_si128((__m128i*)ctx->iv); + + while (block < finish) { + __m128i enc; + __m128i* keysched = (__m128i*)ctx->keysched;/* Key schedule ptr */ + + /* Perform rounds */ + enc = _mm_xor_si128(iv, *keysched); /* Note that we use IV */ + switch (ctx->Nr) { + case 14: + enc = _mm_aesenc_si128(enc, *(++keysched)); + enc = _mm_aesenc_si128(enc, *(++keysched)); + case 12: + enc = _mm_aesenc_si128(enc, *(++keysched)); + enc = _mm_aesenc_si128(enc, *(++keysched)); + case 10: + enc = _mm_aesenc_si128(enc, *(++keysched)); + enc = _mm_aesenc_si128(enc, *(++keysched)); + enc = _mm_aesenc_si128(enc, *(++keysched)); + enc = _mm_aesenc_si128(enc, *(++keysched)); + enc = _mm_aesenc_si128(enc, *(++keysched)); + enc = _mm_aesenc_si128(enc, *(++keysched)); + enc = _mm_aesenc_si128(enc, *(++keysched)); + enc = _mm_aesenc_si128(enc, *(++keysched)); + enc = _mm_aesenc_si128(enc, *(++keysched)); + enc = _mm_aesenclast_si128(enc, *(++keysched)); + break; + default: + assert(0); + } + + /* Xor with block and store result */ + enc = _mm_xor_si128(enc, _mm_loadu_si128(block)); + _mm_storeu_si128(block, enc); + + /* Increment of IV */ + iv = _mm_shuffle_epi8(iv, BSWAP_EPI64); /* Swap endianess */ + iv = _mm_add_epi64(iv, ONE); /* Inc low part */ + enc = _mm_cmpeq_epi64(iv, ZERO); /* Check for carry */ + enc = _mm_unpacklo_epi64(ZERO, enc); /* Pack carry reg */ + iv = _mm_sub_epi64(iv, enc); /* Sub carry reg */ + iv = _mm_shuffle_epi8(iv, BSWAP_EPI64); /* Swap enianess back */ + + /* Go to next block */ + ++block; + } + + /* Update IV */ + _mm_storeu_si128((__m128i*)ctx->iv, iv); +} + +FUNC_ISA +static void aes_inv_key_10(AESContext * ctx) +{ + __m128i* keysched = (__m128i*)ctx->keysched; + __m128i* invkeysched = (__m128i*)ctx->invkeysched; + + *(invkeysched + 10) = *(keysched + 0); + *(invkeysched + 9) = _mm_aesimc_si128(*(keysched + 1)); + *(invkeysched + 8) = _mm_aesimc_si128(*(keysched + 2)); + *(invkeysched + 7) = _mm_aesimc_si128(*(keysched + 3)); + *(invkeysched + 6) = _mm_aesimc_si128(*(keysched + 4)); + *(invkeysched + 5) = _mm_aesimc_si128(*(keysched + 5)); + *(invkeysched + 4) = _mm_aesimc_si128(*(keysched + 6)); + *(invkeysched + 3) = _mm_aesimc_si128(*(keysched + 7)); + *(invkeysched + 2) = _mm_aesimc_si128(*(keysched + 8)); + *(invkeysched + 1) = _mm_aesimc_si128(*(keysched + 9)); + *(invkeysched + 0) = *(keysched + 10); +} + +FUNC_ISA +static void aes_inv_key_12(AESContext * ctx) +{ + __m128i* keysched = (__m128i*)ctx->keysched; + __m128i* invkeysched = (__m128i*)ctx->invkeysched; + + *(invkeysched + 12) = *(keysched + 0); + *(invkeysched + 11) = _mm_aesimc_si128(*(keysched + 1)); + *(invkeysched + 10) = _mm_aesimc_si128(*(keysched + 2)); + *(invkeysched + 9) = _mm_aesimc_si128(*(keysched + 3)); + *(invkeysched + 8) = _mm_aesimc_si128(*(keysched + 4)); + *(invkeysched + 7) = _mm_aesimc_si128(*(keysched + 5)); + *(invkeysched + 6) = _mm_aesimc_si128(*(keysched + 6)); + *(invkeysched + 5) = _mm_aesimc_si128(*(keysched + 7)); + *(invkeysched + 4) = _mm_aesimc_si128(*(keysched + 8)); + *(invkeysched + 3) = _mm_aesimc_si128(*(keysched + 9)); + *(invkeysched + 2) = _mm_aesimc_si128(*(keysched + 10)); + *(invkeysched + 1) = _mm_aesimc_si128(*(keysched + 11)); + *(invkeysched + 0) = *(keysched + 12); +} + +FUNC_ISA +static void aes_inv_key_14(AESContext * ctx) +{ + __m128i* keysched = (__m128i*)ctx->keysched; + __m128i* invkeysched = (__m128i*)ctx->invkeysched; + + *(invkeysched + 14) = *(keysched + 0); + *(invkeysched + 13) = _mm_aesimc_si128(*(keysched + 1)); + *(invkeysched + 12) = _mm_aesimc_si128(*(keysched + 2)); + *(invkeysched + 11) = _mm_aesimc_si128(*(keysched + 3)); + *(invkeysched + 10) = _mm_aesimc_si128(*(keysched + 4)); + *(invkeysched + 9) = _mm_aesimc_si128(*(keysched + 5)); + *(invkeysched + 8) = _mm_aesimc_si128(*(keysched + 6)); + *(invkeysched + 7) = _mm_aesimc_si128(*(keysched + 7)); + *(invkeysched + 6) = _mm_aesimc_si128(*(keysched + 8)); + *(invkeysched + 5) = _mm_aesimc_si128(*(keysched + 9)); + *(invkeysched + 4) = _mm_aesimc_si128(*(keysched + 10)); + *(invkeysched + 3) = _mm_aesimc_si128(*(keysched + 11)); + *(invkeysched + 2) = _mm_aesimc_si128(*(keysched + 12)); + *(invkeysched + 1) = _mm_aesimc_si128(*(keysched + 13)); + *(invkeysched + 0) = *(keysched + 14); +} + +/* + * Set up an AESContext. `keylen' is measured in + * bytes; it can be either 16 (128-bit), 24 (192-bit), or 32 + * (256-bit). + */ +FUNC_ISA +static void aes_setup_ni(AESContext * ctx, unsigned char *key, int keylen) +{ + __m128i *keysched = (__m128i*)ctx->keysched; + + ctx->encrypt_cbc = aes_encrypt_cbc_ni; + ctx->decrypt_cbc = aes_decrypt_cbc_ni; + ctx->sdctr = aes_sdctr_ni; + + /* + * Now do the key setup itself. + */ + switch (keylen) { + case 16: + AES_128_Key_Expansion (key, keysched); + break; + case 24: + AES_192_Key_Expansion (key, keysched); + break; + case 32: + AES_256_Key_Expansion (key, keysched); + break; + default: + assert(0); + } + + /* + * Now prepare the modified keys for the inverse cipher. + */ + switch (ctx->Nr) { + case 10: + aes_inv_key_10(ctx); + break; + case 12: + aes_inv_key_12(ctx); + break; + case 14: + aes_inv_key_14(ctx); + break; + default: + assert(0); + } +} + +#else /* COMPILER_SUPPORTS_AES_NI */ + +static void aes_setup_ni(AESContext * ctx, unsigned char *key, int keylen) +{ + assert(0); +} + +INLINE static int supports_aes_ni() +{ + return 0; +} + +#endif /* COMPILER_SUPPORTS_AES_NI */ From 0a0a1c01d7cc6ca750d39f43b902e86987c5d376 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Fri, 20 Oct 2017 19:14:41 +0100 Subject: [PATCH 094/607] Additional copyright holders, from the AES-NI work. --- LICENCE | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/LICENCE b/LICENCE index 05fbb7d3..c473a6a4 100644 --- a/LICENCE +++ b/LICENCE @@ -4,7 +4,8 @@ Portions copyright Robert de Bath, Joris van Rantwijk, Delian Delchev, Andreas Schultz, Jeroen Massar, Wez Furlong, Nicolas Barry, Justin Bradford, Ben Harris, Malcolm Smith, Ahmad Khalifa, Markus Kuhn, Colin Watson, Christopher Staite, Lorenz Diener, Christian -Brabandt, Jeff Smith, and CORE SDI S.A. +Brabandt, Jeff Smith, Pavel Kryukov, Maxim Kuznetsov, Svyatoslav +Kuzmich, and CORE SDI S.A. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files From 4d15d46473907515d31cd0dc92b3ce86e5c5cb1e Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 26 Nov 2017 08:45:19 +0000 Subject: [PATCH 095/607] Memory leak: free conn->retbuf in uxagentc.c. While debugging some new code, I ran valgrind in leak-checking mode and it pointed out a handful of existing memory leaks, which got in the way of spotting any _new_ leaks I might be introducing :-) This was one: in the case where an asynchronous agent query on Unix is aborted, the dynamically allocated buffer holding the response was not freed. --- unix/uxagentc.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/unix/uxagentc.c b/unix/uxagentc.c index 51f9a1eb..2c748343 100644 --- a/unix/uxagentc.c +++ b/unix/uxagentc.c @@ -95,6 +95,8 @@ void agent_cancel_query(agent_pending_query *conn) uxsel_del(conn->fd); close(conn->fd); del234(agent_pending_queries, conn); + if (conn->retbuf && conn->retbuf != conn->sizebuf) + sfree(conn->retbuf); sfree(conn); } @@ -114,11 +116,12 @@ static void agent_select_result(int fd, int event) return; /* more data to come */ /* - * We have now completed the agent query. Do the callback, and - * clean up. (Of course we don't free retbuf, since ownership - * of that passes to the callback.) + * We have now completed the agent query. Do the callback. */ conn->callback(conn->callback_ctx, conn->retbuf, conn->retlen); + /* Null out conn->retbuf, since ownership of that buffer has + * passed to the callback. */ + conn->retbuf = NULL; agent_cancel_query(conn); } From 90a402c017b6b262b0b2181cf193dd8188fac5c7 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 26 Nov 2017 08:45:37 +0000 Subject: [PATCH 096/607] Memory leak: free term->answerback in term_free(). Not a large leak as these things go, but valgrind's error dump for a memory leak is just as annoying regardless of the size of the leaked object! --- terminal.c | 1 + 1 file changed, 1 insertion(+) diff --git a/terminal.c b/terminal.c index d32d4f42..d5d5314a 100644 --- a/terminal.c +++ b/terminal.c @@ -1739,6 +1739,7 @@ void term_free(Terminal *term) sfree(term->ltemp); sfree(term->wcFrom); sfree(term->wcTo); + sfree(term->answerback); for (i = 0; i < term->bidi_cache_size; i++) { sfree(term->pre_bidi_cache[i].chars); From f1eeeff8cfea1001a1791ba95782ba7bbed3b976 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 26 Nov 2017 08:45:45 +0000 Subject: [PATCH 097/607] Memory leak: add a columns_finalize() method. My custom GTK layout class 'Columns' includes a linked list of dynamically allocated data, and apparently I forgot to write a destructor that frees it all when the class is deallocated, and have never noticed until now. --- unix/gtkcols.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 53 insertions(+), 2 deletions(-) diff --git a/unix/gtkcols.c b/unix/gtkcols.c index e8223a72..ef060d63 100644 --- a/unix/gtkcols.c +++ b/unix/gtkcols.c @@ -8,6 +8,11 @@ static void columns_init(Columns *cols); static void columns_class_init(ColumnsClass *klass); +#if !GTK_CHECK_VERSION(2,0,0) +static void columns_finalize(GtkObject *object); +#else +static void columns_finalize(GObject *object); +#endif static void columns_map(GtkWidget *widget); static void columns_unmap(GtkWidget *widget); #if !GTK_CHECK_VERSION(2,0,0) @@ -96,11 +101,11 @@ static gint (*columns_inherited_focus)(GtkContainer *container, static void columns_class_init(ColumnsClass *klass) { #if !GTK_CHECK_VERSION(2,0,0) - /* GtkObjectClass *object_class = (GtkObjectClass *)klass; */ + GtkObjectClass *object_class = (GtkObjectClass *)klass; GtkWidgetClass *widget_class = (GtkWidgetClass *)klass; GtkContainerClass *container_class = (GtkContainerClass *)klass; #else - /* GObjectClass *object_class = G_OBJECT_CLASS(klass); */ + GObjectClass *object_class = G_OBJECT_CLASS(klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass); GtkContainerClass *container_class = GTK_CONTAINER_CLASS(klass); #endif @@ -111,6 +116,7 @@ static void columns_class_init(ColumnsClass *klass) parent_class = g_type_class_peek_parent(klass); #endif + object_class->finalize = columns_finalize; widget_class->map = columns_map; widget_class->unmap = columns_unmap; #if !GTK_CHECK_VERSION(2,0,0) @@ -149,6 +155,50 @@ static void columns_init(Columns *cols) cols->spacing = 0; } +static void columns_child_free(gpointer vchild) +{ + ColumnsChild *child = (ColumnsChild *)vchild; + if (child->percentages) + g_free(child->percentages); + g_free(child); +} + +static void columns_finalize( +#if !GTK_CHECK_VERSION(2,0,0) + GtkObject *object +#else + GObject *object +#endif + ) +{ + Columns *cols; + + g_return_if_fail(object != NULL); + g_return_if_fail(IS_COLUMNS(object)); + + cols = COLUMNS(object); + +#if !GTK_CHECK_VERSION(2,0,0) + { + GList *node; + for (node = cols->children; node; node = node->next) + if (node->data) + columns_child_free(node->data); + } + g_list_free(cols->children); +#else + g_list_free_full(cols->children, columns_child_free); +#endif + + cols->children = NULL; + +#if !GTK_CHECK_VERSION(2,0,0) + GTK_OBJECT_CLASS(parent_class)->finalize(object); +#else + G_OBJECT_CLASS(parent_class)->finalize(object); +#endif +} + /* * These appear to be thoroughly tedious functions; the only reason * we have to reimplement them at all is because we defined our own @@ -406,6 +456,7 @@ void columns_add(Columns *cols, GtkWidget *child, childdata->colspan = colspan; childdata->force_left = FALSE; childdata->same_height_as = NULL; + childdata->percentages = NULL; cols->children = g_list_append(cols->children, childdata); cols->taborder = g_list_append(cols->taborder, child); From 9909077be131c5dc7b3dee14cb25b8a799040616 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 26 Nov 2017 08:56:16 +0000 Subject: [PATCH 098/607] Make the current code compile again under GTK1. Apparently I haven't tested this compile mode in a while: I had a couple of compile errors due to new code not properly #ifdeffed (the true-colour mode has to be effectively disabled in the palette-based GTK1 graphics model) and one for an unused static function (get_monitor_geometry is only used in GTK2 and above, and with -Werror that means I mustn't even _define_ it in GTK1). With these changes, I still didn't get a clean compile unless I also configured CFLAGS=-std=gnu89, due to the GTK1 headers having an outdated set of ifdefs to figure out the compiler's semantics of 'inline'. (They seem to expect old-style gcc, which inconveniently treats 'inline' and 'extern inline' more or less the opposite way round from the version standardised by C99.) --- unix/gtkwin.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/unix/gtkwin.c b/unix/gtkwin.c index 3a3c2a54..a851c258 100644 --- a/unix/gtkwin.c +++ b/unix/gtkwin.c @@ -3039,11 +3039,16 @@ static void draw_set_colour(struct draw_ctx *dctx, int col, int dim) #ifdef DRAW_TEXT_GDK if (dctx->uctx.type == DRAWTYPE_GDK) { if (dim) { +#if GTK_CHECK_VERSION(2,0,0) GdkColor color; color.red = dctx->inst->cols[col].red * 2 / 3; color.green = dctx->inst->cols[col].green * 2 / 3; color.blue = dctx->inst->cols[col].blue * 2 / 3; gdk_gc_set_rgb_fg_color(dctx->uctx.u.gdk.gc, &color); +#else + /* Poor GTK1 fallback */ + gdk_gc_set_foreground(dctx->uctx.u.gdk.gc, &dctx->inst->cols[col]); +#endif } else { gdk_gc_set_foreground(dctx->uctx.u.gdk.gc, &dctx->inst->cols[col]); } @@ -3064,6 +3069,7 @@ static void draw_set_colour_rgb(struct draw_ctx *dctx, optionalrgb orgb, { #ifdef DRAW_TEXT_GDK if (dctx->uctx.type == DRAWTYPE_GDK) { +#if GTK_CHECK_VERSION(2,0,0) GdkColor color; color.red = orgb.r * 256; color.green = orgb.g * 256; @@ -3074,6 +3080,10 @@ static void draw_set_colour_rgb(struct draw_ctx *dctx, optionalrgb orgb, color.blue = color.blue * 2 / 3; } gdk_gc_set_rgb_fg_color(dctx->uctx.u.gdk.gc, &color); +#else + /* Poor GTK1 fallback */ + gdk_gc_set_foreground(dctx->uctx.u.gdk.gc, &dctx->inst->cols[256]); +#endif } #endif #ifdef DRAW_TEXT_CAIRO @@ -4374,6 +4384,7 @@ static void start_backend(struct gui_data *inst) gtk_widget_set_sensitive(inst->restartitem, FALSE); } +#if GTK_CHECK_VERSION(2,0,0) static void get_monitor_geometry(GtkWidget *widget, GdkRectangle *geometry) { #if GTK_CHECK_VERSION(3,4,0) @@ -4397,6 +4408,7 @@ static void get_monitor_geometry(GtkWidget *widget, GdkRectangle *geometry) geometry->height = gdk_screen_height(); #endif } +#endif struct gui_data *new_session_window(Conf *conf, const char *geometry_string) { From c74d1e3c6a0aa2c4ef275e18fcdc5844f536bab6 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 26 Nov 2017 09:16:22 +0000 Subject: [PATCH 099/607] GTK1 runtime fix: widen extent of ignore_sbar. ignore_sbar is a flag that we set while manually changing the scrollbar settings, so that when those half-finished changes trigger GTK event callbacks, we know to ignore them, and wait until we've finished setting everything up before actually updating the window. But somehow I had managed to leave the functions that actually _have the effect_ (at least in GTK1) outside the pair of statements that set and unset the ignore flag. The effect was that compiling pterm for GTK1, starting it up, and issuing a command like 'ls -l' that scrolls off the bottom of the window would lead to the _top_ half of the ls output being visible, and the scrollbar at the top of the scrollback rather than the bottom. --- unix/gtkwin.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unix/gtkwin.c b/unix/gtkwin.c index a851c258..1038e756 100644 --- a/unix/gtkwin.c +++ b/unix/gtkwin.c @@ -2884,13 +2884,13 @@ void set_sbar(void *frontend, int total, int start, int page) struct gui_data *inst = (struct gui_data *)frontend; if (!conf_get_int(inst->conf, CONF_scrollbar)) return; + inst->ignore_sbar = TRUE; gtk_adjustment_set_lower(inst->sbar_adjust, 0); gtk_adjustment_set_upper(inst->sbar_adjust, total); gtk_adjustment_set_value(inst->sbar_adjust, start); gtk_adjustment_set_page_size(inst->sbar_adjust, page); gtk_adjustment_set_step_increment(inst->sbar_adjust, 1); gtk_adjustment_set_page_increment(inst->sbar_adjust, page/2); - inst->ignore_sbar = TRUE; #if !GTK_CHECK_VERSION(3,18,0) gtk_adjustment_changed(inst->sbar_adjust); #endif From 116dac29ccc99ff498edd7dfcda0f456ce47c3ef Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 25 Nov 2017 21:49:31 +0000 Subject: [PATCH 100/607] Reinstate the SIGCHLD handler in ptermapp. Detecting that the child process in a pterm has terminated is important for _any_ kind of pterm, so it's a mistake to put the signal handler setup _solely_ inside the optional pty_pre_init function which does the privileged setup and forks off a utmp watchdog process. Now the signal handler is installed even in the GtkApplication-based multi-window front end to pterm, meaning it will exist even on OS X. --- unix/uxpty.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/unix/uxpty.c b/unix/uxpty.c index 618fe9bd..4387ad8f 100644 --- a/unix/uxpty.c +++ b/unix/uxpty.c @@ -261,13 +261,20 @@ static void cleanup_utmp(void) } #endif -#ifndef NO_PTY_PRE_INIT static void sigchld_handler(int signum) { if (write(pty_signal_pipe[1], "x", 1) <= 0) /* not much we can do about it */; } -#endif + +static void pty_setup_sigchld_handler(void) +{ + static int setup = FALSE; + if (!setup) { + putty_signal(SIGCHLD, sigchld_handler); + setup = TRUE; + } +} #ifndef OMIT_UTMP static void fatal_sig_handler(int signum) @@ -433,7 +440,7 @@ void pty_pre_init(void) /* set the child signal handler straight away; it needs to be set * before we ever fork. */ - putty_signal(SIGCHLD, sigchld_handler); + pty_setup_sigchld_handler(); pty->master_fd = pty->slave_fd = -1; #ifndef OMIT_UTMP pty_stamped_utmp = FALSE; @@ -790,6 +797,12 @@ static const char *pty_init(void *frontend, void **backend_handle, Conf *conf, windowid = get_windowid(pty->frontend); #endif + /* + * Set up the signal handler to catch SIGCHLD, if pty_pre_init + * didn't already do it. + */ + pty_setup_sigchld_handler(); + /* * Fork and execute the command. */ From 5b13a1b01518c23f38525ec2ae9b4ac9ca3110cd Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 25 Nov 2017 21:51:45 +0000 Subject: [PATCH 101/607] Add a missing conf_copy in gtkapp's Duplicate Session. Without this, the Conf objects in a session and its duplicate were aliases of each other, which could lead to confusing semantic effects if one of the sessions was reconfigured in mid-run, and worse still, a crash if one session got cleaned up and called conf_free on a Conf that the other was still using. None of that was intentional; it was just a matter of forgetting to clone the Conf for the duplicated session. Now we do. --- unix/gtkapp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unix/gtkapp.c b/unix/gtkapp.c index 8b2a794f..b544684e 100644 --- a/unix/gtkapp.c +++ b/unix/gtkapp.c @@ -196,7 +196,7 @@ void launch_duplicate_session(Conf *conf) { extern const int dup_check_launchable; assert(!dup_check_launchable || conf_launchable(conf)); - new_session_window(conf, NULL); + new_session_window(conf_copy(conf), NULL); } void launch_new_session(void) From b6b91b8e177958d870caa116e10cec537892eba8 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 26 Nov 2017 10:58:56 +0000 Subject: [PATCH 102/607] OS X makefile: stop depending on JHBUILD_PREFIX. People who use a packaging system other than jhbuild still ought to be able to run the OS X GTK3 build, so now the gtk-mac-bundler command finds out the locations of things by a more portable method. (I've had this change lurking around uncommitted in a working tree for a while, and only just found it in the course of doing other OS X- related work. Oops.) --- Recipe | 4 ++-- unix/pterm.bundle | 6 +++++- unix/putty.bundle | 36 +++++++++++++++++++++++++++++++++++- 3 files changed, 42 insertions(+), 4 deletions(-) diff --git a/Recipe b/Recipe index 5715938b..33d0f2f7 100644 --- a/Recipe +++ b/Recipe @@ -208,9 +208,9 @@ endif if HAVE_QUARTZ noinst_SCRIPTS = unix/PuTTY.app unix/Pterm.app unix/PuTTY.app: unix/putty.bundle puttyapp osxlaunch - rm -rf $@ && gtk-mac-bundler $< + rm -rf $@ && PUTTY_GTK_PREFIX_FROM_MAKEFILE=$$(pkg-config --variable=prefix gtk+-3.0) gtk-mac-bundler $< unix/Pterm.app: unix/pterm.bundle ptermapp osxlaunch - rm -rf $@ && gtk-mac-bundler $< + rm -rf $@ && PUTTY_GTK_PREFIX_FROM_MAKEFILE=$$(pkg-config --variable=prefix gtk+-3.0) gtk-mac-bundler $< endif !end diff --git a/unix/pterm.bundle b/unix/pterm.bundle index 377fee0d..0d701216 100644 --- a/unix/pterm.bundle +++ b/unix/pterm.bundle @@ -2,7 +2,11 @@ - ${env:JHBUILD_PREFIX} + + ${env:PUTTY_GTK_PREFIX_FROM_MAKEFILE} + gtk+-3.0 + ${env:PUTTY_GTK_PREFIX_FROM_MAKEFILE} + gtk+-3.0 @@ -518,6 +527,7 @@ https://msdn.microsoft.com/en-us/library/windows/desktop/dd391569(v=vs.85).aspx + - + - + + + + + + + + + + + + + + @@ -22,11 +35,8 @@ - - - - - + + @@ -42,6 +52,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -63,7 +107,7 @@ Buildscr. --> Date: Sat, 2 Jun 2018 07:52:26 +0100 Subject: [PATCH 321/607] Fix some missing void * and const in existing APIs. Several changes here that should have been in commit 7babe66a8 but I missed them. --- portfwd.c | 2 +- ssh.c | 4 ++-- ssh.h | 6 +++--- sshecc.c | 6 ++++-- x11fwd.c | 4 +++- 5 files changed, 13 insertions(+), 9 deletions(-) diff --git a/portfwd.c b/portfwd.c index d27abb41..1e4d2d1f 100644 --- a/portfwd.c +++ b/portfwd.c @@ -605,7 +605,7 @@ void pfd_override_throttle(struct PortForwarding *pf, int enable) /* * Called to send data down the raw connection. */ -int pfd_send(struct PortForwarding *pf, char *data, int len) +int pfd_send(struct PortForwarding *pf, const void *data, int len) { if (pf == NULL) return 0; diff --git a/ssh.c b/ssh.c index edf813da..4e87dc0a 100644 --- a/ssh.c +++ b/ssh.c @@ -5890,7 +5890,7 @@ static void ssh1_msg_channel_close(Ssh ssh, struct Packet *pktin) /* * Handle incoming data on an SSH-1 or SSH-2 agent-forwarding channel. */ -static int ssh_agent_channel_data(struct ssh_channel *c, char *data, +static int ssh_agent_channel_data(struct ssh_channel *c, const void *data, int length) { bufchain_add(&c->u.a.inbuffer, data, length); @@ -5908,7 +5908,7 @@ static int ssh_agent_channel_data(struct ssh_channel *c, char *data, } static int ssh_channel_data(struct ssh_channel *c, int is_stderr, - char *data, int length) + const void *data, int length) { switch (c->type) { case CHAN_MAINSESSION: diff --git a/ssh.h b/ssh.h index 398f8352..de31df4a 100644 --- a/ssh.h +++ b/ssh.h @@ -226,7 +226,7 @@ struct ec_key *ssh_ecdhkex_newkey(const struct ssh_kex *kex); void ssh_ecdhkex_freekey(struct ec_key *key); void ssh_ecdhkex_getpublic(struct ec_key *key, BinarySink *bs); Bignum ssh_ecdhkex_getkey(struct ec_key *key, - char *remoteKey, int remoteKeyLen); + const void *remoteKey, int remoteKeyLen); /* * Helper function for k generation in DSA, reused in ECDSA @@ -542,7 +542,7 @@ void ssh_send_port_open(void *channel, const char *hostname, int port, extern char *pfd_connect(struct PortForwarding **pf, char *hostname, int port, void *c, Conf *conf, int addressfamily); extern void pfd_close(struct PortForwarding *); -extern int pfd_send(struct PortForwarding *, char *data, int len); +extern int pfd_send(struct PortForwarding *, const void *data, int len); extern void pfd_send_eof(struct PortForwarding *); extern void pfd_confirm(struct PortForwarding *); extern void pfd_unthrottle(struct PortForwarding *); @@ -622,7 +622,7 @@ void x11_free_fake_auth(struct X11FakeAuth *auth); struct X11Connection; /* opaque outside x11fwd.c */ struct X11Connection *x11_init(tree234 *authtree, void *, const char *, int); extern void x11_close(struct X11Connection *); -extern int x11_send(struct X11Connection *, char *, int); +extern int x11_send(struct X11Connection *, const void *, int); extern void x11_send_eof(struct X11Connection *s); extern void x11_unthrottle(struct X11Connection *s); extern void x11_override_throttle(struct X11Connection *s, int enable); diff --git a/sshecc.c b/sshecc.c index 9ce2784b..57bd3595 100644 --- a/sshecc.c +++ b/sshecc.c @@ -2689,7 +2689,8 @@ void ssh_ecdhkex_getpublic(struct ec_key *ec, BinarySink *bs) } } -Bignum ssh_ecdhkex_getkey(struct ec_key *ec, char *remoteKey, int remoteKeyLen) +Bignum ssh_ecdhkex_getkey(struct ec_key *ec, + const void *remoteKey, int remoteKeyLen) { struct ec_point remote; Bignum ret; @@ -2708,7 +2709,8 @@ Bignum ssh_ecdhkex_getkey(struct ec_key *ec, char *remoteKey, int remoteKeyLen) remote.curve = ec->publicKey.curve; remote.infinity = 0; - remote.x = bignum_from_bytes_le((unsigned char*)remoteKey, remoteKeyLen); + remote.x = bignum_from_bytes_le((const unsigned char *)remoteKey, + remoteKeyLen); remote.y = NULL; remote.z = NULL; } diff --git a/x11fwd.c b/x11fwd.c index 493eca67..eee73095 100644 --- a/x11fwd.c +++ b/x11fwd.c @@ -800,8 +800,10 @@ static int x11_parse_ip(const char *addr_string, unsigned long *ip) /* * Called to send data down the raw connection. */ -int x11_send(struct X11Connection *xconn, char *data, int len) +int x11_send(struct X11Connection *xconn, const void *vdata, int len) { + const char *data = (const char *)vdata; + if (!xconn) return 0; From 9e96af59ce7cd56aa181c1d3da40cedf0ecbaaf5 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 27 May 2018 16:56:51 +0100 Subject: [PATCH 322/607] Introduce a new 'ptrlen' type. This wraps up a (pointer, length) pair into a convenient struct that lets me return it by value from a function, and also pass it through to other functions in one go. Ideally quite a lot of this code base could be switched over to using ptrlen in place of separate pointer and length variables or function parameters. (In fact, in my personal ideal conception of C, the usual string type would be of this form, and all the string.h functions would operate on ptrlens instead of zero-terminated 'char *'.) For the moment, I'm just introducing it to make some upcoming refactoring less inconvenient. Bulk migration of existing code to ptrlen is a project for another time. Along with the type itself, I've provided a convenient system of including the contents of a ptrlen in a printf; a constructor function that wraps up a pointer and length so you can make a ptrlen on the fly in mid-expression; a function to compare a ptrlen against an ordinary C string (which I mostly expect to use with string literals); and a function 'mkstr' to make a dynamically allocated C string out of one. That last function replaces a function of the same name in sftp.c, which I'm promoting to a whole-codebase facility and adjusting its API. --- defs.h | 11 +++++++++++ marshal.c | 5 +++++ marshal.h | 3 +++ misc.c | 32 ++++++++++++++++++++++++++++++++ misc.h | 8 ++++++++ pageant.c | 2 +- sftp.c | 22 +++++----------------- ssh.h | 2 +- sshpubk.c | 21 +++++++++++---------- 9 files changed, 77 insertions(+), 29 deletions(-) diff --git a/defs.h b/defs.h index 3946e1ed..87b48499 100644 --- a/defs.h +++ b/defs.h @@ -11,6 +11,8 @@ #ifndef PUTTY_DEFS_H #define PUTTY_DEFS_H +#include + #ifndef FALSE #define FALSE 0 #endif @@ -50,6 +52,15 @@ typedef struct Plug_vtable Plug_vtable; typedef const Socket_vtable **Socket; typedef const Plug_vtable **Plug; +/* + * A small structure wrapping up a (pointer, length) pair so that it + * can be conveniently passed to or from a function. + */ +typedef struct ptrlen { + const void *ptr; + size_t len; +} ptrlen; + /* Do a compile-time type-check of 'to_check' (without evaluating it), * as a side effect of returning the value 'to_return'. Note that * although this macro double-*expands* to_return, it always diff --git a/marshal.c b/marshal.c index 4c1f1bcc..48bbef78 100644 --- a/marshal.c +++ b/marshal.c @@ -52,6 +52,11 @@ void BinarySink_put_string(BinarySink *bs, const void *data, size_t len) bs->write(bs, data, len); } +void BinarySink_put_stringpl(BinarySink *bs, ptrlen pl) +{ + BinarySink_put_string(bs, pl.ptr, pl.len); +} + void BinarySink_put_stringz(BinarySink *bs, const char *str) { BinarySink_put_string(bs, str, strlen(str)); diff --git a/marshal.h b/marshal.h index 95ec3769..ca5a009f 100644 --- a/marshal.h +++ b/marshal.h @@ -88,6 +88,8 @@ struct BinarySink { * that then gets wrapped into a string container in an outer one). */ #define put_string(bs, val, len) \ BinarySink_put_string(BinarySink_UPCAST(bs),val,len) +#define put_stringpl(bs, ptrlen) \ + BinarySink_put_stringpl(BinarySink_UPCAST(bs),ptrlen) #define put_stringz(bs, val) \ BinarySink_put_stringz(BinarySink_UPCAST(bs), val) #define put_stringsb(bs, val) \ @@ -129,6 +131,7 @@ void BinarySink_put_bool(BinarySink *, int); void BinarySink_put_uint16(BinarySink *, unsigned long); void BinarySink_put_uint32(BinarySink *, unsigned long); void BinarySink_put_string(BinarySink *, const void *data, size_t len); +void BinarySink_put_stringpl(BinarySink *, ptrlen); void BinarySink_put_stringz(BinarySink *, const char *str); struct strbuf; void BinarySink_put_stringsb(BinarySink *, struct strbuf *); diff --git a/misc.c b/misc.c index b14f45d2..30bfec90 100644 --- a/misc.c +++ b/misc.c @@ -360,6 +360,16 @@ int toint(unsigned u) return INT_MIN; /* fallback; should never occur on binary machines */ } +int string_length_for_printf(size_t s) +{ + /* Truncate absurdly long strings (should one show up) to fit + * within a positive 'int', which is what the "%.*s" format will + * expect. */ + if (s > INT_MAX) + return INT_MAX; + return s; +} + /* * Do an sprintf(), but into a custom-allocated buffer. * @@ -1177,6 +1187,28 @@ int match_ssh_id(int stringlen, const void *string, const char *id) return (idlen == stringlen && !memcmp(string, id, idlen)); } +ptrlen make_ptrlen(const void *ptr, size_t len) +{ + ptrlen pl; + pl.ptr = ptr; + pl.len = len; + return pl; +} + +int ptrlen_eq_string(ptrlen pl, const char *str) +{ + size_t len = strlen(str); + return (pl.len == len && !memcmp(pl.ptr, str, len)); +} + +char *mkstr(ptrlen pl) +{ + char *p = snewn(pl.len + 1, char); + memcpy(p, pl.ptr, pl.len); + p[pl.len] = '\0'; + return p; +} + void *get_ssh_string(int *datalen, const void **data, int *stringlen) { void *ret; diff --git a/misc.h b/misc.h index c4da3d6d..de662a87 100644 --- a/misc.h +++ b/misc.h @@ -87,6 +87,14 @@ int validate_manual_hostkey(char *key); struct tm ltime(void); +ptrlen make_ptrlen(const void *ptr, size_t len); +int ptrlen_eq_string(ptrlen pl, const char *str); +char *mkstr(ptrlen pl); +int string_length_for_printf(size_t); +/* Derive two printf arguments from a ptrlen, suitable for "%.*s" */ +#define PTRLEN_PRINTF(pl) \ + string_length_for_printf((pl).len), (const char *)(pl).ptr + /* Wipe sensitive data out of memory that's about to be freed. Simpler * than memset because we don't need the fill char parameter; also * attempts (by fiddly use of volatile) to inhibit the compiler from diff --git a/pageant.c b/pageant.c index c541101f..8528cc02 100644 --- a/pageant.c +++ b/pageant.c @@ -556,7 +556,7 @@ void pageant_handle_msg(BinarySink *bs, key = snew(struct ssh2_userkey); key->data = NULL; key->comment = NULL; - key->alg = find_pubkey_alg_len(alglen, alg); + key->alg = find_pubkey_alg_len(make_ptrlen(alg, alglen)); if (!key->alg) { pageant_failure_msg(bs, "algorithm unknown", logctx, logfn); goto add2_cleanup; diff --git a/sftp.c b/sftp.c index 77162157..ad153396 100644 --- a/sftp.c +++ b/sftp.c @@ -341,18 +341,6 @@ struct sftp_request *sftp_find_request(struct sftp_packet *pktin) return req; } -/* ---------------------------------------------------------------------- - * String handling routines. - */ - -static char *mkstr(char *s, int len) -{ - char *p = snewn(len + 1, char); - memcpy(p, s, len); - p[len] = '\0'; - return p; -} - /* ---------------------------------------------------------------------- * SFTP primitives. */ @@ -500,7 +488,7 @@ char *fxp_realpath_recv(struct sftp_packet *pktin, struct sftp_request *req) sftp_pkt_free(pktin); return NULL; } - path = mkstr(path, len); + path = mkstr(make_ptrlen(path, len)); sftp_pkt_free(pktin); return path; } else { @@ -548,7 +536,7 @@ struct fxp_handle *fxp_open_recv(struct sftp_packet *pktin, return NULL; } handle = snew(struct fxp_handle); - handle->hstring = mkstr(hstring, len); + handle->hstring = mkstr(make_ptrlen(hstring, len)); handle->hlen = len; sftp_pkt_free(pktin); return handle; @@ -590,7 +578,7 @@ struct fxp_handle *fxp_opendir_recv(struct sftp_packet *pktin, return NULL; } handle = snew(struct fxp_handle); - handle->hstring = mkstr(hstring, len); + handle->hstring = mkstr(make_ptrlen(hstring, len)); handle->hlen = len; sftp_pkt_free(pktin); return handle; @@ -977,8 +965,8 @@ struct fxp_names *fxp_readdir_recv(struct sftp_packet *pktin, sfree(pktin); return NULL; } - ret->names[i].filename = mkstr(str1, len1); - ret->names[i].longname = mkstr(str2, len2); + ret->names[i].filename = mkstr(make_ptrlen(str1, len1)); + ret->names[i].longname = mkstr(make_ptrlen(str2, len2)); } sftp_pkt_free(pktin); return ret; diff --git a/ssh.h b/ssh.h index de31df4a..7a1c5766 100644 --- a/ssh.h +++ b/ssh.h @@ -736,7 +736,7 @@ int ssh2_userkey_loadpub(const Filename *filename, char **algorithm, int ssh2_save_userkey(const Filename *filename, struct ssh2_userkey *key, char *passphrase); const ssh_keyalg *find_pubkey_alg(const char *name); -const ssh_keyalg *find_pubkey_alg_len(int namelen, const char *name); +const ssh_keyalg *find_pubkey_alg_len(ptrlen name); enum { SSH_KEYTYPE_UNOPENABLE, diff --git a/sshpubk.c b/sshpubk.c index 7ff7c081..68cf6945 100644 --- a/sshpubk.c +++ b/sshpubk.c @@ -584,19 +584,19 @@ struct ssh2_userkey ssh2_wrong_passphrase = { NULL, NULL, NULL }; -const ssh_keyalg *find_pubkey_alg_len(int namelen, const char *name) +const ssh_keyalg *find_pubkey_alg_len(ptrlen name) { - if (match_ssh_id(namelen, name, "ssh-rsa")) + if (ptrlen_eq_string(name, "ssh-rsa")) return &ssh_rsa; - else if (match_ssh_id(namelen, name, "ssh-dss")) + else if (ptrlen_eq_string(name, "ssh-dss")) return &ssh_dss; - else if (match_ssh_id(namelen, name, "ecdsa-sha2-nistp256")) + else if (ptrlen_eq_string(name, "ecdsa-sha2-nistp256")) return &ssh_ecdsa_nistp256; - else if (match_ssh_id(namelen, name, "ecdsa-sha2-nistp384")) + else if (ptrlen_eq_string(name, "ecdsa-sha2-nistp384")) return &ssh_ecdsa_nistp384; - else if (match_ssh_id(namelen, name, "ecdsa-sha2-nistp521")) + else if (ptrlen_eq_string(name, "ecdsa-sha2-nistp521")) return &ssh_ecdsa_nistp521; - else if (match_ssh_id(namelen, name, "ssh-ed25519")) + else if (ptrlen_eq_string(name, "ssh-ed25519")) return &ssh_ecdsa_ed25519; else return NULL; @@ -604,7 +604,7 @@ const ssh_keyalg *find_pubkey_alg_len(int namelen, const char *name) const ssh_keyalg *find_pubkey_alg(const char *name) { - return find_pubkey_alg_len(strlen(name), name); + return find_pubkey_alg_len(make_ptrlen(name, strlen(name))); } struct ssh2_userkey *ssh2_load_userkey(const Filename *filename, @@ -1535,7 +1535,7 @@ char *ssh2_fingerprint_blob(const void *blob, int bloblen) * If we can actually identify the algorithm as one we know * about, get hold of the key's bit count too. */ - alg = find_pubkey_alg_len(alglen, algstr); + alg = find_pubkey_alg_len(make_ptrlen(algstr, alglen)); if (alg) { int bits = alg->pubkey_bits(alg, blob, bloblen); return dupprintf("%.*s %d %s", alglen, algstr, @@ -1600,7 +1600,8 @@ static int key_type_fp(FILE *fp) (p = p+1 + strspn(p+1, "0123456789"), *p == ' ') && (p = p+1 + strspn(p+1, "0123456789"), *p == ' ' || *p == '\n' || !*p)) return SSH_KEYTYPE_SSH1_PUBLIC; - if ((p = buf + strcspn(buf, " "), find_pubkey_alg_len(p-buf, buf)) && + if ((p = buf + strcspn(buf, " "), + find_pubkey_alg_len(make_ptrlen(buf, p-buf))) && (p = p+1 + strspn(p+1, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghij" "klmnopqrstuvwxyz+/="), *p == ' ' || *p == '\n' || !*p)) From 005ca6b25713682305502e2f1a5e8154a87e8625 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 2 Jun 2018 08:25:19 +0100 Subject: [PATCH 323/607] Introduce a centralised unmarshaller, 'BinarySource'. This is the companion to the BinarySink system I introduced a couple of weeks ago, and provides the same type-genericity which will let me use the same get_* routines on an SSH packet, an SFTP packet or anything else that chooses to include an implementing substructure. However, unlike BinarySink which contained a (one-function) vtable, BinarySource contains only mutable data fields - so another thing you might very well want to do is to simply instantiate a bare one without any containing object at all. I couldn't quite coerce C into letting me use the same setup macro in both cases, so I've arranged a BinarySource_INIT you can use on larger implementing objects and a BinarySource_BARE_INIT you can use on a BinarySource not contained in anything. The API follows the general principle that even if decoding fails, the decode functions will always return _some_ kind of value, with the same dynamically-allocated-ness they would have used for a completely successful value. But they also set an error flag in the BinarySource which can be tested later. So instead of having to decode a 10-field packet by means of 10 separate 'if (!get_foo(src)) throw error' clauses, you can just write 10 'variable = get_foo(src)' statements followed by a single check of get_err(src), and if the error check fails, you have to do exactly the same set of frees you would have after a successful decode. --- defs.h | 1 + int64.h | 1 + marshal.c | 141 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ marshal.h | 123 +++++++++++++++++++++++++++++++++++++++++++++++ ssh.h | 2 + sshbn.c | 42 ++++++++++++++-- 6 files changed, 306 insertions(+), 4 deletions(-) diff --git a/defs.h b/defs.h index 87b48499..55468241 100644 --- a/defs.h +++ b/defs.h @@ -37,6 +37,7 @@ struct RSAKey; typedef uint32_t uint32; typedef struct BinarySink BinarySink; +typedef struct BinarySource BinarySource; typedef struct SockAddr_tag *SockAddr; diff --git a/int64.h b/int64.h index 6ac7f3fc..17122974 100644 --- a/int64.h +++ b/int64.h @@ -24,5 +24,6 @@ uint64 uint64_shift_left(uint64 x, int shift); uint64 uint64_from_decimal(char *str); void BinarySink_put_uint64(BinarySink *, uint64); +uint64 BinarySource_get_uint64(BinarySource *); #endif diff --git a/marshal.c b/marshal.c index 48bbef78..76c7c05f 100644 --- a/marshal.c +++ b/marshal.c @@ -82,3 +82,144 @@ int BinarySink_put_pstring(BinarySink *bs, const char *str) bs->write(bs, str, len); return TRUE; } + +/* ---------------------------------------------------------------------- */ + +static int BinarySource_data_avail(BinarySource *src, size_t wanted) +{ + if (src->err) + return FALSE; + + if (wanted <= src->len - src->pos) + return TRUE; + + src->err = BSE_OUT_OF_DATA; + return FALSE; +} + +#define avail(wanted) BinarySource_data_avail(src, wanted) +#define advance(dist) (src->pos += dist) +#define here ((const void *)((const unsigned char *)src->data + src->pos)) +#define consume(dist) \ + ((const void *)((const unsigned char *)src->data + \ + ((src->pos += dist) - dist))) + +ptrlen BinarySource_get_data(BinarySource *src, size_t wanted) +{ + if (!avail(wanted)) + return make_ptrlen("", 0); + + return make_ptrlen(consume(wanted), wanted); +} + +unsigned char BinarySource_get_byte(BinarySource *src) +{ + const unsigned char *ucp; + + if (!avail(1)) + return 0; + + ucp = consume(1); + return *ucp; +} + +int BinarySource_get_bool(BinarySource *src) +{ + const unsigned char *ucp; + + if (!avail(1)) + return 0; + + ucp = consume(1); + return *ucp != 0; +} + +unsigned BinarySource_get_uint16(BinarySource *src) +{ + const unsigned char *ucp; + + if (!avail(2)) + return 0; + + ucp = consume(2); + return GET_16BIT_MSB_FIRST(ucp); +} + +unsigned long BinarySource_get_uint32(BinarySource *src) +{ + const unsigned char *ucp; + + if (!avail(4)) + return 0; + + ucp = consume(4); + return GET_32BIT_MSB_FIRST(ucp); +} + +uint64 BinarySource_get_uint64(BinarySource *src) +{ + const unsigned char *ucp; + uint64 toret; + + if (!avail(8)) { + toret.hi = toret.lo = 0; + return toret; + } + + ucp = consume(8); + toret.hi = GET_32BIT_MSB_FIRST(ucp); + toret.lo = GET_32BIT_MSB_FIRST(ucp + 4); + return toret; +} + +ptrlen BinarySource_get_string(BinarySource *src) +{ + const unsigned char *ucp; + size_t len; + + if (!avail(4)) + return make_ptrlen("", 0); + + ucp = consume(4); + len = GET_32BIT_MSB_FIRST(ucp); + + if (!avail(len)) + return make_ptrlen("", 0); + + return make_ptrlen(consume(len), len); +} + +const char *BinarySource_get_asciz(BinarySource *src) +{ + const char *start, *end; + + if (src->err) + return ""; + + start = here; + end = memchr(start, '\0', src->len - src->pos); + if (!end) { + src->err = BSE_OUT_OF_DATA; + return ""; + } + + advance(end + 1 - start); + return start; +} + +ptrlen BinarySource_get_pstring(BinarySource *src) +{ + const unsigned char *ucp; + size_t len; + + if (!avail(1)) + return make_ptrlen("", 0); + + ucp = consume(1); + len = *ucp; + + if (!avail(len)) + return make_ptrlen("", 0); + + return make_ptrlen(consume(len), len); +} diff --git a/marshal.h b/marshal.h index ca5a009f..e7603adb 100644 --- a/marshal.h +++ b/marshal.h @@ -138,4 +138,127 @@ void BinarySink_put_stringsb(BinarySink *, struct strbuf *); void BinarySink_put_asciz(BinarySink *, const char *str); int BinarySink_put_pstring(BinarySink *, const char *str); +/* ---------------------------------------------------------------------- */ + +/* + * A complementary trait structure for _un_-marshalling. + * + * This structure contains client-visible data fields rather than + * methods, because that seemed more useful than leaving it totally + * opaque. But it's still got the self-pointer system that will allow + * the set of get_* macros to target one of these itself or any other + * type that 'derives' from it. So, for example, an SSH packet + * structure can act as a BinarySource while also having additional + * fields like the packet type. + */ +typedef enum BinarySourceError { + BSE_NO_ERROR, + BSE_OUT_OF_DATA, + BSE_INVALID +} BinarySourceError; +struct BinarySource { + /* + * (data, len) is the data block being decoded. pos is the current + * position within the block. + */ + const void *data; + size_t pos, len; + + /* + * 'err' indicates whether a decoding error has happened at any + * point. Once this has been set to something other than + * BSE_NO_ERROR, it shouldn't be changed by any unmarshalling + * function. So you can safely do a long sequence of get_foo() + * operations and then test err just once at the end, rather than + * having to conditionalise every single get. + * + * The unmarshalling functions should always return some value, + * even if a decoding error occurs. Generally on error they'll + * return zero (if numeric) or the empty string (if string-based), + * or some other appropriate default value for more complicated + * types. + * + * If the usual return value is dynamically allocated (e.g. a + * Bignum, or a normal C 'char *' string), then the error value is + * also dynamic in the same way. So you have to free exactly the + * same set of things whether or not there was a decoding error, + * which simplifies exit paths - for example, you could call a big + * pile of get_foo functions, then put the actual handling of the + * results under 'if (!get_err(src))', and then free everything + * outside that if. + */ + BinarySourceError err; + + /* + * Self-pointer for the implicit derivation trick, same as + * BinarySink above. + */ + BinarySource *binarysource_; +}; + +/* + * Implementation macros, similar to BinarySink. + */ +#define BinarySource_IMPLEMENTATION BinarySource binarysource_[1] +#define BinarySource_INIT__(obj, data_, len_) \ + ((obj)->data = (data_), \ + (obj)->len = (len_), \ + (obj)->pos = 0, \ + (obj)->err = BSE_NO_ERROR, \ + (obj)->binarysource_ = (obj)) +#define BinarySource_BARE_INIT(obj, data_, len_) \ + TYPECHECK(&(obj)->binarysource_ == (BinarySource **)0, \ + BinarySource_INIT__(obj, data_, len_)) +#define BinarySource_INIT(obj, data_, len_) \ + TYPECHECK(&(obj)->binarysource_ == (BinarySource (*)[1])0, \ + BinarySource_INIT__(BinarySource_UPCAST(obj), data_, len_)) +#define BinarySource_DOWNCAST(object, type) \ + TYPECHECK((object) == ((type *)0)->binarysource_, \ + ((type *)(((char *)(object)) - offsetof(type, binarysource_)))) +#define BinarySource_UPCAST(object) \ + TYPECHECK((object)->binarysource_ == (BinarySource *)0, \ + (object)->binarysource_) +#define BinarySource_COPIED(obj) \ + ((obj)->binarysource_->binarysource_ = (obj)->binarysource_) + +#define get_data(src, len) \ + BinarySource_get_data(BinarySource_UPCAST(src), len) +#define get_byte(src) \ + BinarySource_get_byte(BinarySource_UPCAST(src)) +#define get_bool(src) \ + BinarySource_get_bool(BinarySource_UPCAST(src)) +#define get_uint16(src) \ + BinarySource_get_uint16(BinarySource_UPCAST(src)) +#define get_uint32(src) \ + BinarySource_get_uint32(BinarySource_UPCAST(src)) +#define get_uint64(src) \ + BinarySource_get_uint64(BinarySource_UPCAST(src)) +#define get_string(src) \ + BinarySource_get_string(BinarySource_UPCAST(src)) +#define get_asciz(src) \ + BinarySource_get_asciz(BinarySource_UPCAST(src)) +#define get_pstring(src) \ + BinarySource_get_pstring(BinarySource_UPCAST(src)) +#define get_mp_ssh1(src) \ + BinarySource_get_mp_ssh1(BinarySource_UPCAST(src)) +#define get_mp_ssh2(src) \ + BinarySource_get_mp_ssh2(BinarySource_UPCAST(src)) + +#define get_err(src) (BinarySource_UPCAST(src)->err) +#define get_avail(src) (BinarySource_UPCAST(src)->len - \ + BinarySource_UPCAST(src)->pos) +#define get_ptr(src) \ + ((const void *)( \ + (const unsigned char *)(BinarySource_UPCAST(src)->data) + \ + BinarySource_UPCAST(src)->pos)) + +ptrlen BinarySource_get_data(BinarySource *, size_t); +unsigned char BinarySource_get_byte(BinarySource *); +int BinarySource_get_bool(BinarySource *); +unsigned BinarySource_get_uint16(BinarySource *); +unsigned long BinarySource_get_uint32(BinarySource *); +ptrlen BinarySource_get_string(BinarySource *); +const char *BinarySource_get_asciz(BinarySource *); +ptrlen BinarySource_get_pstring(BinarySource *); + #endif /* PUTTY_MARSHAL_H */ diff --git a/ssh.h b/ssh.h index 7a1c5766..3ab3a526 100644 --- a/ssh.h +++ b/ssh.h @@ -695,6 +695,8 @@ Bignum bignum_from_decimal(const char *decimal); void BinarySink_put_mp_ssh1(BinarySink *, Bignum); void BinarySink_put_mp_ssh2(BinarySink *, Bignum); +Bignum BinarySource_get_mp_ssh1(BinarySource *); +Bignum BinarySource_get_mp_ssh2(BinarySource *); #ifdef DEBUG void diagbn(char *prefix, Bignum md); diff --git a/sshbn.c b/sshbn.c index 39f8dfd8..1f0213c0 100644 --- a/sshbn.c +++ b/sshbn.c @@ -1624,12 +1624,12 @@ int ssh1_write_bignum(void *data, Bignum bn) void BinarySink_put_mp_ssh1(BinarySink *bs, Bignum bn) { - int len = ssh1_bignum_length(bn); + int bits = bignum_bitcount(bn); + int bytes = (bits + 7) / 8; int i; - int bitc = bignum_bitcount(bn); - put_uint16(bs, bitc); - for (i = len - 2; i--;) + put_uint16(bs, bits); + for (i = bytes; i--;) put_byte(bs, bignum_byte(bn, i)); } @@ -1643,6 +1643,40 @@ void BinarySink_put_mp_ssh2(BinarySink *bs, Bignum bn) put_byte(bs, bignum_byte(bn, i)); } +Bignum BinarySource_get_mp_ssh1(BinarySource *src) +{ + unsigned bitc = get_uint16(src); + ptrlen bytes = get_data(src, (bitc + 7) / 8); + if (get_err(src)) { + return bignum_from_long(0); + } else { + Bignum toret = bignum_from_bytes(bytes.ptr, bytes.len); + if (bignum_bitcount(toret) != bitc) { + src->err = BSE_INVALID; + freebn(toret); + toret = bignum_from_long(0); + } + return toret; + } +} + +Bignum BinarySource_get_mp_ssh2(BinarySource *src) +{ + ptrlen bytes = get_string(src); + if (get_err(src)) { + return bignum_from_long(0); + } else { + const unsigned char *p = bytes.ptr; + if ((bytes.len > 0 && + ((p[0] & 0x80) || + (p[0] == 0 && (bytes.len <= 1 || !(p[1] & 0x80)))))) { + src->err = BSE_INVALID; + return bignum_from_long(0); + } + return bignum_from_bytes(bytes.ptr, bytes.len); + } +} + /* * Compare two bignums. Returns like strcmp. */ From 7d8312e71f225d3f50bfbad4bd3032ad0f72eb55 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 27 May 2018 21:51:36 +0100 Subject: [PATCH 324/607] Rewrite SSH-1 RSA handling functions using BinarySource. The SSH-1 RSA key reading functions now have BinarySource-shaped get_* forms, although for the moment I'm still supporting the old API as a wrapper on the new one, because I haven't switched over the client code yet. Also, rsa_public_blob_len uses the new system internally, although its API is unchanged. --- marshal.h | 4 ++ ssh.h | 5 +++ sshrsa.c | 120 ++++++++++++++++++++++++++++++++---------------------- 3 files changed, 80 insertions(+), 49 deletions(-) diff --git a/marshal.h b/marshal.h index e7603adb..3b7a089f 100644 --- a/marshal.h +++ b/marshal.h @@ -243,6 +243,10 @@ struct BinarySource { BinarySource_get_mp_ssh1(BinarySource_UPCAST(src)) #define get_mp_ssh2(src) \ BinarySource_get_mp_ssh2(BinarySource_UPCAST(src)) +#define get_rsa_ssh1_pub(src, rsa, keystr, order) \ + BinarySource_get_rsa_ssh1_pub(BinarySource_UPCAST(src), rsa, keystr, order) +#define get_rsa_ssh1_priv(src, rsa) \ + BinarySource_get_rsa_ssh1_priv(BinarySource_UPCAST(src), rsa) #define get_err(src) (BinarySource_UPCAST(src)->err) #define get_avail(src) (BinarySource_UPCAST(src)->len - \ diff --git a/ssh.h b/ssh.h index 3ab3a526..21ab1593 100644 --- a/ssh.h +++ b/ssh.h @@ -182,8 +182,13 @@ typedef enum { RSA_SSH1_EXPONENT_FIRST, RSA_SSH1_MODULUS_FIRST } RsaSsh1Order; int rsa_ssh1_readpub(const unsigned char *data, int len, struct RSAKey *result, const unsigned char **keystr, RsaSsh1Order order); +void BinarySource_get_rsa_ssh1_pub( + BinarySource *src, struct RSAKey *result, + ptrlen *keystr, RsaSsh1Order order); int rsa_ssh1_readpriv(const unsigned char *data, int len, struct RSAKey *result); +void BinarySource_get_rsa_ssh1_priv( + BinarySource *src, struct RSAKey *rsa); int rsa_ssh1_encrypt(unsigned char *data, int length, struct RSAKey *key); Bignum rsa_ssh1_decrypt(Bignum input, struct RSAKey *key); void rsasanitise(struct RSAKey *key); diff --git a/sshrsa.c b/sshrsa.c index 2fcf5e6b..c0008dc1 100644 --- a/sshrsa.c +++ b/sshrsa.c @@ -10,53 +10,79 @@ #include "ssh.h" #include "misc.h" -int rsa_ssh1_readpub(const unsigned char *data, int len, struct RSAKey *result, - const unsigned char **keystr, RsaSsh1Order order) +void BinarySource_get_rsa_ssh1_pub( + BinarySource *src, struct RSAKey *rsa, ptrlen *keystr, RsaSsh1Order order) { - const unsigned char *p = data; - int i, n; - - if (len < 4) - return -1; + const unsigned char *start, *end; + unsigned bits; + Bignum e, m; - if (result) { - result->bits = 0; - for (i = 0; i < 4; i++) - result->bits = (result->bits << 8) + *p++; - } else - p += 4; + bits = get_uint32(src); + if (order == RSA_SSH1_EXPONENT_FIRST) { + e = get_mp_ssh1(src); + start = get_ptr(src); + m = get_mp_ssh1(src); + end = get_ptr(src); + } else { + start = get_ptr(src); + m = get_mp_ssh1(src); + end = get_ptr(src); + e = get_mp_ssh1(src); + } - len -= 4; + if (keystr) { + start += (end-start >= 2 ? 2 : end-start); + keystr->ptr = start; + keystr->len = end - start; + } - if (order == RSA_SSH1_EXPONENT_FIRST) { - n = ssh1_read_bignum(p, len, result ? &result->exponent : NULL); - if (n < 0) return -1; - p += n; - len -= n; + if (rsa) { + rsa->bits = bits; + rsa->exponent = e; + rsa->modulus = m; + rsa->bytes = (bignum_bitcount(m) + 7) / 8; + } else { + freebn(e); + freebn(m); } +} + +int rsa_ssh1_readpub(const unsigned char *data, int len, struct RSAKey *result, + const unsigned char **keystr, RsaSsh1Order order) +{ + BinarySource src; + ptrlen key_pl; + + BinarySource_BARE_INIT(&src, data, len); + get_rsa_ssh1_pub(&src, result, &key_pl, order); - n = ssh1_read_bignum(p, len, result ? &result->modulus : NULL); - if (n < 0 || (result && bignum_bitcount(result->modulus) == 0)) return -1; - if (result) - result->bytes = n - 2; if (keystr) - *keystr = p + 2; - p += n; - len -= n; - - if (order == RSA_SSH1_MODULUS_FIRST) { - n = ssh1_read_bignum(p, len, result ? &result->exponent : NULL); - if (n < 0) return -1; - p += n; - len -= n; - } - return p - data; + *keystr = key_pl.ptr; + + if (get_err(&src)) + return -1; + else + return key_pl.len; +} + +void BinarySource_get_rsa_ssh1_priv( + BinarySource *src, struct RSAKey *rsa) +{ + rsa->private_exponent = get_mp_ssh1(src); } int rsa_ssh1_readpriv(const unsigned char *data, int len, struct RSAKey *result) { - return ssh1_read_bignum(data, len, &result->private_exponent); + BinarySource src; + + BinarySource_BARE_INIT(&src, data, len); + get_rsa_ssh1_priv(&src, result); + + if (get_err(&src)) + return -1; + else + return src.pos; } int rsa_ssh1_encrypt(unsigned char *data, int length, struct RSAKey *key) @@ -455,25 +481,21 @@ void rsa_ssh1_public_blob(BinarySink *bs, struct RSAKey *key, /* Given a public blob, determine its length. */ int rsa_public_blob_len(void *data, int maxlen) { - unsigned char *p = (unsigned char *)data; - int n; + BinarySource src[1]; - if (maxlen < 4) - return -1; - p += 4; /* length word */ - maxlen -= 4; + BinarySource_BARE_INIT(src, data, maxlen); - n = ssh1_read_bignum(p, maxlen, NULL); /* exponent */ - if (n < 0) - return -1; - p += n; + /* Expect a length word, then exponent and modulus. (It doesn't + * even matter which order.) */ + get_uint32(src); + freebn(get_mp_ssh1(src)); + freebn(get_mp_ssh1(src)); - n = ssh1_read_bignum(p, maxlen, NULL); /* modulus */ - if (n < 0) + if (get_err(src)) return -1; - p += n; - return p - (unsigned char *)data; + /* Return the number of bytes consumed. */ + return src->pos; } void freersakey(struct RSAKey *key) From 2cb4d8913515d1254b0d1760e3c61ae353c424da Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 2 Jun 2018 09:41:39 +0100 Subject: [PATCH 325/607] Replace sftp_pkt_get* with BinarySource. This is the first major piece of code converted to the new unmarshalling system, and allows me to remove all the sftp_pkt_get* functions in sftp.c that were previously duplicating standard decode logic. --- sftp.c | 253 +++++++++++++++++++++++---------------------------------- sftp.h | 1 + 2 files changed, 103 insertions(+), 151 deletions(-) diff --git a/sftp.c b/sftp.c index ad153396..7e7f1ffa 100644 --- a/sftp.c +++ b/sftp.c @@ -19,6 +19,7 @@ struct sftp_packet { unsigned savedpos; int type; BinarySink_IMPLEMENTATION; + BinarySource_IMPLEMENTATION; }; static const char *fxp_error_message; @@ -63,10 +64,8 @@ static struct sftp_packet *sftp_pkt_init(int pkt_type) static void BinarySink_put_fxp_attrs(BinarySink *bs, struct fxp_attrs attrs) { put_uint32(bs, attrs.flags); - if (attrs.flags & SSH_FILEXFER_ATTR_SIZE) { - put_uint32(bs, attrs.size.hi); - put_uint32(bs, attrs.size.lo); - } + if (attrs.flags & SSH_FILEXFER_ATTR_SIZE) + put_uint64(bs, attrs.size); if (attrs.flags & SSH_FILEXFER_ATTR_UIDGID) { put_uint32(bs, attrs.uid); put_uint32(bs, attrs.gid); @@ -93,81 +92,39 @@ static void BinarySink_put_fxp_attrs(BinarySink *bs, struct fxp_attrs attrs) * SFTP packet decode functions. */ -static int sftp_pkt_getbyte(struct sftp_packet *pkt, unsigned char *ret) -{ - if (pkt->length - pkt->savedpos < 1) - return 0; - *ret = (unsigned char) pkt->data[pkt->savedpos]; - pkt->savedpos++; - return 1; -} -static int sftp_pkt_getuint32(struct sftp_packet *pkt, unsigned long *ret) -{ - if (pkt->length - pkt->savedpos < 4) - return 0; - *ret = GET_32BIT(pkt->data + pkt->savedpos); - pkt->savedpos += 4; - return 1; -} -static int sftp_pkt_getstring(struct sftp_packet *pkt, - char **p, int *length) -{ - *p = NULL; - if (pkt->length - pkt->savedpos < 4) - return 0; - *length = toint(GET_32BIT(pkt->data + pkt->savedpos)); - pkt->savedpos += 4; - if ((int)(pkt->length - pkt->savedpos) < *length || *length < 0) { - *length = 0; - return 0; - } - *p = pkt->data + pkt->savedpos; - pkt->savedpos += *length; - return 1; -} -static int sftp_pkt_getattrs(struct sftp_packet *pkt, struct fxp_attrs *ret) +static int BinarySource_get_fxp_attrs(BinarySource *src, + struct fxp_attrs *attrs) { - if (!sftp_pkt_getuint32(pkt, &ret->flags)) - return 0; - if (ret->flags & SSH_FILEXFER_ATTR_SIZE) { - unsigned long hi, lo; - if (!sftp_pkt_getuint32(pkt, &hi) || - !sftp_pkt_getuint32(pkt, &lo)) - return 0; - ret->size = uint64_make(hi, lo); - } - if (ret->flags & SSH_FILEXFER_ATTR_UIDGID) { - if (!sftp_pkt_getuint32(pkt, &ret->uid) || - !sftp_pkt_getuint32(pkt, &ret->gid)) - return 0; - } - if (ret->flags & SSH_FILEXFER_ATTR_PERMISSIONS) { - if (!sftp_pkt_getuint32(pkt, &ret->permissions)) - return 0; + attrs->flags = get_uint32(src); + if (attrs->flags & SSH_FILEXFER_ATTR_SIZE) + attrs->size = get_uint64(src); + if (attrs->flags & SSH_FILEXFER_ATTR_UIDGID) { + attrs->uid = get_uint32(src); + attrs->gid = get_uint32(src); } - if (ret->flags & SSH_FILEXFER_ATTR_ACMODTIME) { - if (!sftp_pkt_getuint32(pkt, &ret->atime) || - !sftp_pkt_getuint32(pkt, &ret->mtime)) - return 0; + if (attrs->flags & SSH_FILEXFER_ATTR_PERMISSIONS) + attrs->permissions = get_uint32(src); + if (attrs->flags & SSH_FILEXFER_ATTR_ACMODTIME) { + attrs->atime = get_uint32(src); + attrs->mtime = get_uint32(src); } - if (ret->flags & SSH_FILEXFER_ATTR_EXTENDED) { - unsigned long count; - if (!sftp_pkt_getuint32(pkt, &count)) - return 0; + if (attrs->flags & SSH_FILEXFER_ATTR_EXTENDED) { + unsigned long count = get_uint32(src); while (count--) { - char *str; - int len; /* * We should try to analyse these, if we ever find one * we recognise. */ - if (!sftp_pkt_getstring(pkt, &str, &len) || - !sftp_pkt_getstring(pkt, &str, &len)) - return 0; + get_string(src); + get_string(src); } } return 1; } + +#define get_fxp_attrs(bs, attrs) \ + BinarySource_get_fxp_attrs(BinarySource_UPCAST(bs), attrs) + static void sftp_pkt_free(struct sftp_packet *pkt) { if (pkt->data) @@ -190,7 +147,6 @@ struct sftp_packet *sftp_recv(void) { struct sftp_packet *pkt; char x[4]; - unsigned char uc; if (!sftp_recvdata(x, 4)) return NULL; @@ -205,11 +161,12 @@ struct sftp_packet *sftp_recv(void) return NULL; } - if (!sftp_pkt_getbyte(pkt, &uc)) { + BinarySource_INIT(pkt, pkt->data, pkt->length); + pkt->type = get_byte(pkt); + + if (get_err(pkt)) { sftp_pkt_free(pkt); return NULL; - } else { - pkt->type = uc; } return pkt; @@ -315,8 +272,7 @@ void sftp_register(struct sftp_request *req) struct sftp_request *sftp_find_request(struct sftp_packet *pktin) { - unsigned long id; - unsigned fid; + unsigned id; struct sftp_request *req; if (!pktin) { @@ -324,13 +280,13 @@ struct sftp_request *sftp_find_request(struct sftp_packet *pktin) return NULL; } - if (!sftp_pkt_getuint32(pktin, &id)) { + id = get_uint32(pktin); + if (get_err(pktin)) { fxp_internal_error("did not receive a valid SFTP packet\n"); return NULL; } - fid = (unsigned)id; - req = find234(sftp_requests, &fid, sftp_reqfind); + req = find234(sftp_requests, &id, sftp_reqfind); if (!req || !req->registered) { fxp_internal_error("request ID mismatch\n"); return NULL; @@ -371,12 +327,11 @@ static int fxp_got_status(struct sftp_packet *pktin) fxp_error_message = "expected FXP_STATUS packet"; fxp_errtype = -1; } else { - unsigned long ul; - if (!sftp_pkt_getuint32(pktin, &ul)) { + fxp_errtype = get_uint32(pktin); + if (get_err(pktin)) { fxp_error_message = "malformed FXP_STATUS packet"; fxp_errtype = -1; } else { - fxp_errtype = ul; if (fxp_errtype < 0 || fxp_errtype >= sizeof(messages) / sizeof(*messages)) fxp_error_message = "unknown error code"; @@ -431,7 +386,8 @@ int fxp_init(void) sftp_pkt_free(pktin); return 0; } - if (!sftp_pkt_getuint32(pktin, &remotever)) { + remotever = get_uint32(pktin); + if (get_err(pktin)) { fxp_internal_error("malformed FXP_VERSION packet"); sftp_pkt_free(pktin); return 0; @@ -475,22 +431,24 @@ char *fxp_realpath_recv(struct sftp_packet *pktin, struct sftp_request *req) if (pktin->type == SSH_FXP_NAME) { unsigned long count; - char *path; - int len; + char *path; + ptrlen name; - if (!sftp_pkt_getuint32(pktin, &count) || count != 1) { + count = get_uint32(pktin); + if (get_err(pktin) || count != 1) { fxp_internal_error("REALPATH did not return name count of 1\n"); sftp_pkt_free(pktin); return NULL; } - if (!sftp_pkt_getstring(pktin, &path, &len)) { + name = get_string(pktin); + if (get_err(pktin)) { fxp_internal_error("REALPATH returned malformed FXP_NAME\n"); sftp_pkt_free(pktin); return NULL; } - path = mkstr(make_ptrlen(path, len)); + path = mkstr(name); sftp_pkt_free(pktin); - return path; + return path; } else { fxp_got_status(pktin); sftp_pkt_free(pktin); @@ -520,26 +478,31 @@ struct sftp_request *fxp_open_send(const char *path, int type, return req; } +static struct fxp_handle *fxp_got_handle(struct sftp_packet *pktin) +{ + ptrlen id; + struct fxp_handle *handle; + + id = get_string(pktin); + if (get_err(pktin)) { + fxp_internal_error("received malformed FXP_HANDLE"); + sftp_pkt_free(pktin); + return NULL; + } + handle = snew(struct fxp_handle); + handle->hstring = mkstr(id); + handle->hlen = id.len; + sftp_pkt_free(pktin); + return handle; +} + struct fxp_handle *fxp_open_recv(struct sftp_packet *pktin, struct sftp_request *req) { sfree(req); if (pktin->type == SSH_FXP_HANDLE) { - char *hstring; - struct fxp_handle *handle; - int len; - - if (!sftp_pkt_getstring(pktin, &hstring, &len)) { - fxp_internal_error("OPEN returned malformed FXP_HANDLE\n"); - sftp_pkt_free(pktin); - return NULL; - } - handle = snew(struct fxp_handle); - handle->hstring = mkstr(make_ptrlen(hstring, len)); - handle->hlen = len; - sftp_pkt_free(pktin); - return handle; + return fxp_got_handle(pktin); } else { fxp_got_status(pktin); sftp_pkt_free(pktin); @@ -568,20 +531,7 @@ struct fxp_handle *fxp_opendir_recv(struct sftp_packet *pktin, { sfree(req); if (pktin->type == SSH_FXP_HANDLE) { - char *hstring; - struct fxp_handle *handle; - int len; - - if (!sftp_pkt_getstring(pktin, &hstring, &len)) { - fxp_internal_error("OPENDIR returned malformed FXP_HANDLE\n"); - sftp_pkt_free(pktin); - return NULL; - } - handle = snew(struct fxp_handle); - handle->hstring = mkstr(make_ptrlen(hstring, len)); - handle->hlen = len; - sftp_pkt_free(pktin); - return handle; + return fxp_got_handle(pktin); } else { fxp_got_status(pktin); sftp_pkt_free(pktin); @@ -736,18 +686,24 @@ struct sftp_request *fxp_stat_send(const char *fname) return req; } +static int fxp_got_attrs(struct sftp_packet *pktin, struct fxp_attrs *attrs) +{ + get_fxp_attrs(pktin, attrs); + if (get_err(pktin)) { + fxp_internal_error("malformed SSH_FXP_ATTRS packet"); + sftp_pkt_free(pktin); + return 0; + } + sftp_pkt_free(pktin); + return 1; +} + int fxp_stat_recv(struct sftp_packet *pktin, struct sftp_request *req, struct fxp_attrs *attrs) { sfree(req); if (pktin->type == SSH_FXP_ATTRS) { - if (!sftp_pkt_getattrs(pktin, attrs)) { - fxp_internal_error("malformed SSH_FXP_ATTRS packet"); - sftp_pkt_free(pktin); - return 0; - } - sftp_pkt_free(pktin); - return 1; + return fxp_got_attrs(pktin, attrs); } else { fxp_got_status(pktin); sftp_pkt_free(pktin); @@ -773,11 +729,7 @@ int fxp_fstat_recv(struct sftp_packet *pktin, struct sftp_request *req, { sfree(req); if (pktin->type == SSH_FXP_ATTRS) { - if (!sftp_pkt_getattrs(pktin, attrs)) { - fxp_internal_error("malformed SSH_FXP_ATTRS packet"); - sftp_pkt_free(pktin); - return 0; - } + return fxp_got_attrs(pktin, attrs); sftp_pkt_free(pktin); return 1; } else { @@ -871,24 +823,24 @@ int fxp_read_recv(struct sftp_packet *pktin, struct sftp_request *req, { sfree(req); if (pktin->type == SSH_FXP_DATA) { - char *str; - int rlen; + ptrlen data; - if (!sftp_pkt_getstring(pktin, &str, &rlen)) { + data = get_string(pktin); + if (get_err(pktin)) { fxp_internal_error("READ returned malformed SSH_FXP_DATA packet"); sftp_pkt_free(pktin); return -1; } - if (rlen > len || rlen < 0) { + if (data.len > len) { fxp_internal_error("READ returned more bytes than requested"); sftp_pkt_free(pktin); return -1; } - memcpy(buffer, str, rlen); + memcpy(buffer, data.ptr, data.len); sftp_pkt_free(pktin); - return rlen; + return data.len; } else { fxp_got_status(pktin); sftp_pkt_free(pktin); @@ -920,6 +872,8 @@ struct fxp_names *fxp_readdir_recv(struct sftp_packet *pktin, struct fxp_names *ret; unsigned long i; + i = get_uint32(pktin); + /* * Sanity-check the number of names. Minimum is obviously * zero. Maximum is the remaining space in the packet @@ -928,8 +882,7 @@ struct fxp_names *fxp_readdir_recv(struct sftp_packet *pktin, * longname, 4 for a set of attribute flags indicating that * no other attributes are supplied). */ - if (!sftp_pkt_getuint32(pktin, &i) || - i > (pktin->length-pktin->savedpos)/12) { + if (get_err(pktin) || i > get_avail(pktin) / 12) { fxp_internal_error("malformed FXP_NAME packet"); sftp_pkt_free(pktin); return NULL; @@ -950,23 +903,21 @@ struct fxp_names *fxp_readdir_recv(struct sftp_packet *pktin, ret->nnames = i; ret->names = snewn(ret->nnames, struct fxp_name); for (i = 0; i < (unsigned long)ret->nnames; i++) { - char *str1, *str2; - int len1, len2; - if (!sftp_pkt_getstring(pktin, &str1, &len1) || - !sftp_pkt_getstring(pktin, &str2, &len2) || - !sftp_pkt_getattrs(pktin, &ret->names[i].attrs)) { - fxp_internal_error("malformed FXP_NAME packet"); - while (i--) { - sfree(ret->names[i].filename); - sfree(ret->names[i].longname); - } - sfree(ret->names); - sfree(ret); - sfree(pktin); - return NULL; - } - ret->names[i].filename = mkstr(make_ptrlen(str1, len1)); - ret->names[i].longname = mkstr(make_ptrlen(str2, len2)); + ret->names[i].filename = mkstr(get_string(pktin)); + ret->names[i].longname = mkstr(get_string(pktin)); + get_fxp_attrs(pktin, &ret->names[i].attrs); + } + + if (get_err(pktin)) { + fxp_internal_error("malformed FXP_NAME packet"); + for (i = 0; i < (unsigned long)ret->nnames; i++) { + sfree(ret->names[i].filename); + sfree(ret->names[i].longname); + } + sfree(ret->names); + sfree(ret); + sfree(pktin); + return NULL; } sftp_pkt_free(pktin); return ret; diff --git a/sftp.h b/sftp.h index b30e49f4..7e93356b 100644 --- a/sftp.h +++ b/sftp.h @@ -2,6 +2,7 @@ * sftp.h: definitions for SFTP and the sftp.c routines. */ +#include "defs.h" #include "int64.h" #define SSH_FXP_INIT 1 /* 0x1 */ From 7535f645aba54c4bdbae0435036bba677c469360 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 27 May 2018 18:13:53 +0100 Subject: [PATCH 326/607] Replace ssh_pkt_get* with BinarySource. The 'savedpos' field in 'struct Packet', which was already unused on the output side after I threw away ssh_pkt_addstring_start, is now unused on the input side too because a BinarySource implementation has taken over. So it's now completely gone. --- ssh.c | 951 +++++++++++++++++++++++----------------------------------- 1 file changed, 372 insertions(+), 579 deletions(-) diff --git a/ssh.c b/ssh.c index 4e87dc0a..4084f007 100644 --- a/ssh.c +++ b/ssh.c @@ -677,20 +677,16 @@ struct Packet { unsigned long sequence; /* SSH-2 incoming sequence number */ unsigned char *data; /* allocated storage */ unsigned char *body; /* offset of payload within `data' */ - long savedpos; /* dual-purpose saved packet position: see below */ long maxlen; /* amount of storage allocated for `data' */ long encrypted_len; /* for SSH-2 total-size counting */ /* - * A note on the 'length' and 'savedpos' fields above. + * A note on the 'length' field above. * * Incoming packets are set up so that pkt->length is measured * relative to pkt->body, which itself points to a few bytes after * pkt->data (skipping some uninteresting header fields including - * the packet type code). The ssh_pkt_get* functions all expect - * this setup, and they also use pkt->savedpos to indicate how far - * through the packet being decoded they've got - and that, too, - * is an offset from pkt->body rather than pkt->data. + * the packet type code). * * During construction of an outgoing packet, however, pkt->length * is measured relative to the base pointer pkt->data, and @@ -707,6 +703,7 @@ struct Packet { const char *additional_log_text; BinarySink_IMPLEMENTATION; + BinarySource_IMPLEMENTATION; }; static void ssh1_protocol_setup(Ssh ssh); @@ -721,9 +718,6 @@ static void ssh_throttle_all(Ssh ssh, int enable, int bufsize); static void ssh2_set_window(struct ssh_channel *c, int newwin); static int ssh_sendbuffer(void *handle); static int ssh_do_close(Ssh ssh, int notify_exit); -static unsigned long ssh_pkt_getuint32(struct Packet *pkt); -static int ssh2_pkt_getbool(struct Packet *pkt); -static void ssh_pkt_getstring(struct Packet *pkt, char **p, int *length); static void ssh2_timer(void *ctx, unsigned long now); static int ssh2_timer_update(Ssh ssh, unsigned long rekey_time); #ifndef NO_GSSAPI @@ -1403,14 +1397,14 @@ static struct Packet *ssh_new_packet(void) return pkt; } -static void ssh1_log_incoming_packet(Ssh ssh, struct Packet *pkt) +static void ssh1_log_incoming_packet(Ssh ssh, const struct Packet *pkt) { int nblanks = 0; struct logblank_t blanks[4]; - char *str; - int slen; + ptrlen str; + BinarySource src[1]; - pkt->savedpos = 0; + BinarySource_BARE_INIT(src, pkt->body, pkt->length); if (ssh->logomitdata && (pkt->type == SSH1_SMSG_STDOUT_DATA || @@ -1418,12 +1412,12 @@ static void ssh1_log_incoming_packet(Ssh ssh, struct Packet *pkt) pkt->type == SSH1_MSG_CHANNEL_DATA)) { /* "Session data" packets - omit the data string. */ if (pkt->type == SSH1_MSG_CHANNEL_DATA) - ssh_pkt_getuint32(pkt); /* skip channel id */ - blanks[nblanks].offset = pkt->savedpos + 4; - blanks[nblanks].type = PKTLOG_OMIT; - ssh_pkt_getstring(pkt, &str, &slen); - if (str) { - blanks[nblanks].len = slen; + get_uint32(src); /* skip channel id */ + str = get_string(src); + if (!get_err(src)) { + blanks[nblanks].offset = src->pos - str.len; + blanks[nblanks].type = PKTLOG_OMIT; + blanks[nblanks].len = str.len; nblanks++; } } @@ -1433,37 +1427,33 @@ static void ssh1_log_incoming_packet(Ssh ssh, struct Packet *pkt) 0, NULL); } -static void ssh1_log_outgoing_packet(Ssh ssh, struct Packet *pkt) +static void ssh1_log_outgoing_packet(Ssh ssh, const struct Packet *pkt) { int nblanks = 0; struct logblank_t blanks[4]; - char *str; - int slen; + ptrlen str; + BinarySource src[1]; /* * For outgoing packets, pkt->length represents the length of the * whole packet starting at pkt->data (including some header), and * pkt->body refers to the point within that where the log-worthy - * payload begins. However, incoming packets expect pkt->length to - * represent only the payload length (that is, it's measured from - * pkt->body not from pkt->data). Temporarily adjust our outgoing - * packet to conform to the incoming-packet semantics, so that we - * can analyse it with the ssh_pkt_get functions. + * payload begins. */ - pkt->length -= (pkt->body - pkt->data); - pkt->savedpos = 0; + BinarySource_BARE_INIT(src, pkt->body, + pkt->length - (pkt->body - pkt->data)); if (ssh->logomitdata && (pkt->type == SSH1_CMSG_STDIN_DATA || pkt->type == SSH1_MSG_CHANNEL_DATA)) { /* "Session data" packets - omit the data string. */ if (pkt->type == SSH1_MSG_CHANNEL_DATA) - ssh_pkt_getuint32(pkt); /* skip channel id */ - blanks[nblanks].offset = pkt->savedpos + 4; - blanks[nblanks].type = PKTLOG_OMIT; - ssh_pkt_getstring(pkt, &str, &slen); - if (str) { - blanks[nblanks].len = slen; + get_uint32(src); /* skip channel id */ + str = get_string(src); + if (!get_err(src)) { + blanks[nblanks].offset = src->pos - str.len; + blanks[nblanks].type = PKTLOG_OMIT; + blanks[nblanks].len = str.len; nblanks++; } } @@ -1489,13 +1479,12 @@ static void ssh1_log_outgoing_packet(Ssh ssh, struct Packet *pkt) * an X connection without having session blanking enabled is * likely to leak your cookie into the log. */ - pkt->savedpos = 0; - ssh_pkt_getstring(pkt, &str, &slen); - blanks[nblanks].offset = pkt->savedpos; - blanks[nblanks].type = PKTLOG_BLANK; - ssh_pkt_getstring(pkt, &str, &slen); - if (str) { - blanks[nblanks].len = pkt->savedpos - blanks[nblanks].offset; + get_string(src); /* skip protocol name */ + str = get_string(src); + if (!get_err(src)) { + blanks[nblanks].offset = src->pos - str.len; + blanks[nblanks].type = PKTLOG_BLANK; + blanks[nblanks].len = str.len; nblanks++; } } @@ -1504,12 +1493,6 @@ static void ssh1_log_outgoing_packet(Ssh ssh, struct Packet *pkt) ssh1_pkt_type(pkt->data[12]), pkt->body, pkt->length, nblanks, blanks, NULL, 0, NULL); - - /* - * Undo the above adjustment of pkt->length, to put the packet - * back in the state we found it. - */ - pkt->length += (pkt->body - pkt->data); } /* @@ -1608,7 +1591,7 @@ static void ssh1_rdpkt(Ssh ssh) if (ssh->logctx) ssh1_log_incoming_packet(ssh, st->pktin); - st->pktin->savedpos = 0; + BinarySource_INIT(st->pktin, st->pktin->body, st->pktin->length); pq_push(&ssh->pq_full, st->pktin); queue_idempotent_callback(&ssh->pq_full_consumer); @@ -1616,27 +1599,27 @@ static void ssh1_rdpkt(Ssh ssh) crFinishV; } -static void ssh2_log_incoming_packet(Ssh ssh, struct Packet *pkt) +static void ssh2_log_incoming_packet(Ssh ssh, const struct Packet *pkt) { int nblanks = 0; struct logblank_t blanks[4]; - char *str; - int slen; + ptrlen str; + BinarySource src[1]; - pkt->savedpos = 0; + BinarySource_BARE_INIT(src, pkt->body, pkt->length); if (ssh->logomitdata && (pkt->type == SSH2_MSG_CHANNEL_DATA || pkt->type == SSH2_MSG_CHANNEL_EXTENDED_DATA)) { /* "Session data" packets - omit the data string. */ - ssh_pkt_getuint32(pkt); /* skip channel id */ + get_uint32(src); /* skip channel id */ if (pkt->type == SSH2_MSG_CHANNEL_EXTENDED_DATA) - ssh_pkt_getuint32(pkt); /* skip extended data type */ - blanks[nblanks].offset = pkt->savedpos + 4; - blanks[nblanks].type = PKTLOG_OMIT; - ssh_pkt_getstring(pkt, &str, &slen); - if (str) { - blanks[nblanks].len = slen; + get_uint32(src); /* skip extended data type */ + str = get_string(src); + if (!get_err(src)) { + blanks[nblanks].offset = src->pos - str.len; + blanks[nblanks].type = PKTLOG_OMIT; + blanks[nblanks].len = str.len; nblanks++; } } @@ -1647,38 +1630,34 @@ static void ssh2_log_incoming_packet(Ssh ssh, struct Packet *pkt) 0, NULL); } -static void ssh2_log_outgoing_packet(Ssh ssh, struct Packet *pkt) +static void ssh2_log_outgoing_packet(Ssh ssh, const struct Packet *pkt) { int nblanks = 0; struct logblank_t blanks[4]; - char *str; - int slen; + ptrlen str; + BinarySource src[1]; /* * For outgoing packets, pkt->length represents the length of the * whole packet starting at pkt->data (including some header), and * pkt->body refers to the point within that where the log-worthy - * payload begins. However, incoming packets expect pkt->length to - * represent only the payload length (that is, it's measured from - * pkt->body not from pkt->data). Temporarily adjust our outgoing - * packet to conform to the incoming-packet semantics, so that we - * can analyse it with the ssh_pkt_get functions. + * payload begins. */ - pkt->length -= (pkt->body - pkt->data); - pkt->savedpos = 0; + BinarySource_BARE_INIT(src, pkt->body, + pkt->length - (pkt->body - pkt->data)); if (ssh->logomitdata && (pkt->type == SSH2_MSG_CHANNEL_DATA || pkt->type == SSH2_MSG_CHANNEL_EXTENDED_DATA)) { /* "Session data" packets - omit the data string. */ - ssh_pkt_getuint32(pkt); /* skip channel id */ + get_uint32(src); /* skip channel id */ if (pkt->type == SSH2_MSG_CHANNEL_EXTENDED_DATA) - ssh_pkt_getuint32(pkt); /* skip extended data type */ - blanks[nblanks].offset = pkt->savedpos + 4; - blanks[nblanks].type = PKTLOG_OMIT; - ssh_pkt_getstring(pkt, &str, &slen); - if (str) { - blanks[nblanks].len = slen; + get_uint32(src); /* skip extended data type */ + str = get_string(src); + if (!get_err(src)) { + blanks[nblanks].offset = src->pos - str.len; + blanks[nblanks].type = PKTLOG_OMIT; + blanks[nblanks].len = str.len; nblanks++; } } @@ -1686,25 +1665,23 @@ static void ssh2_log_outgoing_packet(Ssh ssh, struct Packet *pkt) if (pkt->type == SSH2_MSG_USERAUTH_REQUEST && conf_get_int(ssh->conf, CONF_logomitpass)) { /* If this is a password packet, blank the password(s). */ - pkt->savedpos = 0; - ssh_pkt_getstring(pkt, &str, &slen); - ssh_pkt_getstring(pkt, &str, &slen); - ssh_pkt_getstring(pkt, &str, &slen); - if (slen == 8 && !memcmp(str, "password", 8)) { - ssh2_pkt_getbool(pkt); + get_string(src); /* username */ + get_string(src); /* service name */ + str = get_string(src); /* auth method */ + if (ptrlen_eq_string(str, "password")) { + get_bool(src); /* Blank the password field. */ - blanks[nblanks].offset = pkt->savedpos; - blanks[nblanks].type = PKTLOG_BLANK; - ssh_pkt_getstring(pkt, &str, &slen); - if (str) { - blanks[nblanks].len = pkt->savedpos - blanks[nblanks].offset; + str = get_string(src); + if (!get_err(src)) { + blanks[nblanks].offset = src->pos - str.len; + blanks[nblanks].type = PKTLOG_BLANK; + blanks[nblanks].len = str.len; nblanks++; /* If there's another password field beyond it (change of * password), blank that too. */ - ssh_pkt_getstring(pkt, &str, &slen); - if (str) - blanks[nblanks-1].len = - pkt->savedpos - blanks[nblanks].offset; + str = get_string(src); + if (!get_err(src)) + blanks[nblanks-1].len = src->pos - blanks[nblanks].offset; } } } else if (ssh->pkt_actx == SSH2_PKTCTX_KBDINTER && @@ -1712,16 +1689,13 @@ static void ssh2_log_outgoing_packet(Ssh ssh, struct Packet *pkt) conf_get_int(ssh->conf, CONF_logomitpass)) { /* If this is a keyboard-interactive response packet, blank * the responses. */ - pkt->savedpos = 0; - ssh_pkt_getuint32(pkt); - blanks[nblanks].offset = pkt->savedpos; + get_uint32(src); + blanks[nblanks].offset = src->pos; blanks[nblanks].type = PKTLOG_BLANK; - while (1) { - ssh_pkt_getstring(pkt, &str, &slen); - if (!str) - break; - } - blanks[nblanks].len = pkt->savedpos - blanks[nblanks].offset; + do { + str = get_string(src); + } while (!get_err(src)); + blanks[nblanks].len = src->pos - blanks[nblanks].offset; nblanks++; } else if (pkt->type == SSH2_MSG_CHANNEL_REQUEST && conf_get_int(ssh->conf, CONF_logomitpass)) { @@ -1735,18 +1709,17 @@ static void ssh2_log_outgoing_packet(Ssh ssh, struct Packet *pkt) * an X connection without having session blanking enabled is * likely to leak your cookie into the log. */ - pkt->savedpos = 0; - ssh_pkt_getuint32(pkt); - ssh_pkt_getstring(pkt, &str, &slen); - if (slen == 7 && !memcmp(str, "x11-req", 0)) { - ssh2_pkt_getbool(pkt); - ssh2_pkt_getbool(pkt); - ssh_pkt_getstring(pkt, &str, &slen); - blanks[nblanks].offset = pkt->savedpos; - blanks[nblanks].type = PKTLOG_BLANK; - ssh_pkt_getstring(pkt, &str, &slen); - if (str) { - blanks[nblanks].len = pkt->savedpos - blanks[nblanks].offset; + get_uint32(src); + str = get_string(src); + if (ptrlen_eq_string(str, "x11-req")) { + get_bool(src); + get_bool(src); + get_string(src); + str = get_string(src); + if (!get_err(src)) { + blanks[nblanks].offset = src->pos - str.len; + blanks[nblanks].type = PKTLOG_BLANK; + blanks[nblanks].len = str.len; nblanks++; } } @@ -1757,12 +1730,6 @@ static void ssh2_log_outgoing_packet(Ssh ssh, struct Packet *pkt) pkt->body, pkt->length, nblanks, blanks, &ssh->v2_outgoing_sequence, pkt->downstream_id, pkt->additional_log_text); - - /* - * Undo the above adjustment of pkt->length, to put the packet - * back in the state we found it. - */ - pkt->length += (pkt->body - pkt->data); } static void ssh2_rdpkt(Ssh ssh) @@ -2046,7 +2013,7 @@ static void ssh2_rdpkt(Ssh ssh) if (ssh->logctx) ssh2_log_incoming_packet(ssh, st->pktin); - st->pktin->savedpos = 0; + BinarySource_INIT(st->pktin, st->pktin->body, st->pktin->length); pq_push(&ssh->pq_full, st->pktin); queue_idempotent_callback(&ssh->pq_full_consumer); @@ -2110,7 +2077,7 @@ static void ssh2_bare_connection_rdpkt(Ssh ssh) if (ssh->logctx) ssh2_log_incoming_packet(ssh, st->pktin); - st->pktin->savedpos = 0; + BinarySource_INIT(st->pktin, st->pktin->body, st->pktin->length); pq_push(&ssh->pq_full, st->pktin); queue_idempotent_callback(&ssh->pq_full_consumer); @@ -2722,97 +2689,6 @@ void bndebug(char *string, Bignum b) } #endif -/* - * Packet decode functions for both SSH-1 and SSH-2. - */ -static unsigned long ssh_pkt_getuint32(struct Packet *pkt) -{ - unsigned long value; - if (pkt->length - pkt->savedpos < 4) - return 0; /* arrgh, no way to decline (FIXME?) */ - value = GET_32BIT(pkt->body + pkt->savedpos); - pkt->savedpos += 4; - return value; -} -static int ssh2_pkt_getbool(struct Packet *pkt) -{ - unsigned long value; - if (pkt->length - pkt->savedpos < 1) - return 0; /* arrgh, no way to decline (FIXME?) */ - value = pkt->body[pkt->savedpos] != 0; - pkt->savedpos++; - return value; -} -static void ssh_pkt_getstring(struct Packet *pkt, char **p, int *length) -{ - int len; - *p = NULL; - *length = 0; - if (pkt->length - pkt->savedpos < 4) - return; - len = toint(GET_32BIT(pkt->body + pkt->savedpos)); - if (len < 0) - return; - *length = len; - pkt->savedpos += 4; - if (pkt->length - pkt->savedpos < *length) - return; - *p = (char *)(pkt->body + pkt->savedpos); - pkt->savedpos += *length; -} -static void *ssh_pkt_getdata(struct Packet *pkt, int length) -{ - if (pkt->length - pkt->savedpos < length) - return NULL; - pkt->savedpos += length; - return pkt->body + (pkt->savedpos - length); -} -static int ssh1_pkt_getrsakey(struct Packet *pkt, struct RSAKey *key, - const unsigned char **keystr) -{ - int j; - - j = rsa_ssh1_readpub(pkt->body + pkt->savedpos, - pkt->length - pkt->savedpos, - key, keystr, RSA_SSH1_EXPONENT_FIRST); - - if (j < 0) - return FALSE; - - pkt->savedpos += j; - assert(pkt->savedpos < pkt->length); - - return TRUE; -} -static Bignum ssh1_pkt_getmp(struct Packet *pkt) -{ - int j; - Bignum b; - - j = ssh1_read_bignum(pkt->body + pkt->savedpos, - pkt->length - pkt->savedpos, &b); - - if (j < 0) - return NULL; - - pkt->savedpos += j; - return b; -} -static Bignum ssh2_pkt_getmp(struct Packet *pkt) -{ - char *p; - int length; - Bignum b; - - ssh_pkt_getstring(pkt, &p, &length); - if (!p) - return NULL; - if (p[0] & 0x80) - return NULL; - b = bignum_from_bytes(p, length); - return b; -} - /* * Helper function to add an SSH-2 signature blob to a packet. Expects * to be shown the public key blob as well as the signature blob. @@ -4163,13 +4039,13 @@ static void do_ssh1_login(void *vctx) struct Packet *pktin; int i, j, ret; - unsigned char *ptr; + ptrlen pl; struct MD5Context md5c; struct do_ssh1_login_state { int crLine; int len; unsigned char *rsabuf; - const unsigned char *keystr1, *keystr2; + ptrlen keystr1, keystr2; unsigned long supported_ciphers_mask, supported_auths_mask; int tried_publickey, tried_agent; int tis_auth_refused, ccard_auth_refused; @@ -4208,23 +4084,16 @@ static void do_ssh1_login(void *vctx) logevent("Received public keys"); - ptr = ssh_pkt_getdata(pktin, 8); - if (!ptr) { - bombout(("SSH-1 public key packet stopped before random cookie")); - crStopV; - } - memcpy(s->cookie, ptr, 8); + pl = get_data(pktin, 8); + memcpy(s->cookie, pl.ptr, pl.len); - if (!ssh1_pkt_getrsakey(pktin, &s->servkey, &s->keystr1) || - !ssh1_pkt_getrsakey(pktin, &s->hostkey, &s->keystr2)) { - bombout(("Failed to read SSH-1 public keys from public key packet")); - crStopV; - } + get_rsa_ssh1_pub(pktin, &s->servkey, &s->keystr1, RSA_SSH1_EXPONENT_FIRST); + get_rsa_ssh1_pub(pktin, &s->hostkey, &s->keystr2, RSA_SSH1_EXPONENT_FIRST); /* * Log the host key fingerprint. */ - { + if (!get_err(pktin)) { char logmsg[80]; logevent("Host key fingerprint is:"); strcpy(logmsg, " "); @@ -4234,9 +4103,15 @@ static void do_ssh1_login(void *vctx) logevent(logmsg); } - ssh->v1_remote_protoflags = ssh_pkt_getuint32(pktin); - s->supported_ciphers_mask = ssh_pkt_getuint32(pktin); - s->supported_auths_mask = ssh_pkt_getuint32(pktin); + ssh->v1_remote_protoflags = get_uint32(pktin); + s->supported_ciphers_mask = get_uint32(pktin); + s->supported_auths_mask = get_uint32(pktin); + + if (get_err(pktin)) { + bombout(("Bad SSH-1 public key packet")); + crStopV; + } + if ((ssh->remote_bugs & BUG_CHOKES_ON_RSA)) s->supported_auths_mask &= ~(1 << SSH1_AUTH_RSA); @@ -4245,8 +4120,8 @@ static void do_ssh1_login(void *vctx) ssh->v1_local_protoflags |= SSH1_PROTOFLAG_SCREEN_NUMBER; MD5Init(&md5c); - put_data(&md5c, s->keystr2, s->hostkey.bytes); - put_data(&md5c, s->keystr1, s->servkey.bytes); + put_data(&md5c, s->keystr2.ptr, s->keystr2.len); + put_data(&md5c, s->keystr1.ptr, s->keystr1.len); put_data(&md5c, s->cookie, 8); MD5Final(s->session_id, &md5c); @@ -4641,7 +4516,9 @@ static void do_ssh1_login(void *vctx) continue; } logevent("Received RSA challenge"); - if ((s->challenge = ssh1_pkt_getmp(pktin)) == NULL) { + s->challenge = get_mp_ssh1(pktin); + if (get_err(pktin)) { + freebn(s->challenge); bombout(("Server's RSA challenge was badly formatted")); crStopV; } @@ -4831,7 +4708,9 @@ static void do_ssh1_login(void *vctx) unsigned char buffer[32]; Bignum challenge, response; - if ((challenge = ssh1_pkt_getmp(pktin)) == NULL) { + challenge = get_mp_ssh1(pktin); + if (get_err(pktin)) { + freebn(challenge); bombout(("Server's RSA challenge was badly formatted")); crStopV; } @@ -4890,12 +4769,11 @@ static void do_ssh1_login(void *vctx) s->tis_auth_refused = 1; continue; } else { - char *challenge; - int challengelen; + ptrlen challenge; char *instr_suf, *prompt; - ssh_pkt_getstring(pktin, &challenge, &challengelen); - if (!challenge) { + challenge = get_string(pktin); + if (get_err(pktin)) { bombout(("TIS challenge packet was badly formed")); crStopV; } @@ -4903,11 +4781,11 @@ static void do_ssh1_login(void *vctx) s->cur_prompt->to_server = TRUE; s->cur_prompt->name = dupstr("SSH TIS authentication"); /* Prompt heuristic comes from OpenSSH */ - if (memchr(challenge, '\n', challengelen)) { + if (memchr(challenge.ptr, '\n', challenge.len)) { instr_suf = dupstr(""); - prompt = dupprintf("%.*s", challengelen, challenge); + prompt = mkstr(challenge); } else { - instr_suf = dupprintf("%.*s", challengelen, challenge); + instr_suf = mkstr(challenge); prompt = dupstr("Response: "); } s->cur_prompt->instruction = @@ -4932,12 +4810,11 @@ static void do_ssh1_login(void *vctx) s->ccard_auth_refused = 1; continue; } else { - char *challenge; - int challengelen; + ptrlen challenge; char *instr_suf, *prompt; - ssh_pkt_getstring(pktin, &challenge, &challengelen); - if (!challenge) { + challenge = get_string(pktin); + if (get_err(pktin)) { bombout(("CryptoCard challenge packet was badly formed")); crStopV; } @@ -4946,11 +4823,11 @@ static void do_ssh1_login(void *vctx) s->cur_prompt->name = dupstr("SSH CryptoCard authentication"); s->cur_prompt->name_reqd = FALSE; /* Prompt heuristic comes from OpenSSH */ - if (memchr(challenge, '\n', challengelen)) { + if (memchr(challenge.ptr, '\n', challenge.len)) { instr_suf = dupstr(""); - prompt = dupprintf("%.*s", challengelen, challenge); + prompt = mkstr(challenge); } else { - instr_suf = dupprintf("%.*s", challengelen, challenge); + instr_suf = mkstr(challenge); prompt = dupstr("Response: "); } s->cur_prompt->instruction = @@ -5687,17 +5564,17 @@ static void ssh_setup_portfwd(Ssh ssh, Conf *conf) static void ssh1_smsg_stdout_stderr_data(Ssh ssh, struct Packet *pktin) { - char *string; - int stringlen, bufsize; + ptrlen string; + int bufsize; - ssh_pkt_getstring(pktin, &string, &stringlen); - if (string == NULL) { + string = get_string(pktin); + if (get_err(pktin)) { bombout(("Incoming terminal data packet was badly formed")); return; } bufsize = from_backend(ssh->frontend, pktin->type == SSH1_SMSG_STDERR_DATA, - string, stringlen); + string.ptr, string.len); if (!ssh->v1_stdout_throttling && bufsize > SSH1_BUFFER_LIMIT) { ssh->v1_stdout_throttling = 1; ssh_throttle_conn(ssh, +1); @@ -5709,7 +5586,7 @@ static void ssh1_smsg_x11_open(Ssh ssh, struct Packet *pktin) /* Remote side is trying to open a channel to talk to our * X-Server. Give them back a local channel number. */ struct ssh_channel *c; - int remoteid = ssh_pkt_getuint32(pktin); + int remoteid = get_uint32(pktin); logevent("Received X11 connect request"); /* Refuse if X11 forwarding is disabled. */ @@ -5738,7 +5615,7 @@ static void ssh1_smsg_agent_open(Ssh ssh, struct Packet *pktin) /* Remote side is trying to open a channel to talk to our * agent. Give them back a local channel number. */ struct ssh_channel *c; - int remoteid = ssh_pkt_getuint32(pktin); + int remoteid = toint(get_uint32(pktin)); /* Refuse if agent forwarding is disabled. */ if (!ssh->agentfwd_enabled) { @@ -5765,15 +5642,15 @@ static void ssh1_msg_port_open(Ssh ssh, struct Packet *pktin) * forwarded port. Give them back a local channel number. */ struct ssh_rportfwd pf, *pfp; int remoteid; - int hostsize, port; - char *host; + int port; + ptrlen host; char *err; - remoteid = ssh_pkt_getuint32(pktin); - ssh_pkt_getstring(pktin, &host, &hostsize); - port = ssh_pkt_getuint32(pktin); + remoteid = toint(get_uint32(pktin)); + host = get_string(pktin); + port = toint(get_uint32(pktin)); - pf.dhost = dupprintf("%.*s", hostsize, NULLTOEMPTY(host)); + pf.dhost = mkstr(host); pf.dport = port; pfp = find234(ssh->rportfwds, &pf, NULL); @@ -5817,7 +5694,7 @@ static void ssh1_msg_channel_open_confirmation(Ssh ssh, struct Packet *pktin) c = ssh_channel_msg(ssh, pktin); if (c && c->type == CHAN_SOCKDATA) { - c->remoteid = ssh_pkt_getuint32(pktin); + c->remoteid = get_uint32(pktin); c->halfopen = FALSE; c->throttling_conn = 0; pfd_confirm(c->u.pfd.pf); @@ -5926,15 +5803,14 @@ static int ssh_channel_data(struct ssh_channel *c, int is_stderr, static void ssh1_msg_channel_data(Ssh ssh, struct Packet *pktin) { /* Data sent down one of our channels. */ - char *p; - int len; + ptrlen data; struct ssh_channel *c; c = ssh_channel_msg(ssh, pktin); - ssh_pkt_getstring(pktin, &p, &len); + data = get_string(pktin); if (c) { - int bufsize = ssh_channel_data(c, FALSE, p, len); + int bufsize = ssh_channel_data(c, FALSE, data.ptr, data.len); if (!c->throttling_conn && bufsize > SSH1_BUFFER_LIMIT) { c->throttling_conn = 1; ssh_throttle_conn(ssh, +1); @@ -5944,7 +5820,7 @@ static void ssh1_msg_channel_data(Ssh ssh, struct Packet *pktin) static void ssh1_smsg_exit_status(Ssh ssh, struct Packet *pktin) { - ssh->exitcode = ssh_pkt_getuint32(pktin); + ssh->exitcode = get_uint32(pktin); logeventf(ssh, "Server sent command exit status %d", ssh->exitcode); send_packet(ssh, SSH1_CMSG_EXIT_CONFIRMATION, PKT_END); /* @@ -6190,22 +6066,14 @@ static void do_ssh1_connection(void *vctx) */ static void ssh1_msg_debug(Ssh ssh, struct Packet *pktin) { - char *msg; - int msglen; - - ssh_pkt_getstring(pktin, &msg, &msglen); - logeventf(ssh, "Remote debug message: %.*s", msglen, NULLTOEMPTY(msg)); + ptrlen msg = get_string(pktin); + logeventf(ssh, "Remote debug message: %.*s", PTRLEN_PRINTF(msg)); } static void ssh1_msg_disconnect(Ssh ssh, struct Packet *pktin) { - /* log reason code in disconnect message */ - char *msg; - int msglen; - - ssh_pkt_getstring(pktin, &msg, &msglen); - bombout(("Server sent disconnect message:\n\"%.*s\"", - msglen, NULLTOEMPTY(msg))); + ptrlen msg = get_string(pktin); + bombout(("Server sent disconnect message:\n\"%.*s\"", PTRLEN_PRINTF(msg))); } static void ssh_msg_ignore(Ssh ssh, struct Packet *pktin) @@ -6566,8 +6434,8 @@ static void do_ssh2_transport(void *vctx) int csmac_etm_tobe, scmac_etm_tobe; const struct ssh_compress *cscomp_tobe; const struct ssh_compress *sccomp_tobe; - char *hostkeydata, *sigdata, *rsakeydata, *keystr, *fingerprint; - int hostkeylen, siglen, rsakeylen; + ptrlen hostkeydata, sigdata; + char *keystr, *fingerprint; ssh_key *hkey; /* actual host key */ struct RSAKey *rsakey; /* for RSA kex */ struct ec_key *eckey; /* for ECDH kex */ @@ -6998,8 +6866,8 @@ static void do_ssh2_transport(void *vctx) * to. */ { - char *str; - int i, j, len; + ptrlen str; + int i, j; if (pktin->type != SSH2_MSG_KEXINIT) { bombout(("expected key exchange packet from server")); @@ -7016,12 +6884,12 @@ static void do_ssh2_transport(void *vctx) s->warn_kex = s->warn_hk = FALSE; s->warn_cscipher = s->warn_sccipher = FALSE; - pktin->savedpos += 16; /* skip garbage cookie */ + get_data(pktin, 16); /* skip garbage cookie */ s->guessok = FALSE; for (i = 0; i < NKEXLIST; i++) { - ssh_pkt_getstring(pktin, &str, &len); - if (!str) { + str = get_string(pktin); + if (get_err(pktin)) { bombout(("KEXINIT packet was incomplete")); crStopV; } @@ -7046,12 +6914,13 @@ static void do_ssh2_transport(void *vctx) for (j = 0; j < MAXKEXLIST; j++) { struct kexinit_algorithm *alg = &s->kexlists[i][j]; if (alg->name == NULL) break; - if (in_commasep_string(alg->name, str, len)) { + if (in_commasep_string(alg->name, str.ptr, str.len)) { /* We've found a matching algorithm. */ if (i == KEXLIST_KEX || i == KEXLIST_HOSTKEY) { /* Check if we might need to ignore first kex pkt */ if (j != 0 || - !first_in_commasep_string(alg->name, str, len)) + !first_in_commasep_string(alg->name, + str.ptr, str.len)) s->guessok = FALSE; } if (i == KEXLIST_KEX) { @@ -7089,11 +6958,12 @@ static void do_ssh2_transport(void *vctx) goto matched; } if ((i == KEXLIST_CSCOMP || i == KEXLIST_SCCOMP) && - in_commasep_string(alg->u.comp->delayed_name, str, len)) + in_commasep_string(alg->u.comp->delayed_name, + str.ptr, str.len)) s->pending_compression = TRUE; /* try this later */ } bombout(("Couldn't agree a %s (available: %.*s)", - kexlist_descr[i], len, str)); + kexlist_descr[i], PTRLEN_PRINTF(str))); crStopV; matched:; @@ -7118,7 +6988,7 @@ static void do_ssh2_transport(void *vctx) for (j = 0; j < lenof(hostkey_algs); j++) { if (hostkey_algs[j].alg != ssh->hostkey && in_commasep_string(hostkey_algs[j].alg->name, - str, len) && + str.ptr, str.len) && !have_ssh_host_key(ssh->savedhost, ssh->savedport, hostkey_algs[j].alg->keytype)) { ssh->uncert_hostkeys[ssh->n_uncert_hostkeys++] = j; @@ -7131,9 +7001,9 @@ static void do_ssh2_transport(void *vctx) logevent("Server supports delayed compression; " "will try this later"); } - ssh_pkt_getstring(pktin, &str, &len); /* client->server language */ - ssh_pkt_getstring(pktin, &str, &len); /* server->client language */ - s->ignorepkt = ssh2_pkt_getbool(pktin) && !s->guessok; + get_string(pktin); /* client->server language */ + get_string(pktin); /* server->client language */ + s->ignorepkt = get_bool(pktin) && !s->guessok; ssh->exhash = ssh->kex->hash->init(); ssh->exhash_bs = ssh->kex->hash->sink(ssh->exhash); @@ -7315,9 +7185,11 @@ static void do_ssh2_transport(void *vctx) bombout(("expected key exchange group packet from server")); crStopV; } - s->p = ssh2_pkt_getmp(pktin); - s->g = ssh2_pkt_getmp(pktin); - if (!s->p || !s->g) { + s->p = get_mp_ssh2(pktin); + s->g = get_mp_ssh2(pktin); + if (get_err(pktin)) { + freebn(s->p); + freebn(s->g); bombout(("unable to read mp-ints from incoming group packet")); crStopV; } @@ -7351,20 +7223,12 @@ static void do_ssh2_transport(void *vctx) crStopV; } set_busy_status(ssh->frontend, BUSY_CPU); /* cogitate */ - ssh_pkt_getstring(pktin, &s->hostkeydata, &s->hostkeylen); - if (!s->hostkeydata) { - bombout(("unable to parse key exchange reply packet")); - crStopV; - } + s->hostkeydata = get_string(pktin); s->hkey = ssh->hostkey->newkey(ssh->hostkey, - s->hostkeydata, s->hostkeylen); - s->f = ssh2_pkt_getmp(pktin); - if (!s->f) { - bombout(("unable to parse key exchange reply packet")); - crStopV; - } - ssh_pkt_getstring(pktin, &s->sigdata, &s->siglen); - if (!s->sigdata) { + s->hostkeydata.ptr, s->hostkeydata.len); + s->f = get_mp_ssh2(pktin); + s->sigdata = get_string(pktin); + if (get_err(pktin)) { bombout(("unable to parse key exchange reply packet")); crStopV; } @@ -7382,7 +7246,7 @@ static void do_ssh2_transport(void *vctx) * involve user interaction. */ set_busy_status(ssh->frontend, BUSY_NOT); - put_string(ssh->exhash_bs, s->hostkeydata, s->hostkeylen); + put_stringpl(ssh->exhash_bs, s->hostkeydata); if (dh_is_gex(ssh->kex)) { if (!(ssh->remote_bugs & BUG_SSH2_OLDGEX)) put_uint32(ssh->exhash_bs, DH_MIN_SIZE); @@ -7430,14 +7294,10 @@ static void do_ssh2_transport(void *vctx) crStopV; } - ssh_pkt_getstring(pktin, &s->hostkeydata, &s->hostkeylen); - if (!s->hostkeydata) { - bombout(("unable to parse ECDH reply packet")); - crStopV; - } - put_string(ssh->exhash_bs, s->hostkeydata, s->hostkeylen); + s->hostkeydata = get_string(pktin); + put_stringpl(ssh->exhash_bs, s->hostkeydata); s->hkey = ssh->hostkey->newkey(ssh->hostkey, - s->hostkeydata, s->hostkeylen); + s->hostkeydata.ptr, s->hostkeydata.len); { strbuf *pubpoint = strbuf_new(); @@ -7447,24 +7307,18 @@ static void do_ssh2_transport(void *vctx) } { - char *keydata; - int keylen; - ssh_pkt_getstring(pktin, &keydata, &keylen); - if (!keydata) { - bombout(("unable to parse ECDH reply packet")); - crStopV; - } - put_string(ssh->exhash_bs, keydata, keylen); - s->K = ssh_ecdhkex_getkey(s->eckey, keydata, keylen); - if (!s->K) { + ptrlen keydata = get_string(pktin); + put_stringpl(ssh->exhash_bs, keydata); + s->K = ssh_ecdhkex_getkey(s->eckey, keydata.ptr, keydata.len); + if (!get_err(pktin) && !s->K) { ssh_ecdhkex_freekey(s->eckey); bombout(("point received in ECDH was not valid")); crStopV; } } - ssh_pkt_getstring(pktin, &s->sigdata, &s->siglen); - if (!s->sigdata) { + s->sigdata = get_string(pktin); + if (get_err(pktin)) { bombout(("unable to parse key exchange reply packet")); crStopV; } @@ -7472,14 +7326,11 @@ static void do_ssh2_transport(void *vctx) ssh_ecdhkex_freekey(s->eckey); #ifndef NO_GSSAPI } else if (ssh->kex->main_type == KEXTYPE_GSS) { - int len; - char *data; + ptrlen data; ssh->pkt_kctx = SSH2_PKTCTX_GSSKEX; s->init_token_sent = 0; s->complete_rcvd = 0; - s->hostkeydata = NULL; - s->hostkeylen = 0; s->hkey = NULL; s->fingerprint = NULL; s->keystr = NULL; @@ -7523,9 +7374,9 @@ static void do_ssh2_transport(void *vctx) bombout(("expected key exchange group packet from server")); crStopV; } - s->p = ssh2_pkt_getmp(pktin); - s->g = ssh2_pkt_getmp(pktin); - if (!s->p || !s->g) { + s->p = get_mp_ssh2(pktin); + s->g = get_mp_ssh2(pktin); + if (get_err(pktin)) { bombout(("unable to read mp-ints from incoming group packet")); crStopV; } @@ -7625,34 +7476,35 @@ static void do_ssh2_transport(void *vctx) (pktin = pq_pop(&ssh->pq_ssh2_transport)) != NULL); switch (pktin->type) { case SSH2_MSG_KEXGSS_CONTINUE: - ssh_pkt_getstring(pktin, &data, &len); - s->gss_rcvtok.value = data; - s->gss_rcvtok.length = len; + data = get_string(pktin); + s->gss_rcvtok.value = (char *)data.ptr; + s->gss_rcvtok.length = data.len; continue; case SSH2_MSG_KEXGSS_COMPLETE: s->complete_rcvd = 1; - s->f = ssh2_pkt_getmp(pktin); - ssh_pkt_getstring(pktin, &data, &len); - s->mic.value = data; - s->mic.length = len; + s->f = get_mp_ssh2(pktin); + data = get_string(pktin); + s->mic.value = (char *)data.ptr; + s->mic.length = data.len; /* Save expiration time of cred when delegating */ if (s->gss_delegate && s->gss_cred_expiry != GSS_NO_EXPIRATION) ssh->gss_cred_expiry = s->gss_cred_expiry; /* If there's a final token we loop to consume it */ - if (ssh2_pkt_getbool(pktin)) { - ssh_pkt_getstring(pktin, &data, &len); - s->gss_rcvtok.value = data; - s->gss_rcvtok.length = len; + if (get_bool(pktin)) { + data = get_string(pktin); + s->gss_rcvtok.value = (char *)data.ptr; + s->gss_rcvtok.length = data.len; continue; } break; case SSH2_MSG_KEXGSS_HOSTKEY: - ssh_pkt_getstring(pktin, &s->hostkeydata, &s->hostkeylen); + s->hostkeydata = get_string(pktin); if (ssh->hostkey) { s->hkey = ssh->hostkey->newkey(ssh->hostkey, - s->hostkeydata, - s->hostkeylen); - put_string(ssh->exhash_bs, s->hostkeydata, s->hostkeylen); + s->hostkeydata.ptr, + s->hostkeydata.len); + put_string(ssh->exhash_bs, + s->hostkeydata.ptr, s->hostkeydata.len); } /* * Can't loop as we have no token to pass to @@ -7670,13 +7522,13 @@ static void do_ssh2_transport(void *vctx) * that will produce the most useful information for * us. */ - ssh_pkt_getuint32(pktin); /* server's major status */ - ssh_pkt_getuint32(pktin); /* server's minor status */ - ssh_pkt_getstring(pktin, &data, &len); + get_uint32(pktin); /* server's major status */ + get_uint32(pktin); /* server's minor status */ + data = get_string(pktin); logeventf(ssh, "GSSAPI key exchange failed; " - "server's message: %.*s", len, data); + "server's message: %.*s", PTRLEN_PRINTF(data)); /* Language tag, but we have no use for it */ - ssh_pkt_getstring(pktin, &data, &len); + get_string(pktin); /* * Wait for an error token, if there is one, or the * server's disconnect. The error token, if there @@ -7726,6 +7578,8 @@ static void do_ssh2_transport(void *vctx) } #endif } else { + ptrlen rsakeydata; + assert(ssh->kex->main_type == KEXTYPE_RSA); logeventf(ssh, "Doing RSA key exchange with hash %s", ssh->kex->hash->text_name); @@ -7740,34 +7594,20 @@ static void do_ssh2_transport(void *vctx) crStopV; } - ssh_pkt_getstring(pktin, &s->hostkeydata, &s->hostkeylen); - if (!s->hostkeydata) { - bombout(("unable to parse RSA public key packet")); - crStopV; - } - put_string(ssh->exhash_bs, s->hostkeydata, s->hostkeylen); + s->hostkeydata = get_string(pktin); + put_stringpl(ssh->exhash_bs, s->hostkeydata); s->hkey = ssh->hostkey->newkey(ssh->hostkey, - s->hostkeydata, s->hostkeylen); + s->hostkeydata.ptr, s->hostkeydata.len); - { - char *keydata; - ssh_pkt_getstring(pktin, &keydata, &s->rsakeylen); - if (!keydata) { - bombout(("unable to parse RSA public key packet")); - crStopV; - } - s->rsakeydata = snewn(s->rsakeylen, char); - memcpy(s->rsakeydata, keydata, s->rsakeylen); - } + rsakeydata = get_string(pktin); - s->rsakey = ssh_rsakex_newkey(s->rsakeydata, s->rsakeylen); + s->rsakey = ssh_rsakex_newkey(rsakeydata.ptr, rsakeydata.len); if (!s->rsakey) { - sfree(s->rsakeydata); bombout(("unable to parse RSA public key from server")); crStopV; } - put_string(ssh->exhash_bs, s->rsakeydata, s->rsakeylen); + put_stringpl(ssh->exhash_bs, rsakeydata); /* * Next, set up a shared secret K, of precisely KLEN - @@ -7823,18 +7663,15 @@ static void do_ssh2_transport(void *vctx) crMaybeWaitUntilV((pktin = pq_pop(&ssh->pq_ssh2_transport)) != NULL); if (pktin->type != SSH2_MSG_KEXRSA_DONE) { - sfree(s->rsakeydata); bombout(("expected signature packet from server")); crStopV; } - ssh_pkt_getstring(pktin, &s->sigdata, &s->siglen); - if (!s->sigdata) { + s->sigdata = get_string(pktin); + if (get_err(pktin)) { bombout(("unable to parse signature packet")); crStopV; } - - sfree(s->rsakeydata); } put_mp_ssh2(ssh->exhash_bs, s->K); @@ -7899,7 +7736,7 @@ static void do_ssh2_transport(void *vctx) crStopV; } - if (!ssh->hostkey->verifysig(s->hkey, s->sigdata, s->siglen, + if (!ssh->hostkey->verifysig(s->hkey, s->sigdata.ptr, s->sigdata.len, s->exchange_hash, ssh->kex->hash->hlen)) { #ifndef FUZZING @@ -8712,7 +8549,7 @@ static void ssh2_set_window(struct ssh_channel *c, int newwin) */ static struct ssh_channel *ssh_channel_msg(Ssh ssh, struct Packet *pktin) { - unsigned localid = ssh_pkt_getuint32(pktin); + unsigned localid = get_uint32(pktin); struct ssh_channel *c; int halfopen_ok; @@ -8797,31 +8634,30 @@ static void ssh2_msg_channel_window_adjust(Ssh ssh, struct Packet *pktin) if (!c) return; if (!(c->closes & CLOSES_SENT_EOF)) { - c->v.v2.remwindow += ssh_pkt_getuint32(pktin); + c->v.v2.remwindow += get_uint32(pktin); ssh2_try_send_and_unthrottle(ssh, c); } } static void ssh2_msg_channel_data(Ssh ssh, struct Packet *pktin) { - char *data; - int length; + ptrlen data; unsigned ext_type = 0; /* 0 means not extended */ struct ssh_channel *c; c = ssh_channel_msg(ssh, pktin); if (!c) return; if (pktin->type == SSH2_MSG_CHANNEL_EXTENDED_DATA) - ext_type = ssh_pkt_getuint32(pktin); - ssh_pkt_getstring(pktin, &data, &length); - if (data) { + ext_type = get_uint32(pktin); + data = get_string(pktin); + if (!get_err(pktin)) { int bufsize; - c->v.v2.locwindow -= length; - c->v.v2.remlocwin -= length; + c->v.v2.locwindow -= data.len; + c->v.v2.remlocwin -= data.len; if (ext_type != 0 && ext_type != SSH2_EXTENDED_DATA_STDERR) - length = 0; /* Don't do anything with unknown extended data. */ + data.len = 0; /* Don't do anything with unknown extended data. */ bufsize = ssh_channel_data(c, ext_type == SSH2_EXTENDED_DATA_STDERR, - data, length); + data.ptr, data.len); /* * If it looks like the remote end hit the end of its window, * and we didn't want it to do that, think about using a @@ -9135,10 +8971,10 @@ static void ssh2_msg_channel_open_confirmation(Ssh ssh, struct Packet *pktin) if (!c) return; assert(c->halfopen); /* ssh_channel_msg will have enforced this */ - c->remoteid = ssh_pkt_getuint32(pktin); + c->remoteid = get_uint32(pktin); c->halfopen = FALSE; - c->v.v2.remwindow = ssh_pkt_getuint32(pktin); - c->v.v2.remmaxpkt = ssh_pkt_getuint32(pktin); + c->v.v2.remwindow = get_uint32(pktin); + c->v.v2.remmaxpkt = get_uint32(pktin); if (c->type == CHAN_SOCKDATA) { assert(c->u.pfd.pf != NULL); @@ -9183,10 +9019,9 @@ static char *ssh2_channel_open_failure_error_text(struct Packet *pktin) unsigned reason_code; const char *reason_code_string; char reason_code_buf[256]; - char *reason_string; - int reason_length; + ptrlen reason; - reason_code = ssh_pkt_getuint32(pktin); + reason_code = get_uint32(pktin); if (reason_code < lenof(reasons) && reasons[reason_code]) { reason_code_string = reasons[reason_code]; } else { @@ -9194,10 +9029,9 @@ static char *ssh2_channel_open_failure_error_text(struct Packet *pktin) sprintf(reason_code_buf, "unknown reason code %#x", reason_code); } - ssh_pkt_getstring(pktin, &reason_string, &reason_length); + reason = get_string(pktin); - return dupprintf("%s [%.*s]", reason_code_string, - reason_length, NULLTOEMPTY(reason_string)); + return dupprintf("%s [%.*s]", reason_code_string, PTRLEN_PRINTF(reason)); } static void ssh2_msg_channel_open_failure(Ssh ssh, struct Packet *pktin) @@ -9241,8 +9075,8 @@ static void ssh2_msg_channel_open_failure(Ssh ssh, struct Packet *pktin) static void ssh2_msg_channel_request(Ssh ssh, struct Packet *pktin) { - char *type; - int typelen, want_reply; + ptrlen type; + int want_reply; int reply = SSH2_MSG_CHANNEL_FAILURE; /* default */ struct ssh_channel *c; struct Packet *pktout; @@ -9250,8 +9084,8 @@ static void ssh2_msg_channel_request(Ssh ssh, struct Packet *pktin) c = ssh_channel_msg(ssh, pktin); if (!c) return; - ssh_pkt_getstring(pktin, &type, &typelen); - want_reply = ssh2_pkt_getbool(pktin); + type = get_string(pktin); + want_reply = get_bool(pktin); if (c->closes & CLOSES_SENT_CLOSE) { /* @@ -9273,78 +9107,34 @@ static void ssh2_msg_channel_request(Ssh ssh, struct Packet *pktin) * We recognise "exit-status" and "exit-signal" on * the primary channel. */ - if (typelen == 11 && - !memcmp(type, "exit-status", 11)) { + if (ptrlen_eq_string(type, "exit-status")) { - ssh->exitcode = ssh_pkt_getuint32(pktin); + ssh->exitcode = get_uint32(pktin); logeventf(ssh, "Server sent command exit status %d", ssh->exitcode); reply = SSH2_MSG_CHANNEL_SUCCESS; - } else if (typelen == 11 && - !memcmp(type, "exit-signal", 11)) { - - int is_plausible = TRUE, is_int = FALSE; + } else if (ptrlen_eq_string(type, "exit-signal")) { char *fmt_sig = NULL, *fmt_msg = NULL; - char *msg; - int msglen = 0, core = FALSE; - /* ICK: older versions of OpenSSH (e.g. 3.4p1) + ptrlen errmsg; + int core = FALSE; + int format, exitcode; + + /* ICK: older versions of OpenSSH (e.g. 3.4p1) * provide an `int' for the signal, despite its * having been a `string' in the drafts of RFC 4254 since at * least 2001. (Fixed in session.c 1.147.) Try to * infer which we can safely parse it as. */ - { - unsigned char *p = pktin->body + - pktin->savedpos; - long len = pktin->length - pktin->savedpos; - unsigned long num = GET_32BIT(p); /* what is it? */ - /* If it's 0, it hardly matters; assume string */ - if (num == 0) { - is_int = FALSE; - } else { - int maybe_int = FALSE, maybe_str = FALSE; -#define CHECK_HYPOTHESIS(offset, result) \ - do \ - { \ - int q = toint(offset); \ - if (q >= 0 && q+4 <= len) { \ - q = toint(q + 4 + GET_32BIT(p+q)); \ - if (q >= 0 && q+4 <= len && \ - ((q = toint(q + 4 + GET_32BIT(p+q))) != 0) && \ - q == len) \ - result = TRUE; \ - } \ - } while(0) - CHECK_HYPOTHESIS(4+1, maybe_int); - CHECK_HYPOTHESIS(4+num+1, maybe_str); -#undef CHECK_HYPOTHESIS - if (maybe_int && !maybe_str) - is_int = TRUE; - else if (!maybe_int && maybe_str) - is_int = FALSE; - else - /* Crikey. Either or neither. Panic. */ - is_plausible = FALSE; - } - } - ssh->exitcode = 128; /* means `unknown signal' */ - if (is_plausible) { - if (is_int) { - /* Old non-standard OpenSSH. */ - int signum = ssh_pkt_getuint32(pktin); - fmt_sig = dupprintf(" %d", signum); - ssh->exitcode = 128 + signum; - } else { - /* As per RFC 4254. */ - char *sig; - int siglen; - ssh_pkt_getstring(pktin, &sig, &siglen); - /* Signal name isn't supposed to be blank, but - * let's cope gracefully if it is. */ - if (siglen) { - fmt_sig = dupprintf(" \"%.*s\"", - siglen, sig); - } + + size_t startpos = BinarySource_UPCAST(pktin)->pos; + + for (format = 0; format < 2; format++) { + BinarySource_UPCAST(pktin)->pos = startpos; + BinarySource_UPCAST(pktin)->err = BSE_NO_ERROR; + + if (format == 0) { /* standard string-based format */ + ptrlen signame = get_string(pktin); + fmt_sig = dupprintf(" \"%.*s\"", PTRLEN_PRINTF(signame)); /* * Really hideous method of translating the @@ -9355,8 +9145,8 @@ static void ssh2_msg_channel_request(Ssh ssh, struct Packet *pktin) if (0) ; #define TRANSLATE_SIGNAL(s) \ - else if (siglen == lenof(#s)-1 && !memcmp(sig, #s, siglen)) \ - ssh->exitcode = 128 + SIG ## s + else if (ptrlen_eq_string(signame, #s)) \ + exitcode = 128 + SIG ## s #ifdef SIGABRT TRANSLATE_SIGNAL(ABRT); #endif @@ -9398,15 +9188,32 @@ static void ssh2_msg_channel_request(Ssh ssh, struct Packet *pktin) #endif #undef TRANSLATE_SIGNAL else - ssh->exitcode = 128; - } - core = ssh2_pkt_getbool(pktin); - ssh_pkt_getstring(pktin, &msg, &msglen); - if (msglen) { - fmt_msg = dupprintf(" (\"%.*s\")", msglen, msg); - } - /* ignore lang tag */ - } /* else don't attempt to parse */ + exitcode = 128; + } else { /* nonstandard integer format */ + unsigned signum = get_uint32(pktin); + fmt_sig = dupprintf(" %u", signum); + exitcode = 128 + signum; + } + + core = get_bool(pktin); + errmsg = get_string(pktin); /* error message */ + get_string(pktin); /* language tag */ + if (!get_err(pktin) && get_avail(pktin) == 0) + break; /* successful parse */ + + sfree(fmt_sig); + } + + if (format == 2) { + fmt_sig = NULL; + exitcode = 128; + } + + ssh->exitcode = exitcode; + if (errmsg.len) { + fmt_msg = dupprintf(" (\"%.*s\")", PTRLEN_PRINTF(errmsg)); + } + logeventf(ssh, "Server exited on signal%s%s%s", fmt_sig ? fmt_sig : "", core ? " (core dumped)" : "", @@ -9414,7 +9221,6 @@ static void ssh2_msg_channel_request(Ssh ssh, struct Packet *pktin) sfree(fmt_sig); sfree(fmt_msg); reply = SSH2_MSG_CHANNEL_SUCCESS; - } } else { /* @@ -9434,12 +9240,11 @@ static void ssh2_msg_channel_request(Ssh ssh, struct Packet *pktin) static void ssh2_msg_global_request(Ssh ssh, struct Packet *pktin) { - char *type; - int typelen, want_reply; + int want_reply; struct Packet *pktout; - ssh_pkt_getstring(pktin, &type, &typelen); - want_reply = ssh2_pkt_getbool(pktin); + get_string(pktin); /* ignore request type (see below) */ + want_reply = get_bool(pktin); /* * We currently don't support any global requests @@ -9479,10 +9284,7 @@ void ssh_sharing_remove_x11_display(Ssh ssh, struct X11FakeAuth *auth) static void ssh2_msg_channel_open(Ssh ssh, struct Packet *pktin) { - char *type; - int typelen; - char *peeraddr; - int peeraddrlen; + ptrlen type; int peerport; const char *error = NULL; struct ssh_channel *c; @@ -9490,20 +9292,17 @@ static void ssh2_msg_channel_open(Ssh ssh, struct Packet *pktin) unsigned our_winsize_override = 0; struct Packet *pktout; - ssh_pkt_getstring(pktin, &type, &typelen); + type = get_string(pktin); c = snew(struct ssh_channel); c->ssh = ssh; - remid = ssh_pkt_getuint32(pktin); - winsize = ssh_pkt_getuint32(pktin); - pktsize = ssh_pkt_getuint32(pktin); + remid = get_uint32(pktin); + winsize = get_uint32(pktin); + pktsize = get_uint32(pktin); - if (typelen == 3 && !memcmp(type, "x11", 3)) { - char *addrstr; - - ssh_pkt_getstring(pktin, &peeraddr, &peeraddrlen); - addrstr = dupprintf("%.*s", peeraddrlen, NULLTOEMPTY(peeraddr)); - peerport = ssh_pkt_getuint32(pktin); + if (ptrlen_eq_string(type, "x11")) { + char *addrstr = mkstr(get_string(pktin)); + peerport = get_uint32(pktin); logeventf(ssh, "Received X11 connect request from %s:%d", addrstr, peerport); @@ -9531,20 +9330,18 @@ static void ssh2_msg_channel_open(Ssh ssh, struct Packet *pktin) } sfree(addrstr); - } else if (typelen == 15 && - !memcmp(type, "forwarded-tcpip", 15)) { + } else if (ptrlen_eq_string(type, "forwarded-tcpip")) { struct ssh_rportfwd pf, *realpf; - char *shost; - int shostlen; - ssh_pkt_getstring(pktin, &shost, &shostlen);/* skip address */ - pf.shost = dupprintf("%.*s", shostlen, NULLTOEMPTY(shost)); - pf.sport = ssh_pkt_getuint32(pktin); - ssh_pkt_getstring(pktin, &peeraddr, &peeraddrlen); - peerport = ssh_pkt_getuint32(pktin); + ptrlen peeraddr; + + pf.shost = mkstr(get_string(pktin)); + pf.sport = get_uint32(pktin); + peeraddr = get_string(pktin); + peerport = get_uint32(pktin); realpf = find234(ssh->rportfwds, &pf, NULL); logeventf(ssh, "Received remote port %s:%d open request " "from %.*s:%d", pf.shost, pf.sport, - peeraddrlen, NULLTOEMPTY(peeraddr), peerport); + PTRLEN_PRINTF(peeraddr), peerport); sfree(pf.shost); if (realpf == NULL) { @@ -9578,8 +9375,7 @@ static void ssh2_msg_channel_open(Ssh ssh, struct Packet *pktin) c->type = CHAN_SOCKDATA; } } - } else if (typelen == 22 && - !memcmp(type, "auth-agent@openssh.com", 22)) { + } else if (ptrlen_eq_string(type, "auth-agent@openssh.com")) { if (!ssh->agentfwd_enabled) error = "Agent forwarding is not enabled"; else { @@ -9665,11 +9461,9 @@ static void ssh2_msg_userauth_banner(Ssh ssh, struct Packet *pktin) /* Arbitrary limit to prevent unbounded inflation of buffer */ if (conf_get_int(ssh->conf, CONF_ssh_show_banner) && bufchain_size(&ssh->banner) <= 131072) { - char *banner = NULL; - int size = 0; - ssh_pkt_getstring(pktin, &banner, &size); - if (banner) - bufchain_add(&ssh->banner, banner, size); + ptrlen banner = get_string(pktin); + if (banner.len) + bufchain_add(&ssh->banner, banner.ptr, banner.len); } } @@ -10287,8 +10081,10 @@ static void do_ssh2_userauth(void *vctx) } while (1) { - char *methods = NULL; - int methlen = 0; + ptrlen methods; + + methods.ptr = ""; + methods.len = 0; /* * Wait for the result of the last authentication request. @@ -10337,8 +10133,8 @@ static void do_ssh2_userauth(void *vctx) * helpfully try next. */ if (pktin->type == SSH2_MSG_USERAUTH_FAILURE) { - ssh_pkt_getstring(pktin, &methods, &methlen); - if (!ssh2_pkt_getbool(pktin)) { + methods = get_string(pktin); + if (!get_bool(pktin)) { /* * We have received an unequivocal Access * Denied. This can translate to a variety of @@ -10405,19 +10201,23 @@ static void do_ssh2_userauth(void *vctx) } s->can_pubkey = - in_commasep_string("publickey", methods, methlen); + in_commasep_string("publickey", methods.ptr, methods.len); s->can_passwd = - in_commasep_string("password", methods, methlen); - s->can_keyb_inter = conf_get_int(ssh->conf, CONF_try_ki_auth) && - in_commasep_string("keyboard-interactive", methods, methlen); + in_commasep_string("password", methods.ptr, methods.len); + s->can_keyb_inter = + conf_get_int(ssh->conf, CONF_try_ki_auth) && + in_commasep_string("keyboard-interactive", + methods.ptr, methods.len); #ifndef NO_GSSAPI s->can_gssapi = conf_get_int(ssh->conf, CONF_try_gssapi_auth) && - in_commasep_string("gssapi-with-mic", methods, methlen) && + in_commasep_string("gssapi-with-mic", + methods.ptr, methods.len) && ssh->gsslibs->nlibraries > 0; s->can_gssapi_keyex_auth = conf_get_int(ssh->conf, CONF_try_gssapi_kex) && - in_commasep_string("gssapi-keyex", methods, methlen) && + in_commasep_string("gssapi-keyex", + methods.ptr, methods.len) && ssh->gsslibs->nlibraries > 0 && ssh->gss_ctx; #endif @@ -10752,8 +10552,7 @@ static void do_ssh2_userauth(void *vctx) /* gssapi-with-mic authentication */ - int len; - char *data; + ptrlen data; s->type = AUTH_TYPE_GSSAPI; s->tried_gssapi = TRUE; @@ -10794,9 +10593,9 @@ static void do_ssh2_userauth(void *vctx) /* check returned packet ... */ - ssh_pkt_getstring(pktin, &data, &len); - s->gss_rcvtok.value = data; - s->gss_rcvtok.length = len; + data = get_string(pktin); + s->gss_rcvtok.value = (char *)data.ptr; + s->gss_rcvtok.length = data.len; if (s->gss_rcvtok.length != s->gss_buf.length + 2 || ((char *)s->gss_rcvtok.value)[0] != SSH2_GSS_OIDTYPE || ((char *)s->gss_rcvtok.value)[1] != s->gss_buf.length || @@ -10886,9 +10685,9 @@ static void do_ssh2_userauth(void *vctx) pq_push_front(&ssh->pq_ssh2_userauth, pktin); break; } - ssh_pkt_getstring(pktin, &data, &len); - s->gss_rcvtok.value = data; - s->gss_rcvtok.length = len; + data = get_string(pktin); + s->gss_rcvtok.value = (char *)data.ptr; + s->gss_rcvtok.length = data.len; } } while (s-> gss_stat == SSH_GSS_S_CONTINUE_NEEDED); @@ -10946,47 +10745,43 @@ static void do_ssh2_userauth(void *vctx) */ while (pktin->type == SSH2_MSG_USERAUTH_INFO_REQUEST) { - char *name, *inst, *lang; - int name_len, inst_len, lang_len; + ptrlen name, inst; int i; /* * We've got a fresh USERAUTH_INFO_REQUEST. * Get the preamble and start building a prompt. */ - ssh_pkt_getstring(pktin, &name, &name_len); - ssh_pkt_getstring(pktin, &inst, &inst_len); - ssh_pkt_getstring(pktin, &lang, &lang_len); + name = get_string(pktin); + inst = get_string(pktin); + get_string(pktin); /* skip language tag */ s->cur_prompt = new_prompts(ssh->frontend); s->cur_prompt->to_server = TRUE; /* * Get any prompt(s) from the packet. */ - s->num_prompts = ssh_pkt_getuint32(pktin); + s->num_prompts = get_uint32(pktin); for (i = 0; i < s->num_prompts; i++) { - char *prompt; - int prompt_len; + ptrlen prompt; int echo; static char noprompt[] = ": "; - ssh_pkt_getstring(pktin, &prompt, &prompt_len); - echo = ssh2_pkt_getbool(pktin); - if (!prompt_len) { - prompt = noprompt; - prompt_len = lenof(noprompt)-1; + prompt = get_string(pktin); + echo = get_bool(pktin); + if (!prompt.len) { + prompt.ptr = noprompt; + prompt.len = lenof(noprompt)-1; } - add_prompt(s->cur_prompt, - dupprintf("%.*s", prompt_len, prompt), - echo); + add_prompt(s->cur_prompt, mkstr(prompt), echo); } - if (name_len) { + if (name.len) { /* FIXME: better prefix to distinguish from * local prompts? */ s->cur_prompt->name = - dupprintf("SSH server: %.*s", name_len, name); + dupprintf("SSH server: %.*s", PTRLEN_PRINTF(name)); s->cur_prompt->name_reqd = TRUE; } else { s->cur_prompt->name = @@ -11000,10 +10795,12 @@ static void do_ssh2_userauth(void *vctx) /* Special case: for reasons best known to themselves, * some servers send k-i requests with no prompts and * nothing to display. Keep quiet in this case. */ - if (s->num_prompts || name_len || inst_len) { + if (s->num_prompts || name.len || inst.len) { s->cur_prompt->instruction = - dupprintf("Using keyboard-interactive authentication.%s%.*s", - inst_len ? "\n" : "", inst_len, inst); + dupprintf("Using keyboard-interactive " + "authentication.%s%.*s", + inst.len ? "\n" : "", + PTRLEN_PRINTF(inst)); s->cur_prompt->instr_reqd = TRUE; } else { s->cur_prompt->instr_reqd = FALSE; @@ -11155,8 +10952,7 @@ static void do_ssh2_userauth(void *vctx) */ int got_new = FALSE; /* not live over crReturn */ - char *prompt; /* not live over crReturn */ - int prompt_len; /* not live over crReturn */ + ptrlen prompt; /* not live over crReturn */ { const char *msg; @@ -11169,13 +10965,12 @@ static void do_ssh2_userauth(void *vctx) c_write_str(ssh, "\r\n"); } - ssh_pkt_getstring(pktin, &prompt, &prompt_len); + prompt = get_string(pktin); s->cur_prompt = new_prompts(ssh->frontend); s->cur_prompt->to_server = TRUE; s->cur_prompt->name = dupstr("New SSH password"); - s->cur_prompt->instruction = - dupprintf("%.*s", prompt_len, NULLTOEMPTY(prompt)); + s->cur_prompt->instruction = mkstr(prompt); s->cur_prompt->instr_reqd = TRUE; /* * There's no explicit requirement in the protocol @@ -11308,9 +11103,9 @@ static void do_ssh2_userauth(void *vctx) sfree(s->password); } else { - char *str = dupprintf("No supported authentication methods available" - " (server sent: %.*s)", - methlen, methods); + char *str = dupprintf( + "No supported authentication methods available" + " (server sent: %.*s)", PTRLEN_PRINTF(methods)); ssh_disconnect(ssh, str, "No supported authentication methods available", @@ -11474,7 +11269,7 @@ static void do_ssh2_connection(void *vctx) "channel open request", pktin->type)); crStopV; } - if (ssh_pkt_getuint32(pktin) != ssh->mainchan->localid) { + if (get_uint32(pktin) != ssh->mainchan->localid) { bombout(("Server's response to main channel open cited wrong" " channel number")); crStopV; @@ -11486,10 +11281,10 @@ static void do_ssh2_connection(void *vctx) crStopV; } - ssh->mainchan->remoteid = ssh_pkt_getuint32(pktin); + ssh->mainchan->remoteid = get_uint32(pktin); ssh->mainchan->halfopen = FALSE; - ssh->mainchan->v.v2.remwindow = ssh_pkt_getuint32(pktin); - ssh->mainchan->v.v2.remmaxpkt = ssh_pkt_getuint32(pktin); + ssh->mainchan->v.v2.remwindow = get_uint32(pktin); + ssh->mainchan->v.v2.remmaxpkt = get_uint32(pktin); update_specials_menu(ssh->frontend); logevent("Opened main channel"); } @@ -11700,11 +11495,12 @@ static void ssh2_connection_input(Ssh ssh) static void ssh2_msg_disconnect(Ssh ssh, struct Packet *pktin) { /* log reason code in disconnect message */ - char *buf, *msg; - int reason, msglen; + char *buf; + ptrlen msg; + int reason; - reason = ssh_pkt_getuint32(pktin); - ssh_pkt_getstring(pktin, &msg, &msglen); + reason = get_uint32(pktin); + msg = get_string(pktin); if (reason > 0 && reason < lenof(ssh2_disconnect_reasons)) { buf = dupprintf("Received disconnect message (%s)", @@ -11715,28 +11511,25 @@ static void ssh2_msg_disconnect(Ssh ssh, struct Packet *pktin) } logevent(buf); sfree(buf); - buf = dupprintf("Disconnection message text: %.*s", - msglen, NULLTOEMPTY(msg)); + buf = dupprintf("Disconnection message text: %.*s", PTRLEN_PRINTF(msg)); logevent(buf); bombout(("Server sent disconnect message\ntype %d (%s):\n\"%.*s\"", reason, (reason > 0 && reason < lenof(ssh2_disconnect_reasons)) ? - ssh2_disconnect_reasons[reason] : "unknown", - msglen, NULLTOEMPTY(msg))); + ssh2_disconnect_reasons[reason] : "unknown", PTRLEN_PRINTF(msg))); sfree(buf); } static void ssh2_msg_debug(Ssh ssh, struct Packet *pktin) { /* log the debug message */ - char *msg; - int msglen; + ptrlen msg; /* XXX maybe we should actually take notice of the return value */ - ssh2_pkt_getbool(pktin); - ssh_pkt_getstring(pktin, &msg, &msglen); + get_bool(pktin); + msg = get_string(pktin); - logeventf(ssh, "Remote debug message: %.*s", msglen, NULLTOEMPTY(msg)); + logeventf(ssh, "Remote debug message: %.*s", PTRLEN_PRINTF(msg)); } static void ssh2_msg_transport(Ssh ssh, struct Packet *pktin) From e43605ee0501377fb043dbe7ff5f16634d8df54a Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Tue, 29 May 2018 20:45:42 +0100 Subject: [PATCH 327/607] Rewrite ssh2_add_sigblob using BinarySource. This is the function that breaks apart a signature blob (generated locally or received from an SSH agent) and adds leading zero bytes in front of the signature integer, if we think we're talking to a server that will incorrectly insist on that. The breaking-apart process is just another instance of SSH-style data unmarshalling, so it should be done by the new centralised routines. --- ssh.c | 68 +++++++++++++++++++++++++++-------------------------------- 1 file changed, 31 insertions(+), 37 deletions(-) diff --git a/ssh.c b/ssh.c index 4084f007..515da287 100644 --- a/ssh.c +++ b/ssh.c @@ -2697,11 +2697,12 @@ void bndebug(char *string, Bignum b) * BUG_SSH2_RSA_PADDING. */ static void ssh2_add_sigblob(Ssh ssh, struct Packet *pkt, - void *pkblob_v, int pkblob_len, - void *sigblob_v, int sigblob_len) + const void *pkblob, int pkblob_len, + const void *sigblob, int sigblob_len) { - unsigned char *pkblob = (unsigned char *)pkblob_v; - unsigned char *sigblob = (unsigned char *)sigblob_v; + BinarySource pk[1], sig[1]; + BinarySource_BARE_INIT(pk, pkblob, pkblob_len); + BinarySource_BARE_INIT(sig, sigblob, sigblob_len); /* dmemdump(pkblob, pkblob_len); */ /* dmemdump(sigblob, sigblob_len); */ @@ -2710,48 +2711,41 @@ static void ssh2_add_sigblob(Ssh ssh, struct Packet *pkt, * See if this is in fact an ssh-rsa signature and a buggy * server; otherwise we can just do this the easy way. */ - if ((ssh->remote_bugs & BUG_SSH2_RSA_PADDING) && pkblob_len > 4+7+4 && - (GET_32BIT(pkblob) == 7 && !memcmp(pkblob+4, "ssh-rsa", 7))) { - int pos, len, siglen; + if ((ssh->remote_bugs & BUG_SSH2_RSA_PADDING) && + ptrlen_eq_string(get_string(pk), "ssh-rsa") && + ptrlen_eq_string(get_string(sig), "ssh-rsa")) { + ptrlen mod_mp, sig_mp; + size_t sig_prefix_len; /* - * Find the byte length of the modulus. + * Find the modulus and signature integers. */ - - pos = 4+7; /* skip over "ssh-rsa" */ - len = toint(GET_32BIT(pkblob+pos)); /* get length of exponent */ - if (len < 0 || len > pkblob_len - pos - 4) - goto give_up; - pos += 4 + len; /* skip over exponent */ - if (pkblob_len - pos < 4) + get_string(pk); /* skip over exponent */ + mod_mp = get_string(pk); /* remember modulus */ + sig_prefix_len = sig->pos; + sig_mp = get_string(sig); + if (get_err(pk) || get_err(sig)) goto give_up; - len = toint(GET_32BIT(pkblob+pos)); /* find length of modulus */ - if (len < 0 || len > pkblob_len - pos - 4) - goto give_up; - pos += 4; /* find modulus itself */ - while (len > 0 && pkblob[pos] == 0) - len--, pos++; - /* debug(("modulus length is %d\n", len)); */ - /* - * Now find the signature integer. - */ - pos = 4+7; /* skip over "ssh-rsa" */ - if (sigblob_len < pos+4) - goto give_up; - siglen = toint(GET_32BIT(sigblob+pos)); - if (siglen != sigblob_len - pos - 4) - goto give_up; + /* + * Find the byte length of the modulus, not counting leading + * zeroes. + */ + while (mod_mp.len > 0 && *(const char *)mod_mp.ptr == 0) { + mod_mp.len--; + mod_mp.ptr = (const char *)mod_mp.ptr + 1; + } + + /* debug(("modulus length is %d\n", len)); */ /* debug(("signature length is %d\n", siglen)); */ - if (len != siglen) { + if (mod_mp.len != sig_mp.len) { strbuf *substr = strbuf_new(); - put_data(substr, sigblob, pos); - put_uint32(substr, len); - while (len-- > siglen) + put_data(substr, sigblob, sig_prefix_len); + put_uint32(substr, mod_mp.len); + while (mod_mp.len-- > sig_mp.len) put_byte(substr, 0); - pos += 4; /* point to start of actual sig */ - put_data(substr, sigblob+pos, siglen); + put_data(substr, sig_mp.ptr, sig_mp.len); put_stringsb(pkt, substr); return; } From 392a8c00f60d3cf655865deca09b72e83d0d143b Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 27 May 2018 23:47:40 +0100 Subject: [PATCH 328/607] Pageant server: parse requests using BinarySource. pageant_handle_msg was _particularly_ full of painful manual packet decoding with error checks at every stage, so it's a great relief to throw it all away and replace it with short sequences of calls to the shiny new API! --- pageant.c | 333 ++++++++++++++---------------------------------------- 1 file changed, 86 insertions(+), 247 deletions(-) diff --git a/pageant.c b/pageant.c index 8528cc02..70b7f89b 100644 --- a/pageant.c +++ b/pageant.c @@ -80,7 +80,7 @@ static int cmpkeys_rsa(void *av, void *bv) */ static int cmpkeys_ssh2_asymm(void *av, void *bv) { - strbuf *ablob = (strbuf *) av; + ptrlen *ablob = (ptrlen *) av; struct ssh2_userkey *b = (struct ssh2_userkey *) bv; strbuf *bblob; int i, c; @@ -93,10 +93,11 @@ static int cmpkeys_ssh2_asymm(void *av, void *bv) c = 0; for (i = 0; i < ablob->len && i < bblob->len; i++) { - if (ablob->u[i] < bblob->u[i]) { + unsigned char abyte = ((unsigned char *)ablob->ptr)[i]; + if (abyte < bblob->u[i]) { c = -1; break; - } else if (ablob->u[i] > bblob->u[i]) { + } else if (abyte > bblob->u[i]) { c = +1; break; } @@ -118,11 +119,14 @@ static int cmpkeys_ssh2(void *av, void *bv) { struct ssh2_userkey *a = (struct ssh2_userkey *) av; strbuf *ablob; + ptrlen apl; int toret; ablob = strbuf_new(); a->alg->public_blob(a->data, BinarySink_UPCAST(ablob)); - toret = cmpkeys_ssh2_asymm(ablob, bv); + apl.ptr = ablob->u; + apl.len = ablob->len; + toret = cmpkeys_ssh2_asymm(&apl, bv); strbuf_free(ablob); return toret; } @@ -178,24 +182,20 @@ static void plog(void *logctx, pageant_logfn_t logfn, const char *fmt, ...) } void pageant_handle_msg(BinarySink *bs, - const void *msg, int msglen, + const void *msgdata, int msglen, void *logctx, pageant_logfn_t logfn) { - const unsigned char *p = msg; - const unsigned char *msgend; + BinarySource msg[1]; int type; - msgend = p + msglen; + BinarySource_BARE_INIT(msg, msgdata, msglen); - /* - * Get the message type. - */ - if (msgend < p+1) { + type = get_byte(msg); + if (get_err(msg)) { pageant_failure_msg(bs, "message contained no type code", logctx, logfn); return; } - type = *p++; switch (type) { case SSH1_AGENTC_REQUEST_RSA_IDENTITIES: @@ -253,59 +253,34 @@ void pageant_handle_msg(BinarySink *bs, { struct RSAKey reqkey, *key; Bignum challenge, response; - unsigned char response_source[48], response_md5[16]; + ptrlen session_id; + unsigned response_type; + unsigned char response_md5[16]; struct MD5Context md5c; int i; plog(logctx, logfn, "request: SSH1_AGENTC_RSA_CHALLENGE"); - reqkey.exponent = reqkey.modulus = challenge = response = NULL; + response = NULL; + memset(&reqkey, 0, sizeof(reqkey)); - p += 4; - i = ssh1_read_bignum(p, msgend - p, &reqkey.exponent); - if (i < 0) { - pageant_failure_msg( - bs, "request truncated before key exponent", - logctx, logfn); - goto challenge1_cleanup; - } - p += i; - i = ssh1_read_bignum(p, msgend - p, &reqkey.modulus); - if (i < 0) { - pageant_failure_msg( - bs, "request truncated before key modulus", - logctx, logfn); - goto challenge1_cleanup; - } - p += i; - i = ssh1_read_bignum(p, msgend - p, &challenge); - if (i < 0) { - pageant_failure_msg( - bs, "request truncated before challenge", - logctx, logfn); - goto challenge1_cleanup; - } - p += i; - if (msgend < p+16) { - pageant_failure_msg( - bs, "request truncated before session id", - logctx, logfn); - goto challenge1_cleanup; - } - memcpy(response_source + 32, p, 16); - p += 16; - if (msgend < p+4) { - pageant_failure_msg( - bs, "request truncated before response type", - logctx, logfn); + get_rsa_ssh1_pub(msg, &reqkey, NULL, RSA_SSH1_EXPONENT_FIRST); + challenge = get_mp_ssh1(msg); + session_id = get_data(msg, 16); + response_type = get_uint32(msg); + + if (get_err(msg)) { + pageant_failure_msg(bs, "unable to decode request", + logctx, logfn); goto challenge1_cleanup; } - if (GET_32BIT(p) != 1) { + if (response_type != 1) { pageant_failure_msg( bs, "response type other than 1 not supported", logctx, logfn); goto challenge1_cleanup; } + if (logfn) { char fingerprint[128]; reqkey.comment = NULL; @@ -317,13 +292,12 @@ void pageant_handle_msg(BinarySink *bs, goto challenge1_cleanup; } response = rsa_ssh1_decrypt(challenge, key); - for (i = 0; i < 32; i++) - response_source[i] = bignum_byte(response, 31 - i); MD5Init(&md5c); - put_data(&md5c, response_source, 48); + for (i = 0; i < 32; i++) + put_byte(&md5c, bignum_byte(response, 31 - i)); + put_data(&md5c, session_id.ptr, session_id.len); MD5Final(response_md5, &md5c); - smemclr(response_source, 48); /* burn the evidence */ put_byte(bs, SSH1_AGENT_RSA_RESPONSE); put_data(bs, response_md5, 16); @@ -331,10 +305,11 @@ void pageant_handle_msg(BinarySink *bs, plog(logctx, logfn, "reply: SSH1_AGENT_RSA_RESPONSE"); challenge1_cleanup: - if (response) freebn(response); - if (challenge) freebn(challenge); - if (reqkey.exponent) freebn(reqkey.exponent); - if (reqkey.modulus) freebn(reqkey.modulus); + if (response) + freebn(response); + freebn(challenge); + freebn(reqkey.exponent); + freebn(reqkey.modulus); } break; case SSH2_AGENTC_SIGN_REQUEST: @@ -345,56 +320,20 @@ void pageant_handle_msg(BinarySink *bs, */ { struct ssh2_userkey *key; - const void *blobp; - int bloblen; - const unsigned char *data; + ptrlen keyblob, sigdata; strbuf *signature; - int datalen; plog(logctx, logfn, "request: SSH2_AGENTC_SIGN_REQUEST"); - if (msgend < p+4) { - pageant_failure_msg( - bs, "request truncated before public key", - logctx, logfn); - return; - } - bloblen = toint(GET_32BIT(p)); - if (bloblen < 0 || bloblen > msgend - (p+4)) { - pageant_failure_msg( - bs, "request truncated before public key", - logctx, logfn); - return; - } - p += 4; - blobp = p; - p += bloblen; - if (msgend < p+4) { - pageant_failure_msg( - bs, "request truncated before string to sign", - logctx, logfn); - return; - } - datalen = toint(GET_32BIT(p)); - p += 4; - if (datalen < 0 || datalen > msgend - p) { - pageant_failure_msg( - bs, "request truncated before string to sign", - logctx, logfn); - return; - } - data = p; + keyblob = get_string(msg); + sigdata = get_string(msg); if (logfn) { - char *fingerprint = ssh2_fingerprint_blob(blobp, bloblen); + char *fingerprint = ssh2_fingerprint_blob( + keyblob.ptr, keyblob.len); plog(logctx, logfn, "requested key: %s", fingerprint); sfree(fingerprint); } - { - strbuf *blob = strbuf_new(); - put_data(blob, blobp, bloblen); - key = find234(ssh2keys, blob, cmpkeys_ssh2_asymm); - strbuf_free(blob); - } + key = find234(ssh2keys, &keyblob, cmpkeys_ssh2_asymm); if (!key) { pageant_failure_msg(bs, "key not found", logctx, logfn); return; @@ -403,7 +342,7 @@ void pageant_handle_msg(BinarySink *bs, put_byte(bs, SSH2_AGENT_SIGN_RESPONSE); signature = strbuf_new(); - key->alg->sign(key->data, data, datalen, + key->alg->sign(key->data, sigdata.ptr, sigdata.len, BinarySink_UPCAST(signature)); put_stringsb(bs, signature); @@ -417,88 +356,35 @@ void pageant_handle_msg(BinarySink *bs, */ { struct RSAKey *key; - char *comment; - int n, commentlen; plog(logctx, logfn, "request: SSH1_AGENTC_ADD_RSA_IDENTITY"); key = snew(struct RSAKey); memset(key, 0, sizeof(struct RSAKey)); - n = rsa_ssh1_readpub(p, msgend - p, key, NULL, - RSA_SSH1_MODULUS_FIRST); - if (n < 0) { - pageant_failure_msg( - bs, "request truncated before public key", - logctx, logfn); - goto add1_cleanup; - } - p += n; - - n = rsa_ssh1_readpriv(p, msgend - p, key); - if (n < 0) { - pageant_failure_msg( - bs, "request truncated before private key", - logctx, logfn); - goto add1_cleanup; - } - p += n; + get_rsa_ssh1_pub(msg, key, NULL, RSA_SSH1_MODULUS_FIRST); + get_rsa_ssh1_priv(msg, key); /* SSH-1 names p and q the other way round, i.e. we have * the inverse of p mod q and not of q mod p. We swap the * names, because our internal RSA wants iqmp. */ + key->iqmp = get_mp_ssh1(msg); + key->q = get_mp_ssh1(msg); + key->p = get_mp_ssh1(msg); - n = ssh1_read_bignum(p, msgend - p, &key->iqmp); /* p^-1 mod q */ - if (n < 0) { - pageant_failure_msg(bs, "request truncated before iqmp", - logctx, logfn); - goto add1_cleanup; - } - p += n; + key->comment = mkstr(get_string(msg)); - n = ssh1_read_bignum(p, msgend - p, &key->q); /* p */ - if (n < 0) { - pageant_failure_msg(bs, "request truncated before p", + if (get_err(msg)) { + pageant_failure_msg(bs, "unable to decode request", logctx, logfn); - goto add1_cleanup; - } - p += n; - - n = ssh1_read_bignum(p, msgend - p, &key->p); /* q */ - if (n < 0) { - pageant_failure_msg( - bs, "request truncated before q", logctx, logfn); - goto add1_cleanup; - } - p += n; - - if (msgend < p+4) { - pageant_failure_msg( - bs, "request truncated before key comment", - logctx, logfn); - goto add1_cleanup; - } - commentlen = toint(GET_32BIT(p)); - - if (commentlen < 0 || commentlen > msgend - p) { - pageant_failure_msg( - bs, "request truncated before key comment", - logctx, logfn); - goto add1_cleanup; - } + goto add1_cleanup; + } if (!rsa_verify(key)) { pageant_failure_msg(bs, "key is invalid", logctx, logfn); goto add1_cleanup; } - comment = snewn(commentlen+1, char); - if (comment) { - memcpy(comment, p + 4, commentlen); - comment[commentlen] = '\0'; - key->comment = comment; - } - if (logfn) { char fingerprint[128]; rsa_fingerprint(fingerprint, sizeof(fingerprint), key); @@ -529,73 +415,42 @@ void pageant_handle_msg(BinarySink *bs, */ { struct ssh2_userkey *key = NULL; - char *comment; - const char *alg; - int alglen, commlen; - int bloblen; + ptrlen alg; plog(logctx, logfn, "request: SSH2_AGENTC_ADD_IDENTITY"); - if (msgend < p+4) { - pageant_failure_msg( - bs, "request truncated before key algorithm", - logctx, logfn); - goto add2_cleanup; - } - alglen = toint(GET_32BIT(p)); - p += 4; - if (alglen < 0 || alglen > msgend - p) { - pageant_failure_msg( - bs, "request truncated before key algorithm", - logctx, logfn); - goto add2_cleanup; - } - alg = (const char *)p; - p += alglen; + alg = get_string(msg); key = snew(struct ssh2_userkey); key->data = NULL; key->comment = NULL; - key->alg = find_pubkey_alg_len(make_ptrlen(alg, alglen)); + key->alg = find_pubkey_alg_len(alg); if (!key->alg) { pageant_failure_msg(bs, "algorithm unknown", logctx, logfn); goto add2_cleanup; } - bloblen = msgend - p; - key->data = key->alg->openssh_createkey(key->alg, &p, &bloblen); + { + const unsigned char *p = get_ptr(msg); + int len = get_avail(msg); + key->data = key->alg->openssh_createkey(key->alg, &p, &len); + assert(len >= 0); + assert(len < get_avail(msg)); + msg->pos += get_avail(msg) - len; + } + if (!key->data) { pageant_failure_msg(bs, "key setup failed", logctx, logfn); goto add2_cleanup; } - /* - * p has been advanced by openssh_createkey, but - * certainly not _beyond_ the end of the buffer. - */ - assert(p <= msgend); + key->comment = mkstr(get_string(msg)); - if (msgend < p+4) { - pageant_failure_msg( - bs, "request truncated before key comment", - logctx, logfn); - goto add2_cleanup; - } - commlen = toint(GET_32BIT(p)); - p += 4; - - if (commlen < 0 || commlen > msgend - p) { - pageant_failure_msg( - bs, "request truncated before key comment", - logctx, logfn); - goto add2_cleanup; - } - comment = snewn(commlen + 1, char); - if (comment) { - memcpy(comment, p, commlen); - comment[commlen] = '\0'; - } - key->comment = comment; + if (get_err(msg)) { + pageant_failure_msg(bs, "unable to decode request", + logctx, logfn); + goto add2_cleanup; + } if (logfn) { char *fingerprint = ssh2_fingerprint(key->alg, key->data); @@ -634,17 +489,17 @@ void pageant_handle_msg(BinarySink *bs, */ { struct RSAKey reqkey, *key; - int n; plog(logctx, logfn, "request: SSH1_AGENTC_REMOVE_RSA_IDENTITY"); - n = rsa_ssh1_readpub(p, msgend - p, &reqkey, NULL, - RSA_SSH1_EXPONENT_FIRST); - if (n < 0) { - pageant_failure_msg( - bs, "request truncated before public key", - logctx, logfn); - return; + get_rsa_ssh1_pub(msg, &reqkey, NULL, RSA_SSH1_EXPONENT_FIRST); + + if (get_err(msg)) { + pageant_failure_msg(bs, "unable to decode request", + logctx, logfn); + freebn(reqkey.exponent); + freebn(reqkey.modulus); + return; } if (logfn) { @@ -680,41 +535,25 @@ void pageant_handle_msg(BinarySink *bs, */ { struct ssh2_userkey *key; - const void *blobp; - int bloblen; + ptrlen blob; plog(logctx, logfn, "request: SSH2_AGENTC_REMOVE_IDENTITY"); - if (msgend < p+4) { - pageant_failure_msg( - bs, "request truncated before public key", - logctx, logfn); - return; - } - bloblen = toint(GET_32BIT(p)); - p += 4; + blob = get_string(msg); - if (bloblen < 0 || bloblen > msgend - p) { - pageant_failure_msg( - bs, "request truncated before public key", - logctx, logfn); + if (get_err(msg)) { + pageant_failure_msg(bs, "unable to decode request", + logctx, logfn); return; } - blobp = p; - p += bloblen; if (logfn) { - char *fingerprint = ssh2_fingerprint_blob(blobp, bloblen); + char *fingerprint = ssh2_fingerprint_blob(blob.ptr, blob.len); plog(logctx, logfn, "unwanted key: %s", fingerprint); sfree(fingerprint); } - { - strbuf *blob = strbuf_new(); - put_data(blob, blobp, bloblen); - key = find234(ssh2keys, blob, cmpkeys_ssh2_asymm); - strbuf_free(blob); - } + key = find234(ssh2keys, &blob, cmpkeys_ssh2_asymm); if (!key) { pageant_failure_msg(bs, "key not found", logctx, logfn); return; From e2431c3ef8d9ad48a882f7e7f9ccfb327cb1cf0d Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 27 May 2018 23:58:20 +0100 Subject: [PATCH 329/607] Pageant client code: parse replies using BinarySource. This affects both the client code used by Pageant itself, in pageant.c, and the client code in ssh.c used during SSH userauth. --- pageant.c | 118 ++++++++--------------------- ssh.c | 221 ++++++++++++++++++++---------------------------------- 2 files changed, 113 insertions(+), 226 deletions(-) diff --git a/pageant.c b/pageant.c index 70b7f89b..25d0b9ab 100644 --- a/pageant.c +++ b/pageant.c @@ -1307,145 +1307,91 @@ int pageant_add_keyfile(Filename *filename, const char *passphrase, int pageant_enum_keys(pageant_key_enum_fn_t callback, void *callback_ctx, char **retstr) { - unsigned char *keylist, *p; + unsigned char *keylist; int i, nkeys, keylistlen; - char *comment; + ptrlen comment; struct pageant_pubkey cbkey; + BinarySource src[1]; keylist = pageant_get_keylist1(&keylistlen); - if (keylistlen < 4) { - *retstr = dupstr("Received broken SSH-1 key list from agent"); - sfree(keylist); - return PAGEANT_ACTION_FAILURE; - } - nkeys = toint(GET_32BIT(keylist)); - if (nkeys < 0) { - *retstr = dupstr("Received broken SSH-1 key list from agent"); - sfree(keylist); + if (!keylist) { + *retstr = dupstr("Did not receive an SSH-1 key list from agent"); return PAGEANT_ACTION_FAILURE; } - p = keylist + 4; - keylistlen -= 4; + BinarySource_BARE_INIT(src, keylist, keylistlen); + nkeys = toint(get_uint32(src)); for (i = 0; i < nkeys; i++) { struct RSAKey rkey; char fingerprint[128]; - int n; /* public blob and fingerprint */ memset(&rkey, 0, sizeof(rkey)); - n = rsa_ssh1_readpub(p, keylistlen, &rkey, NULL, - RSA_SSH1_EXPONENT_FIRST); - if (n < 0 || n > keylistlen) { - freersakey(&rkey); - *retstr = dupstr("Received broken SSH-1 key list from agent"); - sfree(keylist); - return PAGEANT_ACTION_FAILURE; - } - p += n, keylistlen -= n; - rsa_fingerprint(fingerprint, sizeof(fingerprint), &rkey); + get_rsa_ssh1_pub(src, &rkey, NULL, RSA_SSH1_EXPONENT_FIRST); + comment = get_string(src); - /* comment */ - if (keylistlen < 4) { + if (get_err(src)) { *retstr = dupstr("Received broken SSH-1 key list from agent"); freersakey(&rkey); sfree(keylist); return PAGEANT_ACTION_FAILURE; } - n = toint(GET_32BIT(p)); - p += 4, keylistlen -= 4; - if (n < 0 || keylistlen < n) { - *retstr = dupstr("Received broken SSH-1 key list from agent"); - freersakey(&rkey); - sfree(keylist); - return PAGEANT_ACTION_FAILURE; - } - comment = dupprintf("%.*s", (int)n, (const char *)p); - p += n, keylistlen -= n; + + rsa_fingerprint(fingerprint, sizeof(fingerprint), &rkey); cbkey.blob = strbuf_new(); rsa_ssh1_public_blob(BinarySink_UPCAST(cbkey.blob), &rkey, RSA_SSH1_EXPONENT_FIRST); - cbkey.comment = comment; + cbkey.comment = mkstr(comment); cbkey.ssh_version = 1; - callback(callback_ctx, fingerprint, comment, &cbkey); + callback(callback_ctx, fingerprint, cbkey.comment, &cbkey); strbuf_free(cbkey.blob); freersakey(&rkey); - sfree(comment); + sfree(cbkey.comment); } sfree(keylist); - if (keylistlen != 0) { + if (get_err(src) || get_avail(src) != 0) { *retstr = dupstr("Received broken SSH-1 key list from agent"); return PAGEANT_ACTION_FAILURE; } keylist = pageant_get_keylist2(&keylistlen); - if (keylistlen < 4) { - *retstr = dupstr("Received broken SSH-2 key list from agent"); - sfree(keylist); + if (!keylist) { + *retstr = dupstr("Did not receive an SSH-2 key list from agent"); return PAGEANT_ACTION_FAILURE; } - nkeys = toint(GET_32BIT(keylist)); - if (nkeys < 0) { - *retstr = dupstr("Received broken SSH-2 key list from agent"); - sfree(keylist); - return PAGEANT_ACTION_FAILURE; - } - p = keylist + 4; - keylistlen -= 4; + BinarySource_BARE_INIT(src, keylist, keylistlen); + nkeys = toint(get_uint32(src)); for (i = 0; i < nkeys; i++) { + ptrlen pubblob; char *fingerprint; - int n; - /* public blob */ - if (keylistlen < 4) { - *retstr = dupstr("Received broken SSH-2 key list from agent"); - sfree(keylist); - return PAGEANT_ACTION_FAILURE; - } - n = toint(GET_32BIT(p)); - p += 4, keylistlen -= 4; - if (n < 0 || keylistlen < n) { - *retstr = dupstr("Received broken SSH-2 key list from agent"); - sfree(keylist); - return PAGEANT_ACTION_FAILURE; - } - fingerprint = ssh2_fingerprint_blob(p, n); - cbkey.blob = strbuf_new(); - put_data(cbkey.blob, p, n); - p += n, keylistlen -= n; + pubblob = get_string(src); + comment = get_string(src); - /* comment */ - if (keylistlen < 4) { + if (get_err(src)) { *retstr = dupstr("Received broken SSH-2 key list from agent"); - sfree(fingerprint); sfree(keylist); return PAGEANT_ACTION_FAILURE; } - n = toint(GET_32BIT(p)); - p += 4, keylistlen -= 4; - if (n < 0 || keylistlen < n) { - *retstr = dupstr("Received broken SSH-2 key list from agent"); - sfree(fingerprint); - sfree(keylist); - return PAGEANT_ACTION_FAILURE; - } - comment = dupprintf("%.*s", (int)n, (const char *)p); - p += n, keylistlen -= n; + + fingerprint = ssh2_fingerprint_blob(pubblob.ptr, pubblob.len); + cbkey.blob = strbuf_new(); + put_data(cbkey.blob, pubblob.ptr, pubblob.len); cbkey.ssh_version = 2; - cbkey.comment = comment; - callback(callback_ctx, fingerprint, comment, &cbkey); + cbkey.comment = mkstr(comment); + callback(callback_ctx, fingerprint, cbkey.comment, &cbkey); sfree(fingerprint); - sfree(comment); + sfree(cbkey.comment); } sfree(keylist); - if (keylistlen != 0) { + if (get_err(src) || get_avail(src) != 0) { *retstr = dupstr("Received broken SSH-2 key list from agent"); return PAGEANT_ACTION_FAILURE; } diff --git a/ssh.c b/ssh.c index 515da287..518372ca 100644 --- a/ssh.c +++ b/ssh.c @@ -4053,14 +4053,13 @@ static void do_ssh1_login(void *vctx) int userpass_ret; char c; int pwpkt_type; - unsigned char *response, *p; - int responselen; + unsigned char *agent_response; + BinarySource asrc[1]; /* response from SSH agent */ int keyi, nkeys; int authed; struct RSAKey key; Bignum challenge; - char *commentp; - int commentlen; + ptrlen comment; int dlgret; Filename *keyfile; struct RSAKey servkey, hostkey; @@ -4425,6 +4424,7 @@ static void do_ssh1_login(void *vctx) * Attempt RSA authentication using Pageant. */ void *r; + int rlen; strbuf *request; s->authed = FALSE; @@ -4435,63 +4435,37 @@ static void do_ssh1_login(void *vctx) request = strbuf_new_for_agent_query(); put_byte(request, SSH1_AGENTC_REQUEST_RSA_IDENTITIES); ssh->auth_agent_query = agent_query( - request, &r, &s->responselen, ssh_agent_callback, ssh); + request, &r, &rlen, ssh_agent_callback, ssh); strbuf_free(request); if (ssh->auth_agent_query) { ssh->agent_response = NULL; crWaitUntilV(ssh->agent_response); r = ssh->agent_response; - s->responselen = ssh->agent_response_len; + rlen = ssh->agent_response_len; } - s->response = (unsigned char *) r; - if (s->response && s->responselen >= 5 && - s->response[4] == SSH1_AGENT_RSA_IDENTITIES_ANSWER) { - s->p = s->response + 5; - s->nkeys = toint(GET_32BIT(s->p)); + s->agent_response = r; + BinarySource_BARE_INIT(s->asrc, r, rlen); + get_uint32(s->asrc); /* skip length field */ + if (get_byte(s->asrc) == SSH1_AGENT_RSA_IDENTITIES_ANSWER) { + s->nkeys = toint(get_uint32(s->asrc)); if (s->nkeys < 0) { logeventf(ssh, "Pageant reported negative key count %d", s->nkeys); s->nkeys = 0; } - s->p += 4; logeventf(ssh, "Pageant has %d SSH-1 keys", s->nkeys); for (s->keyi = 0; s->keyi < s->nkeys; s->keyi++) { - unsigned char *pkblob = s->p; - s->p += 4; - { - int n, ok = FALSE; - do { /* do while (0) to make breaking easy */ - n = ssh1_read_bignum - (s->p, toint(s->responselen-(s->p-s->response)), - &s->key.exponent); - if (n < 0) - break; - s->p += n; - n = ssh1_read_bignum - (s->p, toint(s->responselen-(s->p-s->response)), - &s->key.modulus); - if (n < 0) - break; - s->p += n; - if (s->responselen - (s->p-s->response) < 4) - break; - s->commentlen = toint(GET_32BIT(s->p)); - s->p += 4; - if (s->commentlen < 0 || - toint(s->responselen - (s->p-s->response)) < - s->commentlen) - break; - s->commentp = (char *)s->p; - s->p += s->commentlen; - ok = TRUE; - } while (0); - if (!ok) { - logevent("Pageant key list packet was truncated"); - break; - } - } + ptrlen keystr; + get_rsa_ssh1_pub(s->asrc, &s->key, &keystr, + RSA_SSH1_EXPONENT_FIRST); + s->comment = get_string(s->asrc); + if (get_err(s->asrc)) { + logevent("Pageant key list packet was truncated"); + break; + } if (s->publickey_blob) { - if (!memcmp(pkblob, s->publickey_blob->s, + if (keystr.len == s->publickey_blob->len && + !memcmp(keystr.ptr, s->publickey_blob->s, s->publickey_blob->len)) { logeventf(ssh, "Pageant key #%d matches " "configured key file", s->keyi); @@ -4560,8 +4534,8 @@ static void do_ssh1_login(void *vctx) if (flags & FLAG_VERBOSE) { c_write_str(ssh, "Authenticated using" " RSA key \""); - c_write(ssh, s->commentp, - s->commentlen); + c_write(ssh, s->comment.ptr, + s->comment.len); c_write_str(ssh, "\" from agent\r\n"); } s->authed = TRUE; @@ -4583,7 +4557,7 @@ static void do_ssh1_login(void *vctx) if (s->authed) break; } - sfree(s->response); + sfree(s->agent_response); if (s->publickey_blob && !s->tried_publickey) logevent("Configured key file not in Pageant"); } else { @@ -9730,14 +9704,12 @@ static void do_ssh2_userauth(void *vctx) int privatekey_available, privatekey_encrypted; char *publickey_algorithm; char *publickey_comment; - unsigned char *agent_response, *agentp; - int agent_responselen; - unsigned char *pkblob_in_agent; + unsigned char *agent_response; + BinarySource asrc[1]; /* for reading SSH agent response */ + size_t pkblob_pos_in_agent; int keyi, nkeys; - char *pkblob, *alg, *commentp; - int pklen, alglen, commentlen; - int retlen, len; - char *ret; + ptrlen pk, alg, comment; + int len; struct Packet *pktout; Filename *keyfile; #ifndef NO_GSSAPI @@ -9866,10 +9838,10 @@ static void do_ssh2_userauth(void *vctx) */ s->nkeys = 0; s->agent_response = NULL; - s->pkblob_in_agent = NULL; + s->pkblob_pos_in_agent = 0; if (conf_get_int(ssh->conf, CONF_tryagent) && agent_exists()) { - void *r; + int rlen; strbuf *agent_request; logevent("Pageant is running. Requesting keys."); @@ -9878,23 +9850,22 @@ static void do_ssh2_userauth(void *vctx) agent_request = strbuf_new_for_agent_query(); put_byte(agent_request, SSH2_AGENTC_REQUEST_IDENTITIES); ssh->auth_agent_query = agent_query( - agent_request, &r, &s->agent_responselen, - ssh_agent_callback, ssh); + agent_request, &r, &rlen, ssh_agent_callback, ssh); strbuf_free(agent_request); if (ssh->auth_agent_query) { ssh->agent_response = NULL; crWaitUntilV(ssh->agent_response); r = ssh->agent_response; - s->agent_responselen = ssh->agent_response_len; + rlen = ssh->agent_response_len; } - s->agent_response = (unsigned char *) r; - if (s->agent_response && s->agent_responselen >= 5 && - s->agent_response[4] == SSH2_AGENT_IDENTITIES_ANSWER) { + s->agent_response = r; + BinarySource_BARE_INIT(s->asrc, r, rlen); + get_uint32(s->asrc); /* skip length field */ + if (get_byte(s->asrc) == SSH2_AGENT_IDENTITIES_ANSWER) { int keyi; - unsigned char *p; - p = s->agent_response + 5; - s->nkeys = toint(GET_32BIT(p)); + + s->nkeys = toint(get_uint32(s->asrc)); /* * Vet the Pageant response to ensure that the key @@ -9906,58 +9877,31 @@ static void do_ssh2_userauth(void *vctx) s->nkeys = 0; goto done_agent_query; } else { - unsigned char *q = p + 4; - int lenleft = s->agent_responselen - 5 - 4; + logeventf(ssh, "Pageant has %d SSH-2 keys", s->nkeys); + /* See if configured key is in agent. */ for (keyi = 0; keyi < s->nkeys; keyi++) { - int bloblen, commentlen; - if (lenleft < 4) { + size_t pos = s->asrc->pos; + ptrlen blob = get_string(s->asrc); + get_string(s->asrc); /* skip comment */ + if (get_err(s->asrc)) { logeventf(ssh, "Pageant response was truncated"); s->nkeys = 0; goto done_agent_query; } - bloblen = toint(GET_32BIT(q)); - lenleft -= 4; - q += 4; - if (bloblen < 0 || bloblen > lenleft) { - logeventf(ssh, "Pageant response was truncated"); - s->nkeys = 0; - goto done_agent_query; - } - lenleft -= bloblen; - q += bloblen; - commentlen = toint(GET_32BIT(q)); - lenleft -= 4; - q += 4; - if (commentlen < 0 || commentlen > lenleft) { - logeventf(ssh, "Pageant response was truncated"); - s->nkeys = 0; - goto done_agent_query; - } - lenleft -= commentlen; - q += commentlen; - } - } - p += 4; - logeventf(ssh, "Pageant has %d SSH-2 keys", s->nkeys); - if (s->publickey_blob) { - /* See if configured key is in agent. */ - for (keyi = 0; keyi < s->nkeys; keyi++) { - s->pklen = toint(GET_32BIT(p)); - if (s->pklen == s->publickey_blob->len && - !memcmp(p+4, s->publickey_blob->s, + if (s->publickey_blob && + blob.len == s->publickey_blob->len && + !memcmp(blob.ptr, s->publickey_blob->s, s->publickey_blob->len)) { logeventf(ssh, "Pageant key #%d matches " "configured key file", keyi); s->keyi = keyi; - s->pkblob_in_agent = p; + s->pkblob_pos_in_agent = pos; break; } - p += 4 + s->pklen; - p += toint(GET_32BIT(p)) + 4; /* comment */ } - if (!s->pkblob_in_agent) { + if (s->publickey_blob && !s->pkblob_pos_in_agent) { logevent("Configured key file not in Pageant"); s->nkeys = 0; } @@ -10066,10 +10010,10 @@ static void do_ssh2_userauth(void *vctx) /* Reset agent request state. */ s->done_agent = FALSE; if (s->agent_response) { - if (s->pkblob_in_agent) { - s->agentp = s->pkblob_in_agent; + if (s->pkblob_pos_in_agent) { + s->asrc->pos = s->pkblob_pos_in_agent; } else { - s->agentp = s->agent_response + 5 + 4; + s->asrc->pos = 9; /* skip length + type + key count */ s->keyi = 0; } } @@ -10253,17 +10197,13 @@ static void do_ssh2_userauth(void *vctx) logeventf(ssh, "Trying Pageant key #%d", s->keyi); /* Unpack key from agent response */ - s->pklen = toint(GET_32BIT(s->agentp)); - s->agentp += 4; - s->pkblob = (char *)s->agentp; - s->agentp += s->pklen; - s->alglen = toint(GET_32BIT(s->pkblob)); - s->alg = s->pkblob + 4; - s->commentlen = toint(GET_32BIT(s->agentp)); - s->agentp += 4; - s->commentp = (char *)s->agentp; - s->agentp += s->commentlen; - /* s->agentp now points at next key, if any */ + s->pk = get_string(s->asrc); + s->comment = get_string(s->asrc); + { + BinarySource src[1]; + BinarySource_BARE_INIT(src, s->pk.ptr, s->pk.len); + s->alg = get_string(src); + } /* See if server will accept it */ s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST); @@ -10273,8 +10213,8 @@ static void do_ssh2_userauth(void *vctx) put_stringz(s->pktout, "publickey"); /* method */ put_bool(s->pktout, FALSE); /* no signature included */ - put_string(s->pktout, s->alg, s->alglen); - put_string(s->pktout, s->pkblob, s->pklen); + put_stringpl(s->pktout, s->alg); + put_stringpl(s->pktout, s->pk); ssh2_pkt_send(ssh, s->pktout); s->type = AUTH_TYPE_PUBLICKEY_OFFER_QUIET; @@ -10287,12 +10227,13 @@ static void do_ssh2_userauth(void *vctx) } else { strbuf *agentreq, *sigdata; - void *vret; + void *r; + int rlen; if (flags & FLAG_VERBOSE) { c_write_str(ssh, "Authenticating with " "public key \""); - c_write(ssh, s->commentp, s->commentlen); + c_write(ssh, s->comment.ptr, s->comment.len); c_write_str(ssh, "\" from agent\r\n"); } @@ -10307,13 +10248,13 @@ static void do_ssh2_userauth(void *vctx) put_stringz(s->pktout, "publickey"); /* method */ put_bool(s->pktout, TRUE); /* signature included */ - put_string(s->pktout, s->alg, s->alglen); - put_string(s->pktout, s->pkblob, s->pklen); + put_stringpl(s->pktout, s->alg); + put_stringpl(s->pktout, s->pk); /* Ask agent for signature. */ agentreq = strbuf_new_for_agent_query(); put_byte(agentreq, SSH2_AGENTC_SIGN_REQUEST); - put_string(agentreq, s->pkblob, s->pklen); + put_stringpl(agentreq, s->pk); /* Now the data to be signed... */ sigdata = strbuf_new(); if (ssh->remote_bugs & BUG_SSH2_PK_SESSIONID) { @@ -10329,26 +10270,26 @@ static void do_ssh2_userauth(void *vctx) /* And finally the (zero) flags word. */ put_uint32(agentreq, 0); ssh->auth_agent_query = agent_query( - agentreq, &vret, &s->retlen, - ssh_agent_callback, ssh); + agentreq, &r, &rlen, ssh_agent_callback, ssh); strbuf_free(agentreq); if (ssh->auth_agent_query) { ssh->agent_response = NULL; crWaitUntilV(ssh->agent_response); - vret = ssh->agent_response; - s->retlen = ssh->agent_response_len; + r = ssh->agent_response; + rlen = ssh->agent_response_len; } - s->ret = vret; - if (s->ret) { - if (s->retlen >= 9 && - s->ret[4] == SSH2_AGENT_SIGN_RESPONSE && - GET_32BIT(s->ret + 5) <= (unsigned)(s->retlen-9)) { + if (r) { + ptrlen sigblob; + BinarySource src[1]; + BinarySource_BARE_INIT(src, r, rlen); + get_uint32(src); /* skip length field */ + if (get_byte(src) == SSH2_AGENT_SIGN_RESPONSE && + (sigblob = get_string(src), !get_err(src))) { logevent("Sending Pageant's response"); ssh2_add_sigblob(ssh, s->pktout, - s->pkblob, s->pklen, - s->ret + 9, - GET_32BIT(s->ret + 5)); + s->pk.ptr, s->pk.len, + sigblob.ptr, sigblob.len); ssh2_pkt_send(ssh, s->pktout); s->type = AUTH_TYPE_PUBLICKEY; } else { @@ -10360,7 +10301,7 @@ static void do_ssh2_userauth(void *vctx) } /* Do we have any keys left to try? */ - if (s->pkblob_in_agent) { + if (s->pkblob_pos_in_agent) { s->done_agent = TRUE; s->tried_pubkey_config = TRUE; } else { From 876e1589f845febb4d4a7a5d29e8c533ed68bea4 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Mon, 28 May 2018 15:36:15 +0100 Subject: [PATCH 330/607] Rewrite conf deserialisation using BinarySource. Like the corresponding rewrite of conf serialisation, this affects not just conf_deserialise itself but also the per-platform filename and fontspec deserialisers. --- conf.c | 84 +++++++++++------------------------------------ putty.h | 6 ++-- unix/gtkmain.c | 56 ++++++++++++++++--------------- unix/uxmisc.c | 20 +++-------- windows/window.c | 5 ++- windows/winmisc.c | 33 +++++-------------- 6 files changed, 69 insertions(+), 135 deletions(-) diff --git a/conf.c b/conf.c index 89d6412b..118e5944 100644 --- a/conf.c +++ b/conf.c @@ -504,97 +504,53 @@ void conf_serialise(BinarySink *bs, Conf *conf) put_uint32(bs, 0xFFFFFFFFU); } -int conf_deserialise(Conf *conf, void *vdata, int maxsize) +int conf_deserialise(Conf *conf, BinarySource *src) { - unsigned char *data = (unsigned char *)vdata; - unsigned char *start = data; struct conf_entry *entry; unsigned primary; - int used; - unsigned char *zero; - while (maxsize >= 4) { - primary = GET_32BIT_MSB_FIRST(data); - data += 4, maxsize -= 4; + while (1) { + primary = get_uint32(src); + if (get_err(src)) + return FALSE; + if (primary == 0xFFFFFFFFU) + return TRUE; if (primary >= N_CONFIG_OPTIONS) - break; + return FALSE; entry = snew(struct conf_entry); entry->key.primary = primary; switch (subkeytypes[entry->key.primary]) { case TYPE_INT: - if (maxsize < 4) { - sfree(entry); - goto done; - } - entry->key.secondary.i = toint(GET_32BIT_MSB_FIRST(data)); - data += 4, maxsize -= 4; + entry->key.secondary.i = toint(get_uint32(src)); break; case TYPE_STR: - zero = memchr(data, 0, maxsize); - if (!zero) { - sfree(entry); - goto done; - } - entry->key.secondary.s = dupstr((char *)data); - maxsize -= (zero + 1 - data); - data = zero + 1; + entry->key.secondary.s = dupstr(get_asciz(src)); break; } switch (valuetypes[entry->key.primary]) { case TYPE_INT: - if (maxsize < 4) { - if (subkeytypes[entry->key.primary] == TYPE_STR) - sfree(entry->key.secondary.s); - sfree(entry); - goto done; - } - entry->value.u.intval = toint(GET_32BIT_MSB_FIRST(data)); - data += 4, maxsize -= 4; + entry->value.u.intval = toint(get_uint32(src)); break; case TYPE_STR: - zero = memchr(data, 0, maxsize); - if (!zero) { - if (subkeytypes[entry->key.primary] == TYPE_STR) - sfree(entry->key.secondary.s); - sfree(entry); - goto done; - } - entry->value.u.stringval = dupstr((char *)data); - maxsize -= (zero + 1 - data); - data = zero + 1; + entry->value.u.stringval = dupstr(get_asciz(src)); break; case TYPE_FILENAME: - entry->value.u.fileval = - filename_deserialise(data, maxsize, &used); - if (!entry->value.u.fileval) { - if (subkeytypes[entry->key.primary] == TYPE_STR) - sfree(entry->key.secondary.s); - sfree(entry); - goto done; - } - data += used; - maxsize -= used; + entry->value.u.fileval = filename_deserialise(src); break; case TYPE_FONT: - entry->value.u.fontval = - fontspec_deserialise(data, maxsize, &used); - if (!entry->value.u.fontval) { - if (subkeytypes[entry->key.primary] == TYPE_STR) - sfree(entry->key.secondary.s); - sfree(entry); - goto done; - } - data += used; - maxsize -= used; + entry->value.u.fontval = fontspec_deserialise(src); break; } + + if (get_err(src)) { + free_entry(entry); + return FALSE; + } + conf_insert(conf, entry); } - - done: - return (int)(data - start); } diff --git a/putty.h b/putty.h index d7301509..fb9a2d55 100644 --- a/putty.h +++ b/putty.h @@ -1015,7 +1015,7 @@ void conf_set_filename(Conf *conf, int key, const Filename *val); void conf_set_fontspec(Conf *conf, int key, const FontSpec *val); /* Serialisation functions for Duplicate Session */ void conf_serialise(BinarySink *bs, Conf *conf); -int conf_deserialise(Conf *conf, void *data, int maxsize);/*returns size used*/ +int conf_deserialise(Conf *conf, BinarySource *src);/*returns true on success*/ /* * Functions to copy, free, serialise and deserialise FontSpecs. @@ -1029,7 +1029,7 @@ int conf_deserialise(Conf *conf, void *data, int maxsize);/*returns size used*/ FontSpec *fontspec_copy(const FontSpec *f); void fontspec_free(FontSpec *f); void fontspec_serialise(BinarySink *bs, FontSpec *f); -FontSpec *fontspec_deserialise(void *data, int maxsize, int *used); +FontSpec *fontspec_deserialise(BinarySource *src); /* * Exports from noise.c. @@ -1456,7 +1456,7 @@ int filename_is_null(const Filename *fn); Filename *filename_copy(const Filename *fn); void filename_free(Filename *fn); void filename_serialise(BinarySink *bs, const Filename *f); -Filename *filename_deserialise(void *data, int maxsize, int *used); +Filename *filename_deserialise(BinarySource *src); char *get_username(void); /* return value needs freeing */ char *get_random_data(int bytes, const char *device); /* used in cmdgen.c */ char filename_char_sanitise(char c); /* rewrite special pathname chars */ diff --git a/unix/gtkmain.c b/unix/gtkmain.c index ff6a15cf..906d029a 100644 --- a/unix/gtkmain.c +++ b/unix/gtkmain.c @@ -201,8 +201,9 @@ void launch_saved_session(const char *str) int read_dupsession_data(Conf *conf, char *arg) { - int fd, i, ret, size, size_used; + int fd, i, ret, size; char *data; + BinarySource src[1]; if (sscanf(arg, "---[%d,%d]", &fd, &size) != 2) { fprintf(stderr, "%s: malformed magic argument `%s'\n", appname, arg); @@ -222,35 +223,36 @@ int read_dupsession_data(Conf *conf, char *arg) exit(1); } - size_used = conf_deserialise(conf, data, size); - if (use_pty_argv && size > size_used) { - int n = 0; - i = size_used; - while (i < size) { - while (i < size && data[i]) i++; - if (i >= size) { - fprintf(stderr, "%s: malformed Duplicate Session data\n", - appname); - exit(1); - } - i++; - n++; - } - pty_argv = snewn(n+1, char *); - pty_argv[n] = NULL; - n = 0; - i = size_used; - while (i < size) { - char *p = data + i; - while (i < size && data[i]) i++; - assert(i < size); - i++; - pty_argv[n++] = dupstr(p); - } + BinarySource_BARE_INIT(src, data, size); + if (!conf_deserialise(conf, src)) { + fprintf(stderr, "%s: malformed Duplicate Session data\n", appname); + exit(1); } + if (use_pty_argv) { + int pty_argc = 0; + size_t argv_startpos = src->pos; - sfree(data); + while (get_asciz(src), !get_err(src)) + pty_argc++; + src->err = BSE_NO_ERROR; + + if (pty_argc > 0) { + src->pos = argv_startpos; + + pty_argv = snewn(pty_argc + 1, char *); + pty_argv[pty_argc] = NULL; + for (i = 0; i < pty_argc; i++) + pty_argv[i] = dupstr(get_asciz(src)); + } + } + + if (get_err(src) || get_avail(src) > 0) { + fprintf(stderr, "%s: malformed Duplicate Session data\n", appname); + exit(1); + } + + sfree(data); return 0; } diff --git a/unix/uxmisc.c b/unix/uxmisc.c index e96829c4..c478856b 100644 --- a/unix/uxmisc.c +++ b/unix/uxmisc.c @@ -78,16 +78,9 @@ void filename_serialise(BinarySink *bs, const Filename *f) { put_asciz(bs, f->path); } -Filename *filename_deserialise(void *vdata, int maxsize, int *used) +Filename *filename_deserialise(BinarySource *src) { - char *data = (char *)vdata; - char *end; - end = memchr(data, '\0', maxsize); - if (!end) - return NULL; - end++; - *used = end - data; - return filename_from_str(data); + return filename_from_str(get_asciz(src)); } char filename_char_sanitise(char c) @@ -274,14 +267,9 @@ void fontspec_serialise(BinarySink *bs, FontSpec *f) { put_asciz(bs, f->name); } -FontSpec *fontspec_deserialise(void *vdata, int maxsize, int *used) +FontSpec *fontspec_deserialise(BinarySource *src) { - char *data = (char *)vdata; - char *end = memchr(data, '\0', maxsize); - if (!end) - return NULL; - *used = end - data + 1; - return fontspec_new(data); + return fontspec_new(get_asciz(src)); } char *make_dir_and_check_ours(const char *dirname) diff --git a/windows/window.c b/windows/window.c index d6a67d42..88a251fe 100644 --- a/windows/window.c +++ b/windows/window.c @@ -480,7 +480,10 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) if (sscanf(p + 1, "%p:%u", &filemap, &cpsize) == 2 && (cp = MapViewOfFile(filemap, FILE_MAP_READ, 0, 0, cpsize)) != NULL) { - conf_deserialise(conf, cp, cpsize); + BinarySource src[1]; + BinarySource_BARE_INIT(src, cp, cpsize); + if (!conf_deserialise(conf, src)) + modalfatalbox("Serialised configuration data was invalid"); UnmapViewOfFile(cp); CloseHandle(filemap); } else if (!do_config()) { diff --git a/windows/winmisc.c b/windows/winmisc.c index c3ec8306..e65ba1c9 100644 --- a/windows/winmisc.c +++ b/windows/winmisc.c @@ -54,16 +54,9 @@ void filename_serialise(BinarySink *bs, const Filename *f) { put_asciz(bs, f->path); } -Filename *filename_deserialise(void *vdata, int maxsize, int *used) +Filename *filename_deserialise(BinarySource *src) { - char *data = (char *)vdata; - char *end; - end = memchr(data, '\0', maxsize); - if (!end) - return NULL; - end++; - *used = end - data; - return filename_from_str(data); + return filename_from_str(get_asciz(src)); } char filename_char_sanitise(char c) @@ -561,21 +554,13 @@ void fontspec_serialise(BinarySink *bs, FontSpec *f) put_uint32(bs, f->height); put_uint32(bs, f->charset); } -FontSpec *fontspec_deserialise(void *vdata, int maxsize, int *used) -{ - char *data = (char *)vdata; - char *end; - if (maxsize < 13) - return NULL; - end = memchr(data, '\0', maxsize-12); - if (!end) - return NULL; - end++; - *used = end - data + 12; - return fontspec_new(data, - GET_32BIT_MSB_FIRST(end), - GET_32BIT_MSB_FIRST(end + 4), - GET_32BIT_MSB_FIRST(end + 8)); +FontSpec *fontspec_deserialise(BinarySource *src) +{ + const char *name = get_asciz(src); + unsigned isbold = get_uint32(src); + unsigned height = get_uint32(src); + unsigned charset = get_uint32(src); + return fontspec_new(name, isbold, height, charset); } int open_for_write_would_lose_data(const Filename *fn) From 59e83a8c758c651ac26c434d1a3949dac035f9ee Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Mon, 28 May 2018 17:42:03 +0100 Subject: [PATCH 331/607] Rewrite key import functions using BinarySource. The OpenSSH PEM reader is the most interesting conversion out of these: it was using a standalone function called get_ber_id_len(), which only skipped over the header of an ASN.1 BER data item and left the current position at the start of the payload. That's been replaced by a get_ber() function more in the spirit of the new API, which consumes the entire BER element, returning its header details and also a ptrlen pointing at its payload. (That function could easily be promoted out of import.c to somewhere more central, if we ever had a need to handle ASN.1 on a larger scale - e.g. X.509 certificates would find the same function useful. For the moment, though, it can stay where it is.) Other than that, this is a fairly mechanical API translation. --- import.c | 812 +++++++++++++++++++++++-------------------------------- 1 file changed, 340 insertions(+), 472 deletions(-) diff --git a/import.c b/import.c index 7b9d516b..bc54108a 100644 --- a/import.c +++ b/import.c @@ -168,51 +168,6 @@ void strip_crlf(char *str) /* Primitive versus constructed bit. */ #define ASN1_CONSTRUCTED (1 << 5) -static int ber_read_id_len(void *source, int sourcelen, - int *id, int *length, int *flags) -{ - unsigned char *p = (unsigned char *) source; - - if (sourcelen == 0) - return -1; - - *flags = (*p & 0xE0); - if ((*p & 0x1F) == 0x1F) { - *id = 0; - while (*p & 0x80) { - p++, sourcelen--; - if (sourcelen == 0) - return -1; - *id = (*id << 7) | (*p & 0x7F); - } - p++, sourcelen--; - } else { - *id = *p & 0x1F; - p++, sourcelen--; - } - - if (sourcelen == 0) - return -1; - - if (*p & 0x80) { - unsigned len; - int n = *p & 0x7F; - p++, sourcelen--; - if (sourcelen < n) - return -1; - len = 0; - while (n--) - len = (len << 8) | (*p++); - sourcelen -= n; - *length = toint(len); - } else { - *length = *p; - p++, sourcelen--; - } - - return p - (unsigned char *) source; -} - /* * Write an ASN.1/BER identifier and length pair. Returns the * number of bytes consumed. Assumes dest contains enough space. @@ -265,30 +220,48 @@ static void BinarySink_put_ber_id_len(BinarySink *bs, #define put_ber_id_len(bs, id, len, flags) \ BinarySink_put_ber_id_len(BinarySink_UPCAST(bs), id, len, flags) -/* Simple structure to point to an mp-int within a blob. */ -struct mpint_pos { void *start; int bytes; }; +typedef struct ber_item { + int id; + int flags; + ptrlen data; +} ber_item; -static int ssh2_read_mpint(void *data, int len, struct mpint_pos *ret) +static ber_item BinarySource_get_ber(BinarySource *src) { - int bytes; - unsigned char *d = (unsigned char *) data; + ber_item toret; + unsigned char leadbyte, lenbyte; + size_t length; - if (len < 4) - goto error; - bytes = toint(GET_32BIT(d)); - if (bytes < 0 || len-4 < bytes) - goto error; + leadbyte = get_byte(src); + toret.flags = (leadbyte & 0xE0); + if ((leadbyte & 0x1F) == 0x1F) { + unsigned char idbyte; - ret->start = d + 4; - ret->bytes = bytes; - return bytes+4; + toret.id = 0; + do { + idbyte = get_byte(src); + toret.id = (toret.id << 7) | (idbyte & 0x7F); + } while (idbyte & 0x80); + } else { + toret.id = leadbyte & 0x1F; + } - error: - ret->start = NULL; - ret->bytes = -1; - return len; /* ensure further calls fail as well */ + lenbyte = get_byte(src); + if (lenbyte & 0x80) { + int nbytes = lenbyte & 0x7F; + length = 0; + while (nbytes-- > 0) + length = (length << 8) | get_byte(src); + } else { + length = lenbyte; + } + + toret.data = get_data(src, length); + return toret; } +#define get_ber(bs) BinarySource_get_ber(BinarySource_UPCAST(bs)) + /* ---------------------------------------------------------------------- * Code to read and write OpenSSH private keys, in the old-style PEM * format. @@ -306,8 +279,7 @@ struct openssh_pem_key { int encrypted; openssh_pem_enc encryption; char iv[32]; - unsigned char *keyblob; - int keyblob_len, keyblob_size; + strbuf *keyblob; }; void BinarySink_put_mp_ssh2_from_string( @@ -342,8 +314,7 @@ static struct openssh_pem_key *load_openssh_pem_key(const Filename *filename, int base64_chars = 0; ret = snew(struct openssh_pem_key); - ret->keyblob = NULL; - ret->keyblob_len = ret->keyblob_size = 0; + ret->keyblob = strbuf_new(); fp = f_open(filename, "r", FALSE); if (!fp) { @@ -462,14 +433,7 @@ static struct openssh_pem_key *load_openssh_pem_key(const Filename *filename, goto error; } - if (ret->keyblob_len + len > ret->keyblob_size) { - ret->keyblob_size = ret->keyblob_len + len + 256; - ret->keyblob = sresize(ret->keyblob, ret->keyblob_size, - unsigned char); - } - - memcpy(ret->keyblob + ret->keyblob_len, out, len); - ret->keyblob_len += len; + put_data(ret->keyblob, out, len); smemclr(out, sizeof(out)); } @@ -485,12 +449,12 @@ static struct openssh_pem_key *load_openssh_pem_key(const Filename *filename, fclose(fp); fp = NULL; - if (ret->keyblob_len == 0 || !ret->keyblob) { + if (!ret->keyblob || ret->keyblob->len == 0) { errmsg = "key body not present"; goto error; } - if (ret->encrypted && ret->keyblob_len % 8 != 0) { + if (ret->encrypted && ret->keyblob->len % 8 != 0) { errmsg = "encrypted key blob is not a multiple of " "cipher block size"; goto error; @@ -508,10 +472,8 @@ static struct openssh_pem_key *load_openssh_pem_key(const Filename *filename, } smemclr(base64_bit, sizeof(base64_bit)); if (ret) { - if (ret->keyblob) { - smemclr(ret->keyblob, ret->keyblob_size); - sfree(ret->keyblob); - } + if (ret->keyblob) + strbuf_free(ret->keyblob); smemclr(ret, sizeof(*ret)); sfree(ret); } @@ -528,8 +490,7 @@ int openssh_pem_encrypted(const Filename *filename) if (!key) return 0; ret = key->encrypted; - smemclr(key->keyblob, key->keyblob_size); - sfree(key->keyblob); + strbuf_free(key->keyblob); smemclr(key, sizeof(*key)); sfree(key); return ret; @@ -541,14 +502,13 @@ struct ssh2_userkey *openssh_pem_read(const Filename *filename, { struct openssh_pem_key *key = load_openssh_pem_key(filename, errmsg_p); struct ssh2_userkey *retkey; - unsigned char *p; - int ret, id, len, flags; + BinarySource src[1]; int i, num_integers; struct ssh2_userkey *retval = NULL; const char *errmsg; strbuf *blob = strbuf_new(); int privptr = 0, publen; - char *modptr = NULL; + const char *modptr = NULL; int modlen = 0; if (!key) @@ -586,14 +546,14 @@ struct ssh2_userkey *openssh_pem_read(const Filename *filename, */ if (key->encryption == OP_E_3DES) des3_decrypt_pubkey_ossh(keybuf, key->iv, - key->keyblob, key->keyblob_len); + key->keyblob->u, key->keyblob->len); else { void *ctx; assert(key->encryption == OP_E_AES); ctx = aes_make_context(); aes128_key(ctx, keybuf); aes_iv(ctx, key->iv); - aes_ssh2_decrypt_blk(ctx, key->keyblob, key->keyblob_len); + aes_ssh2_decrypt_blk(ctx, key->keyblob->u, key->keyblob->len); aes_free_context(ctx); } @@ -623,17 +583,21 @@ struct ssh2_userkey *openssh_pem_read(const Filename *filename, * EXPLICIT [0] OID curve, EXPLICIT [1] BIT STRING pubPoint */ - p = key->keyblob; - - /* Expect the SEQUENCE header. Take its absence as a failure to - * decrypt, if the key was encrypted. */ - ret = ber_read_id_len(p, key->keyblob_len, &id, &len, &flags); - p += ret; - if (ret < 0 || id != 16 || len < 0 || - key->keyblob+key->keyblob_len-p < len) { - errmsg = "ASN.1 decoding failure"; - retval = key->encrypted ? SSH2_WRONG_PASSPHRASE : NULL; - goto error; + BinarySource_BARE_INIT(src, key->keyblob->u, key->keyblob->len); + + { + /* Expect the SEQUENCE header. Take its absence as a failure to + * decrypt, if the key was encrypted. */ + ber_item seq = get_ber(src); + if (get_err(src) || seq.id != 16) { + errmsg = "ASN.1 decoding failure"; + retval = key->encrypted ? SSH2_WRONG_PASSPHRASE : NULL; + goto error; + } + + /* Reinitialise our BinarySource to parse just the inside of that + * SEQUENCE. */ + BinarySource_BARE_INIT(src, seq.data.ptr, seq.data.len); } /* Expect a load of INTEGERs. */ @@ -647,81 +611,53 @@ struct ssh2_userkey *openssh_pem_read(const Filename *filename, if (key->keytype == OP_ECDSA) { /* And now for something completely different */ - unsigned char *priv; - int privlen; + ber_item integer, privkey, sub0, sub1, oid, pubkey; const ssh_keyalg *alg; const struct ec_curve *curve; - /* Read INTEGER 1 */ - ret = ber_read_id_len(p, key->keyblob+key->keyblob_len-p, - &id, &len, &flags); - p += ret; - if (ret < 0 || id != 2 || len != 1 || - key->keyblob+key->keyblob_len-p < len || p[0] != 1) { - errmsg = "ASN.1 decoding failure"; - retval = key->encrypted ? SSH2_WRONG_PASSPHRASE : NULL; - goto error; - } - p += 1; - /* Read private key OCTET STRING */ - ret = ber_read_id_len(p, key->keyblob+key->keyblob_len-p, - &id, &len, &flags); - p += ret; - if (ret < 0 || id != 4 || len < 0 || - key->keyblob+key->keyblob_len-p < len) { - errmsg = "ASN.1 decoding failure"; - retval = key->encrypted ? SSH2_WRONG_PASSPHRASE : NULL; - goto error; - } - priv = p; - privlen = len; - p += len; - /* Read curve OID */ - ret = ber_read_id_len(p, key->keyblob+key->keyblob_len-p, - &id, &len, &flags); - p += ret; - if (ret < 0 || id != 0 || len < 0 || - key->keyblob+key->keyblob_len-p < len) { - errmsg = "ASN.1 decoding failure"; - retval = key->encrypted ? SSH2_WRONG_PASSPHRASE : NULL; - goto error; - } - ret = ber_read_id_len(p, key->keyblob+key->keyblob_len-p, - &id, &len, &flags); - p += ret; - if (ret < 0 || id != 6 || len < 0 || - key->keyblob+key->keyblob_len-p < len) { + + /* Parse the outer layer of things inside the containing SEQUENCE */ + integer = get_ber(src); + privkey = get_ber(src); + sub0 = get_ber(src); + sub1 = get_ber(src); + + /* Now look inside sub0 for the curve OID */ + BinarySource_BARE_INIT(src, sub0.data.ptr, sub0.data.len); + oid = get_ber(src); + + /* And inside sub1 for the public-key BIT STRING */ + BinarySource_BARE_INIT(src, sub1.data.ptr, sub1.data.len); + pubkey = get_ber(src); + + if (get_err(src) || + integer.id != 2 || + integer.data.len != 1 || + ((const unsigned char *)integer.data.ptr)[0] != 1 || + privkey.id != 4 || + sub0.id != 0 || + sub1.id != 1 || + oid.id != 6 || + pubkey.id != 3) { + errmsg = "ASN.1 decoding failure"; retval = key->encrypted ? SSH2_WRONG_PASSPHRASE : NULL; goto error; } - alg = ec_alg_by_oid(len, p, &curve); + + alg = ec_alg_by_oid(oid.data.len, oid.data.ptr, &curve); if (!alg) { errmsg = "Unsupported ECDSA curve."; retval = NULL; goto error; } - p += len; - /* Read BIT STRING point */ - ret = ber_read_id_len(p, key->keyblob+key->keyblob_len-p, - &id, &len, &flags); - p += ret; - if (ret < 0 || id != 1 || len < 0 || - key->keyblob+key->keyblob_len-p < len) { - errmsg = "ASN.1 decoding failure"; - retval = key->encrypted ? SSH2_WRONG_PASSPHRASE : NULL; - goto error; - } - ret = ber_read_id_len(p, key->keyblob+key->keyblob_len-p, - &id, &len, &flags); - p += ret; - if (ret < 0 || id != 3 || len < 0 || - key->keyblob+key->keyblob_len-p < len || - len != ((((curve->fieldBits + 7) / 8) * 2) + 2)) { + if (pubkey.data.len != ((((curve->fieldBits + 7) / 8) * 2) + 2)) { errmsg = "ASN.1 decoding failure"; retval = key->encrypted ? SSH2_WRONG_PASSPHRASE : NULL; goto error; } - p += 1; len -= 1; /* Skip 0x00 before point */ + /* Skip 0x00 before point */ + pubkey.data.ptr = (const char *)pubkey.data.ptr + 1; + pubkey.data.len -= 1; /* Construct the key */ retkey = snew(struct ssh2_userkey); @@ -729,9 +665,9 @@ struct ssh2_userkey *openssh_pem_read(const Filename *filename, put_stringz(blob, alg->name); put_stringz(blob, curve->name); - put_string(blob, p, len); + put_stringpl(blob, pubkey.data); publen = blob->len; - put_mp_ssh2_from_string(blob, priv, privlen); + put_mp_ssh2_from_string(blob, privkey.data.ptr, privkey.data.len); retkey->data = retkey->alg->createkey( retkey->alg, blob->u, publen, @@ -748,11 +684,9 @@ struct ssh2_userkey *openssh_pem_read(const Filename *filename, put_stringz(blob, key->keytype == OP_DSA ? "ssh-dss" : "ssh-rsa"); for (i = 0; i < num_integers; i++) { - ret = ber_read_id_len(p, key->keyblob+key->keyblob_len-p, - &id, &len, &flags); - p += ret; - if (ret < 0 || id != 2 || len < 0 || - key->keyblob+key->keyblob_len-p < len) { + ber_item integer = get_ber(src); + + if (get_err(src) || integer.id != 2) { errmsg = "ASN.1 decoding failure"; retval = key->encrypted ? SSH2_WRONG_PASSPHRASE : NULL; goto error; @@ -763,7 +697,8 @@ struct ssh2_userkey *openssh_pem_read(const Filename *filename, * The first integer should be zero always (I think * this is some sort of version indication). */ - if (len != 1 || p[0] != 0) { + if (integer.data.len != 1 || + ((const unsigned char *)integer.data.ptr)[0] != 0) { errmsg = "version number mismatch"; goto error; } @@ -775,10 +710,11 @@ struct ssh2_userkey *openssh_pem_read(const Filename *filename, */ if (i == 1) { /* Save the details for after we deal with number 2. */ - modptr = (char *)p; - modlen = len; + modptr = integer.data.ptr; + modlen = integer.data.len; } else if (i != 6 && i != 7) { - put_mp_ssh2_from_string(blob, p, len); + put_mp_ssh2_from_string(blob, integer.data.ptr, + integer.data.len); if (i == 2) { put_mp_ssh2_from_string(blob, modptr, modlen); privptr = blob->len; @@ -789,13 +725,11 @@ struct ssh2_userkey *openssh_pem_read(const Filename *filename, * Integers 1-4 go into the public blob; integer 5 goes * into the private blob. */ - put_mp_ssh2_from_string(blob, p, len); + put_mp_ssh2_from_string(blob, integer.data.ptr, + integer.data.len); if (i == 4) privptr = blob->len; } - - /* Skip past the number. */ - p += len; } /* @@ -833,8 +767,7 @@ struct ssh2_userkey *openssh_pem_read(const Filename *filename, error: strbuf_free(blob); - smemclr(key->keyblob, key->keyblob_size); - sfree(key->keyblob); + strbuf_free(key->keyblob); smemclr(key, sizeof(*key)); sfree(key); if (errmsg_p) *errmsg_p = errmsg; @@ -847,13 +780,14 @@ int openssh_pem_write(const Filename *filename, struct ssh2_userkey *key, strbuf *pubblob, *privblob, *outblob; unsigned char *spareblob; int sparelen = 0; - struct mpint_pos numbers[9]; + ptrlen numbers[9]; int nnumbers, i; const char *header, *footer; char zero[1]; unsigned char iv[8]; int ret = 0; FILE *fp; + BinarySource src[1]; /* * Fetch the key blobs. @@ -881,29 +815,29 @@ int openssh_pem_write(const Filename *filename, struct ssh2_userkey *key, * common code after that. */ if (key->alg == &ssh_rsa) { - int pos; - struct mpint_pos n, e, d, p, q, iqmp, dmp1, dmq1; + ptrlen n, e, d, p, q, iqmp, dmp1, dmq1; Bignum bd, bp, bq, bdmp1, bdmq1; /* * These blobs were generated from inside PuTTY, so we needn't * treat them as untrusted. */ - pos = 4 + GET_32BIT(pubblob->u); - pos += ssh2_read_mpint(pubblob->u+pos, pubblob->len-pos, &e); - pos += ssh2_read_mpint(pubblob->u+pos, pubblob->len-pos, &n); - pos = 0; - pos += ssh2_read_mpint(privblob->u+pos, privblob->len-pos, &d); - pos += ssh2_read_mpint(privblob->u+pos, privblob->len-pos, &p); - pos += ssh2_read_mpint(privblob->u+pos, privblob->len-pos, &q); - pos += ssh2_read_mpint(privblob->u+pos, privblob->len-pos, &iqmp); - - assert(e.start && iqmp.start); /* can't go wrong */ + BinarySource_BARE_INIT(src, pubblob->u, pubblob->len); + get_string(src); /* skip algorithm name */ + e = get_string(src); + n = get_string(src); + BinarySource_BARE_INIT(src, privblob->u, privblob->len); + d = get_string(src); + p = get_string(src); + q = get_string(src); + iqmp = get_string(src); + + assert(!get_err(src)); /* can't go wrong */ /* We also need d mod (p-1) and d mod (q-1). */ - bd = bignum_from_bytes(d.start, d.bytes); - bp = bignum_from_bytes(p.start, p.bytes); - bq = bignum_from_bytes(q.start, q.bytes); + bd = bignum_from_bytes(d.ptr, d.len); + bp = bignum_from_bytes(p.ptr, p.len); + bq = bignum_from_bytes(q.ptr, q.len); decbn(bp); decbn(bq); bdmp1 = bigmod(bd, bp); @@ -912,20 +846,20 @@ int openssh_pem_write(const Filename *filename, struct ssh2_userkey *key, freebn(bp); freebn(bq); - dmp1.bytes = (bignum_bitcount(bdmp1)+8)/8; - dmq1.bytes = (bignum_bitcount(bdmq1)+8)/8; - sparelen = dmp1.bytes + dmq1.bytes; + dmp1.len = (bignum_bitcount(bdmp1)+8)/8; + dmq1.len = (bignum_bitcount(bdmq1)+8)/8; + sparelen = dmp1.len + dmq1.len; spareblob = snewn(sparelen, unsigned char); - dmp1.start = spareblob; - dmq1.start = spareblob + dmp1.bytes; - for (i = 0; i < dmp1.bytes; i++) - spareblob[i] = bignum_byte(bdmp1, dmp1.bytes-1 - i); - for (i = 0; i < dmq1.bytes; i++) - spareblob[i+dmp1.bytes] = bignum_byte(bdmq1, dmq1.bytes-1 - i); + dmp1.ptr = spareblob; + dmq1.ptr = spareblob + dmp1.len; + for (i = 0; i < dmp1.len; i++) + spareblob[i] = bignum_byte(bdmp1, dmp1.len-1 - i); + for (i = 0; i < dmq1.len; i++) + spareblob[i+dmp1.len] = bignum_byte(bdmq1, dmq1.len-1 - i); freebn(bdmp1); freebn(bdmq1); - numbers[0].start = zero; numbers[0].bytes = 1; zero[0] = '\0'; + numbers[0] = make_ptrlen(zero, 1); zero[0] = '\0'; numbers[1] = n; numbers[2] = e; numbers[3] = d; @@ -939,24 +873,24 @@ int openssh_pem_write(const Filename *filename, struct ssh2_userkey *key, header = "-----BEGIN RSA PRIVATE KEY-----\n"; footer = "-----END RSA PRIVATE KEY-----\n"; } else { /* ssh-dss */ - int pos; - struct mpint_pos p, q, g, y, x; + ptrlen p, q, g, y, x; /* * These blobs were generated from inside PuTTY, so we needn't * treat them as untrusted. */ - pos = 4 + GET_32BIT(pubblob->u); - pos += ssh2_read_mpint(pubblob->u+pos, pubblob->len-pos, &p); - pos += ssh2_read_mpint(pubblob->u+pos, pubblob->len-pos, &q); - pos += ssh2_read_mpint(pubblob->u+pos, pubblob->len-pos, &g); - pos += ssh2_read_mpint(pubblob->u+pos, pubblob->len-pos, &y); - pos = 0; - pos += ssh2_read_mpint(privblob->u+pos, privblob->len-pos, &x); - - assert(y.start && x.start); /* can't go wrong */ - - numbers[0].start = zero; numbers[0].bytes = 1; zero[0] = '\0'; + BinarySource_BARE_INIT(src, pubblob->u, pubblob->len); + get_string(src); /* skip algorithm name */ + p = get_string(src); + q = get_string(src); + g = get_string(src); + y = get_string(src); + BinarySource_BARE_INIT(src, privblob->u, privblob->len); + x = get_string(src); + + assert(!get_err(src)); /* can't go wrong */ + + numbers[0].ptr = zero; numbers[0].len = 1; zero[0] = '\0'; numbers[1] = p; numbers[2] = q; numbers[3] = g; @@ -970,8 +904,8 @@ int openssh_pem_write(const Filename *filename, struct ssh2_userkey *key, seq = strbuf_new(); for (i = 0; i < nnumbers; i++) { - put_ber_id_len(seq, 2, numbers[i].bytes, 0); - put_data(seq, numbers[i].start, numbers[i].bytes); + put_ber_id_len(seq, 2, numbers[i].len, 0); + put_data(seq, numbers[i].ptr, numbers[i].len); } put_ber_id_len(outblob, 16, seq->len, ASN1_CONSTRUCTED); put_data(outblob, seq->s, seq->len); @@ -1161,14 +1095,12 @@ struct openssh_new_key { int rounds; /* This points to a position within keyblob, not a * separately allocated thing */ - const unsigned char *salt; - int saltlen; + ptrlen salt; } bcrypt; } kdfopts; int nkeys, key_wanted; /* This too points to a position within keyblob */ - unsigned char *privatestr; - int privatelen; + ptrlen private; unsigned char *keyblob; int keyblob_len, keyblob_size; @@ -1184,11 +1116,9 @@ static struct openssh_new_key *load_openssh_new_key(const Filename *filename, char *p; char base64_bit[4]; int base64_chars = 0; - const void *filedata; - int filelen; - const void *string, *kdfopts, *bcryptsalt, *pubkey; - int stringlen, kdfoptlen, bcryptsaltlen, pubkeylen; - unsigned bcryptrounds, nkeys, key_index; + BinarySource src[1]; + ptrlen str; + unsigned key_index; ret = snew(struct openssh_new_key); ret->keyblob = NULL; @@ -1268,68 +1198,61 @@ static struct openssh_new_key *load_openssh_new_key(const Filename *filename, goto error; } - filedata = ret->keyblob; - filelen = ret->keyblob_len; + BinarySource_BARE_INIT(src, ret->keyblob, ret->keyblob_len); - if (filelen < 15 || 0 != memcmp(filedata, "openssh-key-v1\0", 15)) { + if (strcmp(get_asciz(src), "openssh-key-v1") != 0) { errmsg = "new-style OpenSSH magic number missing\n"; goto error; } - filedata = (const char *)filedata + 15; - filelen -= 15; - if (!(string = get_ssh_string(&filelen, &filedata, &stringlen))) { - errmsg = "encountered EOF before cipher name\n"; - goto error; - } - if (match_ssh_id(stringlen, string, "none")) { + /* Cipher name */ + str = get_string(src); + if (ptrlen_eq_string(str, "none")) { ret->cipher = ON_E_NONE; - } else if (match_ssh_id(stringlen, string, "aes256-cbc")) { + } else if (ptrlen_eq_string(str, "aes256-cbc")) { ret->cipher = ON_E_AES256CBC; - } else if (match_ssh_id(stringlen, string, "aes256-ctr")) { + } else if (ptrlen_eq_string(str, "aes256-ctr")) { ret->cipher = ON_E_AES256CTR; } else { - errmsg = "unrecognised cipher name\n"; + errmsg = get_err(src) ? "no cipher name found" : + "unrecognised cipher name\n"; goto error; } - if (!(string = get_ssh_string(&filelen, &filedata, &stringlen))) { - errmsg = "encountered EOF before kdf name\n"; - goto error; - } - if (match_ssh_id(stringlen, string, "none")) { + /* Key derivation function name */ + str = get_string(src); + if (ptrlen_eq_string(str, "none")) { ret->kdf = ON_K_NONE; - } else if (match_ssh_id(stringlen, string, "bcrypt")) { + } else if (ptrlen_eq_string(str, "bcrypt")) { ret->kdf = ON_K_BCRYPT; } else { - errmsg = "unrecognised kdf name\n"; + errmsg = get_err(src) ? "no kdf name found" : + "unrecognised kdf name\n"; goto error; } - if (!(kdfopts = get_ssh_string(&filelen, &filedata, &kdfoptlen))) { - errmsg = "encountered EOF before kdf options\n"; - goto error; - } + /* KDF extra options */ + str = get_string(src); switch (ret->kdf) { case ON_K_NONE: - if (kdfoptlen != 0) { + if (str.len != 0) { errmsg = "expected empty options string for 'none' kdf"; goto error; } break; case ON_K_BCRYPT: - if (!(bcryptsalt = get_ssh_string(&kdfoptlen, &kdfopts, - &bcryptsaltlen))) { - errmsg = "bcrypt options string did not contain salt\n"; - goto error; - } - if (!get_ssh_uint32(&kdfoptlen, &kdfopts, &bcryptrounds)) { - errmsg = "bcrypt options string did not contain round count\n"; - goto error; + { + BinarySource opts[1]; + + BinarySource_BARE_INIT(opts, str.ptr, str.len); + ret->kdfopts.bcrypt.salt = get_string(opts); + ret->kdfopts.bcrypt.rounds = get_uint32(opts); + + if (get_err(opts)) { + errmsg = "failed to parse bcrypt options string"; + goto error; + } } - ret->kdfopts.bcrypt.salt = bcryptsalt; - ret->kdfopts.bcrypt.saltlen = bcryptsaltlen; - ret->kdfopts.bcrypt.rounds = bcryptrounds; break; } @@ -1345,35 +1268,27 @@ static struct openssh_new_key *load_openssh_new_key(const Filename *filename, * 'key_wanted' field is set to a value in the range [0, * nkeys) by some mechanism. */ - if (!get_ssh_uint32(&filelen, &filedata, &nkeys)) { - errmsg = "encountered EOF before key count\n"; + ret->nkeys = toint(get_uint32(src)); + if (ret->nkeys != 1) { + errmsg = get_err(src) ? "no key count found" : + "multiple keys in new-style OpenSSH key file not supported\n"; goto error; } - if (nkeys != 1) { - errmsg = "multiple keys in new-style OpenSSH key file " - "not supported\n"; - goto error; - } - ret->nkeys = nkeys; ret->key_wanted = 0; - for (key_index = 0; key_index < nkeys; key_index++) { - if (!(pubkey = get_ssh_string(&filelen, &filedata, &pubkeylen))) { - errmsg = "encountered EOF before kdf options\n"; - goto error; - } - } + /* Read and ignore a string per public key. */ + for (key_index = 0; key_index < ret->nkeys; key_index++) + str = get_string(src); /* * Now we expect a string containing the encrypted part of the * key file. */ - if (!(string = get_ssh_string(&filelen, &filedata, &stringlen))) { - errmsg = "encountered EOF before private key container\n"; + ret->private = get_string(src); + if (get_err(src)) { + errmsg = "no private key container string found\n"; goto error; } - ret->privatestr = (unsigned char *)string; - ret->privatelen = stringlen; /* * And now we're done, until asked to actually decrypt. @@ -1427,9 +1342,9 @@ struct ssh2_userkey *openssh_new_read(const Filename *filename, int i; struct ssh2_userkey *retval = NULL; const char *errmsg; - unsigned checkint0, checkint1; - const void *priv, *string; - int privlen, stringlen, key_index; + unsigned checkint; + BinarySource src[1]; + int key_index; const ssh_keyalg *alg = NULL; if (!key) @@ -1460,8 +1375,8 @@ struct ssh2_userkey *openssh_new_read(const Filename *filename, break; case ON_K_BCRYPT: openssh_bcrypt(passphrase, - key->kdfopts.bcrypt.salt, - key->kdfopts.bcrypt.saltlen, + key->kdfopts.bcrypt.salt.ptr, + key->kdfopts.bcrypt.salt.len, key->kdfopts.bcrypt.rounds, keybuf, keysize); break; @@ -1473,7 +1388,7 @@ struct ssh2_userkey *openssh_new_read(const Filename *filename, break; case ON_E_AES256CBC: case ON_E_AES256CTR: - if (key->privatelen % 16 != 0) { + if (key->private.len % 16 != 0) { errmsg = "private key container length is not a" " multiple of AES block size\n"; goto error; @@ -1482,13 +1397,15 @@ struct ssh2_userkey *openssh_new_read(const Filename *filename, void *ctx = aes_make_context(); aes256_key(ctx, keybuf); aes_iv(ctx, keybuf + 32); + /* Decrypt the private section in place, casting away + * the const from key->private being a ptrlen */ if (key->cipher == ON_E_AES256CBC) { - aes_ssh2_decrypt_blk(ctx, key->privatestr, - key->privatelen); + aes_ssh2_decrypt_blk(ctx, (char *)key->private.ptr, + key->private.len); } else { - aes_ssh2_sdctr(ctx, key->privatestr, - key->privatelen); + aes_ssh2_sdctr(ctx, (char *)key->private.ptr, + key->private.len); } aes_free_context(ctx); } @@ -1502,29 +1419,23 @@ struct ssh2_userkey *openssh_new_read(const Filename *filename, * Now parse the entire encrypted section, and extract the key * identified by key_wanted. */ - priv = key->privatestr; - privlen = key->privatelen; + BinarySource_BARE_INIT(src, key->private.ptr, key->private.len); - if (!get_ssh_uint32(&privlen, &priv, &checkint0) || - !get_ssh_uint32(&privlen, &priv, &checkint1) || - checkint0 != checkint1) { + checkint = get_uint32(src); + if (get_uint32(src) != checkint || get_err(src)) { errmsg = "decryption check failed"; goto error; } retkey = NULL; for (key_index = 0; key_index < key->nkeys; key_index++) { - const unsigned char *thiskey; - int thiskeylen; + ptrlen keytype, thiskey, comment; /* * Read the key type, which will tell us how to scan over * the key to get to the next one. */ - if (!(string = get_ssh_string(&privlen, &priv, &stringlen))) { - errmsg = "expected key type in private string"; - goto error; - } + keytype = get_string(src); /* * Preliminary key type identification, and decide how @@ -1533,38 +1444,35 @@ struct ssh2_userkey *openssh_new_read(const Filename *filename, * of strings, so we just need to know how many of them to * skip over. (The numbers below exclude the key comment.) */ - { - /* find_pubkey_alg needs a zero-terminated copy of the - * algorithm name */ - char *name_zt = dupprintf("%.*s", stringlen, (char *)string); - alg = find_pubkey_alg(name_zt); - sfree(name_zt); - } - + alg = find_pubkey_alg_len(keytype); if (!alg) { errmsg = "private key type not recognised\n"; goto error; } - thiskey = priv; + thiskey.ptr = get_ptr(src); /* * Skip over the pieces of key. */ - for (i = 0; i < alg->openssh_private_npieces; i++) { - if (!(string = get_ssh_string(&privlen, &priv, &stringlen))) { - errmsg = "ran out of data in mid-private-key"; - goto error; - } + for (i = 0; i < alg->openssh_private_npieces; i++) + get_string(src); + + if (get_err(src)) { + errmsg = "unable to read entire private key"; + goto error; } - thiskeylen = (int)((const unsigned char *)priv - - (const unsigned char *)thiskey); + thiskey.len = (const char *)get_ptr(src) - (const char *)thiskey.ptr; + if (key_index == key->key_wanted) { + const unsigned char *blobptr = thiskey.ptr; + int bloblen = thiskey.len; + retkey = snew(struct ssh2_userkey); retkey->comment = NULL; retkey->alg = alg; - retkey->data = alg->openssh_createkey(alg, &thiskey, &thiskeylen); + retkey->data = alg->openssh_createkey(alg, &blobptr, &bloblen); if (!retkey->data) { errmsg = "unable to create key data structure"; goto error; @@ -1574,14 +1482,14 @@ struct ssh2_userkey *openssh_new_read(const Filename *filename, /* * Read the key comment. */ - if (!(string = get_ssh_string(&privlen, &priv, &stringlen))) { - errmsg = "ran out of data at key comment"; + comment = get_string(src); + if (get_err(src)) { + errmsg = "unable to read key comment"; goto error; } if (key_index == key->key_wanted) { assert(retkey); - retkey->comment = dupprintf("%.*s", stringlen, - (const char *)string); + retkey->comment = mkstr(comment); } } @@ -1593,11 +1501,13 @@ struct ssh2_userkey *openssh_new_read(const Filename *filename, /* * Now we expect nothing left but padding. */ - for (i = 0; i < privlen; i++) { - if (((const unsigned char *)priv)[i] != (unsigned char)(i+1)) { - errmsg = "padding at end of private string did not match"; - goto error; - } + { + unsigned char expected_pad_byte = 1; + while (get_avail(src) > 0) + if (get_byte(src) != expected_pad_byte++) { + errmsg = "padding at end of private string did not match"; + goto error; + } } errmsg = NULL; /* no error */ @@ -2014,36 +1924,25 @@ static struct sshcom_key *load_sshcom_key(const Filename *filename, int sshcom_encrypted(const Filename *filename, char **comment) { struct sshcom_key *key = load_sshcom_key(filename, NULL); - int pos, len, answer; - - answer = 0; + BinarySource src[1]; + ptrlen str; + int answer = FALSE; *comment = NULL; if (!key) goto done; - /* - * Check magic number. - */ - if (GET_32BIT(key->keyblob) != 0x3f6ff9eb) { - goto done; /* key is invalid */ - } + BinarySource_BARE_INIT(src, key->keyblob, key->keyblob_len); - /* - * Find the cipher-type string. - */ - pos = 8; - if (key->keyblob_len < pos+4) - goto done; /* key is far too short */ - len = toint(GET_32BIT(key->keyblob + pos)); - if (len < 0 || len > key->keyblob_len - pos - 4) - goto done; /* key is far too short */ - pos += 4 + len; /* skip key type */ - len = toint(GET_32BIT(key->keyblob + pos)); /* find cipher-type length */ - if (len < 0 || len > key->keyblob_len - pos - 4) - goto done; /* cipher type string is incomplete */ - if (len != 4 || 0 != memcmp(key->keyblob + pos + 4, "none", 4)) - answer = 1; + if (get_uint32(src) != SSHCOM_MAGIC_NUMBER) + goto done; /* key is invalid */ + get_uint32(src); /* skip length field */ + get_string(src); /* skip key type */ + str = get_string(src); /* cipher type */ + if (get_err(src)) + goto done; /* key is invalid */ + if (!ptrlen_eq_string(str, "none")) + answer = TRUE; done: if (key) { @@ -2058,29 +1957,6 @@ int sshcom_encrypted(const Filename *filename, char **comment) return answer; } -static int sshcom_read_mpint(void *data, int len, struct mpint_pos *ret) -{ - unsigned bits, bytes; - unsigned char *d = (unsigned char *) data; - - if (len < 4) - goto error; - bits = GET_32BIT(d); - - bytes = (bits + 7) / 8; - if (len < 4+bytes) - goto error; - - ret->start = d + 4; - ret->bytes = bytes; - return bytes+4; - - error: - ret->start = NULL; - ret->bytes = -1; - return len; /* ensure further calls fail as well */ -} - void BinarySink_put_mp_sshcom_from_string( BinarySink *bs, const void *bytesv, int nbytes) { @@ -2101,18 +1977,27 @@ void BinarySink_put_mp_sshcom_from_string( #define put_mp_sshcom_from_string(bs, val, len) \ BinarySink_put_mp_sshcom_from_string(BinarySink_UPCAST(bs), val, len) +static ptrlen BinarySource_get_mp_sshcom_as_string(BinarySource *src) +{ + unsigned bits = get_uint32(src); + return get_data(src, (bits + 7) / 8); +} + +#define get_mp_sshcom_as_string(bs) \ + BinarySource_get_mp_sshcom_as_string(BinarySource_UPCAST(bs)) + struct ssh2_userkey *sshcom_read(const Filename *filename, char *passphrase, const char **errmsg_p) { struct sshcom_key *key = load_sshcom_key(filename, errmsg_p); const char *errmsg; - int pos, len, publen; + BinarySource src[1]; + ptrlen str, ciphertext; + int publen; const char prefix_rsa[] = "if-modn{sign{rsa"; const char prefix_dsa[] = "dl-modp{sign{dsa"; enum { RSA, DSA } type; int encrypted; - char *ciphertext; - int cipherlen; struct ssh2_userkey *ret = NULL, *retkey; const ssh_keyalg *alg; strbuf *blob = NULL; @@ -2120,68 +2005,48 @@ struct ssh2_userkey *sshcom_read(const Filename *filename, char *passphrase, if (!key) return NULL; - /* - * Check magic number. - */ - if (GET_32BIT(key->keyblob) != SSHCOM_MAGIC_NUMBER) { + BinarySource_BARE_INIT(src, key->keyblob, key->keyblob_len); + + if (get_uint32(src) != SSHCOM_MAGIC_NUMBER) { errmsg = "key does not begin with magic number"; goto error; } + get_uint32(src); /* skip length field */ /* * Determine the key type. */ - pos = 8; - if (key->keyblob_len < pos+4 || - (len = toint(GET_32BIT(key->keyblob + pos))) < 0 || - len > key->keyblob_len - pos - 4) { - errmsg = "key blob does not contain a key type string"; - goto error; - } - if (len > sizeof(prefix_rsa) - 1 && - !memcmp(key->keyblob+pos+4, prefix_rsa, sizeof(prefix_rsa) - 1)) { + str = get_string(src); + if (str.len > sizeof(prefix_rsa) - 1 && + !memcmp(str.ptr, prefix_rsa, sizeof(prefix_rsa) - 1)) { type = RSA; - } else if (len > sizeof(prefix_dsa) - 1 && - !memcmp(key->keyblob+pos+4, prefix_dsa, sizeof(prefix_dsa) - 1)) { + } else if (str.len > sizeof(prefix_dsa) - 1 && + !memcmp(str.ptr, prefix_dsa, sizeof(prefix_dsa) - 1)) { type = DSA; } else { errmsg = "key is of unknown type"; goto error; } - pos += 4+len; /* * Determine the cipher type. */ - if (key->keyblob_len < pos+4 || - (len = toint(GET_32BIT(key->keyblob + pos))) < 0 || - len > key->keyblob_len - pos - 4) { - errmsg = "key blob does not contain a cipher type string"; - goto error; - } - if (len == 4 && !memcmp(key->keyblob+pos+4, "none", 4)) + str = get_string(src); + if (ptrlen_eq_string(str, "none")) encrypted = 0; - else if (len == 8 && !memcmp(key->keyblob+pos+4, "3des-cbc", 8)) + else if (ptrlen_eq_string(str, "3des-cbc")) encrypted = 1; else { errmsg = "key encryption is of unknown type"; goto error; } - pos += 4+len; /* * Get hold of the encrypted part of the key. */ - if (key->keyblob_len < pos+4 || - (len = toint(GET_32BIT(key->keyblob + pos))) < 0 || - len > key->keyblob_len - pos - 4) { - errmsg = "key blob does not contain actual key data"; - goto error; - } - ciphertext = (char *)key->keyblob + pos + 4; - cipherlen = len; - if (cipherlen == 0) { - errmsg = "length of key data is zero"; + ciphertext = get_string(src); + if (ciphertext.len == 0) { + errmsg = "no key data found"; goto error; } @@ -2200,7 +2065,7 @@ struct ssh2_userkey *sshcom_read(const Filename *filename, char *passphrase, struct MD5Context md5c; unsigned char keybuf[32], iv[8]; - if (cipherlen % 8 != 0) { + if (ciphertext.len % 8 != 0) { errmsg = "encrypted part of key is not a multiple of cipher block" " size"; goto error; @@ -2216,10 +2081,12 @@ struct ssh2_userkey *sshcom_read(const Filename *filename, char *passphrase, MD5Final(keybuf+16, &md5c); /* - * Now decrypt the key blob. + * Now decrypt the key blob in place (casting away const from + * ciphertext being a ptrlen). */ memset(iv, 0, sizeof(iv)); - des3_decrypt_pubkey_ossh(keybuf, iv, ciphertext, cipherlen); + des3_decrypt_pubkey_ossh(keybuf, iv, + (char *)ciphertext.ptr, ciphertext.len); smemclr(&md5c, sizeof(md5c)); smemclr(keybuf, sizeof(keybuf)); @@ -2235,15 +2102,16 @@ struct ssh2_userkey *sshcom_read(const Filename *filename, char *passphrase, } /* - * Strip away the containing string to get to the real meat. + * Expect the ciphertext to be formatted as a containing string, + * and reinitialise src to start parsing the inside of that string. */ - len = toint(GET_32BIT(ciphertext)); - if (len < 0 || len > cipherlen-4) { + BinarySource_BARE_INIT(src, ciphertext.ptr, ciphertext.len); + str = get_string(src); + if (get_err(src)) { errmsg = "containing string was ill-formed"; goto error; } - ciphertext += 4; - cipherlen = len; + BinarySource_BARE_INIT(src, str.ptr, str.len); /* * Now we break down into RSA versus DSA. In either case we'll @@ -2252,56 +2120,55 @@ struct ssh2_userkey *sshcom_read(const Filename *filename, char *passphrase, */ blob = strbuf_new(); if (type == RSA) { - struct mpint_pos n, e, d, u, p, q; - int pos = 0; - pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &e); - pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &d); - pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &n); - pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &u); - pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &p); - pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &q); - if (!q.start) { + ptrlen n, e, d, u, p, q; + + e = get_mp_sshcom_as_string(src); + d = get_mp_sshcom_as_string(src); + n = get_mp_sshcom_as_string(src); + u = get_mp_sshcom_as_string(src); + p = get_mp_sshcom_as_string(src); + q = get_mp_sshcom_as_string(src); + if (get_err(src)) { errmsg = "key data did not contain six integers"; goto error; } alg = &ssh_rsa; put_stringz(blob, "ssh-rsa"); - put_mp_ssh2_from_string(blob, e.start, e.bytes); - put_mp_ssh2_from_string(blob, n.start, n.bytes); + put_mp_ssh2_from_string(blob, e.ptr, e.len); + put_mp_ssh2_from_string(blob, n.ptr, n.len); publen = blob->len; - put_string(blob, d.start, d.bytes); - put_mp_ssh2_from_string(blob, q.start, q.bytes); - put_mp_ssh2_from_string(blob, p.start, p.bytes); - put_mp_ssh2_from_string(blob, u.start, u.bytes); + put_mp_ssh2_from_string(blob, d.ptr, d.len); + put_mp_ssh2_from_string(blob, q.ptr, q.len); + put_mp_ssh2_from_string(blob, p.ptr, p.len); + put_mp_ssh2_from_string(blob, u.ptr, u.len); } else { - struct mpint_pos p, q, g, x, y; - int pos = 4; + ptrlen p, q, g, x, y; assert(type == DSA); /* the only other option from the if above */ - if (GET_32BIT(ciphertext) != 0) { + if (get_uint32(src) != 0) { errmsg = "predefined DSA parameters not supported"; goto error; } - pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &p); - pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &g); - pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &q); - pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &y); - pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &x); - if (!x.start) { + p = get_mp_sshcom_as_string(src); + g = get_mp_sshcom_as_string(src); + q = get_mp_sshcom_as_string(src); + y = get_mp_sshcom_as_string(src); + x = get_mp_sshcom_as_string(src); + if (get_err(src)) { errmsg = "key data did not contain five integers"; goto error; } alg = &ssh_dss; put_stringz(blob, "ssh-dss"); - put_mp_ssh2_from_string(blob, p.start, p.bytes); - put_mp_ssh2_from_string(blob, q.start, q.bytes); - put_mp_ssh2_from_string(blob, g.start, g.bytes); - put_mp_ssh2_from_string(blob, y.start, y.bytes); + put_mp_ssh2_from_string(blob, p.ptr, p.len); + put_mp_ssh2_from_string(blob, q.ptr, q.len); + put_mp_ssh2_from_string(blob, g.ptr, g.len); + put_mp_ssh2_from_string(blob, y.ptr, y.len); publen = blob->len; - put_mp_ssh2_from_string(blob, x.start, x.bytes); + put_mp_ssh2_from_string(blob, x.ptr, x.len); } retkey = snew(struct ssh2_userkey); @@ -2334,8 +2201,9 @@ int sshcom_write(const Filename *filename, struct ssh2_userkey *key, char *passphrase) { strbuf *pubblob, *privblob, *outblob; - struct mpint_pos numbers[6]; + ptrlen numbers[6]; int nnumbers, initial_zero, lenpos, i; + BinarySource src[1]; const char *type; char *ciphertext; int cipherlen; @@ -2356,23 +2224,23 @@ int sshcom_write(const Filename *filename, struct ssh2_userkey *key, * key blob, and also decide on the header line. */ if (key->alg == &ssh_rsa) { - int pos; - struct mpint_pos n, e, d, p, q, iqmp; + ptrlen n, e, d, p, q, iqmp; /* * These blobs were generated from inside PuTTY, so we needn't * treat them as untrusted. */ - pos = 4 + GET_32BIT(pubblob->u); - pos += ssh2_read_mpint(pubblob->u+pos, pubblob->len-pos, &e); - pos += ssh2_read_mpint(pubblob->u+pos, pubblob->len-pos, &n); - pos = 0; - pos += ssh2_read_mpint(privblob->u+pos, privblob->len-pos, &d); - pos += ssh2_read_mpint(privblob->u+pos, privblob->len-pos, &p); - pos += ssh2_read_mpint(privblob->u+pos, privblob->len-pos, &q); - pos += ssh2_read_mpint(privblob->u+pos, privblob->len-pos, &iqmp); - - assert(e.start && iqmp.start); /* can't go wrong */ + BinarySource_BARE_INIT(src, pubblob->u, pubblob->len); + get_string(src); /* skip algorithm name */ + e = get_string(src); + n = get_string(src); + BinarySource_BARE_INIT(src, privblob->u, privblob->len); + d = get_string(src); + p = get_string(src); + q = get_string(src); + iqmp = get_string(src); + + assert(!get_err(src)); /* can't go wrong */ numbers[0] = e; numbers[1] = d; @@ -2385,22 +2253,22 @@ int sshcom_write(const Filename *filename, struct ssh2_userkey *key, initial_zero = 0; type = "if-modn{sign{rsa-pkcs1-sha1},encrypt{rsa-pkcs1v2-oaep}}"; } else if (key->alg == &ssh_dss) { - int pos; - struct mpint_pos p, q, g, y, x; + ptrlen p, q, g, y, x; /* * These blobs were generated from inside PuTTY, so we needn't * treat them as untrusted. */ - pos = 4 + GET_32BIT(pubblob->u); - pos += ssh2_read_mpint(pubblob->u+pos, pubblob->len-pos, &p); - pos += ssh2_read_mpint(pubblob->u+pos, pubblob->len-pos, &q); - pos += ssh2_read_mpint(pubblob->u+pos, pubblob->len-pos, &g); - pos += ssh2_read_mpint(pubblob->u+pos, pubblob->len-pos, &y); - pos = 0; - pos += ssh2_read_mpint(privblob->u+pos, privblob->len-pos, &x); + BinarySource_BARE_INIT(src, pubblob->u, pubblob->len); + get_string(src); /* skip algorithm name */ + p = get_string(src); + q = get_string(src); + g = get_string(src); + y = get_string(src); + BinarySource_BARE_INIT(src, privblob->u, privblob->len); + x = get_string(src); - assert(y.start && x.start); /* can't go wrong */ + assert(!get_err(src)); /* can't go wrong */ numbers[0] = p; numbers[1] = g; @@ -2431,7 +2299,7 @@ int sshcom_write(const Filename *filename, struct ssh2_userkey *key, if (initial_zero) put_uint32(outblob, 0); for (i = 0; i < nnumbers; i++) - put_mp_sshcom_from_string(outblob, numbers[i].start, numbers[i].bytes); + put_mp_sshcom_from_string(outblob, numbers[i].ptr, numbers[i].len); /* Now wrap up the encrypted payload. */ PUT_32BIT(outblob->s + lenpos + 4, outblob->len - (lenpos + 8)); From 28c086ca9ad79f6ffc4d9af3f69e9eb204e3b5eb Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Tue, 29 May 2018 19:29:54 +0100 Subject: [PATCH 332/607] Rewrite key loading functions using BinarySource. This does for sshpubk.c's handling of PuTTY's native key formats what the previous commit did for the foreign formats handled by import.c. --- sshpubk.c | 157 ++++++++++++++++++++++-------------------------------- 1 file changed, 65 insertions(+), 92 deletions(-) diff --git a/sshpubk.c b/sshpubk.c index 68cf6945..01cacb58 100644 --- a/sshpubk.c +++ b/sshpubk.c @@ -27,70 +27,52 @@ static int rsa_ssh1_load_main(FILE * fp, struct RSAKey *key, int pub_only, char **commentptr, const char *passphrase, const char **error) { - unsigned char buf[16384]; - unsigned char keybuf[16]; - int len; - int i, j, ciphertype; + strbuf *buf; + int ciphertype; int ret = 0; struct MD5Context md5c; - char *comment; + ptrlen comment; + BinarySource src[1]; *error = NULL; /* Slurp the whole file (minus the header) into a buffer. */ - len = fread(buf, 1, sizeof(buf), fp); - fclose(fp); - if (len < 0 || len == sizeof(buf)) { - *error = "error reading file"; - goto end; /* file too big or not read */ + buf = strbuf_new(); + { + int ch; + while ((ch = fgetc(fp)) != EOF) + put_byte(buf, ch); } + fclose(fp); + + BinarySource_BARE_INIT(src, buf->u, buf->len); - i = 0; *error = "file format error"; /* - * A zero byte. (The signature includes a terminating NUL.) + * A zero byte. (The signature includes a terminating NUL, which + * we haven't gone past yet because we read it using fgets which + * stopped after the \n.) */ - if (len - i < 1 || buf[i] != 0) + if (get_byte(src) != 0) goto end; - i++; /* One byte giving encryption type, and one reserved uint32. */ - if (len - i < 1) - goto end; - ciphertype = buf[i]; + ciphertype = get_byte(src); if (ciphertype != 0 && ciphertype != SSH_CIPHER_3DES) goto end; - i++; - if (len - i < 4) - goto end; /* reserved field not present */ - if (buf[i] != 0 || buf[i + 1] != 0 || buf[i + 2] != 0 - || buf[i + 3] != 0) goto end; /* reserved field nonzero, panic! */ - i += 4; + if (get_uint32(src) != 0) + goto end; /* reserved field nonzero, panic! */ /* Now the serious stuff. An ordinary SSH-1 public key. */ - j = rsa_ssh1_readpub(buf + i, len - i, key, NULL, RSA_SSH1_MODULUS_FIRST); - if (j < 0) - goto end; /* overran */ - i += j; + get_rsa_ssh1_pub(src, key, NULL, RSA_SSH1_MODULUS_FIRST); /* Next, the comment field. */ - j = toint(GET_32BIT(buf + i)); - i += 4; - if (j < 0 || len - i < j) - goto end; - comment = snewn(j + 1, char); - if (comment) { - memcpy(comment, buf + i, j); - comment[j] = '\0'; - } - i += j; + comment = get_string(src); if (commentptr) - *commentptr = dupstr(comment); + *commentptr = mkstr(comment); if (key) - key->comment = comment; - else - sfree(comment); + key->comment = mkstr(comment); if (pub_only) { ret = 1; @@ -107,10 +89,16 @@ static int rsa_ssh1_load_main(FILE * fp, struct RSAKey *key, int pub_only, * Decrypt remainder of buffer. */ if (ciphertype) { + unsigned char keybuf[16]; + size_t enclen = buf->len - src->pos; + + if (enclen & 7) + goto end; + MD5Init(&md5c); put_data(&md5c, passphrase, strlen(passphrase)); MD5Final(keybuf, &md5c); - des3_decrypt_pubkey(keybuf, buf + i, (len - i + 7) & ~7); + des3_decrypt_pubkey(keybuf, buf->u + src->pos, enclen); smemclr(keybuf, sizeof(keybuf)); /* burn the evidence */ } @@ -118,32 +106,27 @@ static int rsa_ssh1_load_main(FILE * fp, struct RSAKey *key, int pub_only, * We are now in the secret part of the key. The first four * bytes should be of the form a, b, a, b. */ - if (len - i < 4) - goto end; - if (buf[i] != buf[i + 2] || buf[i + 1] != buf[i + 3]) { - *error = "wrong passphrase"; - ret = -1; - goto end; + { + int b0a = get_byte(src); + int b1a = get_byte(src); + int b0b = get_byte(src); + int b1b = get_byte(src); + if (b0a != b0b || b1a != b1b) { + *error = "wrong passphrase"; + ret = -1; + goto end; + } } - i += 4; /* * After that, we have one further bignum which is our * decryption exponent, and then the three auxiliary values * (iqmp, q, p). */ - j = rsa_ssh1_readpriv(buf + i, len - i, key); - if (j < 0) goto end; - i += j; - j = ssh1_read_bignum(buf + i, len - i, &key->iqmp); - if (j < 0) goto end; - i += j; - j = ssh1_read_bignum(buf + i, len - i, &key->q); - if (j < 0) goto end; - i += j; - j = ssh1_read_bignum(buf + i, len - i, &key->p); - if (j < 0) goto end; - i += j; + get_rsa_ssh1_priv(src, key); + key->iqmp = get_mp_ssh1(src); + key->q = get_mp_ssh1(src); + key->p = get_mp_ssh1(src); if (!rsa_verify(key)) { *error = "rsa_verify failed"; @@ -153,7 +136,7 @@ static int rsa_ssh1_load_main(FILE * fp, struct RSAKey *key, int pub_only, ret = 1; end: - smemclr(buf, sizeof(buf)); /* burn the evidence */ + strbuf_free(buf); return ret; } @@ -1400,31 +1383,25 @@ static char *ssh2_pubkey_openssh_str_internal(const char *comment, int pub_len) { const unsigned char *ssh2blob = (const unsigned char *)v_pub_blob; - const char *alg; - int alglen; + ptrlen alg; char *buffer, *p; int i; - if (pub_len < 4) { - alg = NULL; - } else { - alglen = GET_32BIT(ssh2blob); - if (alglen > 0 && alglen < pub_len - 4) { - alg = (const char *)ssh2blob + 4; - } else { - alg = NULL; + { + BinarySource src[1]; + BinarySource_BARE_INIT(src, ssh2blob, pub_len); + alg = get_string(src); + if (get_err(src)) { + const char *replacement_str = "INVALID-ALGORITHM"; + alg.ptr = replacement_str; + alg.len = strlen(replacement_str); } } - if (!alg) { - alg = "INVALID-ALGORITHM"; - alglen = strlen(alg); - } - - buffer = snewn(alglen + + buffer = snewn(alg.len + 4 * ((pub_len+2) / 3) + (comment ? strlen(comment) : 0) + 3, char); - p = buffer + sprintf(buffer, "%.*s ", alglen, alg); + p = buffer + sprintf(buffer, "%.*s ", PTRLEN_PRINTF(alg)); i = 0; while (i < pub_len) { int n = (pub_len - i < 3 ? pub_len - i : 3); @@ -1512,10 +1489,10 @@ char *ssh2_fingerprint_blob(const void *blob, int bloblen) { unsigned char digest[16]; char fingerprint_str[16*3]; - const char *algstr; - int alglen; + ptrlen algname; const ssh_keyalg *alg; int i; + BinarySource src[1]; /* * The fingerprint hash itself is always just the MD5 of the blob. @@ -1527,21 +1504,17 @@ char *ssh2_fingerprint_blob(const void *blob, int bloblen) /* * Identify the key algorithm, if possible. */ - alglen = toint(GET_32BIT((const unsigned char *)blob)); - if (alglen > 0 && alglen < bloblen-4) { - algstr = (const char *)blob + 4; - - /* - * If we can actually identify the algorithm as one we know - * about, get hold of the key's bit count too. - */ - alg = find_pubkey_alg_len(make_ptrlen(algstr, alglen)); + BinarySource_BARE_INIT(src, blob, bloblen); + algname = get_string(src); + if (!get_err(src)) { + alg = find_pubkey_alg_len(algname); if (alg) { int bits = alg->pubkey_bits(alg, blob, bloblen); - return dupprintf("%.*s %d %s", alglen, algstr, + return dupprintf("%.*s %d %s", PTRLEN_PRINTF(algname), bits, fingerprint_str); } else { - return dupprintf("%.*s %s", alglen, algstr, fingerprint_str); + return dupprintf("%.*s %s", PTRLEN_PRINTF(algname), + fingerprint_str); } } else { /* From 5be57af17365fc6ff3bf5c6a8bfd3334385b9428 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Tue, 29 May 2018 19:11:22 +0100 Subject: [PATCH 333/607] Rewrite packet parsing in sshshare.c using BinarySource. Another set of localised decoding routines get thrown away here. Also, I've changed the APIs of a couple of helper functions in x11fwd.c to take ptrlens in place of zero-terminated C strings, because that's the format in which they come back from the decode, and it saves mallocing a zero-terminated version of each one just to pass to those helpers. --- ssh.h | 4 +- sshshare.c | 259 +++++++++++++++++++---------------------------------- x11fwd.c | 12 +-- 3 files changed, 100 insertions(+), 175 deletions(-) diff --git a/ssh.h b/ssh.h index 21ab1593..855bee89 100644 --- a/ssh.h +++ b/ssh.h @@ -657,8 +657,8 @@ char *platform_get_x_display(void); */ void x11_get_auth_from_authfile(struct X11Display *display, const char *authfilename); -int x11_identify_auth_proto(const char *proto); -void *x11_dehexify(const char *hex, int *outlen); +int x11_identify_auth_proto(ptrlen protoname); +void *x11_dehexify(ptrlen hex, int *outlen); Bignum copybn(Bignum b); Bignum bn_power_2(int n); diff --git a/sshshare.c b/sshshare.c index 862d871a..5f0c01a1 100644 --- a/sshshare.c +++ b/sshshare.c @@ -728,30 +728,30 @@ static void send_packet_to_downstream(struct ssh_sharing_connstate *cs, * If that happens, we just chop up the packet into pieces and * send them as separate CHANNEL_DATA packets. */ - const char *upkt = (const char *)pkt; + BinarySource src[1]; + unsigned channel; + ptrlen data; - int len = toint(GET_32BIT(upkt + 4)); - upkt += 8; /* skip channel id + length field */ - - if (len < 0 || len > pktlen - 8) - len = pktlen - 8; + BinarySource_BARE_INIT(src, pkt, pktlen); + channel = get_uint32(src); + data = get_string(src); do { - int this_len = (len > chan->downstream_maxpkt ? - chan->downstream_maxpkt : len); + int this_len = (data.len > chan->downstream_maxpkt ? + chan->downstream_maxpkt : data.len); packet = strbuf_new(); put_uint32(packet, 0); /* placeholder for length field */ put_byte(packet, type); - put_uint32(packet, chan->downstream_id); + put_uint32(packet, channel); put_uint32(packet, this_len); - put_data(packet, upkt, this_len); - len -= this_len; - upkt += this_len; + put_data(packet, data.ptr, this_len); + data.ptr = (const char *)data.ptr + this_len; + data.len -= this_len; PUT_32BIT(packet->s, packet->len-4); sk_write(cs->sock, packet->s, packet->len); strbuf_free(packet); - } while (len > 0); + } while (data.len > 0); } else { /* * Just do the obvious thing. @@ -924,44 +924,6 @@ static void share_closing(Plug plug, const char *error_msg, int error_code, share_begin_cleanup(cs); } -static int getstring_inner(const void *vdata, int datalen, - char **out, int *outlen) -{ - const unsigned char *data = (const unsigned char *)vdata; - int len; - - if (datalen < 4) - return FALSE; - - len = toint(GET_32BIT(data)); - if (len < 0 || len > datalen - 4) - return FALSE; - - if (outlen) - *outlen = len + 4; /* total size including length field */ - if (out) - *out = dupprintf("%.*s", len, (char *)data + 4); - return TRUE; -} - -static char *getstring(const void *data, int datalen) -{ - char *ret; - if (getstring_inner(data, datalen, &ret, NULL)) - return ret; - else - return NULL; -} - -static int getstring_size(const void *data, int datalen) -{ - int ret; - if (getstring_inner(data, datalen, NULL, &ret)) - return ret; - else - return -1; -} - /* * Append a message to the end of an xchannel's queue. */ @@ -1011,9 +973,11 @@ void share_dead_xchannel_respond(struct ssh_sharing_connstate *cs, * A CHANNEL_REQUEST is responded to by sending * CHANNEL_FAILURE, if it has want_reply set. */ - int wantreplypos = getstring_size(msg->data, msg->datalen); - if (wantreplypos > 0 && wantreplypos < msg->datalen && - msg->data[wantreplypos] != 0) { + BinarySource src[1]; + BinarySource_BARE_INIT(src, msg->data, msg->datalen); + get_uint32(src); /* skip channel id */ + get_string(src); /* skip request type */ + if (get_bool(src)) { strbuf *packet = strbuf_new(); put_uint32(packet, xc->server_id); ssh_send_packet_from_downstream @@ -1170,10 +1134,13 @@ void share_got_pkt_from_server(void *csv, int type, { struct ssh_sharing_connstate *cs = (struct ssh_sharing_connstate *)csv; struct share_globreq *globreq; - int id_pos; + size_t id_pos; unsigned upstream_id, server_id; struct share_channel *chan; struct share_xchannel *xc; + BinarySource src[1]; + + BinarySource_BARE_INIT(src, pkt, pktlen); switch (type) { case SSH2_MSG_REQUEST_SUCCESS: @@ -1207,9 +1174,9 @@ void share_got_pkt_from_server(void *csv, int type, break; case SSH2_MSG_CHANNEL_OPEN: - id_pos = getstring_size(pkt, pktlen); - assert(id_pos >= 0); - server_id = GET_32BIT(pkt + id_pos); + get_string(src); + server_id = get_uint32(src); + assert(!get_err(src)); share_add_halfchannel(cs, server_id); send_packet_to_downstream(cs, type, pkt, pktlen, NULL); @@ -1230,13 +1197,13 @@ void share_got_pkt_from_server(void *csv, int type, * first uint32 field in the packet. Substitute the downstream * channel id for our one and pass the packet downstream. */ - assert(pktlen >= 4); - upstream_id = GET_32BIT(pkt); + id_pos = src->pos; + upstream_id = get_uint32(src); if ((chan = share_find_channel_by_upstream(cs, upstream_id)) != NULL) { /* * The normal case: this id refers to an open channel. */ - PUT_32BIT(pkt, chan->downstream_id); + PUT_32BIT(pkt + id_pos, chan->downstream_id); send_packet_to_downstream(cs, type, pkt, pktlen, chan); /* @@ -1296,9 +1263,10 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs, int type, unsigned char *pkt, int pktlen) { - char *request_name; + ptrlen request_name; struct share_forwarding *fwd; - int id_pos; + size_t id_pos; + unsigned maxpkt; unsigned old_id, new_id, server_id; struct share_globreq *globreq; struct share_channel *chan; @@ -1306,6 +1274,11 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs, struct share_xchannel *xc; strbuf *packet; char *err = NULL; + BinarySource src[1]; + size_t wantreplypos; + int orig_wantreply; + + BinarySource_BARE_INIT(src, pkt, pktlen); switch (type) { case SSH2_MSG_DISCONNECT: @@ -1326,39 +1299,26 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs, * will probably require that too, and so we don't forward on * any request we don't understand. */ - request_name = getstring(pkt, pktlen); - if (request_name == NULL) { - err = dupprintf("Truncated GLOBAL_REQUEST packet"); - goto confused; - } + request_name = get_string(src); + wantreplypos = src->pos; + orig_wantreply = get_bool(src); - if (!strcmp(request_name, "tcpip-forward")) { - int wantreplypos, orig_wantreply, port, ret; + if (ptrlen_eq_string(request_name, "tcpip-forward")) { + ptrlen hostpl; char *host; - - sfree(request_name); + int port, ret; /* * Pick the packet apart to find the want_reply field and * the host/port we're going to ask to listen on. */ - wantreplypos = getstring_size(pkt, pktlen); - if (wantreplypos < 0 || wantreplypos >= pktlen) { + hostpl = get_string(src); + port = toint(get_uint32(src)); + if (get_err(src)) { err = dupprintf("Truncated GLOBAL_REQUEST packet"); goto confused; } - orig_wantreply = pkt[wantreplypos]; - port = getstring_size(pkt + (wantreplypos + 1), - pktlen - (wantreplypos + 1)); - port += (wantreplypos + 1); - if (port < 0 || port > pktlen - 4) { - err = dupprintf("Truncated GLOBAL_REQUEST packet"); - goto confused; - } - host = getstring(pkt + (wantreplypos + 1), - pktlen - (wantreplypos + 1)); - assert(host != NULL); - port = GET_32BIT(pkt + port); + host = mkstr(hostpl); /* * See if we can allocate space in ssh.c's tree of remote @@ -1382,11 +1342,10 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs, * that we know whether this forwarding needs to be * cleaned up if downstream goes away. */ - int old_wantreply = pkt[wantreplypos]; pkt[wantreplypos] = 1; ssh_send_packet_from_downstream (cs->parent->ssh, cs->id, type, pkt, pktlen, - old_wantreply ? NULL : "upstream added want_reply flag"); + orig_wantreply ? NULL : "upstream added want_reply flag"); fwd = share_add_forwarding(cs, host, port); ssh_sharing_queue_global_request(cs->parent->ssh, cs); @@ -1404,34 +1363,23 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs, } sfree(host); - } else if (!strcmp(request_name, "cancel-tcpip-forward")) { - int wantreplypos, orig_wantreply, port; + } else if (ptrlen_eq_string(request_name, "cancel-tcpip-forward")) { + ptrlen hostpl; char *host; + int port; struct share_forwarding *fwd; - sfree(request_name); - /* * Pick the packet apart to find the want_reply field and * the host/port we're going to ask to listen on. */ - wantreplypos = getstring_size(pkt, pktlen); - if (wantreplypos < 0 || wantreplypos >= pktlen) { - err = dupprintf("Truncated GLOBAL_REQUEST packet"); - goto confused; - } - orig_wantreply = pkt[wantreplypos]; - port = getstring_size(pkt + (wantreplypos + 1), - pktlen - (wantreplypos + 1)); - port += (wantreplypos + 1); - if (port < 0 || port > pktlen - 4) { + hostpl = get_string(src); + port = toint(get_uint32(src)); + if (get_err(src)) { err = dupprintf("Truncated GLOBAL_REQUEST packet"); goto confused; } - host = getstring(pkt + (wantreplypos + 1), - pktlen - (wantreplypos + 1)); - assert(host != NULL); - port = GET_32BIT(pkt + port); + host = mkstr(hostpl); /* * Look up the existing forwarding with these details. @@ -1449,11 +1397,10 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs, * that _we_ know whether the forwarding has been * deleted even if downstream doesn't want to know. */ - int old_wantreply = pkt[wantreplypos]; pkt[wantreplypos] = 1; ssh_send_packet_from_downstream (cs->parent->ssh, cs->id, type, pkt, pktlen, - old_wantreply ? NULL : "upstream added want_reply flag"); + orig_wantreply ? NULL : "upstream added want_reply flag"); ssh_sharing_queue_global_request(cs->parent->ssh, cs); } @@ -1463,16 +1410,7 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs, * Request we don't understand. Manufacture a failure * message if an answer was required. */ - int wantreplypos; - - sfree(request_name); - - wantreplypos = getstring_size(pkt, pktlen); - if (wantreplypos < 0 || wantreplypos >= pktlen) { - err = dupprintf("Truncated GLOBAL_REQUEST packet"); - goto confused; - } - if (pkt[wantreplypos]) + if (orig_wantreply) send_packet_to_downstream(cs, SSH2_MSG_REQUEST_FAILURE, "", 0, NULL); } @@ -1480,16 +1418,17 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs, case SSH2_MSG_CHANNEL_OPEN: /* Sender channel id comes after the channel type string */ - id_pos = getstring_size(pkt, pktlen); - if (id_pos < 0 || id_pos > pktlen - 12) { + get_string(src); + id_pos = src->pos; + old_id = get_uint32(src); + new_id = ssh_alloc_sharing_channel(cs->parent->ssh, cs); + get_uint32(src); /* skip initial window size */ + maxpkt = get_uint32(src); + if (get_err(src)) { err = dupprintf("Truncated CHANNEL_OPEN packet"); goto confused; } - - old_id = GET_32BIT(pkt + id_pos); - new_id = ssh_alloc_sharing_channel(cs->parent->ssh, cs); - share_add_channel(cs, old_id, new_id, 0, UNACKNOWLEDGED, - GET_32BIT(pkt + id_pos + 8)); + share_add_channel(cs, old_id, new_id, 0, UNACKNOWLEDGED, maxpkt); PUT_32BIT(pkt + id_pos, new_id); ssh_send_packet_from_downstream(cs->parent->ssh, cs->id, type, pkt, pktlen, NULL); @@ -1501,10 +1440,16 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs, goto confused; } - id_pos = 4; /* sender channel id is 2nd uint32 field in packet */ - old_id = GET_32BIT(pkt + id_pos); + server_id = get_uint32(src); + id_pos = src->pos; + old_id = get_uint32(src); + get_uint32(src); /* skip initial window size */ + maxpkt = get_uint32(src); + if (get_err(src)) { + err = dupprintf("Truncated CHANNEL_OPEN_CONFIRMATION packet"); + goto confused; + } - server_id = GET_32BIT(pkt); /* This server id may refer to either a halfchannel or an xchannel. */ hc = NULL, xc = NULL; /* placate optimiser */ if ((hc = share_find_halfchannel(cs, server_id)) != NULL) { @@ -1519,8 +1464,7 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs, PUT_32BIT(pkt + id_pos, new_id); - chan = share_add_channel(cs, old_id, new_id, server_id, OPEN, - GET_32BIT(pkt + 12)); + chan = share_add_channel(cs, old_id, new_id, server_id, OPEN, maxpkt); if (hc) { ssh_send_packet_from_downstream(cs->parent->ssh, cs->id, @@ -1539,12 +1483,12 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs, break; case SSH2_MSG_CHANNEL_OPEN_FAILURE: - if (pktlen < 4) { + server_id = get_uint32(src); + if (get_err(src)) { err = dupprintf("Truncated CHANNEL_OPEN_FAILURE packet"); goto confused; } - server_id = GET_32BIT(pkt); /* This server id may refer to either a halfchannel or an xchannel. */ if ((hc = share_find_halfchannel(cs, server_id)) != NULL) { ssh_send_packet_from_downstream(cs->parent->ssh, cs->id, @@ -1570,8 +1514,11 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs, case SSH2_MSG_CHANNEL_FAILURE: case SSH2_MSG_IGNORE: case SSH2_MSG_DEBUG: - if (type == SSH2_MSG_CHANNEL_REQUEST && - (request_name = getstring(pkt + 4, pktlen - 4)) != NULL) { + server_id = get_uint32(src); + + if (type == SSH2_MSG_CHANNEL_REQUEST) { + request_name = get_string(src); + /* * Agent forwarding requests from downstream are treated * specially. Because OpenSSHD doesn't let us enable agent @@ -1597,11 +1544,8 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs, * subsequent CHANNEL_OPENs still can't be associated with * a parent session channel.) */ - if (!strcmp(request_name, "auth-agent-req@openssh.com") && + if (ptrlen_eq_string(request_name, "auth-agent-req@openssh.com") && !ssh_agent_forwarding_permitted(cs->parent->ssh)) { - unsigned server_id = GET_32BIT(pkt); - - sfree(request_name); chan = share_find_channel_by_server(cs, server_id); if (chan) { @@ -1630,14 +1574,10 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs, * whether it's one to handle locally or one to pass on to * a downstream, and if the latter, which one. */ - if (!strcmp(request_name, "x11-req")) { - unsigned server_id = GET_32BIT(pkt); + if (ptrlen_eq_string(request_name, "x11-req")) { int want_reply, single_connection, screen; - char *auth_proto_str, *auth_data; + ptrlen auth_data; int auth_proto; - int pos; - - sfree(request_name); chan = share_find_channel_by_server(cs, server_id); if (!chan) { @@ -1652,26 +1592,16 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs, * Pick apart the whole message to find the downstream * auth details. */ - /* we have already seen: 4 bytes channel id, 4+7 request name */ - if (pktlen < 17) { - err = dupprintf("Truncated CHANNEL_REQUEST(\"x11\") packet"); + want_reply = get_bool(src); + single_connection = get_bool(src); + auth_proto = x11_identify_auth_proto(get_string(src)); + auth_data = get_string(src); + screen = toint(get_uint32(src)); + if (get_err(src)) { + err = dupprintf("Truncated CHANNEL_REQUEST(\"x11-req\")" + " packet"); goto confused; } - want_reply = pkt[15] != 0; - single_connection = pkt[16] != 0; - auth_proto_str = getstring(pkt+17, pktlen-17); - auth_proto = x11_identify_auth_proto(auth_proto_str); - sfree(auth_proto_str); - pos = 17 + getstring_size(pkt+17, pktlen-17); - auth_data = getstring(pkt+pos, pktlen-pos); - pos += getstring_size(pkt+pos, pktlen-pos); - - if (pktlen < pos+4) { - err = dupprintf("Truncated CHANNEL_REQUEST(\"x11\") packet"); - sfree(auth_data); - goto confused; - } - screen = GET_32BIT(pkt+pos); if (auth_proto < 0) { /* Reject due to not understanding downstream's @@ -1682,14 +1612,12 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs, cs, SSH2_MSG_CHANNEL_FAILURE, packet->s, packet->len, NULL); strbuf_free(packet); - sfree(auth_data); break; } chan->x11_auth_proto = auth_proto; chan->x11_auth_data = x11_dehexify(auth_data, &chan->x11_auth_datalen); - sfree(auth_data); chan->x11_auth_upstream = ssh_sharing_add_x11_display(cs->parent->ssh, auth_proto, cs, chan); @@ -1715,14 +1643,11 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs, break; } - - sfree(request_name); } ssh_send_packet_from_downstream(cs->parent->ssh, cs->id, type, pkt, pktlen, NULL); if (type == SSH2_MSG_CHANNEL_CLOSE && pktlen >= 4) { - server_id = GET_32BIT(pkt); chan = share_find_channel_by_server(cs, server_id); if (chan) { if (chan->state == RCVD_CLOSE) { diff --git a/x11fwd.c b/x11fwd.c index eee73095..f59f9e2e 100644 --- a/x11fwd.c +++ b/x11fwd.c @@ -974,29 +974,29 @@ void x11_send_eof(struct X11Connection *xconn) * representations of an X11 auth protocol name + hex cookie into our * usual integer protocol id and binary auth data. */ -int x11_identify_auth_proto(const char *protoname) +int x11_identify_auth_proto(ptrlen protoname) { int protocol; for (protocol = 1; protocol < lenof(x11_authnames); protocol++) - if (!strcmp(protoname, x11_authnames[protocol])) + if (ptrlen_eq_string(protoname, x11_authnames[protocol])) return protocol; return -1; } -void *x11_dehexify(const char *hex, int *outlen) +void *x11_dehexify(ptrlen hexpl, int *outlen) { int len, i; unsigned char *ret; - len = strlen(hex) / 2; + len = hexpl.len / 2; ret = snewn(len, unsigned char); for (i = 0; i < len; i++) { char bytestr[3]; unsigned val = 0; - bytestr[0] = hex[2*i]; - bytestr[1] = hex[2*i+1]; + bytestr[0] = ((const char *)hexpl.ptr)[2*i]; + bytestr[1] = ((const char *)hexpl.ptr)[2*i+1]; bytestr[2] = '\0'; sscanf(bytestr, "%x", &val); ret[i] = val; From ae3edcdfc0b6e71377aee57070f43faacd6f6456 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Thu, 31 May 2018 18:40:51 +0100 Subject: [PATCH 334/607] Clean up ssh_keyalg APIs and implementations. Quite a few of the function pointers in the ssh_keyalg vtable now take ptrlen arguments in place of separate pointer and length pairs. Meanwhile, the various key types' implementations of those functions now work by initialising a BinarySource with the input ptrlen and using the new decode functions to walk along it. One exception is the openssh_createkey method which reads a private key in the wire format used by OpenSSH's SSH-2 agent protocol, which has to consume a prefix of a larger data stream, and tell the caller how much of that data was the private key. That function now takes an actual BinarySource, and passes that directly to the decode functions, so that on return the caller finds that the BinarySource's read pointer has been advanced exactly past the private key. This let me throw away _several_ reimplementations of mpint-reading functions, one in each of sshrsa, sshdss.c and sshecc.c. Worse still, they didn't all have exactly the SSH-2 semantics, because the thing in sshrsa.c whose name suggested it was an mpint-reading function actually tolerated the wrong number of leading zero bytes, which it had to be able to do to cope with the "ssh-rsa" signature format which contains a thing that isn't quite an SSH-2 mpint. Now that deviation is clearly commented! --- cmdgen.c | 5 +- import.c | 18 +++--- pageant.c | 9 +-- ssh.c | 18 +++--- ssh.h | 16 ++--- sshdss.c | 171 ++++++++++++++------------------------------------ sshecc.c | 183 ++++++++++++++++++------------------------------------ sshpubk.c | 7 ++- sshrsa.c | 137 +++++++++++++++------------------------- 9 files changed, 189 insertions(+), 375 deletions(-) diff --git a/cmdgen.c b/cmdgen.c index 160169a7..b4fcd567 100644 --- a/cmdgen.c +++ b/cmdgen.c @@ -857,9 +857,8 @@ int main(int argc, char **argv) &origcomment, &error)) { ssh2algf = find_pubkey_alg(ssh2alg); if (ssh2algf) - bits = ssh2algf->pubkey_bits(ssh2algf, - ssh2blob->s, - ssh2blob->len); + bits = ssh2algf->pubkey_bits( + ssh2algf, make_ptrlen(ssh2blob->s, ssh2blob->len)); else bits = -1; } else { diff --git a/import.c b/import.c index bc54108a..0b2d271c 100644 --- a/import.c +++ b/import.c @@ -670,8 +670,8 @@ struct ssh2_userkey *openssh_pem_read(const Filename *filename, put_mp_ssh2_from_string(blob, privkey.data.ptr, privkey.data.len); retkey->data = retkey->alg->createkey( - retkey->alg, blob->u, publen, - blob->u + publen, blob->len - publen); + retkey->alg, make_ptrlen(blob->u, publen), + make_ptrlen(blob->u + publen, blob->len - publen)); if (!retkey->data) { sfree(retkey); @@ -742,7 +742,8 @@ struct ssh2_userkey *openssh_pem_read(const Filename *filename, retkey = snew(struct ssh2_userkey); retkey->alg = (key->keytype == OP_RSA ? &ssh_rsa : &ssh_dss); retkey->data = retkey->alg->createkey( - retkey->alg, blob->u, privptr, blob->u+privptr, blob->len-privptr); + retkey->alg, make_ptrlen(blob->u, privptr), + make_ptrlen(blob->u+privptr, blob->len-privptr)); if (!retkey->data) { sfree(retkey); @@ -1466,13 +1467,13 @@ struct ssh2_userkey *openssh_new_read(const Filename *filename, thiskey.len = (const char *)get_ptr(src) - (const char *)thiskey.ptr; if (key_index == key->key_wanted) { - const unsigned char *blobptr = thiskey.ptr; - int bloblen = thiskey.len; + BinarySource src[1]; + BinarySource_BARE_INIT(src, thiskey.ptr, thiskey.len); retkey = snew(struct ssh2_userkey); retkey->comment = NULL; retkey->alg = alg; - retkey->data = alg->openssh_createkey(alg, &blobptr, &bloblen); + retkey->data = alg->openssh_createkey(alg, src); if (!retkey->data) { errmsg = "unable to create key data structure"; goto error; @@ -2173,8 +2174,9 @@ struct ssh2_userkey *sshcom_read(const Filename *filename, char *passphrase, retkey = snew(struct ssh2_userkey); retkey->alg = alg; - retkey->data = alg->createkey(alg, blob->u, publen, - blob->u + publen, blob->len - publen); + retkey->data = alg->createkey( + alg, make_ptrlen(blob->u, publen), + make_ptrlen(blob->u + publen, blob->len - publen)); if (!retkey->data) { sfree(retkey); errmsg = "unable to create key data structure"; diff --git a/pageant.c b/pageant.c index 25d0b9ab..71256ff3 100644 --- a/pageant.c +++ b/pageant.c @@ -430,14 +430,7 @@ void pageant_handle_msg(BinarySink *bs, goto add2_cleanup; } - { - const unsigned char *p = get_ptr(msg); - int len = get_avail(msg); - key->data = key->alg->openssh_createkey(key->alg, &p, &len); - assert(len >= 0); - assert(len < get_avail(msg)); - msg->pos += get_avail(msg) - len; - } + key->data = key->alg->openssh_createkey(key->alg, msg); if (!key->data) { pageant_failure_msg(bs, "key setup failed", logctx, logfn); diff --git a/ssh.c b/ssh.c index 518372ca..012d7062 100644 --- a/ssh.c +++ b/ssh.c @@ -7192,8 +7192,7 @@ static void do_ssh2_transport(void *vctx) } set_busy_status(ssh->frontend, BUSY_CPU); /* cogitate */ s->hostkeydata = get_string(pktin); - s->hkey = ssh->hostkey->newkey(ssh->hostkey, - s->hostkeydata.ptr, s->hostkeydata.len); + s->hkey = ssh->hostkey->newkey(ssh->hostkey, s->hostkeydata); s->f = get_mp_ssh2(pktin); s->sigdata = get_string(pktin); if (get_err(pktin)) { @@ -7264,8 +7263,7 @@ static void do_ssh2_transport(void *vctx) s->hostkeydata = get_string(pktin); put_stringpl(ssh->exhash_bs, s->hostkeydata); - s->hkey = ssh->hostkey->newkey(ssh->hostkey, - s->hostkeydata.ptr, s->hostkeydata.len); + s->hkey = ssh->hostkey->newkey(ssh->hostkey, s->hostkeydata); { strbuf *pubpoint = strbuf_new(); @@ -7469,8 +7467,7 @@ static void do_ssh2_transport(void *vctx) s->hostkeydata = get_string(pktin); if (ssh->hostkey) { s->hkey = ssh->hostkey->newkey(ssh->hostkey, - s->hostkeydata.ptr, - s->hostkeydata.len); + s->hostkeydata); put_string(ssh->exhash_bs, s->hostkeydata.ptr, s->hostkeydata.len); } @@ -7564,8 +7561,7 @@ static void do_ssh2_transport(void *vctx) s->hostkeydata = get_string(pktin); put_stringpl(ssh->exhash_bs, s->hostkeydata); - s->hkey = ssh->hostkey->newkey(ssh->hostkey, - s->hostkeydata.ptr, s->hostkeydata.len); + s->hkey = ssh->hostkey->newkey(ssh->hostkey, s->hostkeydata); rsakeydata = get_string(pktin); @@ -7704,9 +7700,9 @@ static void do_ssh2_transport(void *vctx) crStopV; } - if (!ssh->hostkey->verifysig(s->hkey, s->sigdata.ptr, s->sigdata.len, - s->exchange_hash, - ssh->kex->hash->hlen)) { + if (!ssh->hostkey->verifysig( + s->hkey, s->sigdata, + make_ptrlen(s->exchange_hash, ssh->kex->hash->hlen))) { #ifndef FUZZING bombout(("Server's host key did not match the signature " "supplied")); diff --git a/ssh.h b/ssh.h index 855bee89..655d72d2 100644 --- a/ssh.h +++ b/ssh.h @@ -394,17 +394,13 @@ struct ssh_kexes { }; struct ssh_keyalg { - ssh_key *(*newkey) (const ssh_keyalg *self, - const void *data, int len); + ssh_key *(*newkey) (const ssh_keyalg *self, ptrlen data); void (*freekey) (ssh_key *key); char *(*fmtkey) (ssh_key *key); void (*public_blob)(ssh_key *key, BinarySink *); void (*private_blob)(ssh_key *key, BinarySink *); - ssh_key *(*createkey) (const ssh_keyalg *self, - const void *pub_blob, int pub_len, - const void *priv_blob, int priv_len); - ssh_key *(*openssh_createkey) (const ssh_keyalg *self, - const unsigned char **blob, int *len); + ssh_key *(*createkey) (const ssh_keyalg *self, ptrlen pub, ptrlen priv); + ssh_key *(*openssh_createkey) (const ssh_keyalg *self, BinarySource *); void (*openssh_fmtkey) (ssh_key *key, BinarySink *); /* OpenSSH private key blobs, as created by openssh_fmtkey and * consumed by openssh_createkey, always (at least so far...) take @@ -415,10 +411,8 @@ struct ssh_keyalg { * skip over the right number to find the next key in the file. * openssh_private_npieces gives that information. */ int openssh_private_npieces; - int (*pubkey_bits) (const ssh_keyalg *self, - const void *blob, int len); - int (*verifysig) (ssh_key *key, const void *sig, int siglen, - const void *data, int datalen); + int (*pubkey_bits) (const ssh_keyalg *self, ptrlen blob); + int (*verifysig) (ssh_key *key, ptrlen sig, ptrlen data); void (*sign) (ssh_key *key, const void *data, int datalen, BinarySink *); const char *name; const char *keytype; /* for host key cache */ diff --git a/sshdss.c b/sshdss.c index 262d3e39..3c9589fb 100644 --- a/sshdss.c +++ b/sshdss.c @@ -9,86 +9,25 @@ #include "ssh.h" #include "misc.h" -static void getstring(const char **data, int *datalen, - const char **p, int *length) -{ - *p = NULL; - if (*datalen < 4) - return; - *length = toint(GET_32BIT(*data)); - if (*length < 0) - return; - *datalen -= 4; - *data += 4; - if (*datalen < *length) - return; - *p = *data; - *data += *length; - *datalen -= *length; -} -static Bignum getmp(const char **data, int *datalen) -{ - const char *p; - int length; - Bignum b; - - getstring(data, datalen, &p, &length); - if (!p) - return NULL; - if (p[0] & 0x80) - return NULL; /* negative mp */ - b = bignum_from_bytes(p, length); - return b; -} - -static Bignum get160(const char **data, int *datalen) -{ - Bignum b; - - if (*datalen < 20) - return NULL; - - b = bignum_from_bytes(*data, 20); - *data += 20; - *datalen -= 20; - - return b; -} - static void dss_freekey(ssh_key *key); /* forward reference */ -static ssh_key *dss_newkey(const ssh_keyalg *self, - const void *vdata, int len) +static ssh_key *dss_newkey(const ssh_keyalg *self, ptrlen data) { - const char *data = (const char *)vdata; - const char *p; - int slen; + BinarySource src[1]; struct dss_key *dss; - dss = snew(struct dss_key); - getstring(&data, &len, &p, &slen); - -#ifdef DEBUG_DSS - { - int i; - printf("key:"); - for (i = 0; i < len; i++) - printf(" %02x", (unsigned char) (data[i])); - printf("\n"); - } -#endif - - if (!p || slen != 7 || memcmp(p, "ssh-dss", 7)) { - sfree(dss); + BinarySource_BARE_INIT(src, data.ptr, data.len); + if (!ptrlen_eq_string(get_string(src), "ssh-dss")) return NULL; - } - dss->p = getmp(&data, &len); - dss->q = getmp(&data, &len); - dss->g = getmp(&data, &len); - dss->y = getmp(&data, &len); + + dss = snew(struct dss_key); + dss->p = get_mp_ssh2(src); + dss->q = get_mp_ssh2(src); + dss->g = get_mp_ssh2(src); + dss->y = get_mp_ssh2(src); dss->x = NULL; - if (!dss->p || !dss->q || !dss->g || !dss->y || + if (get_err(src) || !bignum_cmp(dss->q, Zero) || !bignum_cmp(dss->p, Zero)) { /* Invalid key. */ dss_freekey(&dss->sshk); @@ -164,29 +103,19 @@ static char *dss_fmtkey(ssh_key *key) return p; } -static int dss_verifysig(ssh_key *key, const void *vsig, int siglen, - const void *data, int datalen) +static int dss_verifysig(ssh_key *key, ptrlen sig, ptrlen data) { struct dss_key *dss = FROMFIELD(key, struct dss_key, sshk); - const char *sig = (const char *)vsig; - const char *p; - int slen; - char hash[20]; + BinarySource src[1]; + unsigned char hash[20]; Bignum r, s, w, gu1p, yu2p, gu1yu2p, u1, u2, sha, v; int ret; if (!dss->p) return 0; -#ifdef DEBUG_DSS - { - int i; - printf("sig:"); - for (i = 0; i < siglen; i++) - printf(" %02x", (unsigned char) (sig[i])); - printf("\n"); - } -#endif + BinarySource_BARE_INIT(src, sig.ptr, sig.len); + /* * Commercial SSH (2.0.13) and OpenSSH disagree over the format * of a DSA signature. OpenSSH is in line with RFC 4253: @@ -198,15 +127,18 @@ static int dss_verifysig(ssh_key *key, const void *vsig, int siglen, * the length: length 40 means the commercial-SSH bug, anything * else is assumed to be RFC-compliant. */ - if (siglen != 40) { /* bug not present; read admin fields */ - getstring(&sig, &siglen, &p, &slen); - if (!p || slen != 7 || memcmp(p, "ssh-dss", 7)) { - return 0; - } - sig += 4, siglen -= 4; /* skip yet another length field */ + if (sig.len != 40) { /* bug not present; read admin fields */ + ptrlen type = get_string(src); + sig = get_string(src); + + if (get_err(src) || !ptrlen_eq_string(type, "ssh-dss") || + sig.len != 40) + return 0; } - r = get160(&sig, &siglen); - s = get160(&sig, &siglen); + + /* Now we're sitting on a 40-byte string for sure. */ + r = bignum_from_bytes(sig.ptr, 20); + s = bignum_from_bytes((const char *)sig.ptr + 20, 20); if (!r || !s) { if (r) freebn(r); @@ -234,10 +166,8 @@ static int dss_verifysig(ssh_key *key, const void *vsig, int siglen, /* * Step 2. u1 <- SHA(message) * w mod q. */ - SHA_Simple(data, datalen, (unsigned char *)hash); - p = hash; - slen = 20; - sha = get160(&p, &slen); + SHA_Simple(data.ptr, data.len, hash); + sha = bignum_from_bytes(hash, 20); u1 = modmul(sha, w, dss->q); /* @@ -291,26 +221,24 @@ static void dss_private_blob(ssh_key *key, BinarySink *bs) put_mp_ssh2(bs, dss->x); } -static ssh_key *dss_createkey(const ssh_keyalg *self, - const void *pub_blob, int pub_len, - const void *priv_blob, int priv_len) +static ssh_key *dss_createkey(const ssh_keyalg *self, ptrlen pub, ptrlen priv) { + BinarySource src[1]; ssh_key *sshk; struct dss_key *dss; - const char *pb = (const char *) priv_blob; - const char *hash; - int hashlen; + ptrlen hash; SHA_State s; unsigned char digest[20]; Bignum ytest; - sshk = dss_newkey(self, pub_blob, pub_len); + sshk = dss_newkey(self, pub); if (!sshk) return NULL; dss = FROMFIELD(sshk, struct dss_key, sshk); - dss->x = getmp(&pb, &priv_len); - if (!dss->x) { + BinarySource_BARE_INIT(src, priv.ptr, priv.len); + dss->x = get_mp_ssh2(src); + if (get_err(src)) { dss_freekey(&dss->sshk); return NULL; } @@ -318,15 +246,14 @@ static ssh_key *dss_createkey(const ssh_keyalg *self, /* * Check the obsolete hash in the old DSS key format. */ - hashlen = -1; - getstring(&pb, &priv_len, &hash, &hashlen); - if (hashlen == 20) { + hash = get_string(src); + if (hash.len == 20) { SHA_Init(&s); put_mp_ssh2(&s, dss->p); put_mp_ssh2(&s, dss->q); put_mp_ssh2(&s, dss->g); SHA_Final(&s, digest); - if (0 != memcmp(hash, digest, 20)) { + if (0 != memcmp(hash.ptr, digest, 20)) { dss_freekey(&dss->sshk); return NULL; } @@ -347,20 +274,19 @@ static ssh_key *dss_createkey(const ssh_keyalg *self, } static ssh_key *dss_openssh_createkey(const ssh_keyalg *self, - const unsigned char **blob, int *len) + BinarySource *src) { - const char **b = (const char **) blob; struct dss_key *dss; dss = snew(struct dss_key); - dss->p = getmp(b, len); - dss->q = getmp(b, len); - dss->g = getmp(b, len); - dss->y = getmp(b, len); - dss->x = getmp(b, len); + dss->p = get_mp_ssh2(src); + dss->q = get_mp_ssh2(src); + dss->g = get_mp_ssh2(src); + dss->y = get_mp_ssh2(src); + dss->x = get_mp_ssh2(src); - if (!dss->p || !dss->q || !dss->g || !dss->y || !dss->x || + if (get_err(src) || !bignum_cmp(dss->q, Zero) || !bignum_cmp(dss->p, Zero)) { /* Invalid key. */ dss_freekey(&dss->sshk); @@ -381,14 +307,13 @@ static void dss_openssh_fmtkey(ssh_key *key, BinarySink *bs) put_mp_ssh2(bs, dss->x); } -static int dss_pubkey_bits(const ssh_keyalg *self, - const void *blob, int len) +static int dss_pubkey_bits(const ssh_keyalg *self, ptrlen pub) { ssh_key *sshk; struct dss_key *dss; int ret; - sshk = dss_newkey(self, blob, len); + sshk = dss_newkey(self, pub); if (!sshk) return -1; diff --git a/sshecc.c b/sshecc.c index 57bd3595..0d97395a 100644 --- a/sshecc.c +++ b/sshecc.c @@ -1590,47 +1590,12 @@ static void _ecdsa_sign(const Bignum privateKey, const struct ec_curve *curve, * Misc functions */ -static void getstring(const char **data, int *datalen, - const char **p, int *length) +static Bignum BinarySource_get_mp_le(BinarySource *src) { - *p = NULL; - if (*datalen < 4) - return; - *length = toint(GET_32BIT(*data)); - if (*length < 0) - return; - *datalen -= 4; - *data += 4; - if (*datalen < *length) - return; - *p = *data; - *data += *length; - *datalen -= *length; -} - -static Bignum getmp(const char **data, int *datalen) -{ - const char *p; - int length; - - getstring(data, datalen, &p, &length); - if (!p) - return NULL; - if (p[0] & 0x80) - return NULL; /* negative mp */ - return bignum_from_bytes(p, length); -} - -static Bignum getmp_le(const char **data, int *datalen) -{ - const char *p; - int length; - - getstring(data, datalen, &p, &length); - if (!p) - return NULL; - return bignum_from_bytes_le(p, length); + ptrlen mp_str = get_string(src); + return bignum_from_bytes_le(mp_str.ptr, mp_str.len); } +#define get_mp_le(src) BinarySource_get_mp_le(BinarySource_UPCAST(src)) static int decodepoint_ed(const char *p, int length, struct ec_point *point) { @@ -1709,15 +1674,13 @@ static int decodepoint(const char *p, int length, struct ec_point *point) return 1; } -static int getmppoint(const char **data, int *datalen, struct ec_point *point) +static int BinarySource_get_point(BinarySource *src, struct ec_point *point) { - const char *p; - int length; - - getstring(data, datalen, &p, &length); - if (!p) return 0; - return decodepoint(p, length, point); + ptrlen str = get_string(src); + if (get_err(src)) return 0; + return decodepoint(str.ptr, str.len, point); } +#define get_point(src, pt) BinarySource_get_point(BinarySource_UPCAST(src), pt) /* ---------------------------------------------------------------------- * Exposed ECDSA interface @@ -1750,30 +1713,24 @@ static void ecdsa_freekey(ssh_key *key) sfree(ec); } -static ssh_key *ecdsa_newkey(const ssh_keyalg *self, - const void *vdata, int len) +static ssh_key *ecdsa_newkey(const ssh_keyalg *self, ptrlen data) { const struct ecsign_extra *extra = (const struct ecsign_extra *)self->extra; - const char *data = (const char *)vdata; - const char *p; - int slen; + BinarySource src[1]; struct ec_key *ec; struct ec_curve *curve; - getstring(&data, &len, &p, &slen); + BinarySource_BARE_INIT(src, data.ptr, data.len); + get_string(src); - if (!p) { - return NULL; - } curve = extra->curve(); assert(curve->type == EC_WEIERSTRASS || curve->type == EC_EDWARDS); /* Curve name is duplicated for Weierstrass form */ if (curve->type == EC_WEIERSTRASS) { - getstring(&data, &len, &p, &slen); - if (!p) return NULL; - if (!match_ssh_id(slen, p, curve->name)) return NULL; + if (!ptrlen_eq_string(get_string(src), curve->name)) + return NULL; } ec = snew(struct ec_key); @@ -1785,7 +1742,7 @@ static ssh_key *ecdsa_newkey(const ssh_keyalg *self, ec->publicKey.y = NULL; ec->publicKey.z = NULL; ec->privateKey = NULL; - if (!getmppoint(&data, &len, &ec->publicKey)) { + if (!get_point(src, &ec->publicKey)) { ecdsa_freekey(&ec->sshk); return NULL; } @@ -1908,19 +1865,19 @@ static void ecdsa_private_blob(ssh_key *key, BinarySink *bs) } static ssh_key *ecdsa_createkey(const ssh_keyalg *self, - const void *pub_blob, int pub_len, - const void *priv_blob, int priv_len) + ptrlen pub, ptrlen priv) { + BinarySource src[1]; ssh_key *sshk; struct ec_key *ec; struct ec_point *publicKey; - const char *pb = (const char *) priv_blob; - sshk = ecdsa_newkey(self, pub_blob, pub_len); + sshk = ecdsa_newkey(self, pub); if (!sshk) return NULL; ec = FROMFIELD(sshk, struct ec_key, sshk); + BinarySource_BARE_INIT(src, priv.ptr, priv.len); if (ec->publicKey.curve->type != EC_WEIERSTRASS && ec->publicKey.curve->type != EC_EDWARDS) { @@ -1929,9 +1886,9 @@ static ssh_key *ecdsa_createkey(const ssh_keyalg *self, } if (ec->publicKey.curve->type == EC_EDWARDS) { - ec->privateKey = getmp_le(&pb, &priv_len); + ec->privateKey = get_mp_le(src); } else { - ec->privateKey = getmp(&pb, &priv_len); + ec->privateKey = get_mp_ssh2(src); } if (!ec->privateKey) { ecdsa_freekey(&ec->sshk); @@ -1954,18 +1911,16 @@ static ssh_key *ecdsa_createkey(const ssh_keyalg *self, } static ssh_key *ed25519_openssh_createkey(const ssh_keyalg *self, - const unsigned char **blob, int *len) + BinarySource *src) { struct ec_key *ec; struct ec_point *publicKey; - const char *p, *q; - int plen, qlen; + ptrlen p, q; - getstring((const char**)blob, len, &p, &plen); - if (!p) - { + p = get_string(src); + q = get_string(src); + if (get_err(src) || p.len != 32 || q.len != 64) return NULL; - } ec = snew(struct ec_key); @@ -1977,19 +1932,13 @@ static ssh_key *ed25519_openssh_createkey(const ssh_keyalg *self, ec->publicKey.z = NULL; ec->publicKey.y = NULL; - if (!decodepoint_ed(p, plen, &ec->publicKey)) + if (!decodepoint_ed(p.ptr, p.len, &ec->publicKey)) { ecdsa_freekey(&ec->sshk); return NULL; } - getstring((const char**)blob, len, &q, &qlen); - if (!q || qlen != 64) { - ecdsa_freekey(&ec->sshk); - return NULL; - } - - ec->privateKey = bignum_from_bytes_le(q, 32); + ec->privateKey = bignum_from_bytes_le(q.ptr, 32); /* Check that private key generates public key */ publicKey = ec_public(ec->privateKey, ec->publicKey.curve); @@ -2009,7 +1958,7 @@ static ssh_key *ed25519_openssh_createkey(const ssh_keyalg *self, * correct as well, otherwise the key we think we've imported * won't behave identically to the way OpenSSH would have treated * it. */ - if (plen != 32 || 0 != memcmp(q + 32, p, 32)) { + if (0 != memcmp((const char *)q.ptr + 32, p.ptr, 32)) { ecdsa_freekey(&ec->sshk); return NULL; } @@ -2054,22 +2003,16 @@ static void ed25519_openssh_fmtkey(ssh_key *key, BinarySink *bs) } static ssh_key *ecdsa_openssh_createkey(const ssh_keyalg *self, - const unsigned char **blob, int *len) + BinarySource *src) { const struct ecsign_extra *extra = (const struct ecsign_extra *)self->extra; - const char **b = (const char **) blob; - const char *p; - int slen; struct ec_key *ec; struct ec_curve *curve; struct ec_point *publicKey; - getstring(b, len, &p, &slen); + get_string(src); - if (!p) { - return NULL; - } curve = extra->curve(); assert(curve->type == EC_WEIERSTRASS); @@ -2081,7 +2024,7 @@ static ssh_key *ecdsa_openssh_createkey(const ssh_keyalg *self, ec->publicKey.x = NULL; ec->publicKey.y = NULL; ec->publicKey.z = NULL; - if (!getmppoint(b, len, &ec->publicKey)) { + if (!get_point(src, &ec->publicKey)) { ecdsa_freekey(&ec->sshk); return NULL; } @@ -2095,7 +2038,7 @@ static ssh_key *ecdsa_openssh_createkey(const ssh_keyalg *self, return NULL; } - ec->privateKey = getmp(b, len); + ec->privateKey = get_mp_ssh2(src); if (ec->privateKey == NULL) { ecdsa_freekey(&ec->sshk); @@ -2147,14 +2090,13 @@ static void ecdsa_openssh_fmtkey(ssh_key *key, BinarySink *bs) put_mp_ssh2(bs, ec->privateKey); } -static int ecdsa_pubkey_bits(const ssh_keyalg *self, - const void *blob, int len) +static int ecdsa_pubkey_bits(const ssh_keyalg *self, ptrlen blob) { ssh_key *sshk; struct ec_key *ec; int ret; - sshk = ecdsa_newkey(self, blob, len); + sshk = ecdsa_newkey(self, blob); if (!sshk) return -1; @@ -2165,39 +2107,35 @@ static int ecdsa_pubkey_bits(const ssh_keyalg *self, return ret; } -static int ecdsa_verifysig(ssh_key *key, const void *vsig, int siglen, - const void *vdata, int datalen) +static int ecdsa_verifysig(ssh_key *key, ptrlen sig, ptrlen data) { struct ec_key *ec = FROMFIELD(key, struct ec_key, sshk); - const char *sig = (const char *)vsig; - const char *data = (const char *)vdata; const struct ecsign_extra *extra = (const struct ecsign_extra *)ec->signalg->extra; - const char *p; - int slen; - int digestLen; + BinarySource src[1]; + ptrlen sigstr; int ret; if (!ec->publicKey.x || !ec->publicKey.y || !ec->publicKey.curve) return 0; + BinarySource_BARE_INIT(src, sig.ptr, sig.len); + /* Check the signature starts with the algorithm name */ - getstring(&sig, &siglen, &p, &slen); - if (!p) { + if (!ptrlen_eq_string(get_string(src), ec->signalg->name)) return 0; - } - if (!match_ssh_id(slen, p, ec->signalg->name)) { + + sigstr = get_string(src); + if (get_err(src)) return 0; - } - getstring(&sig, &siglen, &p, &slen); - if (!p) return 0; if (ec->publicKey.curve->type == EC_EDWARDS) { struct ec_point *r; + int pointlen = ec->publicKey.curve->fieldBits / 8; Bignum s, h; /* Check that the signature is two times the length of a point */ - if (slen != (ec->publicKey.curve->fieldBits / 8) * 2) { + if (sigstr.len != pointlen * 2) { return 0; } @@ -2211,25 +2149,23 @@ static int ecdsa_verifysig(ssh_key *key, const void *vsig, int siglen, if (!r) { return 0; } - if (!decodepoint(p, ec->publicKey.curve->fieldBits / 8, r)) { + if (!decodepoint(sigstr.ptr, pointlen, r)) { ec_point_free(r); return 0; } - s = bignum_from_bytes_le((unsigned char*)p + (ec->publicKey.curve->fieldBits / 8), - ec->publicKey.curve->fieldBits / 8); + s = bignum_from_bytes_le( + (const char *)sigstr.ptr + pointlen, pointlen); /* Get the hash of the encoded value of R + encoded value of pk + message */ { - int i, pointlen; + int i; unsigned char digest[512 / 8]; SHA512_State hs; SHA512_Init(&hs); - pointlen = ec->publicKey.curve->fieldBits / 8; - /* Add encoded r (no need to encode it again, it was in * the signature) */ - put_data(&hs, p, pointlen); + put_data(&hs, sigstr.ptr, pointlen); /* Encode pk and add it */ for (i = 0; i < pointlen - 1; ++i) @@ -2239,7 +2175,7 @@ static int ecdsa_verifysig(ssh_key *key, const void *vsig, int siglen, (bignum_bit(ec->publicKey.x, 0) << 7))); /* Add the message itself */ - put_data(&hs, data, datalen); + put_data(&hs, data.ptr, data.len); /* Get the hash */ SHA512_Final(&hs, digest); @@ -2291,20 +2227,23 @@ static int ecdsa_verifysig(ssh_key *key, const void *vsig, int siglen, } else { Bignum r, s; unsigned char digest[512 / 8]; + int digestLen; void *hashctx; - r = getmp(&p, &slen); - if (!r) return 0; - s = getmp(&p, &slen); - if (!s) { + BinarySource_BARE_INIT(src, sigstr.ptr, sigstr.len); + + r = get_mp_ssh2(src); + s = get_mp_ssh2(src); + if (get_err(src)) { freebn(r); + freebn(s); return 0; } digestLen = extra->hash->hlen; assert(digestLen <= sizeof(digest)); hashctx = extra->hash->init(); - put_data(extra->hash->sink(hashctx), data, datalen); + put_data(extra->hash->sink(hashctx), data.ptr, data.len); extra->hash->final(hashctx, digest); /* Verify the signature */ diff --git a/sshpubk.c b/sshpubk.c index 01cacb58..e3a80b0c 100644 --- a/sshpubk.c +++ b/sshpubk.c @@ -799,8 +799,9 @@ struct ssh2_userkey *ssh2_load_userkey(const Filename *filename, ret = snew(struct ssh2_userkey); ret->alg = alg; ret->comment = comment; - ret->data = alg->createkey(alg, public_blob->u, public_blob->len, - private_blob->u, private_blob->len); + ret->data = alg->createkey( + alg, make_ptrlen(public_blob->u, public_blob->len), + make_ptrlen(private_blob->u, private_blob->len)); if (!ret->data) { sfree(ret); ret = NULL; @@ -1509,7 +1510,7 @@ char *ssh2_fingerprint_blob(const void *blob, int bloblen) if (!get_err(src)) { alg = find_pubkey_alg_len(algname); if (alg) { - int bits = alg->pubkey_bits(alg, blob, bloblen); + int bits = alg->pubkey_bits(alg, make_ptrlen(blob, bloblen)); return dupprintf("%.*s %d %s", PTRLEN_PRINTF(algname), bits, fingerprint_str); } else { diff --git a/sshrsa.c b/sshrsa.c index c0008dc1..751d1c3e 100644 --- a/sshrsa.c +++ b/sshrsa.c @@ -520,62 +520,27 @@ void freersakey(struct RSAKey *key) * Implementation of the ssh-rsa signing key type. */ -static void getstring(const char **data, int *datalen, - const char **p, int *length) -{ - *p = NULL; - if (*datalen < 4) - return; - *length = toint(GET_32BIT(*data)); - if (*length < 0) - return; - *datalen -= 4; - *data += 4; - if (*datalen < *length) - return; - *p = *data; - *data += *length; - *datalen -= *length; -} -static Bignum getmp(const char **data, int *datalen) -{ - const char *p; - int length; - Bignum b; - - getstring(data, datalen, &p, &length); - if (!p) - return NULL; - b = bignum_from_bytes(p, length); - return b; -} - static void rsa2_freekey(ssh_key *key); /* forward reference */ -static ssh_key *rsa2_newkey(const ssh_keyalg *self, - const void *vdata, int len) +static ssh_key *rsa2_newkey(const ssh_keyalg *self, ptrlen data) { - const char *p; - const char *data = (const char *)vdata; - int slen; + BinarySource src[1]; struct RSAKey *rsa; - rsa = snew(struct RSAKey); - getstring(&data, &len, &p, &slen); - - if (!p || slen != 7 || memcmp(p, "ssh-rsa", 7)) { - sfree(rsa); + BinarySource_BARE_INIT(src, data.ptr, data.len); + if (!ptrlen_eq_string(get_string(src), "ssh-rsa")) return NULL; - } - rsa->exponent = getmp(&data, &len); - rsa->modulus = getmp(&data, &len); + + rsa = snew(struct RSAKey); + rsa->exponent = get_mp_ssh2(src); + rsa->modulus = get_mp_ssh2(src); rsa->private_exponent = NULL; rsa->p = rsa->q = rsa->iqmp = NULL; rsa->comment = NULL; - if (!rsa->exponent || !rsa->modulus) { - rsa2_freekey(&rsa->sshk); - return NULL; + if (get_err(src)) { + rsa2_freekey(&rsa->sshk); + return NULL; } return &rsa->sshk; @@ -620,24 +585,24 @@ static void rsa2_private_blob(ssh_key *key, BinarySink *bs) } static ssh_key *rsa2_createkey(const ssh_keyalg *self, - const void *pub_blob, int pub_len, - const void *priv_blob, int priv_len) + ptrlen pub, ptrlen priv) { + BinarySource src[1]; ssh_key *sshk; struct RSAKey *rsa; - const char *pb = (const char *) priv_blob; - sshk = rsa2_newkey(self, pub_blob, pub_len); + sshk = rsa2_newkey(self, pub); if (!sshk) return NULL; rsa = FROMFIELD(sshk, struct RSAKey, sshk); - rsa->private_exponent = getmp(&pb, &priv_len); - rsa->p = getmp(&pb, &priv_len); - rsa->q = getmp(&pb, &priv_len); - rsa->iqmp = getmp(&pb, &priv_len); + BinarySource_BARE_INIT(src, priv.ptr, priv.len); + rsa->private_exponent = get_mp_ssh2(src); + rsa->p = get_mp_ssh2(src); + rsa->q = get_mp_ssh2(src); + rsa->iqmp = get_mp_ssh2(src); - if (!rsa_verify(rsa)) { + if (get_err(src) || !rsa_verify(rsa)) { rsa2_freekey(&rsa->sshk); return NULL; } @@ -646,28 +611,21 @@ static ssh_key *rsa2_createkey(const ssh_keyalg *self, } static ssh_key *rsa2_openssh_createkey(const ssh_keyalg *self, - const unsigned char **blob, int *len) + BinarySource *src) { - const char **b = (const char **) blob; struct RSAKey *rsa; rsa = snew(struct RSAKey); rsa->comment = NULL; - rsa->modulus = getmp(b, len); - rsa->exponent = getmp(b, len); - rsa->private_exponent = getmp(b, len); - rsa->iqmp = getmp(b, len); - rsa->p = getmp(b, len); - rsa->q = getmp(b, len); - - if (!rsa->modulus || !rsa->exponent || !rsa->private_exponent || - !rsa->iqmp || !rsa->p || !rsa->q) { - rsa2_freekey(&rsa->sshk); - return NULL; - } + rsa->modulus = get_mp_ssh2(src); + rsa->exponent = get_mp_ssh2(src); + rsa->private_exponent = get_mp_ssh2(src); + rsa->iqmp = get_mp_ssh2(src); + rsa->p = get_mp_ssh2(src); + rsa->q = get_mp_ssh2(src); - if (!rsa_verify(rsa)) { + if (get_err(src) || !rsa_verify(rsa)) { rsa2_freekey(&rsa->sshk); return NULL; } @@ -687,14 +645,13 @@ static void rsa2_openssh_fmtkey(ssh_key *key, BinarySink *bs) put_mp_ssh2(bs, rsa->q); } -static int rsa2_pubkey_bits(const ssh_keyalg *self, - const void *blob, int len) +static int rsa2_pubkey_bits(const ssh_keyalg *self, ptrlen pub) { ssh_key *sshk; struct RSAKey *rsa; int ret; - sshk = rsa2_newkey(self, blob, len); + sshk = rsa2_newkey(self, pub); if (!sshk) return -1; @@ -736,24 +693,32 @@ static const unsigned char asn1_weird_stuff[] = { #define ASN1_LEN ( (int) sizeof(asn1_weird_stuff) ) -static int rsa2_verifysig(ssh_key *key, const void *vsig, int siglen, - const void *data, int datalen) +static int rsa2_verifysig(ssh_key *key, ptrlen sig, ptrlen data) { struct RSAKey *rsa = FROMFIELD(key, struct RSAKey, sshk); - const char *sig = (const char *)vsig; + BinarySource src[1]; + ptrlen type, in_pl; Bignum in, out; - const char *p; - int slen; int bytes, i, j, ret; unsigned char hash[20]; - getstring(&sig, &siglen, &p, &slen); - if (!p || slen != 7 || memcmp(p, "ssh-rsa", 7)) { + BinarySource_BARE_INIT(src, sig.ptr, sig.len); + type = get_string(src); + /* + * RFC 4253 section 6.6: the signature integer in an ssh-rsa + * signature is 'without lengths or padding'. That is, we _don't_ + * expect the usual leading zero byte if the topmost bit of the + * first byte is set. (However, because of the possibility of + * BUG_SSH2_RSA_PADDING at the other end, we tolerate it if it's + * there.) So we can't use get_mp_ssh2, which enforces that + * leading-byte scheme; instead we use get_string and + * bignum_from_bytes, which will tolerate anything. + */ + in_pl = get_string(src); + if (get_err(src) || !ptrlen_eq_string(type, "ssh-rsa")) return 0; - } - in = getmp(&sig, &siglen); - if (!in) - return 0; + + in = bignum_from_bytes(in_pl.ptr, in_pl.len); out = modpow(in, rsa->exponent, rsa->modulus); freebn(in); @@ -777,7 +742,7 @@ static int rsa2_verifysig(ssh_key *key, const void *vsig, int siglen, ret = 0; } /* Finally, we expect to see the SHA-1 hash of the signed data. */ - SHA_Simple(data, datalen, hash); + SHA_Simple(data.ptr, data.len, hash); for (i = 19, j = 0; i >= 0; i--, j++) { if (bignum_byte(out, i) != hash[j]) ret = 0; @@ -846,7 +811,7 @@ const ssh_keyalg ssh_rsa = { struct RSAKey *ssh_rsakex_newkey(const void *data, int len) { - ssh_key *sshk = rsa2_newkey(&ssh_rsa, data, len); + ssh_key *sshk = rsa2_newkey(&ssh_rsa, make_ptrlen(data, len)); if (!sshk) return NULL; return FROMFIELD(sshk, struct RSAKey, sshk); From 5acd523ae6c5b6a4be83b5131d53826606778335 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Tue, 29 May 2018 22:41:37 +0100 Subject: [PATCH 335/607] Rewrite .Xauthority parsing using BinarySource. This rewrite replaces a particularly hairy macro-based system. --- x11fwd.c | 103 ++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 63 insertions(+), 40 deletions(-) diff --git a/x11fwd.c b/x11fwd.c index f59f9e2e..bd4c9289 100644 --- a/x11fwd.c +++ b/x11fwd.c @@ -429,15 +429,28 @@ static const char *x11_verify(unsigned long peer_ip, int peer_port, return NULL; } +ptrlen BinarySource_get_string_xauth(BinarySource *src) +{ + size_t len = get_uint16(src); + return get_data(src, len); +} +#define get_string_xauth(src) \ + BinarySource_get_string_xauth(BinarySource_UPCAST(src)) + void x11_get_auth_from_authfile(struct X11Display *disp, const char *authfilename) { FILE *authfp; - char *buf, *ptr, *str[4]; - int len[4]; + char *buf; + int size; + BinarySource src[1]; int family, protocol; + ptrlen addr, protoname, data; + char *displaynum_string; + int displaynum; int ideal_match = FALSE; char *ourhostname; + const size_t MAX_RECORD_SIZE = 0x80, BUF_SIZE = 2 * MAX_RECORD_SIZE; /* * Normally we should look for precisely the details specified in @@ -468,29 +481,41 @@ void x11_get_auth_from_authfile(struct X11Display *disp, ourhostname = get_hostname(); - /* Records in .Xauthority contain four strings of up to 64K each */ - buf = snewn(65537 * 4, char); + /* + * Allocate enough space to hold two maximally sized records, so + * that a full record can start anywhere in the first half. That + * way we avoid the accidentally-quadratic algorithm that would + * arise if we moved everything to the front of the buffer after + * consuming each record; instead, we only move everything to the + * front after our current position gets past the half-way mark. + * Before then, there's no need to move anyway; so this guarantees + * linear time, in that every byte written into this buffer moves + * at most once (because every move is from the second half of the + * buffer to the first half). + */ + buf = snewn(BUF_SIZE, char); + size = fread(buf, 1, BUF_SIZE, authfp); + BinarySource_BARE_INIT(src, buf, size); while (!ideal_match) { - int c, i, j, match = FALSE; - -#define GET do { c = fgetc(authfp); if (c == EOF) goto done; c = (unsigned char)c; } while (0) - /* Expect a big-endian 2-byte number giving address family */ - GET; family = c; - GET; family = (family << 8) | c; - /* Then expect four strings, each composed of a big-endian 2-byte - * length field followed by that many bytes of data */ - ptr = buf; - for (i = 0; i < 4; i++) { - GET; len[i] = c; - GET; len[i] = (len[i] << 8) | c; - str[i] = ptr; - for (j = 0; j < len[i]; j++) { - GET; *ptr++ = c; - } - *ptr++ = '\0'; - } -#undef GET + int match = FALSE; + + if (src->pos >= MAX_RECORD_SIZE) { + size -= src->pos; + memcpy(buf, buf + src->pos, size); + size += fread(buf + size, 1, BUF_SIZE - size, authfp); + BinarySource_BARE_INIT(src, buf, size); + } + + family = get_uint16(src); + addr = get_string_xauth(src); + displaynum_string = mkstr(get_string_xauth(src)); + displaynum = atoi(displaynum_string); + sfree(displaynum_string); + protoname = get_string_xauth(src); + data = get_string_xauth(src); + if (get_err(src)) + break; /* * Now we have a full X authority record in memory. See @@ -504,7 +529,7 @@ void x11_get_auth_from_authfile(struct X11Display *disp, * connect to the display. 0 means IPv4; 6 means IPv6; * 256 means Unix-domain sockets. * - * - str[0] is the network address itself. For IPv4 and + * - 'addr' is the network address itself. For IPv4 and * IPv6, this is a string of binary data of the * appropriate length (respectively 4 and 16 bytes) * representing the address in big-endian format, e.g. @@ -515,24 +540,23 @@ void x11_get_auth_from_authfile(struct X11Display *disp, * authority entries for Unix-domain displays on * several machines without them clashing). * - * - str[1] is the display number. I've no idea why + * - 'displaynum' is the display number. I've no idea why * .Xauthority stores this as a string when it has a * perfectly good integer format, but there we go. * - * - str[2] is the authorisation method, encoded as its - * canonical string name (i.e. "MIT-MAGIC-COOKIE-1", - * "XDM-AUTHORIZATION-1" or something we don't - * recognise). + * - 'protoname' is the authorisation protocol, encoded as + * its canonical string name (i.e. "MIT-MAGIC-COOKIE-1", + * "XDM-AUTHORIZATION-1" or something we don't recognise). * - * - str[3] is the actual authorisation data, stored in + * - 'data' is the actual authorisation data, stored in * binary form. */ - if (disp->displaynum < 0 || disp->displaynum != atoi(str[1])) + if (disp->displaynum < 0 || disp->displaynum != displaynum) continue; /* not the one */ for (protocol = 1; protocol < lenof(x11_authnames); protocol++) - if (!strcmp(str[2], x11_authnames[protocol])) + if (ptrlen_eq_string(protoname, x11_authnames[protocol])) break; if (protocol == lenof(x11_authnames)) continue; /* don't recognise this protocol, look for another */ @@ -543,7 +567,7 @@ void x11_get_auth_from_authfile(struct X11Display *disp, sk_addrtype(disp->addr) == ADDRTYPE_IPV4) { char buf[4]; sk_addrcopy(disp->addr, buf); - if (len[0] == 4 && !memcmp(str[0], buf, 4)) { + if (addr.len == 4 && !memcmp(addr.ptr, buf, 4)) { match = TRUE; /* If this is a "localhost" entry, note it down * but carry on looking for a Unix-domain entry. */ @@ -556,7 +580,7 @@ void x11_get_auth_from_authfile(struct X11Display *disp, sk_addrtype(disp->addr) == ADDRTYPE_IPV6) { char buf[16]; sk_addrcopy(disp->addr, buf); - if (len[0] == 16 && !memcmp(str[0], buf, 16)) { + if (addr.len == 16 && !memcmp(addr.ptr, buf, 16)) { match = TRUE; ideal_match = !localhost; } @@ -564,7 +588,7 @@ void x11_get_auth_from_authfile(struct X11Display *disp, break; case 256: /* Unix-domain / localhost */ if ((disp->unixdomain || localhost) - && ourhostname && !strcmp(ourhostname, str[0])) + && ourhostname && ptrlen_eq_string(addr, ourhostname)) /* A matching Unix-domain socket is always the best * match. */ match = ideal_match = TRUE; @@ -575,15 +599,14 @@ void x11_get_auth_from_authfile(struct X11Display *disp, /* Current best guess -- may be overridden if !ideal_match */ disp->localauthproto = protocol; sfree(disp->localauthdata); /* free previous guess, if any */ - disp->localauthdata = snewn(len[3], unsigned char); - memcpy(disp->localauthdata, str[3], len[3]); - disp->localauthdatalen = len[3]; + disp->localauthdata = snewn(data.len, unsigned char); + memcpy(disp->localauthdata, data.ptr, data.len); + disp->localauthdatalen = data.len; } } - done: fclose(authfp); - smemclr(buf, 65537 * 4); + smemclr(buf, 2 * MAX_RECORD_SIZE); sfree(buf); sfree(ourhostname); } From 4d8c03359614356244be9591abac4c5f6dc1e34b Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Wed, 30 May 2018 22:36:20 +0100 Subject: [PATCH 336/607] Rewrite SOCKS client code using BinarySource. I've also replaced the entire SOCKS state machine whose states were barely-documented literal integers with one that uses an actual enum. I think the result is a great deal clearer. In the course of this rewrite I noticed that PuTTY's dynamic port forwarding had never got round to supporting the SOCKS5 IPv6 address format - though there was a FIXME comment saying it ought to. So now it does: if a SOCKS5 client provides a binary IPv6 address (which PuTTY's _own_ SOCKS5 client, in proxy.c, is quite capable of doing!), then that will be translated into the usual IPv6 hex literal representation to put in the "direct-tcpip" channel open request. --- portfwd.c | 500 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 259 insertions(+), 241 deletions(-) diff --git a/portfwd.c b/portfwd.c index 1e4d2d1f..069bc3bf 100644 --- a/portfwd.c +++ b/portfwd.c @@ -2,12 +2,25 @@ * SSH port forwarding. */ +#include #include #include #include "putty.h" #include "ssh.h" +/* + * Enumeration of values that live in the 'socks_state' field of + * struct PortForwarding. + */ +typedef enum { + SOCKS_NONE, /* direct connection (no SOCKS, or SOCKS already done) */ + SOCKS_INITIAL, /* don't know if we're SOCKS 4 or 5 yet */ + SOCKS_4, /* expect a SOCKS 4 (or 4A) connection message */ + SOCKS_5_INITIAL, /* expect a SOCKS 5 preliminary message */ + SOCKS_5_CONNECT /* expect a SOCKS 5 connection message */ +} SocksState; + struct PortForwarding { struct ssh_channel *c; /* channel structure held by ssh.c */ void *backhandle; /* instance of SSH backend itself */ @@ -15,13 +28,7 @@ struct PortForwarding { Socket s; int throttled, throttle_override; int ready; - /* - * `dynamic' does double duty. It's set to 0 for an ordinary - * forwarded port, and nonzero for SOCKS-style dynamic port - * forwarding; but the nonzero values are also a state machine - * tracking where the SOCKS exchange has got to. - */ - int dynamic; + SocksState socks_state; /* * `hostname' and `port' are the real hostname and port, once * we know what we're connecting to. @@ -29,18 +36,12 @@ struct PortForwarding { char *hostname; int port; /* - * `socksbuf' is the buffer we use to accumulate a SOCKS request. + * `socksbuf' is the buffer we use to accumulate the initial SOCKS + * segment of the incoming data, plus anything after that that we + * receive before we're ready to send data to the SSH server. */ - char *socksbuf; - int sockslen, sockssize; - /* - * When doing dynamic port forwarding, we can receive - * connection data before we are actually able to send it; so - * we may have to temporarily hold some in a dynamically - * allocated buffer here. - */ - void *buffer; - int buflen; + strbuf *socksbuf; + size_t socksbuf_consumed; const Plug_vtable *plugvt; }; @@ -48,11 +49,7 @@ struct PortForwarding { struct PortListener { void *backhandle; /* instance of SSH backend itself */ Socket s; - /* - * `dynamic' is set to 0 for an ordinary forwarded port, and - * nonzero for SOCKS-style dynamic port forwarding. - */ - int dynamic; + int is_dynamic; /* * `hostname' and `port' are the real hostname and port, for * ordinary forwardings. @@ -68,8 +65,6 @@ static struct PortForwarding *new_portfwd_state(void) struct PortForwarding *pf = snew(struct PortForwarding); pf->hostname = NULL; pf->socksbuf = NULL; - pf->sockslen = pf->sockssize = 0; - pf->buffer = NULL; return pf; } @@ -78,8 +73,8 @@ static void free_portfwd_state(struct PortForwarding *pf) if (!pf) return; sfree(pf->hostname); - sfree(pf->socksbuf); - sfree(pf->buffer); + if (pf->socksbuf) + strbuf_free(pf->socksbuf); sfree(pf); } @@ -162,207 +157,238 @@ static void wrap_send_port_open(void *channel, const char *hostname, int port, sfree(description); } +static char *ipv4_to_string(unsigned ipv4) +{ + return dupprintf("%u.%u.%u.%u", + (ipv4 >> 24) & 0xFF, (ipv4 >> 16) & 0xFF, + (ipv4 >> 8) & 0xFF, (ipv4 ) & 0xFF); +} + +static char *ipv6_to_string(ptrlen ipv6) +{ + const unsigned char *addr = ipv6.ptr; + assert(ipv6.len == 16); + return dupprintf("%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x", + (unsigned)GET_16BIT_MSB_FIRST(addr + 0), + (unsigned)GET_16BIT_MSB_FIRST(addr + 2), + (unsigned)GET_16BIT_MSB_FIRST(addr + 4), + (unsigned)GET_16BIT_MSB_FIRST(addr + 6), + (unsigned)GET_16BIT_MSB_FIRST(addr + 8), + (unsigned)GET_16BIT_MSB_FIRST(addr + 10), + (unsigned)GET_16BIT_MSB_FIRST(addr + 12), + (unsigned)GET_16BIT_MSB_FIRST(addr + 14)); +} + static void pfd_receive(Plug plug, int urgent, char *data, int len) { struct PortForwarding *pf = FROMFIELD(plug, struct PortForwarding, plugvt); - if (pf->dynamic) { - while (len--) { - if (pf->sockslen >= pf->sockssize) { - pf->sockssize = pf->sockslen * 5 / 4 + 256; - pf->socksbuf = sresize(pf->socksbuf, pf->sockssize, char); - } - pf->socksbuf[pf->sockslen++] = *data++; - - /* - * Now check what's in the buffer to see if it's a - * valid and complete message in the SOCKS exchange. - */ - if ((pf->dynamic == 1 || (pf->dynamic >> 12) == 4) && - pf->socksbuf[0] == 4) { - /* - * SOCKS 4. - */ - if (pf->dynamic == 1) - pf->dynamic = 0x4000; - if (pf->sockslen < 2) - continue; /* don't have command code yet */ - if (pf->socksbuf[1] != 1) { - /* Not CONNECT. */ - /* Send back a SOCKS 4 error before closing. */ - char data[8]; - memset(data, 0, sizeof(data)); - data[1] = 91; /* generic `request rejected' */ - sk_write(pf->s, data, 8); - pfd_close(pf); - return; - } - if (pf->sockslen <= 8) - continue; /* haven't started user/hostname */ - if (pf->socksbuf[pf->sockslen-1] != 0) - continue; /* haven't _finished_ user/hostname */ - /* - * Now we have a full SOCKS 4 request. Check it to - * see if it's a SOCKS 4A request. - */ - if (pf->socksbuf[4] == 0 && pf->socksbuf[5] == 0 && - pf->socksbuf[6] == 0 && pf->socksbuf[7] != 0) { - /* - * It's SOCKS 4A. So if we haven't yet - * collected the host name, we should continue - * waiting for data in order to do so; if we - * have, we can go ahead. - */ - int len; - if (pf->dynamic == 0x4000) { - pf->dynamic = 0x4001; - pf->sockslen = 8; /* reset buffer to overwrite name */ - continue; - } - pf->socksbuf[0] = 0; /* reply version code */ - pf->socksbuf[1] = 90; /* request granted */ - sk_write(pf->s, pf->socksbuf, 8); - len = pf->sockslen - 8; - pf->port = GET_16BIT_MSB_FIRST(pf->socksbuf+2); - pf->hostname = snewn(len+1, char); - pf->hostname[len] = '\0'; - memcpy(pf->hostname, pf->socksbuf + 8, len); - goto connect; - } else { - /* - * It's SOCKS 4, which means we should format - * the IP address into the hostname string and - * then just go. - */ - pf->socksbuf[0] = 0; /* reply version code */ - pf->socksbuf[1] = 90; /* request granted */ - sk_write(pf->s, pf->socksbuf, 8); - pf->port = GET_16BIT_MSB_FIRST(pf->socksbuf+2); - pf->hostname = dupprintf("%d.%d.%d.%d", - (unsigned char)pf->socksbuf[4], - (unsigned char)pf->socksbuf[5], - (unsigned char)pf->socksbuf[6], - (unsigned char)pf->socksbuf[7]); - goto connect; - } - } - - if ((pf->dynamic == 1 || (pf->dynamic >> 12) == 5) && - pf->socksbuf[0] == 5) { - /* - * SOCKS 5. - */ - if (pf->dynamic == 1) - pf->dynamic = 0x5000; - - if (pf->dynamic == 0x5000) { - int i, method; - char data[2]; - /* - * We're receiving a set of method identifiers. - */ - if (pf->sockslen < 2) - continue; /* no method count yet */ - if (pf->sockslen < 2 + (unsigned char)pf->socksbuf[1]) - continue; /* no methods yet */ - method = 0xFF; /* invalid */ - for (i = 0; i < (unsigned char)pf->socksbuf[1]; i++) - if (pf->socksbuf[2+i] == 0) { - method = 0;/* no auth */ - break; - } - data[0] = 5; - data[1] = method; - sk_write(pf->s, data, 2); - pf->dynamic = 0x5001; - pf->sockslen = 0; /* re-empty the buffer */ - continue; - } - - if (pf->dynamic == 0x5001) { - /* - * We're receiving a SOCKS request. - */ - unsigned char reply[10]; /* SOCKS5 atyp=1 reply */ - int atype, alen = 0; - - /* - * Pre-fill reply packet. - * In all cases, we set BND.{HOST,ADDR} to 0.0.0.0:0 - * (atyp=1) in the reply; if we succeed, we don't know - * the right answers, and if we fail, they should be - * ignored. - */ - memset(reply, 0, lenof(reply)); - reply[0] = 5; /* VER */ - reply[3] = 1; /* ATYP = 1 (IPv4, 0.0.0.0:0) */ - - if (pf->sockslen < 6) continue; - atype = (unsigned char)pf->socksbuf[3]; - if (atype == 1) /* IPv4 address */ - alen = 4; - if (atype == 4) /* IPv6 address */ - alen = 16; - if (atype == 3) /* domain name has leading length */ - alen = 1 + (unsigned char)pf->socksbuf[4]; - if (pf->sockslen < 6 + alen) continue; - if (pf->socksbuf[1] != 1 || pf->socksbuf[2] != 0) { - /* Not CONNECT or reserved field nonzero - error */ - reply[1] = 1; /* generic failure */ - sk_write(pf->s, reply, lenof(reply)); - pfd_close(pf); - return; - } - /* - * Now we have a viable connect request. Switch - * on atype. - */ - pf->port = GET_16BIT_MSB_FIRST(pf->socksbuf+4+alen); - if (atype == 1) { - /* REP=0 (success) already */ - sk_write(pf->s, reply, lenof(reply)); - pf->hostname = dupprintf("%d.%d.%d.%d", - (unsigned char)pf->socksbuf[4], - (unsigned char)pf->socksbuf[5], - (unsigned char)pf->socksbuf[6], - (unsigned char)pf->socksbuf[7]); - goto connect; - } else if (atype == 3) { - /* REP=0 (success) already */ - sk_write(pf->s, reply, lenof(reply)); - pf->hostname = snewn(alen, char); - pf->hostname[alen-1] = '\0'; - memcpy(pf->hostname, pf->socksbuf + 5, alen-1); - goto connect; - } else { - /* - * Unknown address type. (FIXME: support IPv6!) - */ - reply[1] = 8; /* atype not supported */ - sk_write(pf->s, reply, lenof(reply)); - pfd_close(pf); - return; - } - } - } - - /* - * If we get here without either having done `continue' - * or `goto connect', it must be because there is no - * sensible interpretation of what's in our buffer. So - * close the connection rudely. - */ - pfd_close(pf); - break; - } - return; + + if (len == 0) + return; + + if (pf->socks_state != SOCKS_NONE) { + BinarySource src[1]; + + /* + * Store all the data we've got in socksbuf. + */ + put_data(pf->socksbuf, data, len); + + /* + * Check the start of socksbuf to see if it's a valid and + * complete message in the SOCKS exchange. + */ + + if (pf->socks_state == SOCKS_INITIAL) { + /* Preliminary: check the first byte of the data (which we + * _must_ have by now) to find out which SOCKS major + * version we're speaking. */ + switch (pf->socksbuf->u[0]) { + case 4: + pf->socks_state = SOCKS_4; + break; + case 5: + pf->socks_state = SOCKS_5_INITIAL; + break; + default: + pfd_close(pf); /* unrecognised version */ + return; + } + } + + BinarySource_BARE_INIT(src, pf->socksbuf->u, pf->socksbuf->len); + get_data(src, pf->socksbuf_consumed); + + while (pf->socks_state != SOCKS_NONE) { + unsigned socks_version, message_type, reserved_byte; + unsigned reply_code, port, ipv4, method; + ptrlen methods; + const char *socks4_hostname; + strbuf *output; + + switch (pf->socks_state) { + case SOCKS_INITIAL: + case SOCKS_NONE: + assert(0 && "These case values cannot appear"); + + case SOCKS_4: + /* SOCKS 4/4A connect message */ + socks_version = get_byte(src); + message_type = get_byte(src); + + if (get_err(src) == BSE_OUT_OF_DATA) + return; + if (socks_version == 4 && message_type == 1) { + /* CONNECT message */ + int name_based = FALSE; + + port = get_uint16(src); + ipv4 = get_uint32(src); + if (ipv4 > 0x00000000 && ipv4 < 0x00000100) { + /* + * Addresses in this range indicate the SOCKS 4A + * extension to specify a hostname, which comes + * after the username. + */ + name_based = TRUE; + } + get_asciz(src); /* skip username */ + socks4_hostname = name_based ? get_asciz(src) : NULL; + + if (get_err(src) == BSE_OUT_OF_DATA) + return; + if (get_err(src)) + goto socks4_reject; + + pf->port = port; + if (name_based) { + pf->hostname = dupstr(socks4_hostname); + } else { + pf->hostname = ipv4_to_string(ipv4); + } + + output = strbuf_new(); + put_byte(output, 0); /* reply version */ + put_byte(output, 90); /* SOCKS 4 'request granted' */ + put_uint16(output, 0); /* null port field */ + put_uint32(output, 0); /* null address field */ + sk_write(pf->s, output->u, output->len); + strbuf_free(output); + + pf->socks_state = SOCKS_NONE; + pf->socksbuf_consumed = src->pos; + break; + } + + socks4_reject: + output = strbuf_new(); + put_byte(output, 0); /* reply version */ + put_byte(output, 91); /* SOCKS 4 'request rejected' */ + put_uint16(output, 0); /* null port field */ + put_uint32(output, 0); /* null address field */ + sk_write(pf->s, output->u, output->len); + strbuf_free(output); + pfd_close(pf); + return; + + case SOCKS_5_INITIAL: + /* SOCKS 5 initial method list */ + socks_version = get_byte(src); + methods = get_pstring(src); + + method = 0xFF; /* means 'no usable method found' */ + { + int i; + for (i = 0; i < methods.len; i++) { + if (((const unsigned char *)methods.ptr)[i] == 0 ) { + method = 0; /* no auth */ + break; + } + } + } + + if (get_err(src) == BSE_OUT_OF_DATA) + return; + if (get_err(src)) + method = 0xFF; + + output = strbuf_new(); + put_byte(output, 5); /* SOCKS version */ + put_byte(output, method); /* selected auth method */ + sk_write(pf->s, output->u, output->len); + strbuf_free(output); + + if (method == 0xFF) { + pfd_close(pf); + return; + } + + pf->socks_state = SOCKS_5_CONNECT; + pf->socksbuf_consumed = src->pos; + break; + + case SOCKS_5_CONNECT: + /* SOCKS 5 connect message */ + socks_version = get_byte(src); + message_type = get_byte(src); + reserved_byte = get_byte(src); + + if (socks_version == 5 && message_type == 1 && + reserved_byte == 0) { + + reply_code = 0; /* success */ + + switch (get_byte(src)) { + case 1: /* IPv4 */ + pf->hostname = ipv4_to_string(get_uint32(src)); + break; + case 4: /* IPv6 */ + pf->hostname = ipv6_to_string(get_data(src, 16)); + break; + case 3: /* unresolved domain name */ + pf->hostname = mkstr(get_pstring(src)); + break; + default: + pf->hostname = NULL; + reply_code = 8; /* address type not supported */ + break; + } + + pf->port = get_uint16(src); + } else { + reply_code = 7; /* command not supported */ + } + + if (get_err(src) == BSE_OUT_OF_DATA) + return; + if (get_err(src)) + reply_code = 1; /* general server failure */ + + output = strbuf_new(); + put_byte(output, 5); /* SOCKS version */ + put_byte(output, reply_code); + put_byte(output, 0); /* reserved */ + put_byte(output, 1); /* IPv4 address follows */ + put_uint32(output, 0); /* bound IPv4 address (unused) */ + put_uint16(output, 0); /* bound port number (unused) */ + sk_write(pf->s, output->u, output->len); + strbuf_free(output); + + if (reply_code != 0) { + pfd_close(pf); + return; + } + + pf->socks_state = SOCKS_NONE; + pf->socksbuf_consumed = src->pos; + break; + } + } /* * We come here when we're ready to make an actual * connection. */ - connect: - sfree(pf->socksbuf); - pf->socksbuf = NULL; /* * Freeze the socket until the SSH server confirms the @@ -378,17 +404,6 @@ static void pfd_receive(Plug plug, int urgent, char *data, int len) /* asks to forward to the specified host/port for this */ wrap_send_port_open(pf->c, pf->hostname, pf->port, pf->s); } - pf->dynamic = 0; - - /* - * If there's any data remaining in our current buffer, - * save it to be sent on pfd_confirm(). - */ - if (len > 0) { - pf->buffer = snewn(len, char); - memcpy(pf->buffer, data, len); - pf->buflen = len; - } } if (pf->ready) { if (sshfwd_write(pf->c, data, len) > 0) { @@ -450,7 +465,7 @@ char *pfd_connect(struct PortForwarding **pf_ret, char *hostname,int port, pf->ready = 1; pf->c = c; pf->backhandle = NULL; /* we shouldn't need this */ - pf->dynamic = 0; + pf->socks_state = SOCKS_NONE; pf->s = new_connection(addr, dummy_realhost, port, 0, 1, 0, 0, &pf->plugvt, conf); @@ -493,12 +508,14 @@ static int pfl_accepting(Plug p, accept_fn_t constructor, accept_ctx_t ctx) pf->throttled = pf->throttle_override = 0; pf->ready = 0; - if (pl->dynamic) { - pf->dynamic = 1; + if (pl->is_dynamic) { + pf->socks_state = SOCKS_INITIAL; + pf->socksbuf = strbuf_new(); + pf->socksbuf_consumed = 0; pf->port = 0; /* "hostname" buffer is so far empty */ sk_set_frozen(s, 0); /* we want to receive SOCKS _now_! */ } else { - pf->dynamic = 0; + pf->socks_state = SOCKS_NONE; pf->hostname = dupstr(pl->hostname); pf->port = pl->port; pf->c = new_sock_channel(pl->backhandle, pf); @@ -544,9 +561,9 @@ char *pfl_listen(char *desthost, int destport, char *srcaddr, if (desthost) { pl->hostname = dupstr(desthost); pl->port = destport; - pl->dynamic = 0; + pl->is_dynamic = FALSE; } else - pl->dynamic = 1; + pl->is_dynamic = TRUE; pl->backhandle = backhandle; pl->s = new_listener(srcaddr, port, &pl->plugvt, @@ -625,9 +642,10 @@ void pfd_confirm(struct PortForwarding *pf) pf->ready = 1; sk_set_frozen(pf->s, 0); sk_write(pf->s, NULL, 0); - if (pf->buffer) { - sshfwd_write(pf->c, pf->buffer, pf->buflen); - sfree(pf->buffer); - pf->buffer = NULL; + if (pf->socksbuf) { + sshfwd_write(pf->c, pf->socksbuf->u + pf->socksbuf_consumed, + pf->socksbuf->len - pf->socksbuf_consumed); + strbuf_free(pf->socksbuf); + pf->socksbuf = NULL; } } From 6dc63925965f34e0e898c2c5e465476c536a215f Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Tue, 29 May 2018 20:36:21 +0100 Subject: [PATCH 337/607] Remove obsolete functions. There are several old functions that the previous commits have removed all, or nearly all, of the references to. match_ssh_id is superseded by ptrlen_eq_string; get_ssh_{string,uint32} is yet another replicated set of decode functions (this time _partly_ centralised into misc.c); the old APIs for the SSH-1 RSA decode functions are gone (together with their last couple of holdout clients), as are ssh{1,2}_{read,write}_bignum and ssh{1,2}_bignum_length. Particularly odd was the use of ssh1_{read,write}_bignum in the SSH-2 Diffie-Hellman implementation. I'd completely forgotten I did that! Now replaced with a raw bignum_from_bytes, which is simpler anyway. --- cmdgen.c | 23 +++--------------- misc.c | 33 -------------------------- misc.h | 17 -------------- ssh.h | 8 ------- sshbn.c | 65 +-------------------------------------------------- sshdh.c | 9 ++++--- sshrsa.c | 32 ------------------------- unix/uxpgnt.c | 5 +++- 8 files changed, 12 insertions(+), 180 deletions(-) diff --git a/cmdgen.c b/cmdgen.c index b4fcd567..e2d1e75f 100644 --- a/cmdgen.c +++ b/cmdgen.c @@ -807,30 +807,13 @@ int main(int argc, char **argv) ssh1key = snew(struct RSAKey); if (!load_encrypted) { strbuf *blob; - int n, l; + BinarySource src[1]; blob = strbuf_new(); ret = rsa_ssh1_loadpub(infilename, BinarySink_UPCAST(blob), &origcomment, &error); - - n = 4; /* skip modulus bits */ - - l = ssh1_read_bignum(blob->u + n, - blob->len - n, - &ssh1key->exponent); - if (l < 0) { - error = "SSH-1 public key blob was too short"; - } else { - n += l; - l = ssh1_read_bignum( - blob->u + n, - blob->len - n, &ssh1key->modulus); - if (l < 0) { - error = "SSH-1 public key blob was too short"; - } else - n += l; - } - + BinarySource_BARE_INIT(src, blob->u, blob->len); + get_rsa_ssh1_pub(src, ssh1key, NULL, RSA_SSH1_EXPONENT_FIRST); strbuf_free(blob); ssh1key->comment = dupstr(origcomment); diff --git a/misc.c b/misc.c index 30bfec90..36f27171 100644 --- a/misc.c +++ b/misc.c @@ -1181,12 +1181,6 @@ int smemeq(const void *av, const void *bv, size_t len) return (0x100 - val) >> 8; } -int match_ssh_id(int stringlen, const void *string, const char *id) -{ - int idlen = strlen(id); - return (idlen == stringlen && !memcmp(string, id, idlen)); -} - ptrlen make_ptrlen(const void *ptr, size_t len) { ptrlen pl; @@ -1209,33 +1203,6 @@ char *mkstr(ptrlen pl) return p; } -void *get_ssh_string(int *datalen, const void **data, int *stringlen) -{ - void *ret; - unsigned int len; - - if (*datalen < 4) - return NULL; - len = GET_32BIT_MSB_FIRST((const unsigned char *)*data); - if (*datalen - 4 < len) - return NULL; - ret = (void *)((const char *)*data + 4); - *datalen -= len + 4; - *data = (const char *)*data + len + 4; - *stringlen = len; - return ret; -} - -int get_ssh_uint32(int *datalen, const void **data, unsigned *ret) -{ - if (*datalen < 4) - return FALSE; - *ret = GET_32BIT_MSB_FIRST((const unsigned char *)*data); - *datalen -= 4; - *data = (const char *)*data + 4; - return TRUE; -} - int strstartswith(const char *s, const char *t) { return !memcmp(s, t, strlen(t)); diff --git a/misc.h b/misc.h index de662a87..4b830d99 100644 --- a/misc.h +++ b/misc.h @@ -109,23 +109,6 @@ void smemclr(void *b, size_t len); * by the 'eq' in the name. */ int smemeq(const void *av, const void *bv, size_t len); -/* Extracts an SSH-marshalled string from the start of *data. If - * successful (*datalen is not too small), advances data/datalen past - * the string and returns a pointer to the string itself and its - * length in *stringlen. Otherwise does nothing and returns NULL. - * - * Like strchr, this function can discard const from its parameter. - * Treat it as if it was a family of two functions, one returning a - * non-const string given a non-const pointer, and one taking and - * returning const. */ -void *get_ssh_string(int *datalen, const void **data, int *stringlen); -/* Extracts an SSH uint32, similarly. Returns TRUE on success, and - * leaves the extracted value in *ret. */ -int get_ssh_uint32(int *datalen, const void **data, unsigned *ret); -/* Given a not-necessarily-zero-terminated string in (length,data) - * form, check if it equals an ordinary C zero-terminated string. */ -int match_ssh_id(int stringlen, const void *string, const char *id); - char *buildinfo(const char *newline); /* diff --git a/ssh.h b/ssh.h index 655d72d2..228c7072 100644 --- a/ssh.h +++ b/ssh.h @@ -180,13 +180,9 @@ struct ec_point *ec_public(const Bignum privateKey, const struct ec_curve *curve */ typedef enum { RSA_SSH1_EXPONENT_FIRST, RSA_SSH1_MODULUS_FIRST } RsaSsh1Order; -int rsa_ssh1_readpub(const unsigned char *data, int len, struct RSAKey *result, - const unsigned char **keystr, RsaSsh1Order order); void BinarySource_get_rsa_ssh1_pub( BinarySource *src, struct RSAKey *result, ptrlen *keystr, RsaSsh1Order order); -int rsa_ssh1_readpriv(const unsigned char *data, int len, - struct RSAKey *result); void BinarySource_get_rsa_ssh1_priv( BinarySource *src, struct RSAKey *rsa); int rsa_ssh1_encrypt(unsigned char *data, int length, struct RSAKey *key); @@ -667,14 +663,10 @@ extern Bignum Zero, One; Bignum bignum_from_bytes(const void *data, int nbytes); Bignum bignum_from_bytes_le(const void *data, int nbytes); Bignum bignum_random_in_range(const Bignum lower, const Bignum upper); -int ssh1_read_bignum(const unsigned char *data, int len, Bignum * result); int bignum_bitcount(Bignum bn); -int ssh1_bignum_length(Bignum bn); -int ssh2_bignum_length(Bignum bn); int bignum_byte(Bignum bn, int i); int bignum_bit(Bignum bn, int i); void bignum_set_bit(Bignum bn, int i, int value); -int ssh1_write_bignum(void *data, Bignum bn); Bignum biggcd(Bignum a, Bignum b); unsigned short bignum_mod_short(Bignum number, unsigned short modulus); Bignum bignum_add_long(Bignum number, unsigned long addend); diff --git a/sshbn.c b/sshbn.c index 1f0213c0..9c36f531 100644 --- a/sshbn.c +++ b/sshbn.c @@ -1509,36 +1509,7 @@ Bignum bignum_random_in_range(const Bignum lower, const Bignum upper) } /* - * Read an SSH-1-format bignum from a data buffer. Return the number - * of bytes consumed, or -1 if there wasn't enough data. - */ -int ssh1_read_bignum(const unsigned char *data, int len, Bignum * result) -{ - const unsigned char *p = data; - int i; - int w, b; - - if (len < 2) - return -1; - - w = 0; - for (i = 0; i < 2; i++) - w = (w << 8) + *p++; - b = (w + 7) / 8; /* bits -> bytes */ - - if (len < b+2) - return -1; - - if (!result) /* just return length */ - return b + 2; - - *result = bignum_from_bytes(p, b); - - return p + b - data; -} - -/* - * Return the bit count of a bignum, for SSH-1 encoding. + * Return the bit count of a bignum. */ int bignum_bitcount(Bignum bn) { @@ -1548,22 +1519,6 @@ int bignum_bitcount(Bignum bn) return bitcount + 1; } -/* - * Return the byte length of a bignum when SSH-1 encoded. - */ -int ssh1_bignum_length(Bignum bn) -{ - return 2 + (bignum_bitcount(bn) + 7) / 8; -} - -/* - * Return the byte length of a bignum when SSH-2 encoded. - */ -int ssh2_bignum_length(Bignum bn) -{ - return 4 + (bignum_bitcount(bn) + 8) / 8; -} - /* * Return a byte from a bignum; 0 is least significant, etc. */ @@ -1604,24 +1559,6 @@ void bignum_set_bit(Bignum bn, int bitnum, int value) } } -/* - * Write a SSH-1-format bignum into a buffer. It is assumed the - * buffer is big enough. Returns the number of bytes used. - */ -int ssh1_write_bignum(void *data, Bignum bn) -{ - unsigned char *p = data; - int len = ssh1_bignum_length(bn); - int i; - int bitc = bignum_bitcount(bn); - - *p++ = (bitc >> 8) & 0xFF; - *p++ = (bitc) & 0xFF; - for (i = len - 2; i--;) - *p++ = bignum_byte(bn, i); - return len; -} - void BinarySink_put_mp_ssh1(BinarySink *bs, Bignum bn) { int bits = bignum_bitcount(bn); diff --git a/sshdh.c b/sshdh.c index 46f3a3fc..1c27b021 100644 --- a/sshdh.c +++ b/sshdh.c @@ -247,7 +247,7 @@ Bignum dh_create_e(void *handle, int nbits) int nbytes; unsigned char *buf; - nbytes = ssh1_bignum_length(ctx->qmask); + nbytes = (bignum_bitcount(ctx->qmask) + 7) / 8; buf = snewn(nbytes, unsigned char); do { @@ -258,10 +258,9 @@ Bignum dh_create_e(void *handle, int nbits) if (ctx->x) freebn(ctx->x); if (nbits == 0 || nbits > bignum_bitcount(ctx->qmask)) { - ssh1_write_bignum(buf, ctx->qmask); - for (i = 2; i < nbytes; i++) - buf[i] &= random_byte(); - ssh1_read_bignum(buf, nbytes, &ctx->x); /* can't fail */ + for (i = 0; i < nbytes; i++) + buf[i] = bignum_byte(ctx->qmask, i) & random_byte(); + ctx->x = bignum_from_bytes(buf, nbytes); } else { int b, nb; ctx->x = bn_power_2(nbits); diff --git a/sshrsa.c b/sshrsa.c index 751d1c3e..51396a5c 100644 --- a/sshrsa.c +++ b/sshrsa.c @@ -47,44 +47,12 @@ void BinarySource_get_rsa_ssh1_pub( } } -int rsa_ssh1_readpub(const unsigned char *data, int len, struct RSAKey *result, - const unsigned char **keystr, RsaSsh1Order order) -{ - BinarySource src; - ptrlen key_pl; - - BinarySource_BARE_INIT(&src, data, len); - get_rsa_ssh1_pub(&src, result, &key_pl, order); - - if (keystr) - *keystr = key_pl.ptr; - - if (get_err(&src)) - return -1; - else - return key_pl.len; -} - void BinarySource_get_rsa_ssh1_priv( BinarySource *src, struct RSAKey *rsa) { rsa->private_exponent = get_mp_ssh1(src); } -int rsa_ssh1_readpriv(const unsigned char *data, int len, - struct RSAKey *result) -{ - BinarySource src; - - BinarySource_BARE_INIT(&src, data, len); - get_rsa_ssh1_priv(&src, result); - - if (get_err(&src)) - return -1; - else - return src.pos; -} - int rsa_ssh1_encrypt(unsigned char *data, int length, struct RSAKey *key) { Bignum b1, b2; diff --git a/unix/uxpgnt.c b/unix/uxpgnt.c index 4ef4d433..e3dfe318 100644 --- a/unix/uxpgnt.c +++ b/unix/uxpgnt.c @@ -701,10 +701,13 @@ void run_client(void) FILE *fp = stdout; /* FIXME: add a -o option? */ if (key->ssh_version == 1) { + BinarySource src[1]; struct RSAKey rkey; + + BinarySource_BARE_INIT(src, key->blob->u, key->blob->len); memset(&rkey, 0, sizeof(rkey)); rkey.comment = dupstr(key->comment); - rsa_ssh1_readpub(key->blob->u, key->blob->len, &rkey, NULL, + get_rsa_ssh1_pub(src, &rkey, NULL, RSA_SSH1_EXPONENT_FIRST); ssh1_write_pubkey(fp, &rkey); freersakey(&rkey); From 6cbca87a62683a0342b3bf9265dc833cf7f3e918 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 3 Jun 2018 06:46:28 +0100 Subject: [PATCH 338/607] Try harder not to call connection_fatal twice. If the server sends an SSH_MSG_DISCONNECT, then we call connection_fatal(). But if the server closes the network connection, then we call connection_fatal(). In situations where the former happens, the latter happens too. Currently, calling connection_fatal twice is especially bad on GTK because all dialogs are now non-modal and an assertion fails in the GTK front end when two fatal message boxes try to exist at the same time (the register_dialog system finds that slot is already occupied). But regardless of that, we'd rather not even _try_ to print two fatal boxes, because even if the front end doesn't fail an assertion, there's no guarantee that the _more useful_ one of the messages will end up being displayed. So a better fix is to have ssh.c make a sensible decision about which message is the helpful one - in this case, the actual error message out of the SSH_MSG_DISCONNECT, rather than the predictable fact of the connection having been slammed shut immediately afterwards - and only pass that one to the front end in the first place. --- ssh.c | 47 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/ssh.c b/ssh.c index 012d7062..547ffb5b 100644 --- a/ssh.c +++ b/ssh.c @@ -930,6 +930,7 @@ struct ssh_tag { int exitcode; int close_expected; int clean_exit; + int disconnect_message_seen; tree234 *rportfwds, *portfwds; @@ -1593,6 +1594,20 @@ static void ssh1_rdpkt(Ssh ssh) BinarySource_INIT(st->pktin, st->pktin->body, st->pktin->length); + /* + * Mild layer violation: if the message is a DISCONNECT, we + * should unset the close_expected flag, because now we _do_ + * expect the server to close the network connection + * afterwards. That way, the more informative connection_fatal + * message for the disconnect itself won't fight with 'Server + * unexpectedly closed network connection'. + */ + if (st->pktin->type == SSH1_MSG_DISCONNECT) { + ssh->clean_exit = FALSE; + ssh->close_expected = TRUE; + ssh->disconnect_message_seen = TRUE; + } + pq_push(&ssh->pq_full, st->pktin); queue_idempotent_callback(&ssh->pq_full_consumer); } @@ -2015,6 +2030,20 @@ static void ssh2_rdpkt(Ssh ssh) BinarySource_INIT(st->pktin, st->pktin->body, st->pktin->length); + /* + * Mild layer violation: if the message is a DISCONNECT, we + * should unset the close_expected flag, because now we _do_ + * expect the server to close the network connection + * afterwards. That way, the more informative connection_fatal + * message for the disconnect itself won't fight with 'Server + * unexpectedly closed network connection'. + */ + if (st->pktin->type == SSH2_MSG_DISCONNECT) { + ssh->clean_exit = FALSE; + ssh->close_expected = TRUE; + ssh->disconnect_message_seen = TRUE; + } + pq_push(&ssh->pq_full, st->pktin); queue_idempotent_callback(&ssh->pq_full_consumer); if (st->pktin->type == SSH2_MSG_NEWKEYS) { @@ -2079,6 +2108,20 @@ static void ssh2_bare_connection_rdpkt(Ssh ssh) BinarySource_INIT(st->pktin, st->pktin->body, st->pktin->length); + /* + * Mild layer violation: if the message is a DISCONNECT, we + * should unset the close_expected flag, because now we _do_ + * expect the server to close the network connection + * afterwards. That way, the more informative connection_fatal + * message for the disconnect itself won't fight with 'Server + * unexpectedly closed network connection'. + */ + if (st->pktin->type == SSH2_MSG_DISCONNECT) { + ssh->clean_exit = FALSE; + ssh->close_expected = TRUE; + ssh->disconnect_message_seen = TRUE; + } + pq_push(&ssh->pq_full, st->pktin); queue_idempotent_callback(&ssh->pq_full_consumer); } @@ -3379,7 +3422,8 @@ static void ssh_process_incoming_data(void *ctx) if (error_msg) logevent(error_msg); - if (!ssh->close_expected || !ssh->clean_exit) + if ((!ssh->close_expected || !ssh->clean_exit) && + !ssh->disconnect_message_seen) connection_fatal(ssh->frontend, "%s", error_msg); } } @@ -11959,6 +12003,7 @@ static const char *ssh_init(void *frontend_handle, void **backend_handle, ssh->exitcode = -1; ssh->close_expected = FALSE; ssh->clean_exit = FALSE; + ssh->disconnect_message_seen = FALSE; ssh->state = SSH_STATE_PREPACKET; ssh->size_needed = FALSE; ssh->eof_needed = FALSE; From 7079cf06c8b814fb28d002247bcb22c478bc11a0 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 3 Jun 2018 07:08:47 +0100 Subject: [PATCH 339/607] Outgoing packet logging: log the right amount of data. I must have introduced this bug yesterday when I rewrote the packet censoring functions using BinarySource. The base pointer passed to log_packet was pointing at the right place, but the accompanying length was the gross rather than net one, as it were - it counted the extra header data we're about to insert at the _start_ of the packet, so log_packet() was trying to print that many extra bytes at the _end_ and overrunning its buffer. --- ssh.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ssh.c b/ssh.c index 547ffb5b..77d3f582 100644 --- a/ssh.c +++ b/ssh.c @@ -1492,8 +1492,7 @@ static void ssh1_log_outgoing_packet(Ssh ssh, const struct Packet *pkt) log_packet(ssh->logctx, PKT_OUTGOING, pkt->data[12], ssh1_pkt_type(pkt->data[12]), - pkt->body, pkt->length, - nblanks, blanks, NULL, 0, NULL); + src->data, src->len, nblanks, blanks, NULL, 0, NULL); } /* @@ -1742,7 +1741,7 @@ static void ssh2_log_outgoing_packet(Ssh ssh, const struct Packet *pkt) log_packet(ssh->logctx, PKT_OUTGOING, pkt->data[5], ssh2_pkt_type(ssh->pkt_kctx, ssh->pkt_actx, pkt->data[5]), - pkt->body, pkt->length, nblanks, blanks, + src->data, src->len, nblanks, blanks, &ssh->v2_outgoing_sequence, pkt->downstream_id, pkt->additional_log_text); } From 2b54c86e7e043ebae6f056943bdffd039bfd0ba7 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 3 Jun 2018 07:11:10 +0100 Subject: [PATCH 340/607] Stop calling ssh2_set_window in SSH-1! This must have been a bug introduced during the SSH-2 connection sharing rework. Apparently nobody's ever re-tested SSH-1 X forwarding since then - until I did so yesterday in the course of testing my enormous refactor of the packet unmarshalling code. --- ssh.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ssh.c b/ssh.c index 77d3f582..24c17630 100644 --- a/ssh.c +++ b/ssh.c @@ -9456,7 +9456,9 @@ void sshfwd_x11_is_local(struct ssh_channel *c) * exchange mode. */ c->u.x11.initial = FALSE; - ssh2_set_window(c, ssh_is_simple(c->ssh) ? OUR_V2_BIGWIN : OUR_V2_WINSIZE); + if (c->ssh->version == 2) + ssh2_set_window( + c, ssh_is_simple(c->ssh) ? OUR_V2_BIGWIN : OUR_V2_WINSIZE); } /* From 314c8f5270a8a880faaf30bb11ad3130350e6f55 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 3 Jun 2018 07:37:45 +0100 Subject: [PATCH 341/607] Connection sharing: handle reply to cancel-tcpip-forward. This is another bug that must have been around since connection sharing was introduced, and nobody noticed until I did some unusually thorough testing yesterday. When a sharing downstream asks to set up a remote port forwarding, we pass through the "tcpip-forward" global request, and we also intercept the reply so that we know that the forwarding has been set up (and hence that we should be passing "forwarded-tcpip" channel opens for that port to this downstream). To do that, we set the want-reply flag in the version of the packet we pass to the server, even if it was clear in downstream's version; and we also put an item on a queue local to sshshare.c which reminds us what to do about the reply when it comes back. But when the downstream _cancels_ one of those forwardings, I wrote the code for all parts of that process except adding that queue item. I even wrote the code to _consume_ the queue item, but somehow I completely forgot to generate one in the first place! So the enum value GLOBREQ_CANCEL_TCPIP_FORWARD was declared, tested for, but never actually assigned to anything. --- sshshare.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/sshshare.c b/sshshare.c index 5f0c01a1..75b6940c 100644 --- a/sshshare.c +++ b/sshshare.c @@ -1146,6 +1146,7 @@ void share_got_pkt_from_server(void *csv, int type, case SSH2_MSG_REQUEST_SUCCESS: case SSH2_MSG_REQUEST_FAILURE: globreq = cs->globreq_head; + assert(globreq); /* should match the queue in ssh.c */ if (globreq->type == GLOBREQ_TCPIP_FORWARD) { if (type == SSH2_MSG_REQUEST_FAILURE) { share_remove_forwarding(cs, globreq->fwd); @@ -1402,6 +1403,20 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs, (cs->parent->ssh, cs->id, type, pkt, pktlen, orig_wantreply ? NULL : "upstream added want_reply flag"); ssh_sharing_queue_global_request(cs->parent->ssh, cs); + + /* + * And queue a globreq so that when the reply comes + * back we know to cancel it. + */ + globreq = snew(struct share_globreq); + globreq->next = NULL; + if (cs->globreq_tail) + cs->globreq_tail->next = globreq; + else + cs->globreq_head = globreq; + globreq->fwd = fwd; + globreq->want_reply = orig_wantreply; + globreq->type = GLOBREQ_CANCEL_TCPIP_FORWARD; } sfree(host); From 3f1f7c3ce765f3f60d23f7290910f8bfc5b05b0a Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 3 Jun 2018 07:54:00 +0100 Subject: [PATCH 342/607] Remove downstream remote port forwardings in ssh.c too. Another piece of half-finished machinery that I can't have tested properly when I set up connection sharing: I had the function ssh_alloc_sharing_rportfwd which is how sshshare.c asks ssh.c to start sending it channel-open requests for a given remote forwarded port, but I had no companion function that removes one of those requests again when a downstream remote port forwarding goes away (either by mid-session cancel-tcpip-forward or by the whole downstream disconnecting). As a result, the _second_ attempt to set up the same remote port forwarding, after a sharing downstream had done so once and then stopped, would quietly fail. --- ssh.c | 15 +++++++++++++++ ssh.h | 2 ++ sshshare.c | 8 ++++++++ 3 files changed, 25 insertions(+) diff --git a/ssh.c b/ssh.c index 24c17630..e575fc99 100644 --- a/ssh.c +++ b/ssh.c @@ -5236,6 +5236,21 @@ int ssh_alloc_sharing_rportfwd(Ssh ssh, const char *shost, int sport, return TRUE; } +void ssh_remove_sharing_rportfwd(Ssh ssh, const char *shost, int sport, + void *share_ctx) +{ + struct ssh_rportfwd pf, *realpf; + + assert(ssh->rportfwds); + pf.shost = dupstr(shost); + pf.sport = sport; + realpf = del234(ssh->rportfwds, &pf); + assert(realpf); + assert(realpf->share_ctx == share_ctx); + sfree(realpf->shost); + sfree(realpf); +} + static void ssh_sharing_global_request_response(Ssh ssh, struct Packet *pktin, void *ctx) { diff --git a/ssh.h b/ssh.h index 228c7072..2905037a 100644 --- a/ssh.h +++ b/ssh.h @@ -38,6 +38,8 @@ unsigned ssh_alloc_sharing_channel(Ssh ssh, void *sharing_ctx); void ssh_delete_sharing_channel(Ssh ssh, unsigned localid); int ssh_alloc_sharing_rportfwd(Ssh ssh, const char *shost, int sport, void *share_ctx); +void ssh_remove_sharing_rportfwd(Ssh ssh, const char *shost, int sport, + void *share_ctx); void ssh_sharing_queue_global_request(Ssh ssh, void *share_ctx); struct X11FakeAuth *ssh_sharing_add_x11_display(Ssh ssh, int authtype, void *share_cs, diff --git a/sshshare.c b/sshshare.c index 75b6940c..895c99c8 100644 --- a/sshshare.c +++ b/sshshare.c @@ -857,6 +857,8 @@ static void share_try_cleanup(struct ssh_sharing_connstate *cs) "cleanup after downstream went away"); strbuf_free(packet); + ssh_remove_sharing_rportfwd(cs->parent->ssh, + fwd->host, fwd->port, cs); share_remove_forwarding(cs, fwd); i--; /* don't accidentally skip one as a result */ } @@ -1392,6 +1394,12 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs, "", 0, NULL); } } else { + /* + * Tell ssh.c to stop sending us channel-opens for + * this forwarding. + */ + ssh_remove_sharing_rportfwd(cs->parent->ssh, host, port, cs); + /* * Pass the cancel request on to the SSH server, but * set want_reply even if it wasn't originally set, so From ae3863679d83910fd69fbdd1627d92a61ff112c5 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 3 Jun 2018 08:08:53 +0100 Subject: [PATCH 343/607] Give rsa_fingerprint() a new name and API. It's an SSH-1 specific function, so it should have a name reflecting that, and it didn't. Also it had one of those outdated APIs involving passing it a client-allocated buffer and size. Now it has a sensible name, and internally it constructs the output string using a strbuf and returns it dynamically allocated. --- cmdgen.c | 3 +-- pageant.c | 22 ++++++++++++---------- ssh.c | 14 ++++++-------- ssh.h | 2 +- sshrsa.c | 23 +++++++++-------------- windows/winpgen.c | 25 ++++++++++--------------- windows/winpgnt.c | 11 +++++++---- 7 files changed, 46 insertions(+), 54 deletions(-) diff --git a/cmdgen.c b/cmdgen.c index e2d1e75f..f4771e1f 100644 --- a/cmdgen.c +++ b/cmdgen.c @@ -1017,8 +1017,7 @@ int main(int argc, char **argv) if (sshver == 1) { assert(ssh1key); - fingerprint = snewn(128, char); - rsa_fingerprint(fingerprint, 128, ssh1key); + fingerprint = rsa_ssh1_fingerprint(ssh1key); } else { if (ssh2key) { fingerprint = ssh2_fingerprint(ssh2key->alg, diff --git a/pageant.c b/pageant.c index 71256ff3..41a0c4ff 100644 --- a/pageant.c +++ b/pageant.c @@ -213,9 +213,9 @@ void pageant_handle_msg(BinarySink *bs, int i; struct RSAKey *rkey; for (i = 0; NULL != (rkey = pageant_nth_ssh1_key(i)); i++) { - char fingerprint[128]; - rsa_fingerprint(fingerprint, sizeof(fingerprint), rkey); + char *fingerprint = rsa_ssh1_fingerprint(rkey); plog(logctx, logfn, "returned key: %s", fingerprint); + sfree(fingerprint); } } } @@ -282,10 +282,11 @@ void pageant_handle_msg(BinarySink *bs, } if (logfn) { - char fingerprint[128]; + char *fingerprint; reqkey.comment = NULL; - rsa_fingerprint(fingerprint, sizeof(fingerprint), &reqkey); + fingerprint = rsa_ssh1_fingerprint(&reqkey); plog(logctx, logfn, "requested key: %s", fingerprint); + sfree(fingerprint); } if ((key = find234(rsakeys, &reqkey, NULL)) == NULL) { pageant_failure_msg(bs, "key not found", logctx, logfn); @@ -386,9 +387,9 @@ void pageant_handle_msg(BinarySink *bs, } if (logfn) { - char fingerprint[128]; - rsa_fingerprint(fingerprint, sizeof(fingerprint), key); + char *fingerprint = rsa_ssh1_fingerprint(key); plog(logctx, logfn, "submitted key: %s", fingerprint); + sfree(fingerprint); } if (add234(rsakeys, key) == key) { @@ -496,9 +497,9 @@ void pageant_handle_msg(BinarySink *bs, } if (logfn) { - char fingerprint[128]; + char *fingerprint; reqkey.comment = NULL; - rsa_fingerprint(fingerprint, sizeof(fingerprint), &reqkey); + fingerprint = rsa_ssh1_fingerprint(&reqkey); plog(logctx, logfn, "unwanted key: %s", fingerprint); } @@ -1316,7 +1317,7 @@ int pageant_enum_keys(pageant_key_enum_fn_t callback, void *callback_ctx, nkeys = toint(get_uint32(src)); for (i = 0; i < nkeys; i++) { struct RSAKey rkey; - char fingerprint[128]; + char *fingerprint; /* public blob and fingerprint */ memset(&rkey, 0, sizeof(rkey)); @@ -1330,7 +1331,7 @@ int pageant_enum_keys(pageant_key_enum_fn_t callback, void *callback_ctx, return PAGEANT_ACTION_FAILURE; } - rsa_fingerprint(fingerprint, sizeof(fingerprint), &rkey); + fingerprint = rsa_ssh1_fingerprint(&rkey); cbkey.blob = strbuf_new(); rsa_ssh1_public_blob(BinarySink_UPCAST(cbkey.blob), &rkey, @@ -1341,6 +1342,7 @@ int pageant_enum_keys(pageant_key_enum_fn_t callback, void *callback_ctx, strbuf_free(cbkey.blob); freersakey(&rkey); sfree(cbkey.comment); + sfree(fingerprint); } sfree(keylist); diff --git a/ssh.c b/ssh.c index e575fc99..641543d4 100644 --- a/ssh.c +++ b/ssh.c @@ -4130,13 +4130,10 @@ static void do_ssh1_login(void *vctx) * Log the host key fingerprint. */ if (!get_err(pktin)) { - char logmsg[80]; + char *fingerprint = rsa_ssh1_fingerprint(&s->hostkey); logevent("Host key fingerprint is:"); - strcpy(logmsg, " "); - s->hostkey.comment = NULL; - rsa_fingerprint(logmsg + strlen(logmsg), - sizeof(logmsg) - strlen(logmsg), &s->hostkey); - logevent(logmsg); + logeventf(ssh, " %s", fingerprint); + sfree(fingerprint); } ssh->v1_remote_protoflags = get_uint32(pktin); @@ -4186,13 +4183,14 @@ static void do_ssh1_login(void *vctx) * First format the key into a string. */ int len = rsastr_len(&s->hostkey); - char fingerprint[100]; + char *fingerprint; char *keystr = snewn(len, char); rsastr_fmt(keystr, &s->hostkey); - rsa_fingerprint(fingerprint, sizeof(fingerprint), &s->hostkey); + fingerprint = rsa_ssh1_fingerprint(&s->hostkey); /* First check against manually configured host keys. */ s->dlgret = verify_ssh_manual_host_key(ssh, fingerprint, NULL, NULL); + sfree(fingerprint); if (s->dlgret == 0) { /* did not match */ bombout(("Host key did not appear in manually configured list")); sfree(keystr); diff --git a/ssh.h b/ssh.h index 2905037a..d4ca6584 100644 --- a/ssh.h +++ b/ssh.h @@ -192,7 +192,7 @@ Bignum rsa_ssh1_decrypt(Bignum input, struct RSAKey *key); void rsasanitise(struct RSAKey *key); int rsastr_len(struct RSAKey *key); void rsastr_fmt(char *str, struct RSAKey *key); -void rsa_fingerprint(char *str, int len, struct RSAKey *key); +char *rsa_ssh1_fingerprint(struct RSAKey *key); int rsa_verify(struct RSAKey *key); void rsa_ssh1_public_blob(BinarySink *bs, struct RSAKey *key, RsaSsh1Order order); diff --git a/sshrsa.c b/sshrsa.c index 51396a5c..2aaaf2d3 100644 --- a/sshrsa.c +++ b/sshrsa.c @@ -340,30 +340,25 @@ void rsastr_fmt(char *str, struct RSAKey *key) * Generate a fingerprint string for the key. Compatible with the * OpenSSH fingerprint code. */ -void rsa_fingerprint(char *str, int len, struct RSAKey *key) +char *rsa_ssh1_fingerprint(struct RSAKey *key) { struct MD5Context md5c; unsigned char digest[16]; - char buffer[16 * 3 + 40]; - int slen, i; + strbuf *out; + int i; MD5Init(&md5c); put_mp_ssh1(&md5c, key->modulus); put_mp_ssh1(&md5c, key->exponent); MD5Final(digest, &md5c); - sprintf(buffer, "%d ", bignum_bitcount(key->modulus)); + out = strbuf_new(); + strbuf_catf(out, "%d ", bignum_bitcount(key->modulus)); for (i = 0; i < 16; i++) - sprintf(buffer + strlen(buffer), "%s%02x", i ? ":" : "", - digest[i]); - strncpy(str, buffer, len); - str[len - 1] = '\0'; - slen = strlen(str); - if (key->comment && slen < len - 1) { - str[slen] = ' '; - strncpy(str + slen + 1, key->comment, len - slen - 1); - str[len - 1] = '\0'; - } + strbuf_catf(out, "%s%02x", i ? ":" : "", digest[i]); + if (key->comment) + strbuf_catf(out, " %s", key->comment); + return strbuf_to_str(out); } /* diff --git a/windows/winpgen.c b/windows/winpgen.c index edde9be2..bc68148f 100644 --- a/windows/winpgen.c +++ b/windows/winpgen.c @@ -734,8 +734,7 @@ void load_key_file(HWND hwnd, struct MainDlgState *state, SetDlgItemText(hwnd, IDC_PASSPHRASE2EDIT, passphrase); if (type == SSH_KEYTYPE_SSH1) { - char buf[128]; - char *savecomment; + char *fingerprint, *savecomment; state->ssh2 = FALSE; state->commentptr = &state->key.comment; @@ -746,11 +745,11 @@ void load_key_file(HWND hwnd, struct MainDlgState *state, */ savecomment = state->key.comment; state->key.comment = NULL; - rsa_fingerprint(buf, sizeof(buf), - &state->key); + fingerprint = rsa_ssh1_fingerprint(&state->key); state->key.comment = savecomment; + SetDlgItemText(hwnd, IDC_FINGERPRINT, fingerprint); + sfree(fingerprint); - SetDlgItemText(hwnd, IDC_FINGERPRINT, buf); /* * Construct a decimal representation * of the key, for pasting into @@ -1406,7 +1405,7 @@ static INT_PTR CALLBACK MainDlgProc(HWND hwnd, UINT msg, * Now update the key controls with all the key data. */ { - char *savecomment; + char *fp, *savecomment; /* * Blank passphrase, initially. This isn't dangerous, * because we will warn (Are You Sure?) before allowing @@ -1423,16 +1422,12 @@ static INT_PTR CALLBACK MainDlgProc(HWND hwnd, UINT msg, */ savecomment = *state->commentptr; *state->commentptr = NULL; - if (state->ssh2) { - char *fp; + if (state->ssh2) fp = ssh2_fingerprint(state->ssh2key.alg, state->ssh2key.data); - SetDlgItemText(hwnd, IDC_FINGERPRINT, fp); - sfree(fp); - } else { - char buf[128]; - rsa_fingerprint(buf, sizeof(buf), &state->key); - SetDlgItemText(hwnd, IDC_FINGERPRINT, buf); - } + else + fp = rsa_ssh1_fingerprint(&state->key); + SetDlgItemText(hwnd, IDC_FINGERPRINT, fp); + sfree(fp); *state->commentptr = savecomment; /* * Construct a decimal representation of the key, for diff --git a/windows/winpgnt.c b/windows/winpgnt.c index 6b9f1e6c..43266440 100644 --- a/windows/winpgnt.c +++ b/windows/winpgnt.c @@ -290,14 +290,16 @@ void keylist_update(void) if (keylist) { SendDlgItemMessage(keylist, 100, LB_RESETCONTENT, 0, 0); for (i = 0; NULL != (rkey = pageant_nth_ssh1_key(i)); i++) { - char listentry[512], *p; + char *listentry, *fp, *p; + + fp = rsa_ssh1_fingerprint(rkey); + listentry = dupprintf("ssh1\t%s", fp); + sfree(fp); + /* * Replace two spaces in the fingerprint with tabs, for * nice alignment in the box. */ - strcpy(listentry, "ssh1\t"); - p = listentry + strlen(listentry); - rsa_fingerprint(p, sizeof(listentry) - (p - listentry), rkey); p = strchr(listentry, ' '); if (p) *p = '\t'; @@ -306,6 +308,7 @@ void keylist_update(void) *p = '\t'; SendDlgItemMessage(keylist, 100, LB_ADDSTRING, 0, (LPARAM) listentry); + sfree(listentry); } for (i = 0; NULL != (skey = pageant_nth_ssh2_key(i)); i++) { char *listentry, *p; From ff11e10d62ce4bd29f99015909f953adcb2abd43 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 3 Jun 2018 08:12:57 +0100 Subject: [PATCH 344/607] Rename rsa_public_blob_len to mention SSH-1. It's yet another function with an outdatedly vague name. --- pageant.c | 2 +- ssh.h | 2 +- sshrsa.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pageant.c b/pageant.c index 41a0c4ff..170655d8 100644 --- a/pageant.c +++ b/pageant.c @@ -1073,7 +1073,7 @@ int pageant_add_keyfile(Filename *filename, const char *passphrase, } /* Now skip over public blob */ if (type == SSH_KEYTYPE_SSH1) { - int n = rsa_public_blob_len(p, keylistlen); + int n = rsa_ssh1_public_blob_len(p, keylistlen); if (n < 0) { *retstr = dupstr("Received broken key list from agent"); sfree(keylist); diff --git a/ssh.h b/ssh.h index d4ca6584..ec32d1df 100644 --- a/ssh.h +++ b/ssh.h @@ -196,7 +196,7 @@ char *rsa_ssh1_fingerprint(struct RSAKey *key); int rsa_verify(struct RSAKey *key); void rsa_ssh1_public_blob(BinarySink *bs, struct RSAKey *key, RsaSsh1Order order); -int rsa_public_blob_len(void *data, int maxlen); +int rsa_ssh1_public_blob_len(void *data, int maxlen); void freersakey(struct RSAKey *key); typedef uint32 word32; diff --git a/sshrsa.c b/sshrsa.c index 2aaaf2d3..598894e1 100644 --- a/sshrsa.c +++ b/sshrsa.c @@ -441,8 +441,8 @@ void rsa_ssh1_public_blob(BinarySink *bs, struct RSAKey *key, } } -/* Given a public blob, determine its length. */ -int rsa_public_blob_len(void *data, int maxlen) +/* Given an SSH-1 public key blob, determine its length. */ +int rsa_ssh1_public_blob_len(void *data, int maxlen) { BinarySource src[1]; From 7f56e1e36527e8ca56706dd149e973fff83c0f8a Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 3 Jun 2018 08:23:07 +0100 Subject: [PATCH 345/607] Remove 'keystr' parameter in get_rsa_ssh1_pub. This parameter returned a substring of the input, which was used for two purposes. Firstly, it was used to hash the host and server keys during the initial SSH-1 key setup phase; secondly, it was used to check the keys in Pageant against the public key blob of a key specified on the command line. Unfortunately, those two purposes didn't agree! The first one needs just the bare key modulus bytes (without even the SSH-1 mpint length header); the second needs the entire key blob. So, actually, it seems to have never worked in SSH-1 to say 'putty -i keyfile' and have PuTTY find that key in Pageant and not have to ask for the passphrase to decrypt the version on disk. Fixed by removing that parameter completely, which simplifies all the _other_ call sites, and replacing it by custom code in those two places that each does the actually right thing. --- cmdgen.c | 2 +- marshal.h | 4 ++-- pageant.c | 8 ++++---- ssh.c | 23 ++++++++++++++++------- ssh.h | 3 +-- sshpubk.c | 2 +- sshrsa.c | 13 +------------ unix/uxpgnt.c | 3 +-- 8 files changed, 27 insertions(+), 31 deletions(-) diff --git a/cmdgen.c b/cmdgen.c index f4771e1f..2f0bf7b0 100644 --- a/cmdgen.c +++ b/cmdgen.c @@ -813,7 +813,7 @@ int main(int argc, char **argv) ret = rsa_ssh1_loadpub(infilename, BinarySink_UPCAST(blob), &origcomment, &error); BinarySource_BARE_INIT(src, blob->u, blob->len); - get_rsa_ssh1_pub(src, ssh1key, NULL, RSA_SSH1_EXPONENT_FIRST); + get_rsa_ssh1_pub(src, ssh1key, RSA_SSH1_EXPONENT_FIRST); strbuf_free(blob); ssh1key->comment = dupstr(origcomment); diff --git a/marshal.h b/marshal.h index 3b7a089f..90bb94ff 100644 --- a/marshal.h +++ b/marshal.h @@ -243,8 +243,8 @@ struct BinarySource { BinarySource_get_mp_ssh1(BinarySource_UPCAST(src)) #define get_mp_ssh2(src) \ BinarySource_get_mp_ssh2(BinarySource_UPCAST(src)) -#define get_rsa_ssh1_pub(src, rsa, keystr, order) \ - BinarySource_get_rsa_ssh1_pub(BinarySource_UPCAST(src), rsa, keystr, order) +#define get_rsa_ssh1_pub(src, rsa, order) \ + BinarySource_get_rsa_ssh1_pub(BinarySource_UPCAST(src), rsa, order) #define get_rsa_ssh1_priv(src, rsa) \ BinarySource_get_rsa_ssh1_priv(BinarySource_UPCAST(src), rsa) diff --git a/pageant.c b/pageant.c index 170655d8..f9bdd668 100644 --- a/pageant.c +++ b/pageant.c @@ -264,7 +264,7 @@ void pageant_handle_msg(BinarySink *bs, response = NULL; memset(&reqkey, 0, sizeof(reqkey)); - get_rsa_ssh1_pub(msg, &reqkey, NULL, RSA_SSH1_EXPONENT_FIRST); + get_rsa_ssh1_pub(msg, &reqkey, RSA_SSH1_EXPONENT_FIRST); challenge = get_mp_ssh1(msg); session_id = get_data(msg, 16); response_type = get_uint32(msg); @@ -363,7 +363,7 @@ void pageant_handle_msg(BinarySink *bs, key = snew(struct RSAKey); memset(key, 0, sizeof(struct RSAKey)); - get_rsa_ssh1_pub(msg, key, NULL, RSA_SSH1_MODULUS_FIRST); + get_rsa_ssh1_pub(msg, key, RSA_SSH1_MODULUS_FIRST); get_rsa_ssh1_priv(msg, key); /* SSH-1 names p and q the other way round, i.e. we have @@ -486,7 +486,7 @@ void pageant_handle_msg(BinarySink *bs, plog(logctx, logfn, "request: SSH1_AGENTC_REMOVE_RSA_IDENTITY"); - get_rsa_ssh1_pub(msg, &reqkey, NULL, RSA_SSH1_EXPONENT_FIRST); + get_rsa_ssh1_pub(msg, &reqkey, RSA_SSH1_EXPONENT_FIRST); if (get_err(msg)) { pageant_failure_msg(bs, "unable to decode request", @@ -1321,7 +1321,7 @@ int pageant_enum_keys(pageant_key_enum_fn_t callback, void *callback_ctx, /* public blob and fingerprint */ memset(&rkey, 0, sizeof(rkey)); - get_rsa_ssh1_pub(src, &rkey, NULL, RSA_SSH1_EXPONENT_FIRST); + get_rsa_ssh1_pub(src, &rkey, RSA_SSH1_EXPONENT_FIRST); comment = get_string(src); if (get_err(src)) { diff --git a/ssh.c b/ssh.c index 641543d4..dd96e7a8 100644 --- a/ssh.c +++ b/ssh.c @@ -4082,7 +4082,6 @@ static void do_ssh1_login(void *vctx) int crLine; int len; unsigned char *rsabuf; - ptrlen keystr1, keystr2; unsigned long supported_ciphers_mask, supported_auths_mask; int tried_publickey, tried_agent; int tis_auth_refused, ccard_auth_refused; @@ -4123,8 +4122,8 @@ static void do_ssh1_login(void *vctx) pl = get_data(pktin, 8); memcpy(s->cookie, pl.ptr, pl.len); - get_rsa_ssh1_pub(pktin, &s->servkey, &s->keystr1, RSA_SSH1_EXPONENT_FIRST); - get_rsa_ssh1_pub(pktin, &s->hostkey, &s->keystr2, RSA_SSH1_EXPONENT_FIRST); + get_rsa_ssh1_pub(pktin, &s->servkey, RSA_SSH1_EXPONENT_FIRST); + get_rsa_ssh1_pub(pktin, &s->hostkey, RSA_SSH1_EXPONENT_FIRST); /* * Log the host key fingerprint. @@ -4153,8 +4152,13 @@ static void do_ssh1_login(void *vctx) ssh->v1_local_protoflags |= SSH1_PROTOFLAG_SCREEN_NUMBER; MD5Init(&md5c); - put_data(&md5c, s->keystr2.ptr, s->keystr2.len); - put_data(&md5c, s->keystr1.ptr, s->keystr1.len); + { + int i; + for (i = (bignum_bitcount(s->hostkey.modulus) + 7) / 8; i-- ;) + put_byte(&md5c, bignum_byte(s->hostkey.modulus, i)); + for (i = (bignum_bitcount(s->servkey.modulus) + 7) / 8; i-- ;) + put_byte(&md5c, bignum_byte(s->servkey.modulus, i)); + } put_data(&md5c, s->cookie, 8); MD5Final(s->session_id, &md5c); @@ -4496,15 +4500,20 @@ static void do_ssh1_login(void *vctx) } logeventf(ssh, "Pageant has %d SSH-1 keys", s->nkeys); for (s->keyi = 0; s->keyi < s->nkeys; s->keyi++) { - ptrlen keystr; - get_rsa_ssh1_pub(s->asrc, &s->key, &keystr, + size_t start, end; + start = s->asrc->pos; + get_rsa_ssh1_pub(s->asrc, &s->key, RSA_SSH1_EXPONENT_FIRST); + end = s->asrc->pos; s->comment = get_string(s->asrc); if (get_err(s->asrc)) { logevent("Pageant key list packet was truncated"); break; } if (s->publickey_blob) { + ptrlen keystr = make_ptrlen( + (const char *)s->asrc->data + start, end - start); + if (keystr.len == s->publickey_blob->len && !memcmp(keystr.ptr, s->publickey_blob->s, s->publickey_blob->len)) { diff --git a/ssh.h b/ssh.h index ec32d1df..b4267854 100644 --- a/ssh.h +++ b/ssh.h @@ -183,8 +183,7 @@ struct ec_point *ec_public(const Bignum privateKey, const struct ec_curve *curve typedef enum { RSA_SSH1_EXPONENT_FIRST, RSA_SSH1_MODULUS_FIRST } RsaSsh1Order; void BinarySource_get_rsa_ssh1_pub( - BinarySource *src, struct RSAKey *result, - ptrlen *keystr, RsaSsh1Order order); + BinarySource *src, struct RSAKey *result, RsaSsh1Order order); void BinarySource_get_rsa_ssh1_priv( BinarySource *src, struct RSAKey *rsa); int rsa_ssh1_encrypt(unsigned char *data, int length, struct RSAKey *key); diff --git a/sshpubk.c b/sshpubk.c index e3a80b0c..6c63674b 100644 --- a/sshpubk.c +++ b/sshpubk.c @@ -65,7 +65,7 @@ static int rsa_ssh1_load_main(FILE * fp, struct RSAKey *key, int pub_only, goto end; /* reserved field nonzero, panic! */ /* Now the serious stuff. An ordinary SSH-1 public key. */ - get_rsa_ssh1_pub(src, key, NULL, RSA_SSH1_MODULUS_FIRST); + get_rsa_ssh1_pub(src, key, RSA_SSH1_MODULUS_FIRST); /* Next, the comment field. */ comment = get_string(src); diff --git a/sshrsa.c b/sshrsa.c index 598894e1..9c99f99b 100644 --- a/sshrsa.c +++ b/sshrsa.c @@ -11,31 +11,20 @@ #include "misc.h" void BinarySource_get_rsa_ssh1_pub( - BinarySource *src, struct RSAKey *rsa, ptrlen *keystr, RsaSsh1Order order) + BinarySource *src, struct RSAKey *rsa, RsaSsh1Order order) { - const unsigned char *start, *end; unsigned bits; Bignum e, m; bits = get_uint32(src); if (order == RSA_SSH1_EXPONENT_FIRST) { e = get_mp_ssh1(src); - start = get_ptr(src); m = get_mp_ssh1(src); - end = get_ptr(src); } else { - start = get_ptr(src); m = get_mp_ssh1(src); - end = get_ptr(src); e = get_mp_ssh1(src); } - if (keystr) { - start += (end-start >= 2 ? 2 : end-start); - keystr->ptr = start; - keystr->len = end - start; - } - if (rsa) { rsa->bits = bits; rsa->exponent = e; diff --git a/unix/uxpgnt.c b/unix/uxpgnt.c index e3dfe318..c11bde03 100644 --- a/unix/uxpgnt.c +++ b/unix/uxpgnt.c @@ -707,8 +707,7 @@ void run_client(void) BinarySource_BARE_INIT(src, key->blob->u, key->blob->len); memset(&rkey, 0, sizeof(rkey)); rkey.comment = dupstr(key->comment); - get_rsa_ssh1_pub(src, &rkey, NULL, - RSA_SSH1_EXPONENT_FIRST); + get_rsa_ssh1_pub(src, &rkey, RSA_SSH1_EXPONENT_FIRST); ssh1_write_pubkey(fp, &rkey); freersakey(&rkey); } else { From 15bacbf630ca1b7ffc20170d776cfbae68d8eea0 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 3 Jun 2018 08:37:17 +0100 Subject: [PATCH 346/607] Missing free. --- pageant.c | 1 + 1 file changed, 1 insertion(+) diff --git a/pageant.c b/pageant.c index f9bdd668..7738b68f 100644 --- a/pageant.c +++ b/pageant.c @@ -501,6 +501,7 @@ void pageant_handle_msg(BinarySink *bs, reqkey.comment = NULL; fingerprint = rsa_ssh1_fingerprint(&reqkey); plog(logctx, logfn, "unwanted key: %s", fingerprint); + sfree(fingerprint); } key = find234(rsakeys, &reqkey, NULL); From 06a14fe8b8b96bb1c64ffa578a4598b0eb388e63 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 3 Jun 2018 12:58:05 +0100 Subject: [PATCH 347/607] Reorganise ssh_keyalg and use it as a vtable. After Pavel Kryukov pointed out that I have to put _something_ in the 'ssh_key' structure, I thought of an actually useful thing to put there: why not make it store a pointer to the ssh_keyalg structure? Then ssh_key becomes a classoid - or perhaps 'traitoid' is a closer analogy - in the same style as Socket and Plug. And just like Socket and Plug, I've also arranged a system of wrapper macros that avoid the need to mention the 'object' whose method you're invoking twice at each call site. The new vtable pointer directly replaces an existing field of struct ec_key (which was usable by several different ssh_keyalgs, so it already had to store a pointer to the currently active one), and also replaces the 'alg' field of the ssh2_userkey structure that wraps up a cryptographic key with its comment field. I've also taken the opportunity to clean things up a bit in general: most of the methods now have new and clearer names (e.g. you'd never know that 'newkey' made a public-only key while 'createkey' made a public+private key pair unless you went and looked it up, but now they're called 'new_pub' and 'new_priv' you might be in with a chance), and I've completely removed the openssh_private_npieces field after realising that it was duplicating information that is actually _more_ conveniently obtained by calling the new_priv_openssh method (formerly openssh_createkey) and throwing away the result. --- cmdgen.c | 28 ++++------ import.c | 131 ++++++++++++++++++++-------------------------- pageant.c | 44 ++++++++-------- ssh.c | 129 +++++++++++++++++++++------------------------ ssh.h | 67 ++++++++++++++---------- sshdss.c | 38 ++++++++------ sshdssg.c | 2 + sshecc.c | 119 +++++++++++++++++++++-------------------- sshecdsag.c | 4 +- sshpubk.c | 29 +++++----- sshrsa.c | 40 +++++++------- sshrsag.c | 2 + windows/winpgen.c | 20 +++---- windows/winpgnt.c | 7 +-- 14 files changed, 327 insertions(+), 333 deletions(-) diff --git a/cmdgen.c b/cmdgen.c index 2f0bf7b0..7cf920f3 100644 --- a/cmdgen.c +++ b/cmdgen.c @@ -248,7 +248,6 @@ int main(int argc, char **argv) struct RSAKey *ssh1key = NULL; strbuf *ssh2blob = NULL; char *ssh2alg = NULL; - const ssh_keyalg *ssh2algf = NULL; char *old_passphrase = NULL, *new_passphrase = NULL; int load_encrypted; progfn_t progressfn = is_interactive() ? progress_update : no_progress; @@ -722,22 +721,19 @@ int main(int argc, char **argv) struct dss_key *dsskey = snew(struct dss_key); dsa_generate(dsskey, bits, progressfn, &prog); ssh2key = snew(struct ssh2_userkey); - ssh2key->data = &dsskey->sshk; - ssh2key->alg = &ssh_dss; + ssh2key->key = &dsskey->sshk; ssh1key = NULL; } else if (keytype == ECDSA) { struct ec_key *ec = snew(struct ec_key); ec_generate(ec, bits, progressfn, &prog); ssh2key = snew(struct ssh2_userkey); - ssh2key->data = &ec->sshk; - ssh2key->alg = ec->signalg; + ssh2key->key = &ec->sshk; ssh1key = NULL; } else if (keytype == ED25519) { struct ec_key *ec = snew(struct ec_key); ec_edgenerate(ec, bits, progressfn, &prog); ssh2key = snew(struct ssh2_userkey); - ssh2key->data = &ec->sshk; - ssh2key->alg = &ssh_ecdsa_ed25519; + ssh2key->key = &ec->sshk; ssh1key = NULL; } else { struct RSAKey *rsakey = snew(struct RSAKey); @@ -747,8 +743,7 @@ int main(int argc, char **argv) ssh1key = rsakey; } else { ssh2key = snew(struct ssh2_userkey); - ssh2key->data = &rsakey->sshk; - ssh2key->alg = &ssh_rsa; + ssh2key->key = &rsakey->sshk; } } progressfn(&prog, PROGFN_PROGRESS, INT_MAX, -1); @@ -838,10 +833,10 @@ int main(int argc, char **argv) ssh2blob = strbuf_new(); if (ssh2_userkey_loadpub(infilename, &ssh2alg, BinarySink_UPCAST(ssh2blob), &origcomment, &error)) { - ssh2algf = find_pubkey_alg(ssh2alg); - if (ssh2algf) - bits = ssh2algf->pubkey_bits( - ssh2algf, make_ptrlen(ssh2blob->s, ssh2blob->len)); + const ssh_keyalg *alg = find_pubkey_alg(ssh2alg); + if (alg) + bits = ssh_key_public_bits( + alg, make_ptrlen(ssh2blob->s, ssh2blob->len)); else bits = -1; } else { @@ -995,7 +990,7 @@ int main(int argc, char **argv) if (!ssh2blob) { assert(ssh2key); ssh2blob = strbuf_new(); - ssh2key->alg->public_blob(ssh2key->data, BinarySink_UPCAST(ssh2blob)); + ssh_key_public_blob(ssh2key->key, BinarySink_UPCAST(ssh2blob)); } ssh2_write_pubkey(fp, ssh2key ? ssh2key->comment : origcomment, @@ -1020,8 +1015,7 @@ int main(int argc, char **argv) fingerprint = rsa_ssh1_fingerprint(ssh1key); } else { if (ssh2key) { - fingerprint = ssh2_fingerprint(ssh2key->alg, - ssh2key->data); + fingerprint = ssh2_fingerprint(ssh2key->key); } else { assert(ssh2blob); fingerprint = ssh2_fingerprint_blob( @@ -1085,7 +1079,7 @@ int main(int argc, char **argv) if (ssh1key) freersakey(ssh1key); if (ssh2key) { - ssh2key->alg->freekey(ssh2key->data); + ssh_key_free(ssh2key->key); sfree(ssh2key); } diff --git a/import.c b/import.c index 0b2d271c..ef55b28e 100644 --- a/import.c +++ b/import.c @@ -502,6 +502,7 @@ struct ssh2_userkey *openssh_pem_read(const Filename *filename, { struct openssh_pem_key *key = load_openssh_pem_key(filename, errmsg_p); struct ssh2_userkey *retkey; + const ssh_keyalg *alg; BinarySource src[1]; int i, num_integers; struct ssh2_userkey *retval = NULL; @@ -661,19 +662,18 @@ struct ssh2_userkey *openssh_pem_read(const Filename *filename, /* Construct the key */ retkey = snew(struct ssh2_userkey); - retkey->alg = alg; - put_stringz(blob, alg->name); + put_stringz(blob, alg->ssh_id); put_stringz(blob, curve->name); put_stringpl(blob, pubkey.data); publen = blob->len; put_mp_ssh2_from_string(blob, privkey.data.ptr, privkey.data.len); - retkey->data = retkey->alg->createkey( - retkey->alg, make_ptrlen(blob->u, publen), + retkey->key = ssh_key_new_priv( + alg, make_ptrlen(blob->u, publen), make_ptrlen(blob->u + publen, blob->len - publen)); - if (!retkey->data) { + if (!retkey->key) { sfree(retkey); errmsg = "unable to create key data structure"; goto error; @@ -740,12 +740,12 @@ struct ssh2_userkey *openssh_pem_read(const Filename *filename, */ assert(privptr > 0); /* should have bombed by now if not */ retkey = snew(struct ssh2_userkey); - retkey->alg = (key->keytype == OP_RSA ? &ssh_rsa : &ssh_dss); - retkey->data = retkey->alg->createkey( - retkey->alg, make_ptrlen(blob->u, privptr), + alg = (key->keytype == OP_RSA ? &ssh_rsa : &ssh_dss); + retkey->key = ssh_key_new_priv( + alg, make_ptrlen(blob->u, privptr), make_ptrlen(blob->u+privptr, blob->len-privptr)); - if (!retkey->data) { + if (!retkey->key) { sfree(retkey); errmsg = "unable to create key data structure"; goto error; @@ -794,9 +794,9 @@ int openssh_pem_write(const Filename *filename, struct ssh2_userkey *key, * Fetch the key blobs. */ pubblob = strbuf_new(); - key->alg->public_blob(key->data, BinarySink_UPCAST(pubblob)); + ssh_key_public_blob(key->key, BinarySink_UPCAST(pubblob)); privblob = strbuf_new(); - key->alg->private_blob(key->data, BinarySink_UPCAST(privblob)); + ssh_key_private_blob(key->key, BinarySink_UPCAST(privblob)); spareblob = NULL; outblob = strbuf_new(); @@ -805,7 +805,8 @@ int openssh_pem_write(const Filename *filename, struct ssh2_userkey *key, * Encode the OpenSSH key blob, and also decide on the header * line. */ - if (key->alg == &ssh_rsa || key->alg == &ssh_dss) { + if (ssh_key_alg(key->key) == &ssh_rsa || + ssh_key_alg(key->key) == &ssh_dss) { strbuf *seq; /* @@ -815,7 +816,7 @@ int openssh_pem_write(const Filename *filename, struct ssh2_userkey *key, * bignums per key type and then construct the actual blob in * common code after that. */ - if (key->alg == &ssh_rsa) { + if (ssh_key_alg(key->key) == &ssh_rsa) { ptrlen n, e, d, p, q, iqmp, dmp1, dmq1; Bignum bd, bp, bq, bdmp1, bdmq1; @@ -911,11 +912,11 @@ int openssh_pem_write(const Filename *filename, struct ssh2_userkey *key, put_ber_id_len(outblob, 16, seq->len, ASN1_CONSTRUCTED); put_data(outblob, seq->s, seq->len); strbuf_free(seq); - } else if (key->alg == &ssh_ecdsa_nistp256 || - key->alg == &ssh_ecdsa_nistp384 || - key->alg == &ssh_ecdsa_nistp521) { + } else if (ssh_key_alg(key->key) == &ssh_ecdsa_nistp256 || + ssh_key_alg(key->key) == &ssh_ecdsa_nistp384 || + ssh_key_alg(key->key) == &ssh_ecdsa_nistp521) { const unsigned char *oid; - struct ec_key *ec = FROMFIELD(key->data, struct ec_key, sshk); + struct ec_key *ec = FROMFIELD(key->key, struct ec_key, sshk); int oidlen; int pointlen; strbuf *seq, *sub; @@ -930,7 +931,7 @@ int openssh_pem_write(const Filename *filename, struct ssh2_userkey *key, * [1] * BIT STRING (0x00 public key point) */ - oid = ec_alg_oid(key->alg, &oidlen); + oid = ec_alg_oid(ssh_key_alg(key->key), &oidlen); pointlen = (ec->publicKey.curve->fieldBits + 7) / 8 * 2; seq = strbuf_new(); @@ -1340,7 +1341,6 @@ struct ssh2_userkey *openssh_new_read(const Filename *filename, { struct openssh_new_key *key = load_openssh_new_key(filename, errmsg_p); struct ssh2_userkey *retkey = NULL; - int i; struct ssh2_userkey *retval = NULL; const char *errmsg; unsigned checkint; @@ -1428,56 +1428,42 @@ struct ssh2_userkey *openssh_new_read(const Filename *filename, goto error; } - retkey = NULL; - for (key_index = 0; key_index < key->nkeys; key_index++) { - ptrlen keytype, thiskey, comment; + retkey = snew(struct ssh2_userkey); + retkey->key = NULL; + retkey->comment = NULL; - /* - * Read the key type, which will tell us how to scan over - * the key to get to the next one. - */ - keytype = get_string(src); + for (key_index = 0; key_index < key->nkeys; key_index++) { + ptrlen comment; /* - * Preliminary key type identification, and decide how - * many pieces of key we expect to see. Currently - * (conveniently) all key types can be seen as some number - * of strings, so we just need to know how many of them to - * skip over. (The numbers below exclude the key comment.) + * Identify the key type. */ - alg = find_pubkey_alg_len(keytype); + alg = find_pubkey_alg_len(get_string(src)); if (!alg) { errmsg = "private key type not recognised\n"; goto error; } - thiskey.ptr = get_ptr(src); - /* - * Skip over the pieces of key. + * Read the key. We have to do this even if it's not the one + * we want, because it's the only way to find out how much + * data to skip past to get to the next key in the file. */ - for (i = 0; i < alg->openssh_private_npieces; i++) - get_string(src); - + retkey->key = ssh_key_new_priv_openssh(alg, src); if (get_err(src)) { errmsg = "unable to read entire private key"; goto error; } - - thiskey.len = (const char *)get_ptr(src) - (const char *)thiskey.ptr; - - if (key_index == key->key_wanted) { - BinarySource src[1]; - BinarySource_BARE_INIT(src, thiskey.ptr, thiskey.len); - - retkey = snew(struct ssh2_userkey); - retkey->comment = NULL; - retkey->alg = alg; - retkey->data = alg->openssh_createkey(alg, src); - if (!retkey->data) { - errmsg = "unable to create key data structure"; - goto error; - } + if (!retkey->key) { + errmsg = "unable to create key data structure"; + goto error; + } + if (key_index != key->key_wanted) { + /* + * If this isn't the key we're looking for, throw it away. + */ + ssh_key_free(retkey->key); + retkey->key = NULL; } /* @@ -1518,10 +1504,8 @@ struct ssh2_userkey *openssh_new_read(const Filename *filename, error: if (retkey) { sfree(retkey->comment); - if (retkey->data) { - assert(alg); - alg->freekey(retkey->data); - } + if (retkey->key) + ssh_key_free(retkey->key); sfree(retkey); } smemclr(key->keyblob, key->keyblob_size); @@ -1547,9 +1531,9 @@ int openssh_new_write(const Filename *filename, struct ssh2_userkey *key, * Fetch the key blobs and find out the lengths of things. */ pubblob = strbuf_new(); - key->alg->public_blob(key->data, BinarySink_UPCAST(pubblob)); + ssh_key_public_blob(key->key, BinarySink_UPCAST(pubblob)); privblob = strbuf_new(); - key->alg->openssh_fmtkey(key->data, BinarySink_UPCAST(privblob)); + ssh_key_openssh_blob(key->key, BinarySink_UPCAST(privblob)); /* * Construct the cleartext version of the blob. @@ -1597,7 +1581,7 @@ int openssh_new_write(const Filename *filename, struct ssh2_userkey *key, /* Private key. The main private blob goes inline, with no string * wrapper. */ - put_stringz(cpblob, key->alg->name); + put_stringz(cpblob, ssh_key_ssh_id(key->key)); put_data(cpblob, privblob->s, privblob->len); /* Comment. */ @@ -1669,11 +1653,11 @@ int openssh_auto_write(const Filename *filename, struct ssh2_userkey *key, * assume that anything not in that fixed list is newer, and hence * will use the new format. */ - if (key->alg == &ssh_dss || - key->alg == &ssh_rsa || - key->alg == &ssh_ecdsa_nistp256 || - key->alg == &ssh_ecdsa_nistp384 || - key->alg == &ssh_ecdsa_nistp521) + if (ssh_key_alg(key->key) == &ssh_dss || + ssh_key_alg(key->key) == &ssh_rsa || + ssh_key_alg(key->key) == &ssh_ecdsa_nistp256 || + ssh_key_alg(key->key) == &ssh_ecdsa_nistp384 || + ssh_key_alg(key->key) == &ssh_ecdsa_nistp521) return openssh_pem_write(filename, key, passphrase); else return openssh_new_write(filename, key, passphrase); @@ -2117,7 +2101,7 @@ struct ssh2_userkey *sshcom_read(const Filename *filename, char *passphrase, /* * Now we break down into RSA versus DSA. In either case we'll * construct public and private blobs in our own format, and - * end up feeding them to alg->createkey(). + * end up feeding them to ssh_key_new_priv(). */ blob = strbuf_new(); if (type == RSA) { @@ -2173,11 +2157,10 @@ struct ssh2_userkey *sshcom_read(const Filename *filename, char *passphrase, } retkey = snew(struct ssh2_userkey); - retkey->alg = alg; - retkey->data = alg->createkey( + retkey->key = ssh_key_new_priv( alg, make_ptrlen(blob->u, publen), make_ptrlen(blob->u + publen, blob->len - publen)); - if (!retkey->data) { + if (!retkey->key) { sfree(retkey); errmsg = "unable to create key data structure"; goto error; @@ -2216,16 +2199,16 @@ int sshcom_write(const Filename *filename, struct ssh2_userkey *key, * Fetch the key blobs. */ pubblob = strbuf_new(); - key->alg->public_blob(key->data, BinarySink_UPCAST(pubblob)); + ssh_key_public_blob(key->key, BinarySink_UPCAST(pubblob)); privblob = strbuf_new(); - key->alg->private_blob(key->data, BinarySink_UPCAST(privblob)); + ssh_key_private_blob(key->key, BinarySink_UPCAST(privblob)); outblob = NULL; /* * Find the sequence of integers to be encoded into the OpenSSH * key blob, and also decide on the header line. */ - if (key->alg == &ssh_rsa) { + if (ssh_key_alg(key->key) == &ssh_rsa) { ptrlen n, e, d, p, q, iqmp; /* @@ -2254,7 +2237,7 @@ int sshcom_write(const Filename *filename, struct ssh2_userkey *key, nnumbers = 6; initial_zero = 0; type = "if-modn{sign{rsa-pkcs1-sha1},encrypt{rsa-pkcs1v2-oaep}}"; - } else if (key->alg == &ssh_dss) { + } else if (ssh_key_alg(key->key) == &ssh_dss) { ptrlen p, q, g, y, x; /* diff --git a/pageant.c b/pageant.c index 7738b68f..5c3efb13 100644 --- a/pageant.c +++ b/pageant.c @@ -89,7 +89,7 @@ static int cmpkeys_ssh2_asymm(void *av, void *bv) * Compare purely by public blob. */ bblob = strbuf_new(); - b->alg->public_blob(b->data, BinarySink_UPCAST(bblob)); + ssh_key_public_blob(b->key, BinarySink_UPCAST(bblob)); c = 0; for (i = 0; i < ablob->len && i < bblob->len; i++) { @@ -123,7 +123,7 @@ static int cmpkeys_ssh2(void *av, void *bv) int toret; ablob = strbuf_new(); - a->alg->public_blob(a->data, BinarySink_UPCAST(ablob)); + ssh_key_public_blob(a->key, BinarySink_UPCAST(ablob)); apl.ptr = ablob->u; apl.len = ablob->len; toret = cmpkeys_ssh2_asymm(&apl, bv); @@ -151,7 +151,7 @@ void pageant_make_keylist2(BinarySink *bs) put_uint32(bs, count234(ssh2keys)); for (i = 0; NULL != (key = index234(ssh2keys, i)); i++) { strbuf *blob = strbuf_new(); - key->alg->public_blob(key->data, BinarySink_UPCAST(blob)); + ssh_key_public_blob(key->key, BinarySink_UPCAST(blob)); put_stringsb(bs, blob); put_stringz(bs, key->comment); } @@ -235,8 +235,7 @@ void pageant_handle_msg(BinarySink *bs, int i; struct ssh2_userkey *skey; for (i = 0; NULL != (skey = pageant_nth_ssh2_key(i)); i++) { - char *fingerprint = ssh2_fingerprint(skey->alg, - skey->data); + char *fingerprint = ssh2_fingerprint(skey->key); plog(logctx, logfn, "returned key: %s %s", fingerprint, skey->comment); sfree(fingerprint); @@ -343,8 +342,8 @@ void pageant_handle_msg(BinarySink *bs, put_byte(bs, SSH2_AGENT_SIGN_RESPONSE); signature = strbuf_new(); - key->alg->sign(key->data, sigdata.ptr, sigdata.len, - BinarySink_UPCAST(signature)); + ssh_key_sign(key->key, sigdata.ptr, sigdata.len, + BinarySink_UPCAST(signature)); put_stringsb(bs, signature); plog(logctx, logfn, "reply: SSH2_AGENT_SIGN_RESPONSE"); @@ -416,24 +415,25 @@ void pageant_handle_msg(BinarySink *bs, */ { struct ssh2_userkey *key = NULL; - ptrlen alg; + ptrlen algpl; + const ssh_keyalg *alg; plog(logctx, logfn, "request: SSH2_AGENTC_ADD_IDENTITY"); - alg = get_string(msg); + algpl = get_string(msg); key = snew(struct ssh2_userkey); - key->data = NULL; + key->key = NULL; key->comment = NULL; - key->alg = find_pubkey_alg_len(alg); - if (!key->alg) { + alg = find_pubkey_alg_len(algpl); + if (!alg) { pageant_failure_msg(bs, "algorithm unknown", logctx, logfn); goto add2_cleanup; } - key->data = key->alg->openssh_createkey(key->alg, msg); + key->key = ssh_key_new_priv_openssh(alg, msg); - if (!key->data) { + if (!key->key) { pageant_failure_msg(bs, "key setup failed", logctx, logfn); goto add2_cleanup; } @@ -447,7 +447,7 @@ void pageant_handle_msg(BinarySink *bs, } if (logfn) { - char *fingerprint = ssh2_fingerprint(key->alg, key->data); + char *fingerprint = ssh2_fingerprint(key->key); plog(logctx, logfn, "submitted key: %s %s", fingerprint, key->comment); sfree(fingerprint); @@ -467,8 +467,8 @@ void pageant_handle_msg(BinarySink *bs, add2_cleanup: if (key) { - if (key->data) - key->alg->freekey(key->data); + if (key->key) + ssh_key_free(key->key); if (key->comment) sfree(key->comment); sfree(key); @@ -558,7 +558,7 @@ void pageant_handle_msg(BinarySink *bs, del234(ssh2keys, key); keylist_update(); - key->alg->freekey(key->data); + ssh_key_free(key->key); sfree(key->comment); sfree(key); put_byte(bs, SSH_AGENT_SUCCESS); @@ -599,7 +599,7 @@ void pageant_handle_msg(BinarySink *bs, while ((skey = index234(ssh2keys, 0)) != NULL) { del234(ssh2keys, skey); - skey->alg->freekey(skey->data); + ssh_key_free(skey->key); sfree(skey->comment); sfree(skey); } @@ -1274,8 +1274,8 @@ int pageant_add_keyfile(Filename *filename, const char *passphrase, request = strbuf_new_for_agent_query(); put_byte(request, SSH2_AGENTC_ADD_IDENTITY); - put_stringz(request, skey->alg->name); - skey->alg->openssh_fmtkey(skey->data, BinarySink_UPCAST(request)); + put_stringz(request, ssh_key_ssh_id(skey->key)); + ssh_key_openssh_blob(skey->key, BinarySink_UPCAST(request)); put_stringz(request, skey->comment); agent_query_synchronous(request, &vresponse, &resplen); strbuf_free(request); @@ -1291,7 +1291,7 @@ int pageant_add_keyfile(Filename *filename, const char *passphrase, sfree(response); } else { if (!pageant_add_ssh2_key(skey)) { - skey->alg->freekey(skey->data); + ssh_key_free(skey->key); sfree(skey); /* already present, don't waste RAM */ } } diff --git a/ssh.c b/ssh.c index dd96e7a8..17202e85 100644 --- a/ssh.c +++ b/ssh.c @@ -903,7 +903,7 @@ struct ssh_tag { const struct ssh_compress *cscomp, *sccomp; void *cs_comp_ctx, *sc_comp_ctx; const struct ssh_kex *kex; - const ssh_keyalg *hostkey; + const ssh_keyalg *hostkey_alg; char *hostkey_str; /* string representation, for easy checking in rekeys */ unsigned char v2_session_id[SSH2_KEX_MAX_HASH_LEN]; int v2_session_id_len; @@ -4008,9 +4008,7 @@ static void ssh_disconnect(Ssh ssh, const char *client_reason, sfree(error); } -int verify_ssh_manual_host_key(Ssh ssh, const char *fingerprint, - const ssh_keyalg *ssh2keytype, - void *ssh2keydata) +int verify_ssh_manual_host_key(Ssh ssh, const char *fingerprint, ssh_key *key) { if (!conf_get_str_nthstrkey(ssh->conf, CONF_ssh_manual_hostkeys, 0)) { return -1; /* no manual keys configured */ @@ -4035,7 +4033,7 @@ int verify_ssh_manual_host_key(Ssh ssh, const char *fingerprint, return 1; /* success */ } - if (ssh2keydata) { + if (key) { /* * Construct the base64-encoded public key blob and see if * that's listed. @@ -4044,7 +4042,7 @@ int verify_ssh_manual_host_key(Ssh ssh, const char *fingerprint, char *base64blob; int atoms, i; binblob = strbuf_new(); - ssh2keytype->public_blob(ssh2keydata, BinarySink_UPCAST(binblob)); + ssh_key_public_blob(key, BinarySink_UPCAST(binblob)); atoms = (binblob->len + 2) / 3; base64blob = snewn(atoms * 4 + 1, char); for (i = 0; i < atoms; i++) @@ -4193,7 +4191,7 @@ static void do_ssh1_login(void *vctx) fingerprint = rsa_ssh1_fingerprint(&s->hostkey); /* First check against manually configured host keys. */ - s->dlgret = verify_ssh_manual_host_key(ssh, fingerprint, NULL, NULL); + s->dlgret = verify_ssh_manual_host_key(ssh, fingerprint, NULL); sfree(fingerprint); if (s->dlgret == 0) { /* did not match */ bombout(("Host key did not appear in manually configured list")); @@ -6349,7 +6347,7 @@ static int ssh_transient_hostkey_cache_cmp(void *av, void *bv) const struct ssh_transient_hostkey_cache_entry *a = (const struct ssh_transient_hostkey_cache_entry *)av, *b = (const struct ssh_transient_hostkey_cache_entry *)bv; - return strcmp(a->alg->name, b->alg->name); + return strcmp(a->alg->ssh_id, b->alg->ssh_id); } static int ssh_transient_hostkey_cache_find(void *av, void *bv) @@ -6357,7 +6355,7 @@ static int ssh_transient_hostkey_cache_find(void *av, void *bv) const ssh_keyalg *aalg = (const ssh_keyalg *)av; const struct ssh_transient_hostkey_cache_entry *b = (const struct ssh_transient_hostkey_cache_entry *)bv; - return strcmp(aalg->name, b->alg->name); + return strcmp(aalg->ssh_id, b->alg->ssh_id); } static void ssh_init_transient_hostkey_store(Ssh ssh) @@ -6376,35 +6374,33 @@ static void ssh_cleanup_transient_hostkey_store(Ssh ssh) freetree234(ssh->transient_hostkey_cache); } -static void ssh_store_transient_hostkey( - Ssh ssh, const ssh_keyalg *alg, ssh_key *key) +static void ssh_store_transient_hostkey(Ssh ssh, ssh_key *key) { struct ssh_transient_hostkey_cache_entry *ent, *retd; - if ((ent = find234(ssh->transient_hostkey_cache, (void *)alg, + if ((ent = find234(ssh->transient_hostkey_cache, (void *)ssh_key_alg(key), ssh_transient_hostkey_cache_find)) != NULL) { strbuf_free(ent->pub_blob); sfree(ent); } ent = snew(struct ssh_transient_hostkey_cache_entry); - ent->alg = alg; + ent->alg = ssh_key_alg(key); ent->pub_blob = strbuf_new(); - alg->public_blob(key, BinarySink_UPCAST(ent->pub_blob)); + ssh_key_public_blob(key, BinarySink_UPCAST(ent->pub_blob)); retd = add234(ssh->transient_hostkey_cache, ent); assert(retd == ent); } -static int ssh_verify_transient_hostkey( - Ssh ssh, const ssh_keyalg *alg, ssh_key *key) +static int ssh_verify_transient_hostkey(Ssh ssh, ssh_key *key) { struct ssh_transient_hostkey_cache_entry *ent; int toret = FALSE; - if ((ent = find234(ssh->transient_hostkey_cache, (void *)alg, + if ((ent = find234(ssh->transient_hostkey_cache, (void *)ssh_key_alg(key), ssh_transient_hostkey_cache_find)) != NULL) { strbuf *this_blob = strbuf_new(); - alg->public_blob(key, BinarySink_UPCAST(this_blob)); + ssh_key_public_blob(key, BinarySink_UPCAST(this_blob)); if (this_blob->len == ent->pub_blob->len && !memcmp(this_blob->s, ent->pub_blob->s, @@ -6726,9 +6722,9 @@ static void do_ssh2_transport(void *vctx) if (hostkey_algs[j].id != s->preferred_hk[i]) continue; if (have_ssh_host_key(ssh->savedhost, ssh->savedport, - hostkey_algs[j].alg->keytype)) { + hostkey_algs[j].alg->cache_id)) { alg = ssh2_kexinit_addalg(s->kexlists[KEXLIST_HOSTKEY], - hostkey_algs[j].alg->name); + hostkey_algs[j].alg->ssh_id); alg->u.hk.hostkey = hostkey_algs[j].alg; alg->u.hk.warn = warn; } @@ -6742,7 +6738,7 @@ static void do_ssh2_transport(void *vctx) if (hostkey_algs[j].id != s->preferred_hk[i]) continue; alg = ssh2_kexinit_addalg(s->kexlists[KEXLIST_HOSTKEY], - hostkey_algs[j].alg->name); + hostkey_algs[j].alg->ssh_id); alg->u.hk.hostkey = hostkey_algs[j].alg; alg->u.hk.warn = warn; } @@ -6770,7 +6766,7 @@ static void do_ssh2_transport(void *vctx) continue; if (ssh_have_transient_hostkey(ssh, hostkey_algs[j].alg)) { alg = ssh2_kexinit_addalg(s->kexlists[KEXLIST_HOSTKEY], - hostkey_algs[j].alg->name); + hostkey_algs[j].alg->ssh_id); alg->u.hk.hostkey = hostkey_algs[j].alg; alg->u.hk.warn = warn; } @@ -6787,8 +6783,8 @@ static void do_ssh2_transport(void *vctx) */ assert(ssh->kex); alg = ssh2_kexinit_addalg(s->kexlists[KEXLIST_HOSTKEY], - ssh->hostkey->name); - alg->u.hk.hostkey = ssh->hostkey; + ssh->hostkey_alg->ssh_id); + alg->u.hk.hostkey = ssh->hostkey_alg; alg->u.hk.warn = FALSE; } if (s->can_gssapi_keyex) { @@ -6907,7 +6903,7 @@ static void do_ssh2_transport(void *vctx) crStopV; } ssh->kex = NULL; - ssh->hostkey = NULL; + ssh->hostkey_alg = NULL; s->cscipher_tobe = NULL; s->sccipher_tobe = NULL; s->csmac_tobe = NULL; @@ -6969,7 +6965,7 @@ static void do_ssh2_transport(void *vctx) if (alg->u.hk.hostkey == NULL && ssh->kex->main_type != KEXTYPE_GSS) continue; - ssh->hostkey = alg->u.hk.hostkey; + ssh->hostkey_alg = alg->u.hk.hostkey; s->warn_hk = alg->u.hk.warn; } else if (i == KEXLIST_CSCIPHER) { s->cscipher_tobe = alg->u.cipher.cipher; @@ -7019,11 +7015,11 @@ static void do_ssh2_transport(void *vctx) ssh->n_uncert_hostkeys = 0; for (j = 0; j < lenof(hostkey_algs); j++) { - if (hostkey_algs[j].alg != ssh->hostkey && - in_commasep_string(hostkey_algs[j].alg->name, + if (hostkey_algs[j].alg != ssh->hostkey_alg && + in_commasep_string(hostkey_algs[j].alg->ssh_id, str.ptr, str.len) && !have_ssh_host_key(ssh->savedhost, ssh->savedport, - hostkey_algs[j].alg->keytype)) { + hostkey_algs[j].alg->cache_id)) { ssh->uncert_hostkeys[ssh->n_uncert_hostkeys++] = j; } } @@ -7096,21 +7092,21 @@ static void do_ssh2_transport(void *vctx) if (betteralgs) { char *old_ba = betteralgs; betteralgs = dupcat(betteralgs, ",", - hktype->alg->name, + hktype->alg->ssh_id, (const char *)NULL); sfree(old_ba); } else { - betteralgs = dupstr(hktype->alg->name); + betteralgs = dupstr(hktype->alg->ssh_id); } } } if (betteralgs) { - s->dlgret = askhk(ssh->frontend, ssh->hostkey->name, + s->dlgret = askhk(ssh->frontend, ssh->hostkey_alg->ssh_id, betteralgs, ssh_dialog_callback, ssh); sfree(betteralgs); } else { s->dlgret = askalg(ssh->frontend, "host key type", - ssh->hostkey->name, + ssh->hostkey_alg->ssh_id, ssh_dialog_callback, ssh); } if (s->dlgret < 0) { @@ -7257,7 +7253,7 @@ static void do_ssh2_transport(void *vctx) } set_busy_status(ssh->frontend, BUSY_CPU); /* cogitate */ s->hostkeydata = get_string(pktin); - s->hkey = ssh->hostkey->newkey(ssh->hostkey, s->hostkeydata); + s->hkey = ssh_key_new_pub(ssh->hostkey_alg, s->hostkeydata); s->f = get_mp_ssh2(pktin); s->sigdata = get_string(pktin); if (get_err(pktin)) { @@ -7328,7 +7324,7 @@ static void do_ssh2_transport(void *vctx) s->hostkeydata = get_string(pktin); put_stringpl(ssh->exhash_bs, s->hostkeydata); - s->hkey = ssh->hostkey->newkey(ssh->hostkey, s->hostkeydata); + s->hkey = ssh_key_new_pub(ssh->hostkey_alg, s->hostkeydata); { strbuf *pubpoint = strbuf_new(); @@ -7530,9 +7526,9 @@ static void do_ssh2_transport(void *vctx) break; case SSH2_MSG_KEXGSS_HOSTKEY: s->hostkeydata = get_string(pktin); - if (ssh->hostkey) { - s->hkey = ssh->hostkey->newkey(ssh->hostkey, - s->hostkeydata); + if (ssh->hostkey_alg) { + s->hkey = ssh_key_new_pub(ssh->hostkey_alg, + s->hostkeydata); put_string(ssh->exhash_bs, s->hostkeydata.ptr, s->hostkeydata.len); } @@ -7626,7 +7622,7 @@ static void do_ssh2_transport(void *vctx) s->hostkeydata = get_string(pktin); put_stringpl(ssh->exhash_bs, s->hostkeydata); - s->hkey = ssh->hostkey->newkey(ssh->hostkey, s->hostkeydata); + s->hkey = ssh_key_new_pub(ssh->hostkey_alg, s->hostkeydata); rsakeydata = get_string(pktin); @@ -7765,7 +7761,7 @@ static void do_ssh2_transport(void *vctx) crStopV; } - if (!ssh->hostkey->verifysig( + if (!ssh_key_verify( s->hkey, s->sigdata, make_ptrlen(s->exchange_hash, ssh->kex->hash->hlen))) { #ifndef FUZZING @@ -7776,8 +7772,7 @@ static void do_ssh2_transport(void *vctx) } } - s->keystr = (ssh->hostkey && s->hkey ? - ssh->hostkey->fmtkey(s->hkey) : NULL); + s->keystr = (s->hkey ? ssh_key_cache_str(s->hkey) : NULL); #ifndef NO_GSSAPI if (ssh->gss_kex_used) { /* @@ -7792,12 +7787,12 @@ static void do_ssh2_transport(void *vctx) * host key, store it. */ if (s->hkey) { - s->fingerprint = ssh2_fingerprint(ssh->hostkey, s->hkey); + s->fingerprint = ssh2_fingerprint(s->hkey); logevent("GSS kex provided fallback host key:"); logevent(s->fingerprint); sfree(s->fingerprint); s->fingerprint = NULL; - ssh_store_transient_hostkey(ssh, ssh->hostkey, s->hkey); + ssh_store_transient_hostkey(ssh, s->hkey); } else if (!ssh_have_any_transient_hostkey(ssh)) { /* * But if it didn't, then we currently have no @@ -7812,7 +7807,7 @@ static void do_ssh2_transport(void *vctx) * startup, and only add the key to the transient * cache. */ - if (ssh->hostkey) { + if (ssh->hostkey_alg) { s->need_gss_transient_hostkey = TRUE; } else { /* @@ -7850,15 +7845,14 @@ static void do_ssh2_transport(void *vctx) * triggered on purpose to populate the transient cache. */ assert(s->hkey); /* only KEXTYPE_GSS lets this be null */ - s->fingerprint = ssh2_fingerprint(ssh->hostkey, s->hkey); + s->fingerprint = ssh2_fingerprint(s->hkey); if (s->need_gss_transient_hostkey) { logevent("Post-GSS rekey provided fallback host key:"); logevent(s->fingerprint); - ssh_store_transient_hostkey(ssh, ssh->hostkey, s->hkey); + ssh_store_transient_hostkey(ssh, s->hkey); s->need_gss_transient_hostkey = FALSE; - } else if (!ssh_verify_transient_hostkey( - ssh, ssh->hostkey, s->hkey)) { + } else if (!ssh_verify_transient_hostkey(ssh, s->hkey)) { logevent("Non-GSS rekey after initial GSS kex " "used host key:"); logevent(s->fingerprint); @@ -7878,7 +7872,7 @@ static void do_ssh2_transport(void *vctx) int i, j, nkeys = 0; char *list = NULL; for (i = 0; i < lenof(hostkey_algs); i++) { - if (hostkey_algs[i].alg == ssh->hostkey) + if (hostkey_algs[i].alg == ssh->hostkey_alg) continue; for (j = 0; j < ssh->n_uncert_hostkeys; j++) @@ -7889,9 +7883,9 @@ static void do_ssh2_transport(void *vctx) char *newlist; if (list) newlist = dupprintf("%s/%s", list, - hostkey_algs[i].alg->name); + hostkey_algs[i].alg->ssh_id); else - newlist = dupprintf("%s", hostkey_algs[i].alg->name); + newlist = dupprintf("%s", hostkey_algs[i].alg->ssh_id); sfree(list); list = newlist; nkeys++; @@ -7911,12 +7905,11 @@ static void do_ssh2_transport(void *vctx) * Authenticate remote host: verify host key. (We've already * checked the signature of the exchange hash.) */ - s->fingerprint = ssh2_fingerprint(ssh->hostkey, s->hkey); + s->fingerprint = ssh2_fingerprint(s->hkey); logevent("Host key fingerprint is:"); logevent(s->fingerprint); /* First check against manually configured host keys. */ - s->dlgret = verify_ssh_manual_host_key(ssh, s->fingerprint, - ssh->hostkey, s->hkey); + s->dlgret = verify_ssh_manual_host_key(ssh, s->fingerprint, s->hkey); if (s->dlgret == 0) { /* did not match */ bombout(("Host key did not appear in manually configured list")); crStopV; @@ -7924,8 +7917,8 @@ static void do_ssh2_transport(void *vctx) ssh_set_frozen(ssh, 1); s->dlgret = verify_ssh_host_key(ssh->frontend, ssh->savedhost, ssh->savedport, - ssh->hostkey->keytype, s->keystr, - s->fingerprint, + ssh_key_cache_id(s->hkey), + s->keystr, s->fingerprint, ssh_dialog_callback, ssh); #ifdef FUZZING s->dlgret = 1; @@ -7950,12 +7943,12 @@ static void do_ssh2_transport(void *vctx) ssh->hostkey_str = s->keystr; s->keystr = NULL; } else if (ssh->cross_certifying) { - s->fingerprint = ssh2_fingerprint(ssh->hostkey, s->hkey); + s->fingerprint = ssh2_fingerprint(s->hkey); logevent("Storing additional host key for this host:"); logevent(s->fingerprint); sfree(s->fingerprint); store_host_key(ssh->savedhost, ssh->savedport, - ssh->hostkey->keytype, s->keystr); + ssh_key_cache_id(s->hkey), s->keystr); ssh->cross_certifying = FALSE; /* * Don't forget to store the new key as the one we'll be @@ -7979,7 +7972,7 @@ static void do_ssh2_transport(void *vctx) } sfree(s->keystr); if (s->hkey) { - ssh->hostkey->freekey(s->hkey); + ssh_key_free(s->hkey); s->hkey = NULL; } @@ -10505,9 +10498,9 @@ static void do_ssh2_userauth(void *vctx) /* service requested */ put_stringz(s->pktout, "publickey"); /* method */ put_bool(s->pktout, TRUE); /* signature follows */ - put_stringz(s->pktout, key->alg->name); + put_stringz(s->pktout, ssh_key_ssh_id(key->key)); pkblob = strbuf_new(); - key->alg->public_blob(key->data, BinarySink_UPCAST(pkblob)); + ssh_key_public_blob(key->key, BinarySink_UPCAST(pkblob)); put_string(s->pktout, pkblob->s, pkblob->len); /* @@ -10529,8 +10522,8 @@ static void do_ssh2_userauth(void *vctx) put_data(sigdata, s->pktout->data + 5, s->pktout->length - 5); sigblob = strbuf_new(); - key->alg->sign(key->data, sigdata->s, sigdata->len, - BinarySink_UPCAST(sigblob)); + ssh_key_sign(key->key, sigdata->s, sigdata->len, + BinarySink_UPCAST(sigblob)); strbuf_free(sigdata); ssh2_add_sigblob(ssh, s->pktout, pkblob->s, pkblob->len, sigblob->s, sigblob->len); @@ -10540,7 +10533,7 @@ static void do_ssh2_userauth(void *vctx) ssh2_pkt_send(ssh, s->pktout); logevent("Sent public key signature"); s->type = AUTH_TYPE_PUBLICKEY; - key->alg->freekey(key->data); + ssh_key_free(key->key); sfree(key->comment); sfree(key); } @@ -12021,7 +12014,7 @@ static const char *ssh_init(void *frontend_handle, void **backend_handle, ssh->sc_comp_ctx = NULL; ssh->kex = NULL; ssh->kex_ctx = NULL; - ssh->hostkey = NULL; + ssh->hostkey_alg = NULL; ssh->hostkey_str = NULL; ssh->exitcode = -1; ssh->close_expected = FALSE; @@ -12538,7 +12531,7 @@ static const struct telnet_special *ssh_get_specials(void *handle) struct telnet_special uncert[1]; const ssh_keyalg *alg = hostkey_algs[ssh->uncert_hostkeys[i]].alg; - uncert[0].name = alg->name; + uncert[0].name = alg->ssh_id; uncert[0].code = TS_LOCALSTART + ssh->uncert_hostkeys[i]; ADD_SPECIALS(uncert); } @@ -12607,7 +12600,7 @@ static void ssh_special(void *handle, Telnet_Special code) queue_idempotent_callback(&ssh->ssh2_transport_icb); } } else if (code >= TS_LOCALSTART) { - ssh->hostkey = hostkey_algs[code - TS_LOCALSTART].alg; + ssh->hostkey_alg = hostkey_algs[code - TS_LOCALSTART].alg; ssh->cross_certifying = TRUE; if (!ssh->kex_in_progress && !ssh->bare_connection && ssh->version == 2) { diff --git a/ssh.h b/ssh.h index b4267854..6cc925f9 100644 --- a/ssh.h +++ b/ssh.h @@ -77,11 +77,8 @@ void share_setup_x11_channel(void *csv, void *chanv, typedef void *Bignum; #endif -typedef struct ssh_key { - int dummy; -} ssh_key; - typedef struct ssh_keyalg ssh_keyalg; +typedef const struct ssh_keyalg *ssh_key; struct RSAKey { int bits; @@ -164,10 +161,9 @@ int ec_ed_alg_and_curve_by_bits(int bits, const ssh_keyalg **alg); struct ec_key { - const ssh_keyalg *signalg; struct ec_point publicKey; Bignum privateKey; - struct ssh_key sshk; + ssh_key sshk; }; struct ec_point *ec_public(const Bignum privateKey, const struct ec_curve *curve); @@ -391,31 +387,47 @@ struct ssh_kexes { }; struct ssh_keyalg { - ssh_key *(*newkey) (const ssh_keyalg *self, ptrlen data); + /* Constructors that create an ssh_key */ + ssh_key *(*new_pub) (const ssh_keyalg *self, ptrlen pub); + ssh_key *(*new_priv) (const ssh_keyalg *self, ptrlen pub, ptrlen priv); + ssh_key *(*new_priv_openssh) (const ssh_keyalg *self, BinarySource *); + + /* Methods that operate on an existing ssh_key */ void (*freekey) (ssh_key *key); - char *(*fmtkey) (ssh_key *key); + void (*sign) (ssh_key *key, const void *data, int datalen, BinarySink *); + int (*verify) (ssh_key *key, ptrlen sig, ptrlen data); void (*public_blob)(ssh_key *key, BinarySink *); void (*private_blob)(ssh_key *key, BinarySink *); - ssh_key *(*createkey) (const ssh_keyalg *self, ptrlen pub, ptrlen priv); - ssh_key *(*openssh_createkey) (const ssh_keyalg *self, BinarySource *); - void (*openssh_fmtkey) (ssh_key *key, BinarySink *); - /* OpenSSH private key blobs, as created by openssh_fmtkey and - * consumed by openssh_createkey, always (at least so far...) take - * the form of a number of SSH-2 strings / mpints concatenated - * end-to-end. Because the new-style OpenSSH private key format - * stores those blobs without a containing string wrapper, we need - * to know how many strings each one consists of, so that we can - * skip over the right number to find the next key in the file. - * openssh_private_npieces gives that information. */ - int openssh_private_npieces; + void (*openssh_blob) (ssh_key *key, BinarySink *); + char *(*cache_str) (ssh_key *key); + + /* 'Class methods' that don't deal with an ssh_key at all */ int (*pubkey_bits) (const ssh_keyalg *self, ptrlen blob); - int (*verifysig) (ssh_key *key, ptrlen sig, ptrlen data); - void (*sign) (ssh_key *key, const void *data, int datalen, BinarySink *); - const char *name; - const char *keytype; /* for host key cache */ - const void *extra; /* private to the public key methods */ + + /* Constant data fields giving information about the key type */ + const char *ssh_id; /* string identifier in the SSH protocol */ + const char *cache_id; /* identifier used in PuTTY's host key cache */ + const void *extra; /* private to the public key methods */ }; +#define ssh_key_new_pub(alg, data) ((alg)->new_pub(alg, data)) +#define ssh_key_new_priv(alg, pub, priv) ((alg)->new_priv(alg, pub, priv)) +#define ssh_key_new_priv_openssh(alg, bs) ((alg)->new_priv_openssh(alg, bs)) + +#define ssh_key_free(key) ((*(key))->freekey(key)) +#define ssh_key_sign(key, data, len, bs) ((*(key))->sign(key, data, len, bs)) +#define ssh_key_verify(key, sig, data) ((*(key))->verify(key, sig, data)) +#define ssh_key_public_blob(key, bs) ((*(key))->public_blob(key, bs)) +#define ssh_key_private_blob(key, bs) ((*(key))->private_blob(key, bs)) +#define ssh_key_openssh_blob(key, bs) ((*(key))->openssh_blob(key, bs)) +#define ssh_key_cache_str(key) ((*(key))->cache_str(key)) + +#define ssh_key_public_bits(alg, blob) ((alg)->pubkey_bits(alg, blob)) + +#define ssh_key_alg(key) (*(key)) +#define ssh_key_ssh_id(key) ((*(key))->ssh_id) +#define ssh_key_cache_id(key) ((*(key))->cache_id) + struct ssh_compress { const char *name; /* For zlib@openssh.com: if non-NULL, this name will be considered once @@ -434,8 +446,7 @@ struct ssh_compress { }; struct ssh2_userkey { - const ssh_keyalg *alg; /* the key algorithm */ - ssh_key *data; /* the key data */ + ssh_key *key; /* the key itself */ char *comment; /* the key comment */ }; @@ -782,7 +793,7 @@ void ssh2_write_pubkey(FILE *fp, const char *comment, const void *v_pub_blob, int pub_len, int keytype); char *ssh2_fingerprint_blob(const void *blob, int bloblen); -char *ssh2_fingerprint(const ssh_keyalg *alg, ssh_key *key); +char *ssh2_fingerprint(ssh_key *key); int key_type(const Filename *filename); const char *key_type_to_str(int type); diff --git a/sshdss.c b/sshdss.c index 3c9589fb..c4686645 100644 --- a/sshdss.c +++ b/sshdss.c @@ -11,7 +11,7 @@ static void dss_freekey(ssh_key *key); /* forward reference */ -static ssh_key *dss_newkey(const ssh_keyalg *self, ptrlen data) +static ssh_key *dss_new_pub(const ssh_keyalg *self, ptrlen data) { BinarySource src[1]; struct dss_key *dss; @@ -21,6 +21,7 @@ static ssh_key *dss_newkey(const ssh_keyalg *self, ptrlen data) return NULL; dss = snew(struct dss_key); + dss->sshk = &ssh_dss; dss->p = get_mp_ssh2(src); dss->q = get_mp_ssh2(src); dss->g = get_mp_ssh2(src); @@ -53,7 +54,7 @@ static void dss_freekey(ssh_key *key) sfree(dss); } -static char *dss_fmtkey(ssh_key *key) +static char *dss_cache_str(ssh_key *key) { struct dss_key *dss = FROMFIELD(key, struct dss_key, sshk); char *p; @@ -103,7 +104,7 @@ static char *dss_fmtkey(ssh_key *key) return p; } -static int dss_verifysig(ssh_key *key, ptrlen sig, ptrlen data) +static int dss_verify(ssh_key *key, ptrlen sig, ptrlen data) { struct dss_key *dss = FROMFIELD(key, struct dss_key, sshk); BinarySource src[1]; @@ -221,7 +222,7 @@ static void dss_private_blob(ssh_key *key, BinarySink *bs) put_mp_ssh2(bs, dss->x); } -static ssh_key *dss_createkey(const ssh_keyalg *self, ptrlen pub, ptrlen priv) +static ssh_key *dss_new_priv(const ssh_keyalg *self, ptrlen pub, ptrlen priv) { BinarySource src[1]; ssh_key *sshk; @@ -231,7 +232,7 @@ static ssh_key *dss_createkey(const ssh_keyalg *self, ptrlen pub, ptrlen priv) unsigned char digest[20]; Bignum ytest; - sshk = dss_newkey(self, pub); + sshk = dss_new_pub(self, pub); if (!sshk) return NULL; @@ -273,12 +274,13 @@ static ssh_key *dss_createkey(const ssh_keyalg *self, ptrlen pub, ptrlen priv) return &dss->sshk; } -static ssh_key *dss_openssh_createkey(const ssh_keyalg *self, - BinarySource *src) +static ssh_key *dss_new_priv_openssh(const ssh_keyalg *self, + BinarySource *src) { struct dss_key *dss; dss = snew(struct dss_key); + dss->sshk = &ssh_dss; dss->p = get_mp_ssh2(src); dss->q = get_mp_ssh2(src); @@ -296,7 +298,7 @@ static ssh_key *dss_openssh_createkey(const ssh_keyalg *self, return &dss->sshk; } -static void dss_openssh_fmtkey(ssh_key *key, BinarySink *bs) +static void dss_openssh_blob(ssh_key *key, BinarySink *bs) { struct dss_key *dss = FROMFIELD(key, struct dss_key, sshk); @@ -313,7 +315,7 @@ static int dss_pubkey_bits(const ssh_keyalg *self, ptrlen pub) struct dss_key *dss; int ret; - sshk = dss_newkey(self, pub); + sshk = dss_new_pub(self, pub); if (!sshk) return -1; @@ -485,18 +487,20 @@ static void dss_sign(ssh_key *key, const void *data, int datalen, } const ssh_keyalg ssh_dss = { - dss_newkey, + dss_new_pub, + dss_new_priv, + dss_new_priv_openssh, + dss_freekey, - dss_fmtkey, + dss_sign, + dss_verify, dss_public_blob, dss_private_blob, - dss_createkey, - dss_openssh_createkey, - dss_openssh_fmtkey, - 5 /* p,q,g,y,x */, + dss_openssh_blob, + dss_cache_str, + dss_pubkey_bits, - dss_verifysig, - dss_sign, + "ssh-dss", "dss", NULL, diff --git a/sshdssg.c b/sshdssg.c index 3d7b0ef6..882fbc1d 100644 --- a/sshdssg.c +++ b/sshdssg.c @@ -12,6 +12,8 @@ int dsa_generate(struct dss_key *key, int bits, progfn_t pfn, unsigned pfirst, qfirst; int progress; + key->sshk = &ssh_dss; + /* * Set up the phase limits for the progress report. We do this * by passing minus the phase number. diff --git a/sshecc.c b/sshecc.c index 0d97395a..ce663bfb 100644 --- a/sshecc.c +++ b/sshecc.c @@ -1713,7 +1713,7 @@ static void ecdsa_freekey(ssh_key *key) sfree(ec); } -static ssh_key *ecdsa_newkey(const ssh_keyalg *self, ptrlen data) +static ssh_key *ecdsa_new_pub(const ssh_keyalg *self, ptrlen data) { const struct ecsign_extra *extra = (const struct ecsign_extra *)self->extra; @@ -1734,8 +1734,8 @@ static ssh_key *ecdsa_newkey(const ssh_keyalg *self, ptrlen data) } ec = snew(struct ec_key); + ec->sshk = self; - ec->signalg = self; ec->publicKey.curve = curve; ec->publicKey.infinity = 0; ec->publicKey.x = NULL; @@ -1758,7 +1758,7 @@ static ssh_key *ecdsa_newkey(const ssh_keyalg *self, ptrlen data) return &ec->sshk; } -static char *ecdsa_fmtkey(ssh_key *key) +static char *ecdsa_cache_str(ssh_key *key) { struct ec_key *ec = FROMFIELD(key, struct ec_key, sshk); char *p; @@ -1810,7 +1810,7 @@ static void ecdsa_public_blob(ssh_key *key, BinarySink *bs) assert(pointlen >= 2); - put_stringz(bs, ec->signalg->name); + put_stringz(bs, ec->sshk->ssh_id); put_uint32(bs, pointlen); /* Unset last bit of y and set first bit of x in its place */ @@ -1824,7 +1824,7 @@ static void ecdsa_public_blob(ssh_key *key, BinarySink *bs) pointlen = (bignum_bitcount(ec->publicKey.curve->p) + 7) / 8; - put_stringz(bs, ec->signalg->name); + put_stringz(bs, ec->sshk->ssh_id); put_stringz(bs, ec->publicKey.curve->name); put_uint32(bs, (2 * pointlen) + 1); put_byte(bs, 0x04); @@ -1864,15 +1864,14 @@ static void ecdsa_private_blob(ssh_key *key, BinarySink *bs) } } -static ssh_key *ecdsa_createkey(const ssh_keyalg *self, - ptrlen pub, ptrlen priv) +static ssh_key *ecdsa_new_priv(const ssh_keyalg *self, ptrlen pub, ptrlen priv) { BinarySource src[1]; ssh_key *sshk; struct ec_key *ec; struct ec_point *publicKey; - sshk = ecdsa_newkey(self, pub); + sshk = ecdsa_new_pub(self, pub); if (!sshk) return NULL; @@ -1910,8 +1909,8 @@ static ssh_key *ecdsa_createkey(const ssh_keyalg *self, return &ec->sshk; } -static ssh_key *ed25519_openssh_createkey(const ssh_keyalg *self, - BinarySource *src) +static ssh_key *ed25519_new_priv_openssh(const ssh_keyalg *self, + BinarySource *src) { struct ec_key *ec; struct ec_point *publicKey; @@ -1923,8 +1922,8 @@ static ssh_key *ed25519_openssh_createkey(const ssh_keyalg *self, return NULL; ec = snew(struct ec_key); + ec->sshk = self; - ec->signalg = self; ec->publicKey.curve = ec_ed25519(); ec->publicKey.infinity = 0; ec->privateKey = NULL; @@ -1966,7 +1965,7 @@ static ssh_key *ed25519_openssh_createkey(const ssh_keyalg *self, return &ec->sshk; } -static void ed25519_openssh_fmtkey(ssh_key *key, BinarySink *bs) +static void ed25519_openssh_blob(ssh_key *key, BinarySink *bs) { struct ec_key *ec = FROMFIELD(key, struct ec_key, sshk); strbuf *pub; @@ -2002,8 +2001,8 @@ static void ed25519_openssh_fmtkey(ssh_key *key, BinarySink *bs) strbuf_free(pub); } -static ssh_key *ecdsa_openssh_createkey(const ssh_keyalg *self, - BinarySource *src) +static ssh_key *ecdsa_new_priv_openssh(const ssh_keyalg *self, + BinarySource *src) { const struct ecsign_extra *extra = (const struct ecsign_extra *)self->extra; @@ -2017,8 +2016,8 @@ static ssh_key *ecdsa_openssh_createkey(const ssh_keyalg *self, assert(curve->type == EC_WEIERSTRASS); ec = snew(struct ec_key); + ec->sshk = self; - ec->signalg = self; ec->publicKey.curve = curve; ec->publicKey.infinity = 0; ec->publicKey.x = NULL; @@ -2067,7 +2066,7 @@ static ssh_key *ecdsa_openssh_createkey(const ssh_keyalg *self, return &ec->sshk; } -static void ecdsa_openssh_fmtkey(ssh_key *key, BinarySink *bs) +static void ecdsa_openssh_blob(ssh_key *key, BinarySink *bs) { struct ec_key *ec = FROMFIELD(key, struct ec_key, sshk); @@ -2096,7 +2095,7 @@ static int ecdsa_pubkey_bits(const ssh_keyalg *self, ptrlen blob) struct ec_key *ec; int ret; - sshk = ecdsa_newkey(self, blob); + sshk = ecdsa_new_pub(self, blob); if (!sshk) return -1; @@ -2107,11 +2106,11 @@ static int ecdsa_pubkey_bits(const ssh_keyalg *self, ptrlen blob) return ret; } -static int ecdsa_verifysig(ssh_key *key, ptrlen sig, ptrlen data) +static int ecdsa_verify(ssh_key *key, ptrlen sig, ptrlen data) { struct ec_key *ec = FROMFIELD(key, struct ec_key, sshk); const struct ecsign_extra *extra = - (const struct ecsign_extra *)ec->signalg->extra; + (const struct ecsign_extra *)ec->sshk->extra; BinarySource src[1]; ptrlen sigstr; int ret; @@ -2122,7 +2121,7 @@ static int ecdsa_verifysig(ssh_key *key, ptrlen sig, ptrlen data) BinarySource_BARE_INIT(src, sig.ptr, sig.len); /* Check the signature starts with the algorithm name */ - if (!ptrlen_eq_string(get_string(src), ec->signalg->name)) + if (!ptrlen_eq_string(get_string(src), ec->sshk->ssh_id)) return 0; sigstr = get_string(src); @@ -2261,7 +2260,7 @@ static void ecdsa_sign(ssh_key *key, const void *data, int datalen, { struct ec_key *ec = FROMFIELD(key, struct ec_key, sshk); const struct ecsign_extra *extra = - (const struct ecsign_extra *)ec->signalg->extra; + (const struct ecsign_extra *)ec->sshk->extra; unsigned char digest[512 / 8]; int digestLen; Bignum r = NULL, s = NULL; @@ -2347,7 +2346,7 @@ static void ecdsa_sign(ssh_key *key, const void *data, int datalen, } /* Format the output */ - put_stringz(bs, ec->signalg->name); + put_stringz(bs, ec->sshk->ssh_id); pointlen = ec->publicKey.curve->fieldBits / 8; put_uint32(bs, pointlen * 2); @@ -2379,7 +2378,7 @@ static void ecdsa_sign(ssh_key *key, const void *data, int datalen, assert(s); /* Format the output */ - put_stringz(bs, ec->signalg->name); + put_stringz(bs, ec->sshk->ssh_id); substr = strbuf_new(); put_mp_ssh2(substr, r); @@ -2396,18 +2395,20 @@ const struct ecsign_extra sign_extra_ed25519 = { NULL, 0, }; const ssh_keyalg ssh_ecdsa_ed25519 = { - ecdsa_newkey, + ecdsa_new_pub, + ecdsa_new_priv, + ed25519_new_priv_openssh, + ecdsa_freekey, - ecdsa_fmtkey, + ecdsa_sign, + ecdsa_verify, ecdsa_public_blob, ecdsa_private_blob, - ecdsa_createkey, - ed25519_openssh_createkey, - ed25519_openssh_fmtkey, - 2 /* point, private exponent */, + ed25519_openssh_blob, + ecdsa_cache_str, + ecdsa_pubkey_bits, - ecdsa_verifysig, - ecdsa_sign, + "ssh-ed25519", "ssh-ed25519", &sign_extra_ed25519, @@ -2422,18 +2423,20 @@ const struct ecsign_extra sign_extra_nistp256 = { nistp256_oid, lenof(nistp256_oid), }; const ssh_keyalg ssh_ecdsa_nistp256 = { - ecdsa_newkey, + ecdsa_new_pub, + ecdsa_new_priv, + ecdsa_new_priv_openssh, + ecdsa_freekey, - ecdsa_fmtkey, + ecdsa_sign, + ecdsa_verify, ecdsa_public_blob, ecdsa_private_blob, - ecdsa_createkey, - ecdsa_openssh_createkey, - ecdsa_openssh_fmtkey, - 3 /* curve name, point, private exponent */, + ecdsa_openssh_blob, + ecdsa_cache_str, + ecdsa_pubkey_bits, - ecdsa_verifysig, - ecdsa_sign, + "ecdsa-sha2-nistp256", "ecdsa-sha2-nistp256", &sign_extra_nistp256, @@ -2448,18 +2451,20 @@ const struct ecsign_extra sign_extra_nistp384 = { nistp384_oid, lenof(nistp384_oid), }; const ssh_keyalg ssh_ecdsa_nistp384 = { - ecdsa_newkey, + ecdsa_new_pub, + ecdsa_new_priv, + ecdsa_new_priv_openssh, + ecdsa_freekey, - ecdsa_fmtkey, + ecdsa_sign, + ecdsa_verify, ecdsa_public_blob, ecdsa_private_blob, - ecdsa_createkey, - ecdsa_openssh_createkey, - ecdsa_openssh_fmtkey, - 3 /* curve name, point, private exponent */, + ecdsa_openssh_blob, + ecdsa_cache_str, + ecdsa_pubkey_bits, - ecdsa_verifysig, - ecdsa_sign, + "ecdsa-sha2-nistp384", "ecdsa-sha2-nistp384", &sign_extra_nistp384, @@ -2474,18 +2479,20 @@ const struct ecsign_extra sign_extra_nistp521 = { nistp521_oid, lenof(nistp521_oid), }; const ssh_keyalg ssh_ecdsa_nistp521 = { - ecdsa_newkey, + ecdsa_new_pub, + ecdsa_new_priv, + ecdsa_new_priv_openssh, + ecdsa_freekey, - ecdsa_fmtkey, + ecdsa_sign, + ecdsa_verify, ecdsa_public_blob, ecdsa_private_blob, - ecdsa_createkey, - ecdsa_openssh_createkey, - ecdsa_openssh_fmtkey, - 3 /* curve name, point, private exponent */, + ecdsa_openssh_blob, + ecdsa_cache_str, + ecdsa_pubkey_bits, - ecdsa_verifysig, - ecdsa_sign, + "ecdsa-sha2-nistp521", "ecdsa-sha2-nistp521", &sign_extra_nistp521, @@ -2559,7 +2566,7 @@ struct ec_key *ssh_ecdhkex_newkey(const struct ssh_kex *kex) key = snew(struct ec_key); - key->signalg = NULL; + key->sshk = NULL; key->publicKey.curve = curve; if (curve->type == EC_MONTGOMERY) { diff --git a/sshecdsag.c b/sshecdsag.c index 83eeeb03..7523fa7a 100644 --- a/sshecdsag.c +++ b/sshecdsag.c @@ -13,7 +13,7 @@ int ec_generate(struct ec_key *key, int bits, progfn_t pfn, struct ec_point *publicKey; if (!ec_nist_alg_and_curve_by_bits(bits, &key->publicKey.curve, - &key->signalg)) + &key->sshk)) return 0; key->privateKey = bignum_random_in_range(One, key->publicKey.curve->w.n); @@ -40,7 +40,7 @@ int ec_edgenerate(struct ec_key *key, int bits, progfn_t pfn, struct ec_point *publicKey; if (!ec_ed_alg_and_curve_by_bits(bits, &key->publicKey.curve, - &key->signalg)) + &key->sshk)) return 0; { diff --git a/sshpubk.c b/sshpubk.c index 6c63674b..3732a6f2 100644 --- a/sshpubk.c +++ b/sshpubk.c @@ -563,9 +563,7 @@ static int read_blob(FILE *fp, int nlines, BinarySink *bs) /* * Magic error return value for when the passphrase is wrong. */ -struct ssh2_userkey ssh2_wrong_passphrase = { - NULL, NULL, NULL -}; +struct ssh2_userkey ssh2_wrong_passphrase = { NULL, NULL }; const ssh_keyalg *find_pubkey_alg_len(ptrlen name) { @@ -741,7 +739,7 @@ struct ssh2_userkey *ssh2_load_userkey(const Filename *filename, free_macdata = FALSE; } else { macdata = strbuf_new(); - put_stringz(macdata, alg->name); + put_stringz(macdata, alg->ssh_id); put_stringz(macdata, encryption); put_stringz(macdata, comment); put_string(macdata, public_blob->s, @@ -797,12 +795,11 @@ struct ssh2_userkey *ssh2_load_userkey(const Filename *filename, * Create and return the key. */ ret = snew(struct ssh2_userkey); - ret->alg = alg; ret->comment = comment; - ret->data = alg->createkey( + ret->key = ssh_key_new_priv( alg, make_ptrlen(public_blob->u, public_blob->len), make_ptrlen(private_blob->u, private_blob->len)); - if (!ret->data) { + if (!ret->key) { sfree(ret); ret = NULL; error = "createkey failed"; @@ -1129,7 +1126,7 @@ int ssh2_userkey_loadpub(const Filename *filename, char **algorithm, fclose(fp); if (algorithm) - *algorithm = dupstr(alg->name); + *algorithm = dupstr(alg->ssh_id); return TRUE; /* @@ -1252,9 +1249,9 @@ int ssh2_save_userkey(const Filename *filename, struct ssh2_userkey *key, * Fetch the key component blobs. */ pub_blob = strbuf_new(); - key->alg->public_blob(key->data, BinarySink_UPCAST(pub_blob)); + ssh_key_public_blob(key->key, BinarySink_UPCAST(pub_blob)); priv_blob = strbuf_new(); - key->alg->private_blob(key->data, BinarySink_UPCAST(priv_blob)); + ssh_key_private_blob(key->key, BinarySink_UPCAST(priv_blob)); /* * Determine encryption details, and encrypt the private blob. @@ -1286,7 +1283,7 @@ int ssh2_save_userkey(const Filename *filename, struct ssh2_userkey *key, char header[] = "putty-private-key-file-mac-key"; macdata = strbuf_new(); - put_stringz(macdata, key->alg->name); + put_stringz(macdata, ssh_key_ssh_id(key->key)); put_stringz(macdata, cipherstr); put_stringz(macdata, key->comment); put_string(macdata, pub_blob->s, pub_blob->len); @@ -1333,7 +1330,7 @@ int ssh2_save_userkey(const Filename *filename, struct ssh2_userkey *key, sfree(priv_blob_encrypted); return 0; } - fprintf(fp, "PuTTY-User-Key-File-2: %s\n", key->alg->name); + fprintf(fp, "PuTTY-User-Key-File-2: %s\n", ssh_key_ssh_id(key->key)); fprintf(fp, "Encryption: %s\n", cipherstr); fprintf(fp, "Comment: %s\n", key->comment); fprintf(fp, "Public-Lines: %d\n", base64_lines(pub_blob->len)); @@ -1425,7 +1422,7 @@ char *ssh2_pubkey_openssh_str(struct ssh2_userkey *key) char *ret; blob = strbuf_new(); - key->alg->public_blob(key->data, BinarySink_UPCAST(blob)); + ssh_key_public_blob(key->key, BinarySink_UPCAST(blob)); ret = ssh2_pubkey_openssh_str_internal( key->comment, blob->s, blob->len); strbuf_free(blob); @@ -1510,7 +1507,7 @@ char *ssh2_fingerprint_blob(const void *blob, int bloblen) if (!get_err(src)) { alg = find_pubkey_alg_len(algname); if (alg) { - int bits = alg->pubkey_bits(alg, make_ptrlen(blob, bloblen)); + int bits = ssh_key_public_bits(alg, make_ptrlen(blob, bloblen)); return dupprintf("%.*s %d %s", PTRLEN_PRINTF(algname), bits, fingerprint_str); } else { @@ -1526,10 +1523,10 @@ char *ssh2_fingerprint_blob(const void *blob, int bloblen) } } -char *ssh2_fingerprint(const ssh_keyalg *alg, ssh_key *data) +char *ssh2_fingerprint(ssh_key *data) { strbuf *blob = strbuf_new(); - alg->public_blob(data, BinarySink_UPCAST(blob)); + ssh_key_public_blob(data, BinarySink_UPCAST(blob)); char *ret = ssh2_fingerprint_blob(blob->s, blob->len); strbuf_free(blob); return ret; diff --git a/sshrsa.c b/sshrsa.c index 9c99f99b..f66af550 100644 --- a/sshrsa.c +++ b/sshrsa.c @@ -474,7 +474,7 @@ void freersakey(struct RSAKey *key) static void rsa2_freekey(ssh_key *key); /* forward reference */ -static ssh_key *rsa2_newkey(const ssh_keyalg *self, ptrlen data) +static ssh_key *rsa2_new_pub(const ssh_keyalg *self, ptrlen data) { BinarySource src[1]; struct RSAKey *rsa; @@ -484,6 +484,7 @@ static ssh_key *rsa2_newkey(const ssh_keyalg *self, ptrlen data) return NULL; rsa = snew(struct RSAKey); + rsa->sshk = &ssh_rsa; rsa->exponent = get_mp_ssh2(src); rsa->modulus = get_mp_ssh2(src); rsa->private_exponent = NULL; @@ -505,7 +506,7 @@ static void rsa2_freekey(ssh_key *key) sfree(rsa); } -static char *rsa2_fmtkey(ssh_key *key) +static char *rsa2_cache_str(ssh_key *key) { struct RSAKey *rsa = FROMFIELD(key, struct RSAKey, sshk); char *p; @@ -536,14 +537,14 @@ static void rsa2_private_blob(ssh_key *key, BinarySink *bs) put_mp_ssh2(bs, rsa->iqmp); } -static ssh_key *rsa2_createkey(const ssh_keyalg *self, +static ssh_key *rsa2_new_priv(const ssh_keyalg *self, ptrlen pub, ptrlen priv) { BinarySource src[1]; ssh_key *sshk; struct RSAKey *rsa; - sshk = rsa2_newkey(self, pub); + sshk = rsa2_new_pub(self, pub); if (!sshk) return NULL; @@ -562,12 +563,13 @@ static ssh_key *rsa2_createkey(const ssh_keyalg *self, return &rsa->sshk; } -static ssh_key *rsa2_openssh_createkey(const ssh_keyalg *self, - BinarySource *src) +static ssh_key *rsa2_new_priv_openssh(const ssh_keyalg *self, + BinarySource *src) { struct RSAKey *rsa; rsa = snew(struct RSAKey); + rsa->sshk = &ssh_rsa; rsa->comment = NULL; rsa->modulus = get_mp_ssh2(src); @@ -585,7 +587,7 @@ static ssh_key *rsa2_openssh_createkey(const ssh_keyalg *self, return &rsa->sshk; } -static void rsa2_openssh_fmtkey(ssh_key *key, BinarySink *bs) +static void rsa2_openssh_blob(ssh_key *key, BinarySink *bs) { struct RSAKey *rsa = FROMFIELD(key, struct RSAKey, sshk); @@ -603,7 +605,7 @@ static int rsa2_pubkey_bits(const ssh_keyalg *self, ptrlen pub) struct RSAKey *rsa; int ret; - sshk = rsa2_newkey(self, pub); + sshk = rsa2_new_pub(self, pub); if (!sshk) return -1; @@ -645,7 +647,7 @@ static const unsigned char asn1_weird_stuff[] = { #define ASN1_LEN ( (int) sizeof(asn1_weird_stuff) ) -static int rsa2_verifysig(ssh_key *key, ptrlen sig, ptrlen data) +static int rsa2_verify(ssh_key *key, ptrlen sig, ptrlen data) { struct RSAKey *rsa = FROMFIELD(key, struct RSAKey, sshk); BinarySource src[1]; @@ -744,18 +746,20 @@ static void rsa2_sign(ssh_key *key, const void *data, int datalen, } const ssh_keyalg ssh_rsa = { - rsa2_newkey, + rsa2_new_pub, + rsa2_new_priv, + rsa2_new_priv_openssh, + rsa2_freekey, - rsa2_fmtkey, + rsa2_sign, + rsa2_verify, rsa2_public_blob, rsa2_private_blob, - rsa2_createkey, - rsa2_openssh_createkey, - rsa2_openssh_fmtkey, - 6 /* n,e,d,iqmp,q,p */, + rsa2_openssh_blob, + rsa2_cache_str, + rsa2_pubkey_bits, - rsa2_verifysig, - rsa2_sign, + "ssh-rsa", "rsa2", NULL, @@ -763,7 +767,7 @@ const ssh_keyalg ssh_rsa = { struct RSAKey *ssh_rsakex_newkey(const void *data, int len) { - ssh_key *sshk = rsa2_newkey(&ssh_rsa, make_ptrlen(data, len)); + ssh_key *sshk = rsa2_new_pub(&ssh_rsa, make_ptrlen(data, len)); if (!sshk) return NULL; return FROMFIELD(sshk, struct RSAKey, sshk); diff --git a/sshrsag.c b/sshrsag.c index d754890d..7800ec94 100644 --- a/sshrsag.c +++ b/sshrsag.c @@ -14,6 +14,8 @@ int rsa_generate(struct RSAKey *key, int bits, progfn_t pfn, Bignum pm1, qm1, phi_n; unsigned pfirst, qfirst; + key->sshk = &ssh_rsa; + /* * Set up the phase limits for the progress report. We do this * by passing minus the phase number. diff --git a/windows/winpgen.c b/windows/winpgen.c index bc68148f..fecd4f00 100644 --- a/windows/winpgen.c +++ b/windows/winpgen.c @@ -769,7 +769,7 @@ void load_key_file(HWND hwnd, struct MainDlgState *state, savecomment = state->ssh2key.comment; state->ssh2key.comment = NULL; - fp = ssh2_fingerprint(state->ssh2key.alg, state->ssh2key.data); + fp = ssh2_fingerprint(state->ssh2key.key); state->ssh2key.comment = savecomment; SetDlgItemText(hwnd, IDC_FINGERPRINT, fp); @@ -1321,8 +1321,8 @@ static INT_PTR CALLBACK MainDlgProc(HWND hwnd, UINT msg, } else { if (state->ssh2) { strbuf *blob = strbuf_new(); - state->ssh2key.alg->public_blob( - state->ssh2key.data, BinarySink_UPCAST(blob)); + ssh_key_public_blob( + state->ssh2key.key, BinarySink_UPCAST(blob)); ssh2_write_pubkey(fp, state->ssh2key.comment, blob->u, blob->len, SSH_KEYTYPE_SSH2_PUBLIC_RFC4716); @@ -1365,17 +1365,13 @@ static INT_PTR CALLBACK MainDlgProc(HWND hwnd, UINT msg, SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETPOS, PROGRESSRANGE, 0); if (state->ssh2) { if (state->keytype == DSA) { - state->ssh2key.data = &state->dsskey.sshk; - state->ssh2key.alg = &ssh_dss; + state->ssh2key.key = &state->dsskey.sshk; } else if (state->keytype == ECDSA) { - state->ssh2key.data = &state->eckey.sshk; - state->ssh2key.alg = state->eckey.signalg; + state->ssh2key.key = &state->eckey.sshk; } else if (state->keytype == ED25519) { - state->ssh2key.data = &state->eckey.sshk; - state->ssh2key.alg = &ssh_ecdsa_ed25519; + state->ssh2key.key = &state->eckey.sshk; } else { - state->ssh2key.data = &state->key.sshk; - state->ssh2key.alg = &ssh_rsa; + state->ssh2key.key = &state->key.sshk; } state->commentptr = &state->ssh2key.comment; } else { @@ -1423,7 +1419,7 @@ static INT_PTR CALLBACK MainDlgProc(HWND hwnd, UINT msg, savecomment = *state->commentptr; *state->commentptr = NULL; if (state->ssh2) - fp = ssh2_fingerprint(state->ssh2key.alg, state->ssh2key.data); + fp = ssh2_fingerprint(state->ssh2key.key); else fp = rsa_ssh1_fingerprint(&state->key); SetDlgItemText(hwnd, IDC_FINGERPRINT, fp); diff --git a/windows/winpgnt.c b/windows/winpgnt.c index 43266440..4aff8338 100644 --- a/windows/winpgnt.c +++ b/windows/winpgnt.c @@ -339,7 +339,7 @@ void keylist_update(void) * stop and leave out a tab character. Urgh. */ - p = ssh2_fingerprint(skey->alg, skey->data); + p = ssh2_fingerprint(skey->key); listentry = dupprintf("%s\t%s", p, skey->comment); sfree(p); @@ -350,7 +350,8 @@ void keylist_update(void) break; listentry[pos++] = '\t'; } - if (skey->alg != &ssh_dss && skey->alg != &ssh_rsa) { + if (ssh_key_alg(skey->key) != &ssh_dss && + ssh_key_alg(skey->key) != &ssh_rsa) { /* * Remove the bit-count field, which is between the * first and second \t. @@ -647,7 +648,7 @@ static INT_PTR CALLBACK KeyListProc(HWND hwnd, UINT msg, if (selectedArray[itemNum] == rCount + i) { pageant_delete_ssh2_key(skey); - skey->alg->freekey(skey->data); + ssh_key_free(skey->key); sfree(skey); itemNum--; } From 025599ec999dd8454f2a8fdd11c08329ac608571 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 3 Jun 2018 14:30:28 +0100 Subject: [PATCH 348/607] Unix PuTTYgen: switch to /dev/urandom by default. The general wisdom these days - in particular as given by the Linux urandom(4) man page - seems to be that there's no need to use the blocking /dev/random any more unless you're running at very early boot time when the system random pool is at serious risk of not having any entropy in it at all. In case of non-Linux systems that don't think /dev/urandom is a standard name, I fall back to /dev/random if /dev/urandom can't be found. --- unix/uxgen.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/unix/uxgen.c b/unix/uxgen.c index f593a960..ed14188d 100644 --- a/unix/uxgen.c +++ b/unix/uxgen.c @@ -16,8 +16,26 @@ char *get_random_data(int len, const char *device) int fd; int ngot, ret; - if (!device) - device = "/dev/random"; + if (!device) { + static const char *const default_devices[] = { + "/dev/urandom", "/dev/random" + }; + size_t i; + + for (i = 0; i < lenof(default_devices); i++) { + if (access(default_devices[i], R_OK) == 0) { + device = default_devices[i]; + break; + } + } + + if (!device) { + sfree(buf); + fprintf(stderr, "puttygen: cannot find a readable " + "random number source; use --random-device\n"); + return NULL; + } + } fd = open(device, O_RDONLY); if (fd < 0) { From 6142013abc701f235772e3caf94246420b1ac9d4 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 3 Jun 2018 14:41:31 +0100 Subject: [PATCH 349/607] Windows PuTTYgen: switch to CryptGenRandom. We now only use the mouse-movement based entropy collection system if the system CPRNG fails to provide us with as much entropy as we want. --- windows/winnoise.c | 44 ++++++++------ windows/winpgen.c | 145 +++++++++++++++++++++++++++------------------ windows/winstuff.h | 5 ++ 3 files changed, 120 insertions(+), 74 deletions(-) diff --git a/windows/winnoise.c b/windows/winnoise.c index 31364546..1dd0481b 100644 --- a/windows/winnoise.c +++ b/windows/winnoise.c @@ -19,6 +19,29 @@ DECL_WINDOWS_FUNCTION(static, BOOL, CryptReleaseContext, (HCRYPTPROV, DWORD)); static HMODULE wincrypt_module = NULL; +int win_read_random(void *buf, unsigned wanted) +{ + int toret = FALSE; + HCRYPTPROV crypt_provider; + + if (!wincrypt_module) { + wincrypt_module = load_system32_dll("advapi32.dll"); + GET_WINDOWS_FUNCTION(wincrypt_module, CryptAcquireContextA); + GET_WINDOWS_FUNCTION(wincrypt_module, CryptGenRandom); + GET_WINDOWS_FUNCTION(wincrypt_module, CryptReleaseContext); + } + + if (wincrypt_module && p_CryptAcquireContextA && + p_CryptGenRandom && p_CryptReleaseContext && + p_CryptAcquireContextA(&crypt_provider, NULL, NULL, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT)) { + toret = p_CryptGenRandom(crypt_provider, wanted, buf); + p_CryptReleaseContext(crypt_provider, 0); + } + + return toret; +} + /* * This function is called once, at PuTTY startup. */ @@ -28,8 +51,8 @@ void noise_get_heavy(void (*func) (void *, int)) HANDLE srch; WIN32_FIND_DATA finddata; DWORD pid; - HCRYPTPROV crypt_provider; char winpath[MAX_PATH + 3]; + BYTE buf[32]; GetWindowsDirectory(winpath, sizeof(winpath)); strcat(winpath, "\\*"); @@ -44,22 +67,9 @@ void noise_get_heavy(void (*func) (void *, int)) pid = GetCurrentProcessId(); func(&pid, sizeof(pid)); - if (!wincrypt_module) { - wincrypt_module = load_system32_dll("advapi32.dll"); - GET_WINDOWS_FUNCTION(wincrypt_module, CryptAcquireContextA); - GET_WINDOWS_FUNCTION(wincrypt_module, CryptGenRandom); - GET_WINDOWS_FUNCTION(wincrypt_module, CryptReleaseContext); - } - - if (wincrypt_module && p_CryptAcquireContextA && - p_CryptGenRandom && p_CryptReleaseContext && - p_CryptAcquireContextA(&crypt_provider, NULL, NULL, PROV_RSA_FULL, - CRYPT_VERIFYCONTEXT)) { - BYTE buf[32]; - if (p_CryptGenRandom(crypt_provider, 32, buf)) { - func(buf, sizeof(buf)); - } - p_CryptReleaseContext(crypt_provider, 0); + if (win_read_random(buf, sizeof(buf))) { + func(buf, sizeof(buf)); + smemclr(buf, sizeof(buf)); } read_random_seed(func); diff --git a/windows/winpgen.c b/windows/winpgen.c index fecd4f00..d2840113 100644 --- a/windows/winpgen.c +++ b/windows/winpgen.c @@ -809,14 +809,45 @@ void load_key_file(HWND hwnd, struct MainDlgState *state, burnstr(passphrase); } +static void start_generating_key(HWND hwnd, struct MainDlgState *state) +{ + static const char generating_msg[] = + "Please wait while a key is generated..."; + + struct rsa_key_thread_params *params; + DWORD threadid; + + SetDlgItemText(hwnd, IDC_GENERATING, generating_msg); + SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETRANGE, 0, + MAKELPARAM(0, PROGRESSRANGE)); + SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETPOS, 0, 0); + + params = snew(struct rsa_key_thread_params); + params->progressbar = GetDlgItem(hwnd, IDC_PROGRESS); + params->dialog = hwnd; + params->key_bits = state->key_bits; + params->curve_bits = state->curve_bits; + params->keytype = state->keytype; + params->key = &state->key; + params->dsskey = &state->dsskey; + + if (!CreateThread(NULL, 0, generate_key_thread, + params, 0, &threadid)) { + MessageBox(hwnd, "Out of thread resources", + "Key generation error", + MB_OK | MB_ICONERROR); + sfree(params); + } else { + state->generation_thread_exists = TRUE; + } +} + /* * Dialog-box function for the main PuTTYgen dialog box. */ static INT_PTR CALLBACK MainDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { - static const char generating_msg[] = - "Please wait while a key is generated..."; static const char entropy_msg[] = "Please generate some randomness by moving the mouse over the blank area."; struct MainDlgState *state; @@ -1009,9 +1040,6 @@ static INT_PTR CALLBACK MainDlgProc(HWND hwnd, UINT msg, SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETPOS, state->entropy_got, 0); if (state->entropy_got >= state->entropy_required) { - struct rsa_key_thread_params *params; - DWORD threadid; - /* * Seed the entropy pool */ @@ -1020,29 +1048,7 @@ static INT_PTR CALLBACK MainDlgProc(HWND hwnd, UINT msg, sfree(state->entropy); state->collecting_entropy = FALSE; - SetDlgItemText(hwnd, IDC_GENERATING, generating_msg); - SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETRANGE, 0, - MAKELPARAM(0, PROGRESSRANGE)); - SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETPOS, 0, 0); - - params = snew(struct rsa_key_thread_params); - params->progressbar = GetDlgItem(hwnd, IDC_PROGRESS); - params->dialog = hwnd; - params->key_bits = state->key_bits; - params->curve_bits = state->curve_bits; - params->keytype = state->keytype; - params->key = &state->key; - params->dsskey = &state->dsskey; - - if (!CreateThread(NULL, 0, generate_key_thread, - params, 0, &threadid)) { - MessageBox(hwnd, "Out of thread resources", - "Key generation error", - MB_OK | MB_ICONERROR); - sfree(params); - } else { - state->generation_thread_exists = TRUE; - } + start_generating_key(hwnd, state); } } break; @@ -1102,6 +1108,8 @@ static INT_PTR CALLBACK MainDlgProc(HWND hwnd, UINT msg, state = (struct MainDlgState *) GetWindowLongPtr(hwnd, GWLP_USERDATA); if (!state->generation_thread_exists) { + unsigned raw_entropy_required; + unsigned char *raw_entropy_buf; BOOL ok; state->key_bits = GetDlgItemInt(hwnd, IDC_BITS, &ok, FALSE); if (!ok) @@ -1149,39 +1157,62 @@ static INT_PTR CALLBACK MainDlgProc(HWND hwnd, UINT msg, break; } - ui_set_state(hwnd, state, 1); - SetDlgItemText(hwnd, IDC_GENERATING, entropy_msg); - state->key_exists = FALSE; - state->collecting_entropy = TRUE; - - /* - * My brief statistical tests on mouse movements - * suggest that there are about 2.5 bits of - * randomness in the x position, 2.5 in the y - * position, and 1.7 in the message time, making - * 5.7 bits of unpredictability per mouse movement. - * However, other people have told me it's far less - * than that, so I'm going to be stupidly cautious - * and knock that down to a nice round 2. With this - * method, we require two words per mouse movement, - * so with 2 bits per mouse movement we expect 2 - * bits every 2 words. - */ if (state->keytype == RSA || state->keytype == DSA) - state->entropy_required = (state->key_bits / 2) * 2; + raw_entropy_required = (state->key_bits / 2) * 2; else if (state->keytype == ECDSA) - state->entropy_required = (state->curve_bits / 2) * 2; + raw_entropy_required = (state->curve_bits / 2) * 2; else - state->entropy_required = 256; - - state->entropy_got = 0; - state->entropy_size = (state->entropy_required * - sizeof(unsigned)); - state->entropy = snewn(state->entropy_required, unsigned); + raw_entropy_required = 256; + + raw_entropy_buf = snewn(raw_entropy_required, unsigned char); + if (win_read_random(raw_entropy_buf, raw_entropy_required)) { + /* + * If we can get the entropy we need from + * CryptGenRandom, just do that, and go straight + * to the key-generation phase. + */ + random_add_heavynoise(raw_entropy_buf, + raw_entropy_required); + start_generating_key(hwnd, state); + } else { + /* + * Manual entropy input, by making the user wave + * the mouse over the window a lot. + * + * My brief statistical tests on mouse movements + * suggest that there are about 2.5 bits of + * randomness in the x position, 2.5 in the y + * position, and 1.7 in the message time, making + * 5.7 bits of unpredictability per mouse + * movement. However, other people have told me + * it's far less than that, so I'm going to be + * stupidly cautious and knock that down to a nice + * round 2. With this method, we require two words + * per mouse movement, so with 2 bits per mouse + * movement we expect 2 bits every 2 words, i.e. + * the number of _words_ of mouse data we want to + * collect is just the same as the number of + * _bits_ of entropy we want. + */ + state->entropy_required = raw_entropy_required; + + ui_set_state(hwnd, state, 1); + SetDlgItemText(hwnd, IDC_GENERATING, entropy_msg); + state->key_exists = FALSE; + state->collecting_entropy = TRUE; + + state->entropy_got = 0; + state->entropy_size = (state->entropy_required * + sizeof(unsigned)); + state->entropy = snewn(state->entropy_required, unsigned); + + SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETRANGE, 0, + MAKELPARAM(0, state->entropy_required)); + SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETPOS, 0, 0); + } - SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETRANGE, 0, - MAKELPARAM(0, state->entropy_required)); - SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETPOS, 0, 0); + smemclr(raw_entropy_buf, raw_entropy_required); + sfree(raw_entropy_buf); } break; case IDC_SAVE: diff --git a/windows/winstuff.h b/windows/winstuff.h index a41974f1..20e8b97e 100644 --- a/windows/winstuff.h +++ b/windows/winstuff.h @@ -607,6 +607,11 @@ void remove_session_from_jumplist(const char * const sessionname); void clear_jumplist(void); BOOL set_explicit_app_user_model_id(); +/* + * Exports from winnoise.c. + */ +int win_read_random(void *buf, unsigned wanted); /* returns TRUE on success */ + /* * Extra functions in winstore.c over and above the interface in * storage.h. From f1fae1bfaa6c409f0a37dcaada73ebe2fb8f1b35 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 3 Jun 2018 14:53:29 +0100 Subject: [PATCH 350/607] Fix a Windows warning on a strange cast. The specific thing that's strange about it is that it's _not_ an error even though the compiler is quite justified in being suspicious about it! The MS APIs define two different structures to have identical formats. --- windows/wingss.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/windows/wingss.c b/windows/wingss.c index c9bd2b31..4b511b2a 100644 --- a/windows/wingss.c +++ b/windows/wingss.c @@ -369,8 +369,23 @@ static void localexp_to_exp_lifetime(TimeStamp *localexp, if (expiry) *expiry = GSS_NO_EXPIRATION; - if (!LocalFileTimeToFileTime(localexp, &expUTC)) - return; + /* + * Type oddity: localexp is a pointer to 'TimeStamp', whereas + * LocalFileTimeToFileTime expects a pointer to FILETIME. However, + * despite having different formal type names from the compiler's + * point of view, these two structures are specified to be + * isomorphic in the MS documentation, so it's legitimate to copy + * between them: + * + * https://msdn.microsoft.com/en-us/library/windows/desktop/aa380511(v=vs.85).aspx + */ + { + FILETIME localexp_ft; + enum { vorpal_sword = 1 / (sizeof(*localexp) == sizeof(localexp_ft)) }; + memcpy(&localexp_ft, localexp, sizeof(localexp_ft)); + if (!LocalFileTimeToFileTime(&localexp_ft, &expUTC)) + return; + } TIME_WIN_TO_POSIX(expUTC, exp); delta = exp - now; From 869a0f5f710129f775d8d9384ce46e6115e1cfeb Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 3 Jun 2018 15:05:44 +0100 Subject: [PATCH 351/607] Fix Windows warning about GetVersionEx deprecation. Rather than squelching the warning, I'm actually paying attention to the deprecation, in that I'm allowing for the possibility that the function might stop existing or stop returning success. --- windows/window.c | 29 +++++++++++------------------ windows/winjump.c | 6 ++---- windows/winmisc.c | 37 ++++++++++++++++++++++++++++++++++--- windows/winpgnt.c | 10 ++-------- windows/winprint.c | 2 +- windows/winstuff.h | 4 ++-- 6 files changed, 52 insertions(+), 36 deletions(-) diff --git a/windows/window.c b/windows/window.c index 88a251fe..c635720d 100644 --- a/windows/window.c +++ b/windows/window.c @@ -374,23 +374,15 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) * config box. */ defuse_showwindow(); - if (!init_winver()) - { - char *str = dupprintf("%s Fatal Error", appname); - MessageBox(NULL, "Windows refuses to report a version", - str, MB_OK | MB_ICONEXCLAMATION); - sfree(str); - return 1; - } + init_winver(); /* * If we're running a version of Windows that doesn't support * WM_MOUSEWHEEL, find out what message number we should be * using instead. */ - if (osVersion.dwMajorVersion < 4 || - (osVersion.dwMajorVersion == 4 && - osVersion.dwPlatformId != VER_PLATFORM_WIN32_NT)) + if (osMajorVersion < 4 || + (osMajorVersion == 4 && osPlatformId != VER_PLATFORM_WIN32_NT)) wm_mousewheel = RegisterWindowMessage("MSWHEEL_ROLLMSG"); init_help(); @@ -3111,8 +3103,9 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, int n; char *buff; - if(osVersion.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS || - osVersion.dwPlatformId == VER_PLATFORM_WIN32s) break; /* no Unicode */ + if (osPlatformId == VER_PLATFORM_WIN32_WINDOWS || + osPlatformId == VER_PLATFORM_WIN32s) + break; /* no Unicode */ if ((lParam & GCS_RESULTSTR) == 0) /* Composition unfinished. */ break; /* fall back to DefWindowProc */ @@ -3317,10 +3310,10 @@ static void sys_cursor_update(void) SetCaretPos(caret_x, caret_y); /* IMM calls on Win98 and beyond only */ - if(osVersion.dwPlatformId == VER_PLATFORM_WIN32s) return; /* 3.11 */ + if (osPlatformId == VER_PLATFORM_WIN32s) return; /* 3.11 */ - if(osVersion.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS && - osVersion.dwMinorVersion == 0) return; /* 95 */ + if (osPlatformId == VER_PLATFORM_WIN32_WINDOWS && + osMinorVersion == 0) return; /* 95 */ /* we should have the IMM functions */ hIMC = ImmGetContext(hwnd); @@ -4672,7 +4665,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, /* XXX how do we know what the max size of the keys array should * be is? There's indication on MS' website of an Inquire/InquireEx * functioning returning a KBINFO structure which tells us. */ - if (osVersion.dwPlatformId == VER_PLATFORM_WIN32_NT && p_ToUnicodeEx) { + if (osPlatformId == VER_PLATFORM_WIN32_NT && p_ToUnicodeEx) { r = p_ToUnicodeEx(wParam, scan, keystate, keys_unicode, lenof(keys_unicode), 0, kbd_layout); } else { @@ -5671,7 +5664,7 @@ void do_beep(void *frontend, int mode) * We must beep in different ways depending on whether this * is a 95-series or NT-series OS. */ - if(osVersion.dwPlatformId == VER_PLATFORM_WIN32_NT) + if (osPlatformId == VER_PLATFORM_WIN32_NT) Beep(800, 100); else MessageBeep(-1); diff --git a/windows/winjump.c b/windows/winjump.c index d0dea863..7e7b34e8 100644 --- a/windows/winjump.c +++ b/windows/winjump.c @@ -688,8 +688,7 @@ void clear_jumplist(void) /* Adds a saved session to the Windows 7 jumplist. */ void add_session_to_jumplist(const char * const sessionname) { - if ((osVersion.dwMajorVersion < 6) || - (osVersion.dwMajorVersion == 6 && osVersion.dwMinorVersion < 1)) + if ((osMajorVersion < 6) || (osMajorVersion == 6 && osMinorVersion < 1)) return; /* do nothing on pre-Win7 systems */ if (add_to_jumplist_registry(sessionname) == JUMPLISTREG_OK) { @@ -703,8 +702,7 @@ void add_session_to_jumplist(const char * const sessionname) /* Removes a saved session from the Windows jumplist. */ void remove_session_from_jumplist(const char * const sessionname) { - if ((osVersion.dwMajorVersion < 6) || - (osVersion.dwMajorVersion == 6 && osVersion.dwMinorVersion < 1)) + if ((osMajorVersion < 6) || (osMajorVersion == 6 && osMinorVersion < 1)) return; /* do nothing on pre-Win7 systems */ if (remove_from_jumplist_registry(sessionname) == JUMPLISTREG_OK) { diff --git a/windows/winmisc.c b/windows/winmisc.c index e65ba1c9..4a53757e 100644 --- a/windows/winmisc.c +++ b/windows/winmisc.c @@ -4,13 +4,14 @@ #include #include +#include #include "putty.h" #ifndef SECURITY_WIN32 #define SECURITY_WIN32 #endif #include -OSVERSIONINFO osVersion; +DWORD osMajorVersion, osMinorVersion, osPlatformId; char *platform_get_x_display(void) { /* We may as well check for DISPLAY in case it's useful. */ @@ -186,11 +187,41 @@ void dll_hijacking_protection(void) } } -BOOL init_winver(void) +void init_winver(void) { + OSVERSIONINFO osVersion; + static HMODULE kernel32_module; + DECL_WINDOWS_FUNCTION(static, BOOL, GetVersionExA, (LPOSVERSIONINFO)); + + if (!kernel32_module) { + kernel32_module = load_system32_dll("kernel32.dll"); + /* Deliberately don't type-check this function, because that + * would involve using its declaration in a header file which + * triggers a deprecation warning. I know it's deprecated (see + * below) and don't need telling. */ + GET_WINDOWS_FUNCTION_NO_TYPECHECK(kernel32_module, GetVersionExA); + } + ZeroMemory(&osVersion, sizeof(osVersion)); osVersion.dwOSVersionInfoSize = sizeof (OSVERSIONINFO); - return GetVersionEx ( (OSVERSIONINFO *) &osVersion); + if (p_GetVersionExA && p_GetVersionExA(&osVersion)) { + osMajorVersion = osVersion.dwMajorVersion; + osMinorVersion = osVersion.dwMinorVersion; + osPlatformId = osVersion.dwPlatformId; + } else { + /* + * GetVersionEx is deprecated, so allow for it perhaps going + * away in future API versions. If it's not there, simply + * assume that's because Windows is too _new_, so fill in the + * variables we care about to a value that will always compare + * higher than any given test threshold. + * + * Normally we should be checking against the presence of a + * specific function if possible in any case. + */ + osMajorVersion = osMinorVersion = UINT_MAX; /* a very high number */ + osPlatformId = VER_PLATFORM_WIN32_NT; /* not Win32s or Win95-like */ + } } HMODULE load_system32_dll(const char *libname) diff --git a/windows/winpgnt.c b/windows/winpgnt.c index 4aff8338..9c57a2d6 100644 --- a/windows/winpgnt.c +++ b/windows/winpgnt.c @@ -1129,14 +1129,8 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) * Determine whether we're an NT system (should have security * APIs) or a non-NT system (don't do security). */ - if (!init_winver()) - { - modalfatalbox("Windows refuses to report a version"); - } - if (osVersion.dwPlatformId == VER_PLATFORM_WIN32_NT) { - has_security = TRUE; - } else - has_security = FALSE; + init_winver(); + has_security = (osPlatformId == VER_PLATFORM_WIN32_NT); if (has_security) { #ifndef NO_SECURITY diff --git a/windows/winprint.c b/windows/winprint.c index 6a1a74c2..083f6e1c 100644 --- a/windows/winprint.c +++ b/windows/winprint.c @@ -105,7 +105,7 @@ printer_enum *printer_start_enum(int *nprinters_ptr) * PRINTER_INFO_5 is recommended. * Bletch. */ - if (osVersion.dwPlatformId != VER_PLATFORM_WIN32_NT) { + if (osPlatformId != VER_PLATFORM_WIN32_NT) { ret->enum_level = 5; } else { ret->enum_level = 4; diff --git a/windows/winstuff.h b/windows/winstuff.h index 20e8b97e..5dc18fb1 100644 --- a/windows/winstuff.h +++ b/windows/winstuff.h @@ -521,9 +521,9 @@ void show_help(HWND hwnd); /* * Exports from winmisc.c. */ -extern OSVERSIONINFO osVersion; +GLOBAL DWORD osMajorVersion, osMinorVersion, osPlatformId; +void init_winver(void); void dll_hijacking_protection(void); -BOOL init_winver(void); HMODULE load_system32_dll(const char *libname); const char *win_strerror(int error); void restrict_process_acl(void); From 405800290dd0bcfe0e509b7a46763e42be5f3e35 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 3 Jun 2018 15:38:06 +0100 Subject: [PATCH 352/607] Fix assertion failure on ssh.com export of ECDSA. It's a key type that format doesn't know how to handle, but that's no excuse to fail an assertion - we have a perfectly good failure code we can return from the export function, so we should use it. --- import.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/import.c b/import.c index ef55b28e..218670ee 100644 --- a/import.c +++ b/import.c @@ -2265,8 +2265,7 @@ int sshcom_write(const Filename *filename, struct ssh2_userkey *key, initial_zero = 1; type = "dl-modp{sign{dsa-nist-sha1},dh{plain}}"; } else { - assert(0); /* zoinks! */ - exit(1); /* XXX: GCC doesn't understand assert() on some systems. */ + goto error; /* unsupported key type */ } outblob = strbuf_new(); From 0603256964a9f3c7e918affd0f904f6a3a234e1f Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 3 Jun 2018 15:38:57 +0100 Subject: [PATCH 353/607] Unix Pageant: add alias '-L' for '--private-openssh'. Matches the -L option in Unix PuTTYgen, and is much easier to type. --- unix/uxpgnt.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/unix/uxpgnt.c b/unix/uxpgnt.c index c11bde03..0e37c1a0 100644 --- a/unix/uxpgnt.c +++ b/unix/uxpgnt.c @@ -108,7 +108,7 @@ static void usage(void) printf(" pageant -a [key files]\n"); printf(" pageant -d [key identifiers]\n"); printf(" pageant --public [key identifiers]\n"); - printf(" pageant --public-openssh [key identifiers]\n"); + printf(" pageant ( --public-openssh | -L ) [key identifiers]\n"); printf(" pageant -l\n"); printf(" pageant -D\n"); printf("Lifetime options, for running Pageant as an agent:\n"); @@ -121,7 +121,7 @@ static void usage(void) printf(" -a add key(s) to the existing agent\n"); printf(" -l list currently loaded key fingerprints and comments\n"); printf(" --public print public keys in RFC 4716 format\n"); - printf(" --public-openssh print public keys in OpenSSH format\n"); + printf(" --public-openssh, -L print public keys in OpenSSH format\n"); printf(" -d delete key(s) from the agent\n"); printf(" -D delete all keys from the agent\n"); printf("Other options:\n"); @@ -1052,7 +1052,7 @@ int main(int argc, char **argv) add_keyact(KEYACT_CLIENT_LIST, NULL); } else if (!strcmp(p, "--public")) { curr_keyact = KEYACT_CLIENT_PUBLIC; - } else if (!strcmp(p, "--public-openssh")) { + } else if (!strcmp(p, "--public-openssh") || !strcmp(p, "-L")) { curr_keyact = KEYACT_CLIENT_PUBLIC_OPENSSH; } else if (!strcmp(p, "-X")) { life = LIFE_X11; From f4314b8d66f12b045ce22697fae4fd8df47bce58 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 3 Jun 2018 21:48:08 +0100 Subject: [PATCH 354/607] Fix a few compiler warnings from MinGW. A few variables that gcc couldn't tell I'd initialised on all the important paths, a variable that didn't really need to be there anyway, and yet another use of GET_WINDOWS_FUNCTION_NO_TYPECHECK. --- windows/wincons.c | 2 +- windows/window.c | 2 +- windows/winnet.c | 6 +++++- windows/winser.c | 6 +++--- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/windows/wincons.c b/windows/wincons.c index 120bffe8..e315f64a 100644 --- a/windows/wincons.c +++ b/windows/wincons.c @@ -354,7 +354,7 @@ static void console_data_untrusted(HANDLE hout, const char *data, int len) int console_get_userpass_input(prompts_t *p) { - HANDLE hin, hout; + HANDLE hin = INVALID_HANDLE_VALUE, hout = INVALID_HANDLE_VALUE; size_t curr_prompt; /* diff --git a/windows/window.c b/windows/window.c index c635720d..1a7bb472 100644 --- a/windows/window.c +++ b/windows/window.c @@ -1016,7 +1016,7 @@ void update_specials_menu(void *frontend) static void update_mouse_pointer(void) { - LPTSTR curstype; + LPTSTR curstype = NULL; int force_visible = FALSE; static int forced_visible = FALSE; switch (busy_status) { diff --git a/windows/winnet.c b/windows/winnet.c index ac2eae27..b5efc955 100644 --- a/windows/winnet.c +++ b/windows/winnet.c @@ -290,7 +290,11 @@ void sk_init(void) GET_WINDOWS_FUNCTION(winsock_module, WSAAsyncSelect); GET_WINDOWS_FUNCTION(winsock_module, WSAEventSelect); - GET_WINDOWS_FUNCTION(winsock_module, select); + /* We don't type-check select because at least some MinGW versions + * of the Windows API headers seem to disagree with the + * documentation on whether the 'struct timeval *' pointer is + * const or not. */ + GET_WINDOWS_FUNCTION_NO_TYPECHECK(winsock_module, select); GET_WINDOWS_FUNCTION(winsock_module, WSAGetLastError); GET_WINDOWS_FUNCTION(winsock_module, WSAEnumNetworkEvents); GET_WINDOWS_FUNCTION(winsock_module, WSAStartup); diff --git a/windows/winser.c b/windows/winser.c index 646cd254..976f8955 100644 --- a/windows/winser.c +++ b/windows/winser.c @@ -291,12 +291,12 @@ static void serial_free(void *handle) static void serial_reconfig(void *handle, Conf *conf) { Serial serial = (Serial) handle; - const char *err; - err = serial_configure(serial, serial->port, conf); + serial_configure(serial, serial->port, conf); /* - * FIXME: what should we do if err returns something? + * FIXME: what should we do if that call returned a non-NULL error + * message? */ } From 10a4f1156c59d44ef146f1c4ec665785025b1057 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Mon, 4 Jun 2018 19:10:57 +0100 Subject: [PATCH 355/607] Add a GDB Python script to pretty-print Bignum. I've been playing around with GDB's Python scripting system recently, and this is a thing I've always thought it would be nice to be able to do: if you load this script (which, on Ubuntu 18.04's gdb, is as simple as 'source contrib/gdb.py' at the gdb prompt, or similar), then variables of type Bignum will be printed as (e.g.) 'Bignum(0x12345)', or 'Bignum(NULL)' if they're null pointers, or a fallback representation if they're non-null pointers but gdb can't read anything sensible from them. --- contrib/gdb.py | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 contrib/gdb.py diff --git a/contrib/gdb.py b/contrib/gdb.py new file mode 100644 index 00000000..14574bb2 --- /dev/null +++ b/contrib/gdb.py @@ -0,0 +1,37 @@ +import gdb +import re +import gdb.printing + +class PuTTYBignumPrettyPrinter(gdb.printing.PrettyPrinter): + "Pretty-print PuTTY's Bignum type." + name = "Bignum" + + def __init__(self, val): + super(PuTTYBignumPrettyPrinter, self).__init__(self.name) + self.val = val + + def to_string(self): + type_BignumInt = gdb.lookup_type("BignumInt") + type_BignumIntPtr = type_BignumInt.pointer() + BIGNUM_INT_BITS = 8 * type_BignumInt.sizeof + array = self.val.cast(type_BignumIntPtr) + aget = lambda i: int(array[i]) & ((1 << BIGNUM_INT_BITS)-1) + + try: + length = aget(0) + value = 0 + for i in range(length): + value |= aget(i+1) << (BIGNUM_INT_BITS * i) + return "Bignum({:#x})".format(value) + + except gdb.MemoryError: + address = int(array) + if address == 0: + return "Bignum(NULL)".format(address) + return "Bignum(invalid @ {:#x})".format(address) + +rcpp = gdb.printing.RegexpCollectionPrettyPrinter("PuTTY") +rcpp.add_printer(PuTTYBignumPrettyPrinter.name, "^Bignum$", + PuTTYBignumPrettyPrinter) + +gdb.printing.register_pretty_printer(None, rcpp) From accb6931ce7f49336436c7e51c577af2ed4c2d1f Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Mon, 4 Jun 2018 19:13:13 +0100 Subject: [PATCH 356/607] Add HTTP redirects for the Windows on Arm installers. There's always one - I did everything else in the build script, but forgot to arrange for the wa32 and wa64 output subdirs to have a .htaccess redirect from a fixed name like 'putty-arm64-installer.msi' to whatever the real file name is in that particular build. --- Buildscr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Buildscr b/Buildscr index 5f67d065..08be3ec6 100644 --- a/Buildscr +++ b/Buildscr @@ -267,4 +267,4 @@ in-dest putty do echo "AddType application/octet-stream .hlp" >> .htaccess in-dest putty do echo "AddType application/octet-stream .cnt" >> .htaccess in-dest putty do set -- putty*.tar.gz; for k in '' .gpg; do echo RedirectMatch temp '(.*/)'putty.tar.gz$$k\$$ '$$1'"$$1$$k" >> .htaccess; done # And one in each binary directory, providing links for the installers. -in-dest putty do for params in "w32 putty-installer" "w64 putty-64bit-installer"; do (set -- $$params; subdir=$$1; installername=$$2; cd $$subdir && for ext in msi exe; do set -- putty*installer.$$ext; if test -f $$1; then for k in '' .gpg; do echo RedirectMatch temp '(.*/)'$${installername}.$$ext$$k\$$ '$$1'"$$1$$k" >> .htaccess; done; fi; done); done +in-dest putty do for params in "w32 putty-installer" "w64 putty-64bit-installer" "wa32 putty-arm32-installer" "wa64 putty-arm64-installer"; do (set -- $$params; subdir=$$1; installername=$$2; cd $$subdir && for ext in msi exe; do set -- putty*installer.$$ext; if test -f $$1; then for k in '' .gpg; do echo RedirectMatch temp '(.*/)'$${installername}.$$ext$$k\$$ '$$1'"$$1$$k" >> .htaccess; done; fi; done); done From 22d2c721013ee229d154af43a074539e439ffbba Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Mon, 4 Jun 2018 19:14:33 +0100 Subject: [PATCH 357/607] x11_get_auth_from_authfile: correct MAX_RECORD_SIZE. I reset this to a very small value during testing, because my real .Xauthority file is not absurdly enormous, so this was the easiest way to check the algorithm that periodically moves everything up the buffer. Then that test found and fixed a bug, and of course my temporary test value of MAX_RECORD_SIZE got swept up in the 'git commit -a --amend', and pushed with the rest of the refactoring, and I didn't notice until today. --- x11fwd.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/x11fwd.c b/x11fwd.c index bd4c9289..190b6f68 100644 --- a/x11fwd.c +++ b/x11fwd.c @@ -450,7 +450,15 @@ void x11_get_auth_from_authfile(struct X11Display *disp, int displaynum; int ideal_match = FALSE; char *ourhostname; - const size_t MAX_RECORD_SIZE = 0x80, BUF_SIZE = 2 * MAX_RECORD_SIZE; + + /* A maximally sized (wildly implausible) .Xauthority record + * consists of a 16-bit integer to start with, then four strings, + * each of which has a 16-bit length field followed by that many + * bytes of data (i.e. up to 0xFFFF bytes). */ + const size_t MAX_RECORD_SIZE = 2 + 4 * (2+0xFFFF); + + /* We'll want a buffer of twice that size (see below). */ + const size_t BUF_SIZE = 2 * MAX_RECORD_SIZE; /* * Normally we should look for precisely the details specified in From 452114c3d3f4340d14f1117055f0deaecb9e64ef Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Wed, 6 Jun 2018 06:42:52 +0100 Subject: [PATCH 358/607] New memory management macro 'snew_plus'. This formalises my occasional habit of using a single malloc to make a block that contains a header structure and a data buffer that a field of the structure will point to, allowing it to be freed in one go later. Previously I had to do this by hand, losing the type-checking advantages of snew; now I've written an snew-style macro to do the job, plus an accessor macro to cleanly get the auxiliary buffer pointer afterwards, and switched existing instances of the pattern over to using that. --- puttymem.h | 15 +++++++++++++++ sshshare.c | 11 ++++------- unix/gtkfont.c | 10 ++++------ 3 files changed, 23 insertions(+), 13 deletions(-) diff --git a/puttymem.h b/puttymem.h index 941aded3..b927f1ba 100644 --- a/puttymem.h +++ b/puttymem.h @@ -49,4 +49,19 @@ void safefree(void *); ((type *)snrealloc(sizeof((type *)0 == (ptr)) ? (ptr) : (ptr), \ (n), sizeof(type))) +/* + * For cases where you want to allocate a struct plus a subsidiary + * data buffer in one step, this macro lets you add a constant to the + * amount malloced. + * + * Since the return value is already cast to the struct type, a + * pointer to that many bytes of extra data can be conveniently + * obtained by simply adding 1 to the returned pointer! + * snew_plus_get_aux is a handy macro that does that and casts the + * result to void *, so you can assign it straight to wherever you + * wanted it. + */ +#define snew_plus(type, extra) ((type *)snmalloc(1, sizeof(type) + (extra))) +#define snew_plus_get_aux(ptr) ((void *)((ptr) + 1)) + #endif diff --git a/sshshare.c b/sshshare.c index 895c99c8..d5faa3ab 100644 --- a/sshshare.c +++ b/sshshare.c @@ -932,17 +932,14 @@ static void share_closing(Plug plug, const char *error_msg, int error_code, static void share_xchannel_add_message( struct share_xchannel *xc, int type, const void *data, int len) { - unsigned char *block; struct share_xchannel_message *msg; /* - * Be a little tricksy here by allocating a single memory block - * containing both the 'struct share_xchannel_message' and the - * actual data. Simplifies freeing it later. + * Allocate the 'struct share_xchannel_message' and the actual + * data in one unit. */ - block = smalloc(sizeof(struct share_xchannel_message) + len); - msg = (struct share_xchannel_message *)block; - msg->data = block + sizeof(struct share_xchannel_message); + msg = snew_plus(struct share_xchannel_message, len); + msg->data = snew_plus_get_aux(msg); msg->datalen = len; msg->type = type; memcpy(msg->data, data, len); diff --git a/unix/gtkfont.c b/unix/gtkfont.c index 4dd7919c..086669e2 100644 --- a/unix/gtkfont.c +++ b/unix/gtkfont.c @@ -258,7 +258,6 @@ struct xlfd_decomposed { static struct xlfd_decomposed *xlfd_decompose(const char *xlfd) { - void *mem; char *p, *components[14]; struct xlfd_decomposed *dec; int i; @@ -266,15 +265,14 @@ static struct xlfd_decomposed *xlfd_decompose(const char *xlfd) if (!xlfd) return NULL; - mem = smalloc(sizeof(struct xlfd_decomposed) + strlen(xlfd) + 1); - p = ((char *)mem) + sizeof(struct xlfd_decomposed); + dec = snew_plus(struct xlfd_decomposed, strlen(xlfd) + 1); + p = snew_plus_get_aux(dec); strcpy(p, xlfd); - dec = (struct xlfd_decomposed *)mem; for (i = 0; i < 14; i++) { if (*p != '-') { /* Malformed XLFD: not enough '-' */ - sfree(mem); + sfree(dec); return NULL; } *p++ = '\0'; @@ -283,7 +281,7 @@ static struct xlfd_decomposed *xlfd_decompose(const char *xlfd) } if (*p) { /* Malformed XLFD: too many '-' */ - sfree(mem); + sfree(dec); return NULL; } From 61a972c3326abe0a0276cda48ac15c9195f4b161 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Wed, 6 Jun 2018 07:19:57 +0100 Subject: [PATCH 359/607] Make share_got_pkt_from_server take a const pointer. It was horrible - even if harmless in practice - that it wrote the NATed channel id over its input buffer, and I think it's worth the extra memory management to avoid doing that. --- ssh.h | 2 +- sshshare.c | 10 +++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/ssh.h b/ssh.h index 6cc925f9..1c0f276c 100644 --- a/ssh.h +++ b/ssh.h @@ -27,7 +27,7 @@ extern Socket ssh_connection_sharing_init( void **state); int ssh_share_test_for_upstream(const char *host, int port, Conf *conf); void share_got_pkt_from_server(void *ctx, int type, - unsigned char *pkt, int pktlen); + const void *pkt, int pktlen); void share_activate(void *state, const char *server_verstring); void sharestate_free(void *state); int share_ndownstreams(void *state); diff --git a/sshshare.c b/sshshare.c index d5faa3ab..30fe7360 100644 --- a/sshshare.c +++ b/sshshare.c @@ -1129,8 +1129,9 @@ void share_setup_x11_channel(void *csv, void *chanv, } void share_got_pkt_from_server(void *csv, int type, - unsigned char *pkt, int pktlen) + const void *vpkt, int pktlen) { + const unsigned char *pkt = (const unsigned char *)vpkt; struct ssh_sharing_connstate *cs = (struct ssh_sharing_connstate *)csv; struct share_globreq *globreq; size_t id_pos; @@ -1203,8 +1204,11 @@ void share_got_pkt_from_server(void *csv, int type, /* * The normal case: this id refers to an open channel. */ - PUT_32BIT(pkt + id_pos, chan->downstream_id); - send_packet_to_downstream(cs, type, pkt, pktlen, chan); + unsigned char *rewritten = snewn(pktlen, unsigned char); + memcpy(rewritten, pkt, pktlen); + PUT_32BIT(rewritten + id_pos, chan->downstream_id); + send_packet_to_downstream(cs, type, rewritten, pktlen, chan); + sfree(rewritten); /* * Update the channel state, for messages that need it. From ce6c65aba1e11e7293cefc0d9d2bd7377582edf5 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Tue, 5 Jun 2018 08:20:10 +0100 Subject: [PATCH 360/607] Separate Packet into two structures. This is the first stage of massively tidying up this very confused data structure. In this commit, I replace the unified 'struct Packet' with two structures PktIn and PktOut, each of which contains only the fields of struct Packet that are actually used for packets going in that direction - most notably, PktIn doesn't implement BinarySink, and PktOut doesn't implement BinarySource. All uses of the old structure were statically determinable to be one or the other, so I've done that determination and changed all the types of variables and function signatures. Unlike PktIn, PktOut is not reference-counted, so there's a new ssh_pktout_free function. The most immediately pleasing thing about this change is that it lets me finally get rid of the tedious comment explaining how the 'length' field in struct Packet meant something different depending on direction. Now it's two fields of the same name in two different structures, I can comment the same thing much less verbosely! (I've also got rid of the comment claiming the type field was only used for incoming packets. That wasn't even true! It might have been once, because you can write an outgoing packet's type byte straight into its data buffer, but in fact in the current code pktout->type is nonetheless used in various other places, e.g. log_outgoing_packet.) In this commit I've only removed the fields from each structure that were _already_ unused. There are still quite a few we can get rid of by _making_ them unused. --- ssh.c | 381 ++++++++++++++++++++++++++++++---------------------------- 1 file changed, 196 insertions(+), 185 deletions(-) diff --git a/ssh.c b/ssh.c index 17202e85..7de32b50 100644 --- a/ssh.c +++ b/ssh.c @@ -359,28 +359,29 @@ enum { #define crMaybeWaitUntil(c) do { while (!(c)) crReturn(0); } while (0) #define crMaybeWaitUntilV(c) do { while (!(c)) crReturnV; } while (0) -struct Packet; - -static struct Packet *ssh1_pkt_init(int pkt_type); -static struct Packet *ssh2_pkt_init(int pkt_type); -static void ssh_pkt_ensure(struct Packet *, int length); -static void ssh_pkt_adddata(struct Packet *, const void *data, int len); -static int ssh2_pkt_construct(Ssh, struct Packet *); -static void ssh2_pkt_send(Ssh, struct Packet *); -static void ssh2_pkt_send_noqueue(Ssh, struct Packet *); +typedef struct PktIn PktIn; +typedef struct PktOut PktOut; + +static struct PktOut *ssh1_pkt_init(int pkt_type); +static struct PktOut *ssh2_pkt_init(int pkt_type); +static void ssh_pkt_ensure(struct PktOut *, int length); +static void ssh_pkt_adddata(struct PktOut *, const void *data, int len); +static int ssh2_pkt_construct(Ssh, struct PktOut *); +static void ssh2_pkt_send(Ssh, struct PktOut *); +static void ssh2_pkt_send_noqueue(Ssh, struct PktOut *); static void do_ssh1_login(void *vctx); static void do_ssh2_userauth(void *vctx); static void ssh2_connection_setup(Ssh ssh); static void do_ssh2_connection(void *vctx); static void ssh_channel_init(struct ssh_channel *c); -static struct ssh_channel *ssh_channel_msg(Ssh ssh, struct Packet *pktin); +static struct ssh_channel *ssh_channel_msg(Ssh ssh, PktIn *pktin); static void ssh_channel_got_eof(struct ssh_channel *c); static void ssh2_channel_check_close(struct ssh_channel *c); static void ssh_channel_close_local(struct ssh_channel *c, char const *reason); static void ssh_channel_destroy(struct ssh_channel *c); static void ssh_channel_unthrottle(struct ssh_channel *c, int bufsize); -static void ssh2_msg_something_unimplemented(Ssh ssh, struct Packet *pktin); -static void ssh2_general_packet_processing(Ssh ssh, struct Packet *pktin); +static void ssh2_msg_something_unimplemented(Ssh ssh, PktIn *pktin); +static void ssh2_general_packet_processing(Ssh ssh, PktIn *pktin); static void ssh1_login_input(Ssh ssh); static void ssh2_userauth_input(Ssh ssh); static void ssh2_connection_input(Ssh ssh); @@ -496,9 +497,9 @@ enum { /* channel types */ CHAN_ZOMBIE }; -typedef void (*handler_fn_t)(Ssh ssh, struct Packet *pktin); -typedef void (*chandler_fn_t)(Ssh ssh, struct Packet *pktin, void *ctx); -typedef void (*cchandler_fn_t)(struct ssh_channel *, struct Packet *, void *); +typedef void (*handler_fn_t)(Ssh ssh, PktIn *pktin); +typedef void (*chandler_fn_t)(Ssh ssh, PktIn *pktin, void *ctx); +typedef void (*cchandler_fn_t)(struct ssh_channel *, PktIn *, void *); /* * Each channel has a queue of outstanding CHANNEL_REQUESTS and their @@ -669,30 +670,26 @@ struct ssh_portfwd { ((pf) ? (sfree((pf)->saddr), sfree((pf)->daddr), \ sfree((pf)->sserv), sfree((pf)->dserv)) : (void)0 ), sfree(pf) ) -struct Packet { +struct PktIn { int refcount; - long length; /* length of packet: see below */ - long forcepad; /* SSH-2: force padding to at least this length */ - int type; /* only used for incoming packets */ + long length; /* length relative to 'body' */ + int type; unsigned long sequence; /* SSH-2 incoming sequence number */ unsigned char *data; /* allocated storage */ unsigned char *body; /* offset of payload within `data' */ long maxlen; /* amount of storage allocated for `data' */ long encrypted_len; /* for SSH-2 total-size counting */ + BinarySource_IMPLEMENTATION; +}; - /* - * A note on the 'length' field above. - * - * Incoming packets are set up so that pkt->length is measured - * relative to pkt->body, which itself points to a few bytes after - * pkt->data (skipping some uninteresting header fields including - * the packet type code). - * - * During construction of an outgoing packet, however, pkt->length - * is measured relative to the base pointer pkt->data, and - * pkt->body is not really used for anything until the packet is - * ready for sending. - */ +struct PktOut { + long length; /* length relative to 'data' */ + int type; + long forcepad; /* SSH-2: force padding to at least this length */ + unsigned char *data; /* allocated storage */ + unsigned char *body; /* offset of payload within `data' */ + long maxlen; /* amount of storage allocated for `data' */ + long encrypted_len; /* for SSH-2 total-size counting */ /* Extra metadata used in SSH packet logging mode, allowing us to * log in the packet header line that the packet came from a @@ -703,7 +700,6 @@ struct Packet { const char *additional_log_text; BinarySink_IMPLEMENTATION; - BinarySource_IMPLEMENTATION; }; static void ssh1_protocol_setup(Ssh ssh); @@ -722,15 +718,15 @@ static void ssh2_timer(void *ctx, unsigned long now); static int ssh2_timer_update(Ssh ssh, unsigned long rekey_time); #ifndef NO_GSSAPI static void ssh2_gss_update(Ssh ssh, int definitely_rekeying); -static struct Packet *ssh2_gss_authpacket(Ssh ssh, Ssh_gss_ctx gss_ctx, - const char *authtype); +static PktOut *ssh2_gss_authpacket(Ssh ssh, Ssh_gss_ctx gss_ctx, + const char *authtype); #endif -static void ssh2_msg_unexpected(Ssh ssh, struct Packet *pktin); -static void ssh_unref_packet(struct Packet *pkt); +static void ssh2_msg_unexpected(Ssh ssh, PktIn *pktin); +static void ssh_unref_packet(PktIn *pkt); struct PacketQueueNode { struct PacketQueueNode *next, *prev; - struct Packet *pkt; + PktIn *pkt; }; struct PacketQueue { @@ -743,7 +739,7 @@ static void pq_init(struct PacketQueue *pq) pq->end.pkt = NULL; } -static void pq_push(struct PacketQueue *pq, struct Packet *pkt) +static void pq_push(struct PacketQueue *pq, PktIn *pkt) { struct PacketQueueNode *node = snew(struct PacketQueueNode); node->pkt = pkt; @@ -753,7 +749,7 @@ static void pq_push(struct PacketQueue *pq, struct Packet *pkt) node->prev->next = node; } -static void pq_push_front(struct PacketQueue *pq, struct Packet *pkt) +static void pq_push_front(struct PacketQueue *pq, PktIn *pkt) { struct PacketQueueNode *node = snew(struct PacketQueueNode); node->pkt = pkt; @@ -763,15 +759,15 @@ static void pq_push_front(struct PacketQueue *pq, struct Packet *pkt) node->prev->next = node; } -static struct Packet *pq_peek(struct PacketQueue *pq) +static PktIn *pq_peek(struct PacketQueue *pq) { return pq->end.next->pkt; /* works even if next == &end, because * end.pkt is NULL */ } -static struct Packet *pq_pop(struct PacketQueue *pq) +static PktIn *pq_pop(struct PacketQueue *pq) { - struct Packet *pkt; + PktIn *pkt; struct PacketQueueNode *node; node = pq->end.next; @@ -788,7 +784,7 @@ static struct Packet *pq_pop(struct PacketQueue *pq) static void pq_clear(struct PacketQueue *pq) { - struct Packet *pkt; + PktIn *pkt; while ((pkt = pq_pop(pq)) != NULL) ssh_unref_packet(pkt); } @@ -816,20 +812,20 @@ struct rdpkt1_state_tag { long len, pad, biglen; unsigned long realcrc, gotcrc; int chunk; - struct Packet *pktin; + PktIn *pktin; }; struct rdpkt2_state_tag { long len, pad, payload, packetlen, maclen; int cipherblk; unsigned long incoming_sequence; - struct Packet *pktin; + PktIn *pktin; }; struct rdpkt2_bare_state_tag { long packetlen; unsigned long incoming_sequence; - struct Packet *pktin; + PktIn *pktin; }; struct queued_handler; @@ -946,7 +942,7 @@ struct ssh_tag { int sent_console_eof; int got_pty; /* affects EOF behaviour on main channel */ - struct Packet **queue; + PktOut **queue; int queuelen, queuesize; int queueing; unsigned char *deferred_send_data; @@ -1021,7 +1017,7 @@ struct ssh_tag { struct rdpkt2_state_tag rdpkt2_state; struct rdpkt2_bare_state_tag rdpkt2_bare_state; - void (*general_packet_processing)(Ssh ssh, struct Packet *pkt); + void (*general_packet_processing)(Ssh ssh, PktIn *pkt); void (*current_incoming_data_fn) (Ssh ssh); void (*current_user_input_fn) (Ssh ssh); @@ -1377,28 +1373,34 @@ static void c_write_str(Ssh ssh, const char *buf) c_write(ssh, buf, strlen(buf)); } -static void ssh_unref_packet(struct Packet *pkt) +static void ssh_unref_packet(PktIn *pkt) { if (--pkt->refcount <= 0) { sfree(pkt->data); sfree(pkt); } } + +static void ssh_free_pktout(PktOut *pkt) +{ + sfree(pkt->data); + sfree(pkt); +} + static void ssh_pkt_BinarySink_write(BinarySink *bs, const void *data, size_t len); -static struct Packet *ssh_new_packet(void) +static PktOut *ssh_new_packet(void) { - struct Packet *pkt = snew(struct Packet); + PktOut *pkt = snew(PktOut); BinarySink_INIT(pkt, ssh_pkt_BinarySink_write); pkt->body = pkt->data = NULL; pkt->maxlen = 0; - pkt->refcount = 1; return pkt; } -static void ssh1_log_incoming_packet(Ssh ssh, const struct Packet *pkt) +static void ssh1_log_incoming_packet(Ssh ssh, const PktIn *pkt) { int nblanks = 0; struct logblank_t blanks[4]; @@ -1428,7 +1430,7 @@ static void ssh1_log_incoming_packet(Ssh ssh, const struct Packet *pkt) 0, NULL); } -static void ssh1_log_outgoing_packet(Ssh ssh, const struct Packet *pkt) +static void ssh1_log_outgoing_packet(Ssh ssh, const PktOut *pkt) { int nblanks = 0; struct logblank_t blanks[4]; @@ -1508,7 +1510,10 @@ static void ssh1_rdpkt(Ssh ssh) crBegin(ssh->ssh1_rdpkt_crstate); while (1) { - st->pktin = ssh_new_packet(); + st->pktin = snew(PktIn); + st->pktin->body = st->pktin->data = NULL; + st->pktin->maxlen = 0; + st->pktin->refcount = 1; st->pktin->type = 0; st->pktin->length = 0; @@ -1613,7 +1618,7 @@ static void ssh1_rdpkt(Ssh ssh) crFinishV; } -static void ssh2_log_incoming_packet(Ssh ssh, const struct Packet *pkt) +static void ssh2_log_incoming_packet(Ssh ssh, const PktIn *pkt) { int nblanks = 0; struct logblank_t blanks[4]; @@ -1644,7 +1649,7 @@ static void ssh2_log_incoming_packet(Ssh ssh, const struct Packet *pkt) 0, NULL); } -static void ssh2_log_outgoing_packet(Ssh ssh, const struct Packet *pkt) +static void ssh2_log_outgoing_packet(Ssh ssh, const PktOut *pkt) { int nblanks = 0; struct logblank_t blanks[4]; @@ -1753,7 +1758,10 @@ static void ssh2_rdpkt(Ssh ssh) crBegin(ssh->ssh2_rdpkt_crstate); while (1) { - st->pktin = ssh_new_packet(); + st->pktin = snew(PktIn); + st->pktin->body = st->pktin->data = NULL; + st->pktin->maxlen = 0; + st->pktin->refcount = 1; st->pktin->type = 0; st->pktin->length = 0; @@ -2077,7 +2085,10 @@ static void ssh2_bare_connection_rdpkt(Ssh ssh) crStopV; } - st->pktin = ssh_new_packet(); + st->pktin = snew(PktIn); + st->pktin->body = NULL; + st->pktin->maxlen = 0; + st->pktin->refcount = 1; st->pktin->data = snewn(st->packetlen, unsigned char); st->pktin->encrypted_len = st->packetlen; @@ -2127,7 +2138,7 @@ static void ssh2_bare_connection_rdpkt(Ssh ssh) crFinishV; } -static int s_wrpkt_prepare(Ssh ssh, struct Packet *pkt, int *offset_p) +static int s_wrpkt_prepare(Ssh ssh, PktOut *pkt, int *offset_p) { int pad, biglen, i, pktoffs; unsigned long crc; @@ -2188,17 +2199,17 @@ static int s_write(Ssh ssh, void *data, int len) return sk_write(ssh->s, data, len); } -static void s_wrpkt(Ssh ssh, struct Packet *pkt) +static void s_wrpkt(Ssh ssh, PktOut *pkt) { int len, backlog, offset; len = s_wrpkt_prepare(ssh, pkt, &offset); backlog = s_write(ssh, pkt->data + offset, len); if (backlog > SSH_MAX_BACKLOG) ssh_throttle_all(ssh, 1, backlog); - ssh_unref_packet(pkt); + ssh_free_pktout(pkt); } -static void s_wrpkt_defer(Ssh ssh, struct Packet *pkt) +static void s_wrpkt_defer(Ssh ssh, PktOut *pkt) { int len, offset; len = s_wrpkt_prepare(ssh, pkt, &offset); @@ -2211,7 +2222,7 @@ static void s_wrpkt_defer(Ssh ssh, struct Packet *pkt) memcpy(ssh->deferred_send_data + ssh->deferred_len, pkt->data + offset, len); ssh->deferred_len += len; - ssh_unref_packet(pkt); + ssh_free_pktout(pkt); } /* @@ -2219,11 +2230,11 @@ static void s_wrpkt_defer(Ssh ssh, struct Packet *pkt) * (This all-at-once interface used to be the only one, but now SSH-1 * packets can also be constructed incrementally.) */ -static struct Packet *construct_packet(Ssh ssh, int pkttype, va_list ap) +static PktOut *construct_packet(Ssh ssh, int pkttype, va_list ap) { int argtype; Bignum bn; - struct Packet *pkt; + PktOut *pkt; pkt = ssh1_pkt_init(pkttype); @@ -2263,7 +2274,7 @@ static struct Packet *construct_packet(Ssh ssh, int pkttype, va_list ap) static void send_packet(Ssh ssh, int pkttype, ...) { - struct Packet *pkt; + PktOut *pkt; va_list ap; va_start(ap, pkttype); pkt = construct_packet(ssh, pkttype, ap); @@ -2273,7 +2284,7 @@ static void send_packet(Ssh ssh, int pkttype, ...) static void defer_packet(Ssh ssh, int pkttype, ...) { - struct Packet *pkt; + PktOut *pkt; va_list ap; va_start(ap, pkttype); pkt = construct_packet(ssh, pkttype, ap); @@ -2304,7 +2315,7 @@ static int ssh_versioncmp(const char *a, const char *b) /* * Packet construction functions. Mostly shared between SSH-1 and SSH-2. */ -static void ssh_pkt_ensure(struct Packet *pkt, int length) +static void ssh_pkt_ensure(PktOut *pkt, int length) { if (pkt->maxlen < length) { unsigned char *body = pkt->body; @@ -2314,7 +2325,7 @@ static void ssh_pkt_ensure(struct Packet *pkt, int length) if (body) pkt->body = pkt->data + offset; } } -static void ssh_pkt_adddata(struct Packet *pkt, const void *data, int len) +static void ssh_pkt_adddata(PktOut *pkt, const void *data, int len) { pkt->length += len; ssh_pkt_ensure(pkt, pkt->length); @@ -2324,13 +2335,13 @@ static void ssh_pkt_adddata(struct Packet *pkt, const void *data, int len) static void ssh_pkt_BinarySink_write(BinarySink *bs, const void *data, size_t len) { - struct Packet *pkt = BinarySink_DOWNCAST(bs, struct Packet); + PktOut *pkt = BinarySink_DOWNCAST(bs, PktOut); ssh_pkt_adddata(pkt, data, len); } -static struct Packet *ssh1_pkt_init(int pkt_type) +static PktOut *ssh1_pkt_init(int pkt_type) { - struct Packet *pkt = ssh_new_packet(); + PktOut *pkt = ssh_new_packet(); pkt->length = 4 + 8; /* space for length + max padding */ put_byte(pkt, pkt_type); pkt->body = pkt->data + pkt->length; @@ -2340,9 +2351,9 @@ static struct Packet *ssh1_pkt_init(int pkt_type) return pkt; } -static struct Packet *ssh2_pkt_init(int pkt_type) +static PktOut *ssh2_pkt_init(int pkt_type) { - struct Packet *pkt = ssh_new_packet(); + PktOut *pkt = ssh_new_packet(); pkt->length = 5; /* space for packet length + padding length */ pkt->forcepad = 0; pkt->type = pkt_type; @@ -2358,7 +2369,7 @@ static struct Packet *ssh2_pkt_init(int pkt_type) * put the MAC on it. Final packet, ready to be sent, is stored in * pkt->data. Total length is returned. */ -static int ssh2_pkt_construct(Ssh ssh, struct Packet *pkt) +static int ssh2_pkt_construct(Ssh ssh, PktOut *pkt) { int cipherblk, maclen, padding, unencrypted_prefix, i; @@ -2489,13 +2500,13 @@ static int ssh2_pkt_construct(Ssh ssh, struct Packet *pkt) * CBC. */ -static void ssh2_pkt_defer_noqueue(Ssh, struct Packet *, int); +static void ssh2_pkt_defer_noqueue(Ssh, PktOut *, int); static void ssh_pkt_defersend(Ssh); /* * Send an SSH-2 packet immediately, without queuing or deferring. */ -static void ssh2_pkt_send_noqueue(Ssh ssh, struct Packet *pkt) +static void ssh2_pkt_send_noqueue(Ssh ssh, PktOut *pkt) { int len; int backlog; @@ -2520,13 +2531,13 @@ static void ssh2_pkt_send_noqueue(Ssh ssh, struct Packet *pkt) queue_idempotent_callback(&ssh->ssh2_transport_icb); } - ssh_unref_packet(pkt); + ssh_free_pktout(pkt); } /* * Defer an SSH-2 packet. */ -static void ssh2_pkt_defer_noqueue(Ssh ssh, struct Packet *pkt, int noignore) +static void ssh2_pkt_defer_noqueue(Ssh ssh, PktOut *pkt, int noignore) { int len; if (ssh->cscipher != NULL && (ssh->cscipher->flags & SSH_CIPHER_IS_CBC) && @@ -2536,7 +2547,7 @@ static void ssh2_pkt_defer_noqueue(Ssh ssh, struct Packet *pkt, int noignore) * Interpose an SSH_MSG_IGNORE to ensure that user data don't * get encrypted with a known IV. */ - struct Packet *ipkt = ssh2_pkt_init(SSH2_MSG_IGNORE); + PktOut *ipkt = ssh2_pkt_init(SSH2_MSG_IGNORE); put_stringz(ipkt, ""); ssh2_pkt_defer_noqueue(ssh, ipkt, TRUE); } @@ -2550,19 +2561,19 @@ static void ssh2_pkt_defer_noqueue(Ssh ssh, struct Packet *pkt, int noignore) memcpy(ssh->deferred_send_data + ssh->deferred_len, pkt->body, len); ssh->deferred_len += len; ssh->deferred_data_size += pkt->encrypted_len; - ssh_unref_packet(pkt); + ssh_free_pktout(pkt); } /* * Queue an SSH-2 packet. */ -static void ssh2_pkt_queue(Ssh ssh, struct Packet *pkt) +static void ssh2_pkt_queue(Ssh ssh, PktOut *pkt) { assert(ssh->queueing); if (ssh->queuelen >= ssh->queuesize) { ssh->queuesize = ssh->queuelen + 32; - ssh->queue = sresize(ssh->queue, ssh->queuesize, struct Packet *); + ssh->queue = sresize(ssh->queue, ssh->queuesize, PktOut *); } ssh->queue[ssh->queuelen++] = pkt; @@ -2572,7 +2583,7 @@ static void ssh2_pkt_queue(Ssh ssh, struct Packet *pkt) * Either queue or send a packet, depending on whether queueing is * set. */ -static void ssh2_pkt_send(Ssh ssh, struct Packet *pkt) +static void ssh2_pkt_send(Ssh ssh, PktOut *pkt) { if (ssh->queueing) ssh2_pkt_queue(ssh, pkt); @@ -2584,7 +2595,7 @@ static void ssh2_pkt_send(Ssh ssh, struct Packet *pkt) * Either queue or defer a packet, depending on whether queueing is * set. */ -static void ssh2_pkt_defer(Ssh ssh, struct Packet *pkt) +static void ssh2_pkt_defer(Ssh ssh, PktOut *pkt) { if (ssh->queueing) ssh2_pkt_queue(ssh, pkt); @@ -2633,8 +2644,7 @@ static void ssh_pkt_defersend(Ssh ssh) * Send a packet whose length needs to be disguised (typically * passwords or keyboard-interactive responses). */ -static void ssh2_pkt_send_with_padding(Ssh ssh, struct Packet *pkt, - int padsize) +static void ssh2_pkt_send_with_padding(Ssh ssh, PktOut *pkt, int padsize) { #if 0 if (0) { @@ -2738,7 +2748,7 @@ void bndebug(char *string, Bignum b) * that it optionally breaks it open and fiddle with it to work around * BUG_SSH2_RSA_PADDING. */ -static void ssh2_add_sigblob(Ssh ssh, struct Packet *pkt, +static void ssh2_add_sigblob(Ssh ssh, PktOut *pkt, const void *pkblob, int pkblob_len, const void *sigblob, int sigblob_len) { @@ -3430,7 +3440,7 @@ static void ssh_process_incoming_data(void *ctx) static void ssh_process_pq_full(void *ctx) { Ssh ssh = (Ssh)ctx; - struct Packet *pktin; + PktIn *pktin; while ((pktin = pq_pop(&ssh->pq_full)) != NULL) { if (ssh->general_packet_processing) @@ -3995,7 +4005,7 @@ static void ssh_disconnect(Ssh ssh, const char *client_reason, send_packet(ssh, SSH1_MSG_DISCONNECT, PKT_STR, wire_reason, PKT_END); } else if (ssh->version == 2) { - struct Packet *pktout = ssh2_pkt_init(SSH2_MSG_DISCONNECT); + PktOut *pktout = ssh2_pkt_init(SSH2_MSG_DISCONNECT); put_uint32(pktout, code); put_stringz(pktout, wire_reason); put_stringz(pktout, "en"); /* language tag */ @@ -4061,8 +4071,8 @@ int verify_ssh_manual_host_key(Ssh ssh, const char *fingerprint, ssh_key *key) return 0; } -static void ssh1_coro_wrapper_initial(Ssh ssh, struct Packet *pktin); -static void ssh1_coro_wrapper_session(Ssh ssh, struct Packet *pktin); +static void ssh1_coro_wrapper_initial(Ssh ssh, PktIn *pktin); +static void ssh1_coro_wrapper_session(Ssh ssh, PktIn *pktin); static void ssh1_connection_input(Ssh ssh); /* @@ -4071,7 +4081,7 @@ static void ssh1_connection_input(Ssh ssh); static void do_ssh1_login(void *vctx) { Ssh ssh = (Ssh)vctx; - struct Packet *pktin; + PktIn *pktin; int i, j, ret; ptrlen pl; @@ -5069,7 +5079,7 @@ static void ssh_channel_try_eof(struct ssh_channel *c) PKT_END); c->closes |= CLOSES_SENT_EOF; } else { - struct Packet *pktout; + PktOut *pktout; pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_EOF); put_uint32(pktout, c->remoteid); ssh2_pkt_send(ssh, pktout); @@ -5134,7 +5144,7 @@ void sshfwd_unthrottle(struct ssh_channel *c, int bufsize) ssh_channel_unthrottle(c, bufsize); } -static void ssh_queueing_handler(Ssh ssh, struct Packet *pktin) +static void ssh_queueing_handler(Ssh ssh, PktIn *pktin) { struct queued_handler *qh = ssh->qhead; @@ -5200,7 +5210,7 @@ static void ssh_queue_handler(Ssh ssh, int msg1, int msg2, ssh->qtail = qh; } -static void ssh_rportfwd_succfail(Ssh ssh, struct Packet *pktin, void *ctx) +static void ssh_rportfwd_succfail(Ssh ssh, PktIn *pktin, void *ctx) { struct ssh_rportfwd *rpf, *pf = (struct ssh_rportfwd *)ctx; @@ -5256,7 +5266,7 @@ void ssh_remove_sharing_rportfwd(Ssh ssh, const char *shost, int sport, sfree(realpf); } -static void ssh_sharing_global_request_response(Ssh ssh, struct Packet *pktin, +static void ssh_sharing_global_request_response(Ssh ssh, PktIn *pktin, void *ctx) { share_got_pkt_from_server(ctx, pktin->type, @@ -5432,7 +5442,7 @@ static void ssh_setup_portfwd(Ssh ssh, Conf *conf) * forwarding failed. */ if (epf->remote) { struct ssh_rportfwd *rpf = epf->remote; - struct Packet *pktout; + PktOut *pktout; /* * Cancel the port forwarding at the server @@ -5574,7 +5584,7 @@ static void ssh_setup_portfwd(Ssh ssh, Conf *conf) SSH1_SMSG_FAILURE, ssh_rportfwd_succfail, pf); } else { - struct Packet *pktout; + PktOut *pktout; pktout = ssh2_pkt_init(SSH2_MSG_GLOBAL_REQUEST); put_stringz(pktout, "tcpip-forward"); put_bool(pktout, 1);/* want reply */ @@ -5593,7 +5603,7 @@ static void ssh_setup_portfwd(Ssh ssh, Conf *conf) } } -static void ssh1_smsg_stdout_stderr_data(Ssh ssh, struct Packet *pktin) +static void ssh1_smsg_stdout_stderr_data(Ssh ssh, PktIn *pktin) { ptrlen string; int bufsize; @@ -5612,7 +5622,7 @@ static void ssh1_smsg_stdout_stderr_data(Ssh ssh, struct Packet *pktin) } } -static void ssh1_smsg_x11_open(Ssh ssh, struct Packet *pktin) +static void ssh1_smsg_x11_open(Ssh ssh, PktIn *pktin) { /* Remote side is trying to open a channel to talk to our * X-Server. Give them back a local channel number. */ @@ -5641,7 +5651,7 @@ static void ssh1_smsg_x11_open(Ssh ssh, struct Packet *pktin) } } -static void ssh1_smsg_agent_open(Ssh ssh, struct Packet *pktin) +static void ssh1_smsg_agent_open(Ssh ssh, PktIn *pktin) { /* Remote side is trying to open a channel to talk to our * agent. Give them back a local channel number. */ @@ -5667,7 +5677,7 @@ static void ssh1_smsg_agent_open(Ssh ssh, struct Packet *pktin) } } -static void ssh1_msg_port_open(Ssh ssh, struct Packet *pktin) +static void ssh1_msg_port_open(Ssh ssh, PktIn *pktin) { /* Remote side is trying to open a channel to talk to a * forwarded port. Give them back a local channel number. */ @@ -5719,7 +5729,7 @@ static void ssh1_msg_port_open(Ssh ssh, struct Packet *pktin) sfree(pf.dhost); } -static void ssh1_msg_channel_open_confirmation(Ssh ssh, struct Packet *pktin) +static void ssh1_msg_channel_open_confirmation(Ssh ssh, PktIn *pktin) { struct ssh_channel *c; @@ -5742,7 +5752,7 @@ static void ssh1_msg_channel_open_confirmation(Ssh ssh, struct Packet *pktin) } } -static void ssh1_msg_channel_open_failure(Ssh ssh, struct Packet *pktin) +static void ssh1_msg_channel_open_failure(Ssh ssh, PktIn *pktin) { struct ssh_channel *c; @@ -5755,7 +5765,7 @@ static void ssh1_msg_channel_open_failure(Ssh ssh, struct Packet *pktin) } } -static void ssh1_msg_channel_close(Ssh ssh, struct Packet *pktin) +static void ssh1_msg_channel_close(Ssh ssh, PktIn *pktin) { /* Remote side closes a channel. */ struct ssh_channel *c; @@ -5831,7 +5841,7 @@ static int ssh_channel_data(struct ssh_channel *c, int is_stderr, return 0; } -static void ssh1_msg_channel_data(Ssh ssh, struct Packet *pktin) +static void ssh1_msg_channel_data(Ssh ssh, PktIn *pktin) { /* Data sent down one of our channels. */ ptrlen data; @@ -5849,7 +5859,7 @@ static void ssh1_msg_channel_data(Ssh ssh, struct Packet *pktin) } } -static void ssh1_smsg_exit_status(Ssh ssh, struct Packet *pktin) +static void ssh1_smsg_exit_status(Ssh ssh, PktIn *pktin) { ssh->exitcode = get_uint32(pktin); logeventf(ssh, "Server sent command exit status %d", ssh->exitcode); @@ -5888,7 +5898,7 @@ int ssh_agent_forwarding_permitted(Ssh ssh) static void do_ssh1_connection(void *vctx) { Ssh ssh = (Ssh)vctx; - struct Packet *pktin; + PktIn *pktin; crBegin(ssh->do_ssh1_connection_crstate); @@ -5969,7 +5979,7 @@ static void do_ssh1_connection(void *vctx) ssh->packet_dispatch[SSH1_MSG_PORT_OPEN] = ssh1_msg_port_open; if (!conf_get_int(ssh->conf, CONF_nopty)) { - struct Packet *pkt; + PktOut *pkt; /* Unpick the terminal-speed string. */ /* XXX perhaps we should allow no speeds to be sent. */ ssh->ospeed = 38400; ssh->ispeed = 38400; /* last-resort defaults */ @@ -6095,19 +6105,19 @@ static void do_ssh1_connection(void *vctx) /* * Handle the top-level SSH-2 protocol. */ -static void ssh1_msg_debug(Ssh ssh, struct Packet *pktin) +static void ssh1_msg_debug(Ssh ssh, PktIn *pktin) { ptrlen msg = get_string(pktin); logeventf(ssh, "Remote debug message: %.*s", PTRLEN_PRINTF(msg)); } -static void ssh1_msg_disconnect(Ssh ssh, struct Packet *pktin) +static void ssh1_msg_disconnect(Ssh ssh, PktIn *pktin) { ptrlen msg = get_string(pktin); bombout(("Server sent disconnect message:\n\"%.*s\"", PTRLEN_PRINTF(msg))); } -static void ssh_msg_ignore(Ssh ssh, struct Packet *pktin) +static void ssh_msg_ignore(Ssh ssh, PktIn *pktin) { /* Do nothing, because we're ignoring it! Duhh. */ } @@ -6122,14 +6132,14 @@ static void ssh1_connection_input(Ssh ssh) do_ssh1_connection(ssh); } -static void ssh1_coro_wrapper_initial(Ssh ssh, struct Packet *pktin) +static void ssh1_coro_wrapper_initial(Ssh ssh, PktIn *pktin) { pktin->refcount++; /* avoid packet being freed when we return */ pq_push(&ssh->pq_ssh1_login, pktin); queue_idempotent_callback(&ssh->ssh1_login_icb); } -static void ssh1_coro_wrapper_session(Ssh ssh, struct Packet *pktin) +static void ssh1_coro_wrapper_session(Ssh ssh, PktIn *pktin) { pktin->refcount++; /* avoid packet being freed when we return */ pq_push(&ssh->pq_ssh1_connection, pktin); @@ -6434,7 +6444,7 @@ static int ssh_have_any_transient_hostkey(Ssh ssh) static void do_ssh2_transport(void *vctx) { Ssh ssh = (Ssh)vctx; - struct Packet *pktin; + PktIn *pktin; enum kexlist { KEXLIST_KEX, KEXLIST_HOSTKEY, KEXLIST_CSCIPHER, KEXLIST_SCCIPHER, @@ -6482,7 +6492,7 @@ static void do_ssh2_transport(void *vctx) int userauth_succeeded; /* for delayed compression */ int pending_compression; int got_session_id; - struct Packet *pktout; + PktOut *pktout; int dlgret; int guessok; int ignorepkt; @@ -8300,7 +8310,7 @@ static int ssh_send_channel_data(struct ssh_channel *c, const char *buf, static int ssh2_try_send(struct ssh_channel *c) { Ssh ssh = c->ssh; - struct Packet *pktout; + PktOut *pktout; int ret; while (c->v.v2.remwindow > 0 && bufchain_size(&c->v.v2.outbuffer) > 0) { @@ -8400,10 +8410,10 @@ static void ssh_channel_init(struct ssh_channel *c) /* * Construct the common parts of a CHANNEL_OPEN. */ -static struct Packet *ssh2_chanopen_init(struct ssh_channel *c, +static PktOut *ssh2_chanopen_init(struct ssh_channel *c, const char *type) { - struct Packet *pktout; + PktOut *pktout; pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_OPEN); put_stringz(pktout, type); @@ -8448,11 +8458,11 @@ static void ssh2_queue_chanreq_handler(struct ssh_channel *c, * the server initiated channel closure before we saw the response) * and the handler should free any storage it's holding. */ -static struct Packet *ssh2_chanreq_init(struct ssh_channel *c, +static PktOut *ssh2_chanreq_init(struct ssh_channel *c, const char *type, cchandler_fn_t handler, void *ctx) { - struct Packet *pktout; + PktOut *pktout; assert(!(c->closes & (CLOSES_SENT_CLOSE | CLOSES_RCVD_CLOSE))); pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST); @@ -8488,7 +8498,7 @@ static void ssh_channel_unthrottle(struct ssh_channel *c, int bufsize) /* * Potentially enlarge the window on an SSH-2 channel. */ -static void ssh2_handle_winadj_response(struct ssh_channel *, struct Packet *, +static void ssh2_handle_winadj_response(struct ssh_channel *, PktIn *, void *); static void ssh2_set_window(struct ssh_channel *c, int newwin) { @@ -8527,7 +8537,7 @@ static void ssh2_set_window(struct ssh_channel *c, int newwin) * "Significant" is arbitrarily defined as half the window size. */ if (newwin / 2 >= c->v.v2.locwindow) { - struct Packet *pktout; + PktOut *pktout; unsigned *up; /* @@ -8569,7 +8579,7 @@ static void ssh2_set_window(struct ssh_channel *c, int newwin) * If the channel is shared, pass the message on to downstream and * also return NULL (meaning the caller should ignore this message). */ -static struct ssh_channel *ssh_channel_msg(Ssh ssh, struct Packet *pktin) +static struct ssh_channel *ssh_channel_msg(Ssh ssh, PktIn *pktin) { unsigned localid = get_uint32(pktin); struct ssh_channel *c; @@ -8602,7 +8612,7 @@ static struct ssh_channel *ssh_channel_msg(Ssh ssh, struct Packet *pktin) } static void ssh2_handle_winadj_response(struct ssh_channel *c, - struct Packet *pktin, void *ctx) + PktIn *pktin, void *ctx) { unsigned *sizep = ctx; @@ -8625,7 +8635,7 @@ static void ssh2_handle_winadj_response(struct ssh_channel *c, c->v.v2.throttle_state = UNTHROTTLED; } -static void ssh2_msg_channel_response(Ssh ssh, struct Packet *pktin) +static void ssh2_msg_channel_response(Ssh ssh, PktIn *pktin) { struct ssh_channel *c = ssh_channel_msg(ssh, pktin); struct outstanding_channel_request *ocr; @@ -8649,7 +8659,7 @@ static void ssh2_msg_channel_response(Ssh ssh, struct Packet *pktin) ssh2_channel_check_close(c); } -static void ssh2_msg_channel_window_adjust(Ssh ssh, struct Packet *pktin) +static void ssh2_msg_channel_window_adjust(Ssh ssh, PktIn *pktin) { struct ssh_channel *c; c = ssh_channel_msg(ssh, pktin); @@ -8661,7 +8671,7 @@ static void ssh2_msg_channel_window_adjust(Ssh ssh, struct Packet *pktin) } } -static void ssh2_msg_channel_data(Ssh ssh, struct Packet *pktin) +static void ssh2_msg_channel_data(Ssh ssh, PktIn *pktin) { ptrlen data; unsigned ext_type = 0; /* 0 means not extended */ @@ -8823,7 +8833,7 @@ static void ssh_channel_destroy(struct ssh_channel *c) static void ssh2_channel_check_close(struct ssh_channel *c) { Ssh ssh = c->ssh; - struct Packet *pktout; + PktOut *pktout; assert(ssh->version == 2); if (c->halfopen) { @@ -8897,7 +8907,7 @@ static void ssh_channel_got_eof(struct ssh_channel *c) } } -static void ssh2_msg_channel_eof(Ssh ssh, struct Packet *pktin) +static void ssh2_msg_channel_eof(Ssh ssh, PktIn *pktin) { struct ssh_channel *c; @@ -8908,7 +8918,7 @@ static void ssh2_msg_channel_eof(Ssh ssh, struct Packet *pktin) ssh2_channel_check_close(c); } -static void ssh2_msg_channel_close(Ssh ssh, struct Packet *pktin) +static void ssh2_msg_channel_close(Ssh ssh, PktIn *pktin) { struct ssh_channel *c; @@ -8985,7 +8995,7 @@ static void ssh2_msg_channel_close(Ssh ssh, struct Packet *pktin) } } -static void ssh2_msg_channel_open_confirmation(Ssh ssh, struct Packet *pktin) +static void ssh2_msg_channel_open_confirmation(Ssh ssh, PktIn *pktin) { struct ssh_channel *c; @@ -9029,7 +9039,7 @@ static void ssh2_msg_channel_open_confirmation(Ssh ssh, struct Packet *pktin) ssh_channel_try_eof(c); /* in case we had a pending EOF */ } -static char *ssh2_channel_open_failure_error_text(struct Packet *pktin) +static char *ssh2_channel_open_failure_error_text(PktIn *pktin) { static const char *const reasons[] = { NULL, @@ -9056,7 +9066,7 @@ static char *ssh2_channel_open_failure_error_text(struct Packet *pktin) return dupprintf("%s [%.*s]", reason_code_string, PTRLEN_PRINTF(reason)); } -static void ssh2_msg_channel_open_failure(Ssh ssh, struct Packet *pktin) +static void ssh2_msg_channel_open_failure(Ssh ssh, PktIn *pktin) { struct ssh_channel *c; @@ -9095,13 +9105,13 @@ static void ssh2_msg_channel_open_failure(Ssh ssh, struct Packet *pktin) sfree(c); } -static void ssh2_msg_channel_request(Ssh ssh, struct Packet *pktin) +static void ssh2_msg_channel_request(Ssh ssh, PktIn *pktin) { ptrlen type; int want_reply; int reply = SSH2_MSG_CHANNEL_FAILURE; /* default */ struct ssh_channel *c; - struct Packet *pktout; + PktOut *pktout; c = ssh_channel_msg(ssh, pktin); if (!c) @@ -9260,10 +9270,10 @@ static void ssh2_msg_channel_request(Ssh ssh, struct Packet *pktin) } } -static void ssh2_msg_global_request(Ssh ssh, struct Packet *pktin) +static void ssh2_msg_global_request(Ssh ssh, PktIn *pktin) { int want_reply; - struct Packet *pktout; + PktOut *pktout; get_string(pktin); /* ignore request type (see below) */ want_reply = get_bool(pktin); @@ -9304,7 +9314,7 @@ void ssh_sharing_remove_x11_display(Ssh ssh, struct X11FakeAuth *auth) x11_free_fake_auth(auth); } -static void ssh2_msg_channel_open(Ssh ssh, struct Packet *pktin) +static void ssh2_msg_channel_open(Ssh ssh, PktIn *pktin) { ptrlen type; int peerport; @@ -9312,7 +9322,7 @@ static void ssh2_msg_channel_open(Ssh ssh, struct Packet *pktin) struct ssh_channel *c; unsigned remid, winsize, pktsize; unsigned our_winsize_override = 0; - struct Packet *pktout; + PktOut *pktout; type = get_string(pktin); c = snew(struct ssh_channel); @@ -9480,7 +9490,7 @@ void sshfwd_x11_is_local(struct ssh_channel *c) * Buffer banner messages for later display at some convenient point, * if we're going to display them. */ -static void ssh2_msg_userauth_banner(Ssh ssh, struct Packet *pktin) +static void ssh2_msg_userauth_banner(Ssh ssh, PktIn *pktin) { /* Arbitrary limit to prevent unbounded inflation of buffer */ if (conf_get_int(ssh->conf, CONF_ssh_show_banner) && @@ -9507,14 +9517,14 @@ static void ssh2_send_ttymode(BinarySink *bs, } } -static void ssh2_setup_x11(struct ssh_channel *c, struct Packet *pktin, +static void ssh2_setup_x11(struct ssh_channel *c, PktIn *pktin, void *ctx) { struct ssh2_setup_x11_state { int crLine; }; Ssh ssh = c->ssh; - struct Packet *pktout; + PktOut *pktout; crStateP(ssh2_setup_x11_state, ctx); crBeginState; @@ -9543,14 +9553,14 @@ static void ssh2_setup_x11(struct ssh_channel *c, struct Packet *pktin, crFinishFreeV; } -static void ssh2_setup_agent(struct ssh_channel *c, struct Packet *pktin, +static void ssh2_setup_agent(struct ssh_channel *c, PktIn *pktin, void *ctx) { struct ssh2_setup_agent_state { int crLine; }; Ssh ssh = c->ssh; - struct Packet *pktout; + PktOut *pktout; crStateP(ssh2_setup_agent_state, ctx); crBeginState; @@ -9575,14 +9585,14 @@ static void ssh2_setup_agent(struct ssh_channel *c, struct Packet *pktin, crFinishFreeV; } -static void ssh2_setup_pty(struct ssh_channel *c, struct Packet *pktin, +static void ssh2_setup_pty(struct ssh_channel *c, PktIn *pktin, void *ctx) { struct ssh2_setup_pty_state { int crLine; }; Ssh ssh = c->ssh; - struct Packet *pktout; + PktOut *pktout; crStateP(ssh2_setup_pty_state, ctx); crBeginState; @@ -9630,7 +9640,7 @@ static void ssh2_setup_pty(struct ssh_channel *c, struct Packet *pktin, crFinishFreeV; } -static void ssh2_setup_env(struct ssh_channel *c, struct Packet *pktin, +static void ssh2_setup_env(struct ssh_channel *c, PktIn *pktin, void *ctx) { struct ssh2_setup_env_state { @@ -9638,7 +9648,7 @@ static void ssh2_setup_env(struct ssh_channel *c, struct Packet *pktin, int num_env, env_left, env_ok; }; Ssh ssh = c->ssh; - struct Packet *pktout; + PktOut *pktout; crStateP(ssh2_setup_env_state, ctx); crBeginState; @@ -9699,7 +9709,7 @@ static void ssh2_setup_env(struct ssh_channel *c, struct Packet *pktin, /* * Handle the SSH-2 userauth layer. */ -static void ssh2_msg_userauth(Ssh ssh, struct Packet *pktin) +static void ssh2_msg_userauth(Ssh ssh, PktIn *pktin) { pktin->refcount++; /* avoid packet being freed when we return */ pq_push(&ssh->pq_ssh2_userauth, pktin); @@ -9724,7 +9734,7 @@ static void ssh2_msg_userauth(Ssh ssh, struct Packet *pktin) static void do_ssh2_userauth(void *vctx) { Ssh ssh = (Ssh)vctx; - struct Packet *pktin; + PktIn *pktin; struct do_ssh2_userauth_state { int crLine; @@ -9766,7 +9776,7 @@ static void do_ssh2_userauth(void *vctx) int keyi, nkeys; ptrlen pk, alg, comment; int len; - struct Packet *pktout; + PktOut *pktout; Filename *keyfile; #ifndef NO_GSSAPI Ssh_gss_ctx gss_ctx; @@ -11156,7 +11166,7 @@ static void ssh2_userauth_input(Ssh ssh) /* * Handle the SSH-2 connection layer. */ -static void ssh2_msg_connection(Ssh ssh, struct Packet *pktin) +static void ssh2_msg_connection(Ssh ssh, PktIn *pktin) { pktin->refcount++; /* avoid packet being freed when we return */ pq_push(&ssh->pq_ssh2_connection, pktin); @@ -11164,7 +11174,7 @@ static void ssh2_msg_connection(Ssh ssh, struct Packet *pktin) } static void ssh2_response_connection(struct ssh_channel *c, - struct Packet *pktin, void *ctx) + PktIn *pktin, void *ctx) { if (pktin) ssh2_msg_connection(c->ssh, pktin); @@ -11207,11 +11217,11 @@ static void ssh2_connection_setup(Ssh ssh) static void do_ssh2_connection(void *vctx) { Ssh ssh = (Ssh)vctx; - struct Packet *pktin; + PktIn *pktin; struct do_ssh2_connection_state { int crLine; - struct Packet *pktout; + PktOut *pktout; }; crState(do_ssh2_connection_state); @@ -11483,7 +11493,7 @@ static void ssh2_connection_input(Ssh ssh) /* * Handlers for SSH-2 messages that might arrive at any moment. */ -static void ssh2_msg_disconnect(Ssh ssh, struct Packet *pktin) +static void ssh2_msg_disconnect(Ssh ssh, PktIn *pktin) { /* log reason code in disconnect message */ char *buf; @@ -11511,7 +11521,7 @@ static void ssh2_msg_disconnect(Ssh ssh, struct Packet *pktin) sfree(buf); } -static void ssh2_msg_debug(Ssh ssh, struct Packet *pktin) +static void ssh2_msg_debug(Ssh ssh, PktIn *pktin) { /* log the debug message */ ptrlen msg; @@ -11523,7 +11533,7 @@ static void ssh2_msg_debug(Ssh ssh, struct Packet *pktin) logeventf(ssh, "Remote debug message: %.*s", PTRLEN_PRINTF(msg)); } -static void ssh2_msg_transport(Ssh ssh, struct Packet *pktin) +static void ssh2_msg_transport(Ssh ssh, PktIn *pktin) { pktin->refcount++; /* avoid packet being freed when we return */ pq_push(&ssh->pq_ssh2_transport, pktin); @@ -11535,7 +11545,7 @@ static void ssh2_msg_transport(Ssh ssh, struct Packet *pktin) * This only applies to packets whose meaning PuTTY understands. * Entirely unknown packets are handled below. */ -static void ssh2_msg_unexpected(Ssh ssh, struct Packet *pktin) +static void ssh2_msg_unexpected(Ssh ssh, PktIn *pktin) { char *buf = dupprintf("Server protocol violation: unexpected %s packet", ssh2_pkt_type(ssh->pkt_kctx, ssh->pkt_actx, @@ -11544,9 +11554,9 @@ static void ssh2_msg_unexpected(Ssh ssh, struct Packet *pktin) sfree(buf); } -static void ssh2_msg_something_unimplemented(Ssh ssh, struct Packet *pktin) +static void ssh2_msg_something_unimplemented(Ssh ssh, PktIn *pktin) { - struct Packet *pktout; + PktOut *pktout; pktout = ssh2_pkt_init(SSH2_MSG_UNIMPLEMENTED); put_uint32(pktout, pktin->sequence); /* @@ -11689,29 +11699,30 @@ static void ssh2_bare_connection_protocol_setup(Ssh ssh) } #ifndef NO_GSSAPI -static struct Packet *ssh2_gss_authpacket(Ssh ssh, Ssh_gss_ctx gss_ctx, - const char *authtype) +static PktOut *ssh2_gss_authpacket(Ssh ssh, Ssh_gss_ctx gss_ctx, + const char *authtype) { - struct Packet *p = ssh2_pkt_init(0); - int micoffset = p->length; + strbuf *sb; + PktOut *p; Ssh_gss_buf buf; Ssh_gss_buf mic; /* - * The mic is computed over the session id + intended packet, so we - * build an artificial packet with a prepended session id. + * The mic is computed over the session id + intended + * USERAUTH_REQUEST packet. */ - put_string(p, ssh->v2_session_id, ssh->v2_session_id_len); - put_byte(p, SSH2_MSG_USERAUTH_REQUEST); - put_stringz(p, ssh->username); - put_stringz(p, "ssh-connection"); - put_stringz(p, authtype); + sb = strbuf_new(); + put_string(sb, ssh->v2_session_id, ssh->v2_session_id_len); + put_byte(sb, SSH2_MSG_USERAUTH_REQUEST); + put_stringz(sb, ssh->username); + put_stringz(sb, "ssh-connection"); + put_stringz(sb, authtype); /* Compute the mic */ - buf.value = (char *)p->data + micoffset; - buf.length = p->length - micoffset; + buf.value = sb->s; + buf.length = sb->len; ssh->gsslib->get_mic(ssh->gsslib, gss_ctx, &buf, &mic); - ssh_unref_packet(p); + strbuf_free(sb); /* Now we can build the real packet */ if (strcmp(authtype, "gssapi-with-mic") == 0) { @@ -11962,7 +11973,7 @@ static void ssh2_timer(void *ctx, unsigned long now) (void) ssh2_timer_update(ssh, 0); } -static void ssh2_general_packet_processing(Ssh ssh, struct Packet *pktin) +static void ssh2_general_packet_processing(Ssh ssh, PktIn *pktin) { ssh->incoming_data_size += pktin->encrypted_len; if (!ssh->kex_in_progress && @@ -12200,7 +12211,7 @@ static void ssh_free(void *handle) sfree(ssh->savedhost); while (ssh->queuelen-- > 0) - ssh_unref_packet(ssh->queue[ssh->queuelen]); + ssh_free_pktout(ssh->queue[ssh->queuelen]); sfree(ssh->queue); while (ssh->qhead) { @@ -12413,7 +12424,7 @@ static int ssh_sendbuffer(void *handle) static void ssh_size(void *handle, int width, int height) { Ssh ssh = (Ssh) handle; - struct Packet *pktout; + PktOut *pktout; ssh->term_width = width; ssh->term_height = height; @@ -12560,7 +12571,7 @@ static const struct telnet_special *ssh_get_specials(void *handle) static void ssh_special(void *handle, Telnet_Special code) { Ssh ssh = (Ssh) handle; - struct Packet *pktout; + PktOut *pktout; if (code == TS_EOF) { if (ssh->state != SSH_STATE_SESSION) { @@ -12689,7 +12700,7 @@ void ssh_send_packet_from_downstream(Ssh ssh, unsigned id, int type, const void *data, int datalen, const char *additional_log_text) { - struct Packet *pkt; + PktOut *pkt; pkt = ssh2_pkt_init(type); pkt->downstream_id = id; @@ -12728,7 +12739,7 @@ void ssh_send_port_open(void *channel, const char *hostname, int port, { struct ssh_channel *c = (struct ssh_channel *)channel; Ssh ssh = c->ssh; - struct Packet *pktout; + PktOut *pktout; logeventf(ssh, "Opening connection to %s:%d for %s", hostname, port, org); From bf3c9df54a9ed55088d7c381f3798095ae48767e Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Wed, 6 Jun 2018 07:17:09 +0100 Subject: [PATCH 361/607] Remove body and length fields from PktIn. They were duplicating values stored in the BinarySource substructure. Mostly they're not referred to directly any more (instead, we call get_foo to access the BinarySource); and when they are, we can switch to reading the same values back out of the BinarySource anyway. --- ssh.c | 93 ++++++++++++++++++++++++++++------------------------------- 1 file changed, 44 insertions(+), 49 deletions(-) diff --git a/ssh.c b/ssh.c index 7de32b50..e8a90e69 100644 --- a/ssh.c +++ b/ssh.c @@ -672,11 +672,9 @@ struct ssh_portfwd { struct PktIn { int refcount; - long length; /* length relative to 'body' */ int type; unsigned long sequence; /* SSH-2 incoming sequence number */ unsigned char *data; /* allocated storage */ - unsigned char *body; /* offset of payload within `data' */ long maxlen; /* amount of storage allocated for `data' */ long encrypted_len; /* for SSH-2 total-size counting */ BinarySource_IMPLEMENTATION; @@ -809,14 +807,14 @@ static int pq_empty_on_to_front_of(struct PacketQueue *src, } struct rdpkt1_state_tag { - long len, pad, biglen; + long len, pad, biglen, length; unsigned long realcrc, gotcrc; int chunk; PktIn *pktin; }; struct rdpkt2_state_tag { - long len, pad, payload, packetlen, maclen; + long len, pad, payload, packetlen, maclen, length; int cipherblk; unsigned long incoming_sequence; PktIn *pktin; @@ -1407,7 +1405,8 @@ static void ssh1_log_incoming_packet(Ssh ssh, const PktIn *pkt) ptrlen str; BinarySource src[1]; - BinarySource_BARE_INIT(src, pkt->body, pkt->length); + BinarySource_BARE_INIT(src, BinarySource_UPCAST(pkt)->data, + BinarySource_UPCAST(pkt)->len); if (ssh->logomitdata && (pkt->type == SSH1_SMSG_STDOUT_DATA || @@ -1424,10 +1423,8 @@ static void ssh1_log_incoming_packet(Ssh ssh, const PktIn *pkt) nblanks++; } } - log_packet(ssh->logctx, PKT_INCOMING, pkt->type, - ssh1_pkt_type(pkt->type), - pkt->body, pkt->length, nblanks, blanks, NULL, - 0, NULL); + log_packet(ssh->logctx, PKT_INCOMING, pkt->type, ssh1_pkt_type(pkt->type), + src->data, src->len, nblanks, blanks, NULL, 0, NULL); } static void ssh1_log_outgoing_packet(Ssh ssh, const PktOut *pkt) @@ -1511,12 +1508,12 @@ static void ssh1_rdpkt(Ssh ssh) while (1) { st->pktin = snew(PktIn); - st->pktin->body = st->pktin->data = NULL; + st->pktin->data = NULL; st->pktin->maxlen = 0; st->pktin->refcount = 1; st->pktin->type = 0; - st->pktin->length = 0; + st->length = 0; { unsigned char lenbuf[4]; @@ -1527,7 +1524,7 @@ static void ssh1_rdpkt(Ssh ssh) st->pad = 8 - (st->len % 8); st->biglen = st->len + st->pad; - st->pktin->length = st->len - 5; + st->length = st->len - 5; if (st->biglen < 0) { bombout(("Extremely large packet length from server suggests" @@ -1561,13 +1558,12 @@ static void ssh1_rdpkt(Ssh ssh) crStopV; } - st->pktin->body = st->pktin->data + st->pad + 1; - if (ssh->v1_compressing) { unsigned char *decompblk; int decomplen; if (!zlib_decompress_block(ssh->sc_comp_ctx, - st->pktin->body - 1, st->pktin->length + 1, + st->pktin->data + st->pad, + st->length + 1, &decompblk, &decomplen)) { bombout(("Zlib decompression encountered invalid data")); ssh_unref_packet(st->pktin); @@ -1578,26 +1574,25 @@ static void ssh1_rdpkt(Ssh ssh) st->pktin->maxlen = st->pad + decomplen; st->pktin->data = sresize(st->pktin->data, st->pktin->maxlen, unsigned char); - st->pktin->body = st->pktin->data + st->pad + 1; } - memcpy(st->pktin->body - 1, decompblk, decomplen); + memcpy(st->pktin->data + st->pad, decompblk, decomplen); sfree(decompblk); - st->pktin->length = decomplen - 1; + st->length = decomplen - 1; } - st->pktin->type = st->pktin->body[-1]; + st->pktin->type = st->pktin->data[st->pad]; /* - * Now pktin->body and pktin->length identify the semantic content - * of the packet, excluding the initial type byte. + * Now we know the bounds of the semantic content of the + * packet, excluding the initial type byte. */ + BinarySource_INIT(st->pktin, st->pktin->data + st->pad + 1, + st->length); if (ssh->logctx) ssh1_log_incoming_packet(ssh, st->pktin); - BinarySource_INIT(st->pktin, st->pktin->body, st->pktin->length); - /* * Mild layer violation: if the message is a DISCONNECT, we * should unset the close_expected flag, because now we _do_ @@ -1625,7 +1620,8 @@ static void ssh2_log_incoming_packet(Ssh ssh, const PktIn *pkt) ptrlen str; BinarySource src[1]; - BinarySource_BARE_INIT(src, pkt->body, pkt->length); + BinarySource_BARE_INIT(src, BinarySource_UPCAST(pkt)->data, + BinarySource_UPCAST(pkt)->len); if (ssh->logomitdata && (pkt->type == SSH2_MSG_CHANNEL_DATA || @@ -1645,7 +1641,7 @@ static void ssh2_log_incoming_packet(Ssh ssh, const PktIn *pkt) log_packet(ssh->logctx, PKT_INCOMING, pkt->type, ssh2_pkt_type(ssh->pkt_kctx, ssh->pkt_actx, pkt->type), - pkt->body, pkt->length, nblanks, blanks, &pkt->sequence, + src->data, src->len, nblanks, blanks, &pkt->sequence, 0, NULL); } @@ -1759,12 +1755,12 @@ static void ssh2_rdpkt(Ssh ssh) while (1) { st->pktin = snew(PktIn); - st->pktin->body = st->pktin->data = NULL; + st->pktin->data = NULL; st->pktin->maxlen = 0; st->pktin->refcount = 1; st->pktin->type = 0; - st->pktin->length = 0; + st->length = 0; if (ssh->sccipher) st->cipherblk = ssh->sccipher->blksize; else @@ -1984,13 +1980,13 @@ static void ssh2_rdpkt(Ssh ssh) */ st->payload = st->len - st->pad - 1; - st->pktin->length = st->payload + 5; + st->length = st->payload + 5; st->pktin->encrypted_len = st->packetlen; st->pktin->sequence = st->incoming_sequence++; - st->pktin->length = st->packetlen - st->pad; - assert(st->pktin->length >= 0); + st->length = st->packetlen - st->pad; + assert(st->length >= 0); /* * Decompress packet payload. @@ -2000,7 +1996,7 @@ static void ssh2_rdpkt(Ssh ssh) int newlen; if (ssh->sccomp && ssh->sccomp->decompress(ssh->sc_comp_ctx, - st->pktin->data + 5, st->pktin->length - 5, + st->pktin->data + 5, st->length - 5, &newpayload, &newlen)) { if (st->pktin->maxlen < newlen + 5) { st->pktin->maxlen = newlen + 5; @@ -2008,7 +2004,7 @@ static void ssh2_rdpkt(Ssh ssh) st->pktin->maxlen, unsigned char); } - st->pktin->length = 5 + newlen; + st->length = 5 + newlen; memcpy(st->pktin->data + 5, newpayload, newlen); sfree(newpayload); } @@ -2019,24 +2015,22 @@ static void ssh2_rdpkt(Ssh ssh) * with no type byte are forbidden, so treat them as deserving * an SSH_MSG_UNIMPLEMENTED. */ - if (st->pktin->length <= 5) { /* == 5 we hope, but robustness */ + if (st->length <= 5) { /* == 5 we hope, but robustness */ ssh2_msg_something_unimplemented(ssh, st->pktin); crStopV; } /* - * pktin->body and pktin->length should identify the semantic - * content of the packet, excluding the initial type byte. + * Now we can identify the semantic content of the packet, + * and also the initial type byte. */ st->pktin->type = st->pktin->data[5]; - st->pktin->body = st->pktin->data + 6; - st->pktin->length -= 6; - assert(st->pktin->length >= 0); /* one last double-check */ + st->length -= 6; + assert(st->length >= 0); /* one last double-check */ + BinarySource_INIT(st->pktin, st->pktin->data + 6, st->length); if (ssh->logctx) ssh2_log_incoming_packet(ssh, st->pktin); - BinarySource_INIT(st->pktin, st->pktin->body, st->pktin->length); - /* * Mild layer violation: if the message is a DISCONNECT, we * should unset the close_expected flag, because now we _do_ @@ -2086,7 +2080,6 @@ static void ssh2_bare_connection_rdpkt(Ssh ssh) } st->pktin = snew(PktIn); - st->pktin->body = NULL; st->pktin->maxlen = 0; st->pktin->refcount = 1; st->pktin->data = snewn(st->packetlen, unsigned char); @@ -2107,8 +2100,7 @@ static void ssh2_bare_connection_rdpkt(Ssh ssh) * content of the packet, excluding the initial type byte. */ st->pktin->type = st->pktin->data[0]; - st->pktin->body = st->pktin->data + 1; - st->pktin->length = st->packetlen - 1; + BinarySource_INIT(st->pktin, st->pktin->data + 1, st->packetlen - 1); /* * Log incoming packet, possibly omitting sensitive fields. @@ -2116,8 +2108,6 @@ static void ssh2_bare_connection_rdpkt(Ssh ssh) if (ssh->logctx) ssh2_log_incoming_packet(ssh, st->pktin); - BinarySource_INIT(st->pktin, st->pktin->body, st->pktin->length); - /* * Mild layer violation: if the message is a DISCONNECT, we * should unset the close_expected flag, because now we _do_ @@ -5270,7 +5260,8 @@ static void ssh_sharing_global_request_response(Ssh ssh, PktIn *pktin, void *ctx) { share_got_pkt_from_server(ctx, pktin->type, - pktin->body, pktin->length); + BinarySource_UPCAST(pktin)->data, + BinarySource_UPCAST(pktin)->len); } void ssh_sharing_queue_global_request(Ssh ssh, void *share_ctx) @@ -7051,7 +7042,9 @@ static void do_ssh2_transport(void *vctx) put_string(ssh->exhash_bs, s->our_kexinit, s->our_kexinitlen); sfree(s->our_kexinit); /* Include the type byte in the hash of server's KEXINIT */ - put_string(ssh->exhash_bs, pktin->body - 1, pktin->length + 1); + put_string(ssh->exhash_bs, + (const char *)BinarySource_UPCAST(pktin)->data - 1, + BinarySource_UPCAST(pktin)->len + 1); if (s->warn_kex) { ssh_set_frozen(ssh, 1); @@ -8605,7 +8598,8 @@ static struct ssh_channel *ssh_channel_msg(Ssh ssh, PktIn *pktin) } if (c->type == CHAN_SHARING) { share_got_pkt_from_server(c->u.sharing.ctx, pktin->type, - pktin->body, pktin->length); + BinarySource_UPCAST(pktin)->data, + BinarySource_UPCAST(pktin)->len); return NULL; } return c; @@ -9389,7 +9383,8 @@ static void ssh2_msg_channel_open(Ssh ssh, PktIn *pktin) * to sshshare.c. */ share_got_pkt_from_server(realpf->share_ctx, pktin->type, - pktin->body, pktin->length); + BinarySource_UPCAST(pktin)->data, + BinarySource_UPCAST(pktin)->len); sfree(c); return; } From ea04bf3da98173b22325dee30acca9146cc24851 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Tue, 5 Jun 2018 18:13:08 +0100 Subject: [PATCH 362/607] Remove data and maxlen fields from PktIn. These were only used in the rdpkt coroutines, during construction of the incoming packet; once it's complete, they're never touched again. So really they should have been fields in the rdpkt coroutines' state - and now they are. The new memory allocation strategy for incoming packets is to defer creation of the returned pktin structure until we know how big its data buffer will really need to be, and then use snew_plus to make the PktIn and the payload block in the same allocation. When we have to read and keep some amount of the packet before allocating the returned structure, we do it by having a persistent buffer in the rdpkt state, which is retained for the whole connection and only freed once in ssh_free. --- ssh.c | 233 +++++++++++++++++++++++++++++++++------------------------- 1 file changed, 134 insertions(+), 99 deletions(-) diff --git a/ssh.c b/ssh.c index e8a90e69..9a71cd5d 100644 --- a/ssh.c +++ b/ssh.c @@ -674,8 +674,6 @@ struct PktIn { int refcount; int type; unsigned long sequence; /* SSH-2 incoming sequence number */ - unsigned char *data; /* allocated storage */ - long maxlen; /* amount of storage allocated for `data' */ long encrypted_len; /* for SSH-2 total-size counting */ BinarySource_IMPLEMENTATION; }; @@ -807,21 +805,26 @@ static int pq_empty_on_to_front_of(struct PacketQueue *src, } struct rdpkt1_state_tag { - long len, pad, biglen, length; + long len, pad, biglen, length, maxlen; + unsigned char *data; unsigned long realcrc, gotcrc; int chunk; PktIn *pktin; }; struct rdpkt2_state_tag { - long len, pad, payload, packetlen, maclen, length; + long len, pad, payload, packetlen, maclen, length, maxlen; + unsigned char *buf; + size_t bufsize; + unsigned char *data; int cipherblk; unsigned long incoming_sequence; PktIn *pktin; }; struct rdpkt2_bare_state_tag { - long packetlen; + long packetlen, maxlen; + unsigned char *data; unsigned long incoming_sequence; PktIn *pktin; }; @@ -1373,10 +1376,8 @@ static void c_write_str(Ssh ssh, const char *buf) static void ssh_unref_packet(PktIn *pkt) { - if (--pkt->refcount <= 0) { - sfree(pkt->data); + if (--pkt->refcount <= 0) sfree(pkt); - } } static void ssh_free_pktout(PktOut *pkt) @@ -1507,12 +1508,7 @@ static void ssh1_rdpkt(Ssh ssh) crBegin(ssh->ssh1_rdpkt_crstate); while (1) { - st->pktin = snew(PktIn); - st->pktin->data = NULL; - st->pktin->maxlen = 0; - st->pktin->refcount = 1; - - st->pktin->type = 0; + st->maxlen = 0; st->length = 0; { @@ -1533,14 +1529,20 @@ static void ssh1_rdpkt(Ssh ssh) crStopV; } - st->pktin->maxlen = st->biglen; - st->pktin->data = snewn(st->biglen, unsigned char); + /* + * Allocate the packet to return, now we know its length. + */ + st->pktin = snew_plus(PktIn, st->biglen); + st->pktin->refcount = 1; + st->pktin->type = 0; + + st->maxlen = st->biglen; + st->data = snew_plus_get_aux(st->pktin); crMaybeWaitUntilV(bufchain_try_fetch_consume( - &ssh->incoming_data, - st->pktin->data, st->biglen)); + &ssh->incoming_data, st->data, st->biglen)); - if (ssh->cipher && detect_attack(ssh->crcda_ctx, st->pktin->data, + if (ssh->cipher && detect_attack(ssh->crcda_ctx, st->data, st->biglen, NULL)) { bombout(("Network attack (CRC compensation) detected!")); ssh_unref_packet(st->pktin); @@ -1548,10 +1550,10 @@ static void ssh1_rdpkt(Ssh ssh) } if (ssh->cipher) - ssh->cipher->decrypt(ssh->v1_cipher_ctx, st->pktin->data, st->biglen); + ssh->cipher->decrypt(ssh->v1_cipher_ctx, st->data, st->biglen); - st->realcrc = crc32_compute(st->pktin->data, st->biglen - 4); - st->gotcrc = GET_32BIT(st->pktin->data + st->biglen - 4); + st->realcrc = crc32_compute(st->data, st->biglen - 4); + st->gotcrc = GET_32BIT(st->data + st->biglen - 4); if (st->gotcrc != st->realcrc) { bombout(("Incorrect CRC received on packet")); ssh_unref_packet(st->pktin); @@ -1562,33 +1564,36 @@ static void ssh1_rdpkt(Ssh ssh) unsigned char *decompblk; int decomplen; if (!zlib_decompress_block(ssh->sc_comp_ctx, - st->pktin->data + st->pad, - st->length + 1, + st->data + st->pad, st->length + 1, &decompblk, &decomplen)) { bombout(("Zlib decompression encountered invalid data")); ssh_unref_packet(st->pktin); crStopV; } - if (st->pktin->maxlen < st->pad + decomplen) { - st->pktin->maxlen = st->pad + decomplen; - st->pktin->data = sresize(st->pktin->data, st->pktin->maxlen, - unsigned char); + if (st->maxlen < st->pad + decomplen) { + PktIn *old_pktin = st->pktin; + + st->maxlen = st->pad + decomplen; + st->pktin = snew_plus(PktIn, st->maxlen); + *st->pktin = *old_pktin; /* structure copy */ + st->data = snew_plus_get_aux(st->pktin); + + smemclr(old_pktin, st->biglen); + sfree(old_pktin); } - memcpy(st->pktin->data + st->pad, decompblk, decomplen); + memcpy(st->data + st->pad, decompblk, decomplen); sfree(decompblk); st->length = decomplen - 1; } - st->pktin->type = st->pktin->data[st->pad]; - /* - * Now we know the bounds of the semantic content of the - * packet, excluding the initial type byte. + * Now we can find the bounds of the semantic content of the + * packet, and the initial type byte. */ - BinarySource_INIT(st->pktin, st->pktin->data + st->pad + 1, - st->length); + st->pktin->type = st->data[st->pad]; + BinarySource_INIT(st->pktin, st->data + st->pad + 1, st->length); if (ssh->logctx) ssh1_log_incoming_packet(ssh, st->pktin); @@ -1753,13 +1758,11 @@ static void ssh2_rdpkt(Ssh ssh) crBegin(ssh->ssh2_rdpkt_crstate); - while (1) { - st->pktin = snew(PktIn); - st->pktin->data = NULL; - st->pktin->maxlen = 0; - st->pktin->refcount = 1; + st->buf = NULL; + st->bufsize = 0; - st->pktin->type = 0; + while (1) { + st->maxlen = 0; st->length = 0; if (ssh->sccipher) st->cipherblk = ssh->sccipher->blksize; @@ -1789,14 +1792,18 @@ static void ssh2_rdpkt(Ssh ssh) * detecting it before we decrypt anything. */ - /* May as well allocate the whole lot now. */ - st->pktin->data = snewn(OUR_V2_PACKETLIMIT + st->maclen, - unsigned char); + /* + * Make sure we have buffer space for a maximum-size packet. + */ + int buflimit = OUR_V2_PACKETLIMIT + st->maclen; + if (st->bufsize < buflimit) { + st->bufsize = buflimit; + st->buf = sresize(st->buf, st->bufsize, unsigned char); + } /* Read an amount corresponding to the MAC. */ crMaybeWaitUntilV(bufchain_try_fetch_consume( - &ssh->incoming_data, - st->pktin->data, st->maclen)); + &ssh->incoming_data, st->buf, st->maclen)); st->packetlen = 0; ssh->scmac->start(ssh->sc_mac_ctx); @@ -1807,51 +1814,59 @@ static void ssh2_rdpkt(Ssh ssh) /* Read another cipher-block's worth, and tack it onto the end. */ crMaybeWaitUntilV(bufchain_try_fetch_consume( &ssh->incoming_data, - st->pktin->data + (st->packetlen + - st->maclen), + st->buf + (st->packetlen + st->maclen), st->cipherblk)); /* Decrypt one more block (a little further back in the stream). */ ssh->sccipher->decrypt(ssh->sc_cipher_ctx, - st->pktin->data + st->packetlen, + st->buf + st->packetlen, st->cipherblk); /* Feed that block to the MAC. */ put_data(ssh->sc_mac_bs, - st->pktin->data + st->packetlen, st->cipherblk); + st->buf + st->packetlen, st->cipherblk); st->packetlen += st->cipherblk; /* See if that gives us a valid packet. */ if (ssh->scmac->verresult(ssh->sc_mac_ctx, - st->pktin->data + st->packetlen) && - ((st->len = toint(GET_32BIT(st->pktin->data))) == + st->buf + st->packetlen) && + ((st->len = toint(GET_32BIT(st->buf))) == st->packetlen-4)) break; if (st->packetlen >= OUR_V2_PACKETLIMIT) { bombout(("No valid incoming packet found")); - ssh_unref_packet(st->pktin); crStopV; } } - st->pktin->maxlen = st->packetlen + st->maclen; - st->pktin->data = sresize(st->pktin->data, st->pktin->maxlen, - unsigned char); + st->maxlen = st->packetlen + st->maclen; + + /* + * Now transfer the data into an output packet. + */ + st->pktin = snew_plus(PktIn, st->maxlen); + st->pktin->refcount = 1; + st->pktin->type = 0; + st->data = snew_plus_get_aux(st->pktin); + memcpy(st->data, st->buf, st->maxlen); } else if (ssh->scmac && ssh->scmac_etm) { - st->pktin->data = snewn(4, unsigned char); + if (st->bufsize < 4) { + st->bufsize = 4; + st->buf = sresize(st->buf, st->bufsize, unsigned char); + } /* * OpenSSH encrypt-then-MAC mode: the packet length is * unencrypted, unless the cipher supports length encryption. */ crMaybeWaitUntilV(bufchain_try_fetch_consume( - &ssh->incoming_data, st->pktin->data, 4)); + &ssh->incoming_data, st->buf, 4)); /* Cipher supports length decryption, so do it */ if (ssh->sccipher && (ssh->sccipher->flags & SSH_CIPHER_SEPARATE_LENGTH)) { /* Keep the packet the same though, so the MAC passes */ unsigned char len[4]; - memcpy(len, st->pktin->data, 4); + memcpy(len, st->buf, 4); ssh->sccipher->decrypt_length(ssh->sc_cipher_ctx, len, 4, st->incoming_sequence); st->len = toint(GET_32BIT(len)); } else { - st->len = toint(GET_32BIT(st->pktin->data)); + st->len = toint(GET_32BIT(st->buf)); } /* @@ -1861,7 +1876,6 @@ static void ssh2_rdpkt(Ssh ssh) if (st->len < 0 || st->len > OUR_V2_PACKETLIMIT || st->len % st->cipherblk != 0) { bombout(("Incoming packet length field was garbled")); - ssh_unref_packet(st->pktin); crStopV; } @@ -1871,24 +1885,26 @@ static void ssh2_rdpkt(Ssh ssh) st->packetlen = st->len + 4; /* - * Allocate memory for the rest of the packet. + * Allocate the packet to return, now we know its length. */ - st->pktin->maxlen = st->packetlen + st->maclen; - st->pktin->data = sresize(st->pktin->data, st->pktin->maxlen, - unsigned char); + st->pktin = snew_plus(PktIn, OUR_V2_PACKETLIMIT + st->maclen); + st->pktin->refcount = 1; + st->pktin->type = 0; + st->data = snew_plus_get_aux(st->pktin); + memcpy(st->data, st->buf, 4); /* * Read the remainder of the packet. */ crMaybeWaitUntilV(bufchain_try_fetch_consume( - &ssh->incoming_data, st->pktin->data + 4, + &ssh->incoming_data, st->data + 4, st->packetlen + st->maclen - 4)); /* * Check the MAC. */ if (ssh->scmac - && !ssh->scmac->verify(ssh->sc_mac_ctx, st->pktin->data, + && !ssh->scmac->verify(ssh->sc_mac_ctx, st->data, st->len + 4, st->incoming_sequence)) { bombout(("Incorrect MAC received on packet")); ssh_unref_packet(st->pktin); @@ -1898,10 +1914,12 @@ static void ssh2_rdpkt(Ssh ssh) /* Decrypt everything between the length field and the MAC. */ if (ssh->sccipher) ssh->sccipher->decrypt(ssh->sc_cipher_ctx, - st->pktin->data + 4, - st->packetlen - 4); + st->data + 4, st->packetlen - 4); } else { - st->pktin->data = snewn(st->cipherblk, unsigned char); + if (st->bufsize < st->cipherblk) { + st->bufsize = st->cipherblk; + st->buf = sresize(st->buf, st->bufsize, unsigned char); + } /* * Acquire and decrypt the first block of the packet. This will @@ -1909,16 +1927,16 @@ static void ssh2_rdpkt(Ssh ssh) */ crMaybeWaitUntilV(bufchain_try_fetch_consume( &ssh->incoming_data, - st->pktin->data, st->cipherblk)); + st->buf, st->cipherblk)); if (ssh->sccipher) ssh->sccipher->decrypt(ssh->sc_cipher_ctx, - st->pktin->data, st->cipherblk); + st->buf, st->cipherblk); /* * Now get the length figure. */ - st->len = toint(GET_32BIT(st->pktin->data)); + st->len = toint(GET_32BIT(st->buf)); /* * _Completely_ silly lengths should be stomped on before they @@ -1937,31 +1955,34 @@ static void ssh2_rdpkt(Ssh ssh) st->packetlen = st->len + 4; /* - * Allocate memory for the rest of the packet. + * Allocate the packet to return, now we know its length. */ - st->pktin->maxlen = st->packetlen + st->maclen; - st->pktin->data = sresize(st->pktin->data, st->pktin->maxlen, - unsigned char); + st->maxlen = st->packetlen + st->maclen; + st->pktin = snew_plus(PktIn, st->maxlen); + st->pktin->refcount = 1; + st->pktin->type = 0; + st->data = snew_plus_get_aux(st->pktin); + memcpy(st->data, st->buf, st->cipherblk); /* * Read and decrypt the remainder of the packet. */ crMaybeWaitUntilV(bufchain_try_fetch_consume( &ssh->incoming_data, - st->pktin->data + st->cipherblk, + st->data + st->cipherblk, st->packetlen + st->maclen - st->cipherblk)); /* Decrypt everything _except_ the MAC. */ if (ssh->sccipher) ssh->sccipher->decrypt(ssh->sc_cipher_ctx, - st->pktin->data + st->cipherblk, + st->data + st->cipherblk, st->packetlen - st->cipherblk); /* * Check the MAC. */ if (ssh->scmac - && !ssh->scmac->verify(ssh->sc_mac_ctx, st->pktin->data, + && !ssh->scmac->verify(ssh->sc_mac_ctx, st->data, st->len + 4, st->incoming_sequence)) { bombout(("Incorrect MAC received on packet")); ssh_unref_packet(st->pktin); @@ -1969,7 +1990,7 @@ static void ssh2_rdpkt(Ssh ssh) } } /* Get and sanity-check the amount of random padding. */ - st->pad = st->pktin->data[4]; + st->pad = st->data[4]; if (st->pad < 4 || st->len - st->pad < 1) { bombout(("Invalid padding length on received packet")); ssh_unref_packet(st->pktin); @@ -1996,16 +2017,21 @@ static void ssh2_rdpkt(Ssh ssh) int newlen; if (ssh->sccomp && ssh->sccomp->decompress(ssh->sc_comp_ctx, - st->pktin->data + 5, st->length - 5, + st->data + 5, st->length - 5, &newpayload, &newlen)) { - if (st->pktin->maxlen < newlen + 5) { - st->pktin->maxlen = newlen + 5; - st->pktin->data = sresize(st->pktin->data, - st->pktin->maxlen, - unsigned char); + if (st->maxlen < newlen + 5) { + PktIn *old_pktin = st->pktin; + + st->maxlen = newlen + 5; + st->pktin = snew_plus(PktIn, st->maxlen); + *st->pktin = *old_pktin; /* structure copy */ + st->data = snew_plus_get_aux(st->pktin); + + smemclr(old_pktin, st->packetlen + st->maclen); + sfree(old_pktin); } st->length = 5 + newlen; - memcpy(st->pktin->data + 5, newpayload, newlen); + memcpy(st->data + 5, newpayload, newlen); sfree(newpayload); } } @@ -2019,14 +2045,15 @@ static void ssh2_rdpkt(Ssh ssh) ssh2_msg_something_unimplemented(ssh, st->pktin); crStopV; } + /* * Now we can identify the semantic content of the packet, * and also the initial type byte. */ - st->pktin->type = st->pktin->data[5]; + st->pktin->type = st->data[5]; st->length -= 6; assert(st->length >= 0); /* one last double-check */ - BinarySource_INIT(st->pktin, st->pktin->data + 6, st->length); + BinarySource_INIT(st->pktin, st->data + 6, st->length); if (ssh->logctx) ssh2_log_incoming_packet(ssh, st->pktin); @@ -2079,10 +2106,13 @@ static void ssh2_bare_connection_rdpkt(Ssh ssh) crStopV; } - st->pktin = snew(PktIn); - st->pktin->maxlen = 0; + /* + * Allocate the packet to return, now we know its length. + */ + st->pktin = snew_plus(PktIn, st->packetlen); + st->maxlen = 0; st->pktin->refcount = 1; - st->pktin->data = snewn(st->packetlen, unsigned char); + st->data = snew_plus_get_aux(st->pktin); st->pktin->encrypted_len = st->packetlen; @@ -2092,15 +2122,14 @@ static void ssh2_bare_connection_rdpkt(Ssh ssh) * Read the remainder of the packet. */ crMaybeWaitUntilV(bufchain_try_fetch_consume( - &ssh->incoming_data, - st->pktin->data, st->packetlen)); + &ssh->incoming_data, st->data, st->packetlen)); /* - * pktin->body and pktin->length should identify the semantic - * content of the packet, excluding the initial type byte. + * The data we just read is precisely the initial type byte + * followed by the packet payload. */ - st->pktin->type = st->pktin->data[0]; - BinarySource_INIT(st->pktin, st->pktin->data + 1, st->packetlen - 1); + st->pktin->type = st->data[0]; + BinarySource_INIT(st->pktin, st->data + 1, st->packetlen - 1); /* * Log incoming packet, possibly omitting sensitive fields. @@ -12045,6 +12074,7 @@ static const char *ssh_init(void *frontend_handle, void **backend_handle, ssh->ssh1_rdpkt_crstate = 0; ssh->ssh2_rdpkt_crstate = 0; ssh->ssh2_bare_rdpkt_crstate = 0; + ssh->rdpkt2_state.buf = NULL; ssh->do_ssh1_connection_crstate = 0; ssh->do_ssh_init_state = NULL; ssh->do_ssh_connection_init_state = NULL; @@ -12205,6 +12235,11 @@ static void ssh_free(void *handle) dh_cleanup(ssh->kex_ctx); sfree(ssh->savedhost); + if (ssh->rdpkt2_state.buf) { + smemclr(ssh->rdpkt2_state.buf, ssh->rdpkt2_state.bufsize); + sfree(ssh->rdpkt2_state.buf); + } + while (ssh->queuelen-- > 0) ssh_free_pktout(ssh->queue[ssh->queuelen]); sfree(ssh->queue); From 8c4680a97264258e1412213a65a7e3db0eda2040 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Wed, 6 Jun 2018 07:17:32 +0100 Subject: [PATCH 363/607] Replace PktOut body pointer with a prefix length. The body pointer was used after encryption to mark the start of the fully wire-ready packet by ssh2_pkt_construct, and before encryption by the log_outgoing_packet functions. Now the former returns a nice modern ptrlen (it never really needed to store the pointer _in_ the packet structure anyway), and the latter uses an integer 'prefix' field, which isn't very different in concept but saves effort on reallocs. --- ssh.c | 75 ++++++++++++++++++++++++----------------------------------- 1 file changed, 30 insertions(+), 45 deletions(-) diff --git a/ssh.c b/ssh.c index 9a71cd5d..d7d77e17 100644 --- a/ssh.c +++ b/ssh.c @@ -366,7 +366,7 @@ static struct PktOut *ssh1_pkt_init(int pkt_type); static struct PktOut *ssh2_pkt_init(int pkt_type); static void ssh_pkt_ensure(struct PktOut *, int length); static void ssh_pkt_adddata(struct PktOut *, const void *data, int len); -static int ssh2_pkt_construct(Ssh, struct PktOut *); +static ptrlen ssh2_pkt_construct(Ssh, struct PktOut *); static void ssh2_pkt_send(Ssh, struct PktOut *); static void ssh2_pkt_send_noqueue(Ssh, struct PktOut *); static void do_ssh1_login(void *vctx); @@ -679,11 +679,11 @@ struct PktIn { }; struct PktOut { - long length; /* length relative to 'data' */ + long prefix; /* bytes up to and including type field */ + long length; /* total bytes, including prefix */ int type; long forcepad; /* SSH-2: force padding to at least this length */ unsigned char *data; /* allocated storage */ - unsigned char *body; /* offset of payload within `data' */ long maxlen; /* amount of storage allocated for `data' */ long encrypted_len; /* for SSH-2 total-size counting */ @@ -1393,7 +1393,7 @@ static PktOut *ssh_new_packet(void) PktOut *pkt = snew(PktOut); BinarySink_INIT(pkt, ssh_pkt_BinarySink_write); - pkt->body = pkt->data = NULL; + pkt->data = NULL; pkt->maxlen = 0; return pkt; @@ -1435,14 +1435,8 @@ static void ssh1_log_outgoing_packet(Ssh ssh, const PktOut *pkt) ptrlen str; BinarySource src[1]; - /* - * For outgoing packets, pkt->length represents the length of the - * whole packet starting at pkt->data (including some header), and - * pkt->body refers to the point within that where the log-worthy - * payload begins. - */ - BinarySource_BARE_INIT(src, pkt->body, - pkt->length - (pkt->body - pkt->data)); + BinarySource_BARE_INIT(src, pkt->data + pkt->prefix, + pkt->length - pkt->prefix); if (ssh->logomitdata && (pkt->type == SSH1_CMSG_STDIN_DATA || @@ -1657,14 +1651,8 @@ static void ssh2_log_outgoing_packet(Ssh ssh, const PktOut *pkt) ptrlen str; BinarySource src[1]; - /* - * For outgoing packets, pkt->length represents the length of the - * whole packet starting at pkt->data (including some header), and - * pkt->body refers to the point within that where the log-worthy - * payload begins. - */ - BinarySource_BARE_INIT(src, pkt->body, - pkt->length - (pkt->body - pkt->data)); + BinarySource_BARE_INIT(src, pkt->data + pkt->prefix, + pkt->length - pkt->prefix); if (ssh->logomitdata && (pkt->type == SSH2_MSG_CHANNEL_DATA || @@ -2208,7 +2196,7 @@ static int s_wrpkt_prepare(Ssh ssh, PktOut *pkt, int *offset_p) return biglen + 4; /* len(length+padding+type+data+CRC) */ } -static int s_write(Ssh ssh, void *data, int len) +static int s_write(Ssh ssh, const void *data, int len) { if (len && ssh->logctx) log_packet(ssh->logctx, PKT_OUTGOING, -1, NULL, data, len, @@ -2337,11 +2325,8 @@ static int ssh_versioncmp(const char *a, const char *b) static void ssh_pkt_ensure(PktOut *pkt, int length) { if (pkt->maxlen < length) { - unsigned char *body = pkt->body; - int offset = body ? body - pkt->data : 0; pkt->maxlen = length + 256; pkt->data = sresize(pkt->data, pkt->maxlen, unsigned char); - if (body) pkt->body = pkt->data + offset; } } static void ssh_pkt_adddata(PktOut *pkt, const void *data, int len) @@ -2363,7 +2348,7 @@ static PktOut *ssh1_pkt_init(int pkt_type) PktOut *pkt = ssh_new_packet(); pkt->length = 4 + 8; /* space for length + max padding */ put_byte(pkt, pkt_type); - pkt->body = pkt->data + pkt->length; + pkt->prefix = pkt->length; pkt->type = pkt_type; pkt->downstream_id = 0; pkt->additional_log_text = NULL; @@ -2377,18 +2362,18 @@ static PktOut *ssh2_pkt_init(int pkt_type) pkt->forcepad = 0; pkt->type = pkt_type; put_byte(pkt, (unsigned char) pkt_type); - pkt->body = pkt->data + pkt->length; /* after packet type */ + pkt->prefix = pkt->length; pkt->downstream_id = 0; pkt->additional_log_text = NULL; return pkt; } /* - * Construct an SSH-2 final-form packet: compress it, encrypt it, - * put the MAC on it. Final packet, ready to be sent, is stored in - * pkt->data. Total length is returned. + * Construct an SSH-2 final-form packet: compress it, encrypt it, put + * the MAC on it. Return a slice of pkt->data giving the final packet + * in ready-to-send form. */ -static int ssh2_pkt_construct(Ssh ssh, PktOut *pkt) +static ptrlen ssh2_pkt_construct(Ssh ssh, PktOut *pkt) { int cipherblk, maclen, padding, unencrypted_prefix, i; @@ -2400,10 +2385,12 @@ static int ssh2_pkt_construct(Ssh ssh, PktOut *pkt) * Trivial packet construction for the bare connection * protocol. */ - PUT_32BIT(pkt->data + 1, pkt->length - 5); - pkt->body = pkt->data + 1; + long start = pkt->prefix - 1; + long length = pkt->length - start; + assert(start >= 4); + PUT_32BIT(pkt->data + start - 4, length); ssh->v2_outgoing_sequence++; /* only for diagnostics, really */ - return pkt->length - 1; + return make_ptrlen(pkt->data + start - 4, length + 4); } /* @@ -2477,9 +2464,7 @@ static int ssh2_pkt_construct(Ssh ssh, PktOut *pkt) ssh->v2_outgoing_sequence++; /* whether or not we MACed */ pkt->encrypted_len = pkt->length + padding; - /* Ready-to-send packet starts at pkt->data. We return length. */ - pkt->body = pkt->data; - return pkt->length + padding + maclen; + return make_ptrlen(pkt->data, pkt->length + padding + maclen); } /* @@ -2527,7 +2512,7 @@ static void ssh_pkt_defersend(Ssh); */ static void ssh2_pkt_send_noqueue(Ssh ssh, PktOut *pkt) { - int len; + ptrlen data; int backlog; if (ssh->cscipher != NULL && (ssh->cscipher->flags & SSH_CIPHER_IS_CBC)) { /* We need to send two packets, so use the deferral mechanism. */ @@ -2535,8 +2520,8 @@ static void ssh2_pkt_send_noqueue(Ssh ssh, PktOut *pkt) ssh_pkt_defersend(ssh); return; } - len = ssh2_pkt_construct(ssh, pkt); - backlog = s_write(ssh, pkt->body, len); + data = ssh2_pkt_construct(ssh, pkt); + backlog = s_write(ssh, data.ptr, data.len); if (backlog > SSH_MAX_BACKLOG) ssh_throttle_all(ssh, 1, backlog); @@ -2558,7 +2543,7 @@ static void ssh2_pkt_send_noqueue(Ssh ssh, PktOut *pkt) */ static void ssh2_pkt_defer_noqueue(Ssh ssh, PktOut *pkt, int noignore) { - int len; + ptrlen data; if (ssh->cscipher != NULL && (ssh->cscipher->flags & SSH_CIPHER_IS_CBC) && ssh->deferred_len == 0 && !noignore && !(ssh->remote_bugs & BUG_CHOKES_ON_SSH2_IGNORE)) { @@ -2570,15 +2555,15 @@ static void ssh2_pkt_defer_noqueue(Ssh ssh, PktOut *pkt, int noignore) put_stringz(ipkt, ""); ssh2_pkt_defer_noqueue(ssh, ipkt, TRUE); } - len = ssh2_pkt_construct(ssh, pkt); - if (ssh->deferred_len + len > ssh->deferred_size) { - ssh->deferred_size = ssh->deferred_len + len + 128; + data = ssh2_pkt_construct(ssh, pkt); + if (ssh->deferred_len + data.len > ssh->deferred_size) { + ssh->deferred_size = ssh->deferred_len + data.len + 128; ssh->deferred_send_data = sresize(ssh->deferred_send_data, ssh->deferred_size, unsigned char); } - memcpy(ssh->deferred_send_data + ssh->deferred_len, pkt->body, len); - ssh->deferred_len += len; + memcpy(ssh->deferred_send_data + ssh->deferred_len, data.ptr, data.len); + ssh->deferred_len += data.len; ssh->deferred_data_size += pkt->encrypted_len; ssh_free_pktout(pkt); } From eb5bc3191151638bb800d582701a524dd095e411 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Tue, 5 Jun 2018 23:02:31 +0100 Subject: [PATCH 364/607] Make PktIn contain its own PacketQueueNode. This saves a malloc and free every time we add or remove a packet from a packet queue - it can now be done by pure pointer-shuffling instead of allocating a separate list node structure. --- ssh.c | 44 ++++++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/ssh.c b/ssh.c index d7d77e17..3bac57d2 100644 --- a/ssh.c +++ b/ssh.c @@ -670,11 +670,17 @@ struct ssh_portfwd { ((pf) ? (sfree((pf)->saddr), sfree((pf)->daddr), \ sfree((pf)->sserv), sfree((pf)->dserv)) : (void)0 ), sfree(pf) ) +typedef struct PacketQueueNode PacketQueueNode; +struct PacketQueueNode { + PacketQueueNode *next, *prev; +}; + struct PktIn { int refcount; int type; unsigned long sequence; /* SSH-2 incoming sequence number */ long encrypted_len; /* for SSH-2 total-size counting */ + PacketQueueNode qnode; /* for linking this packet on to a queue */ BinarySource_IMPLEMENTATION; }; @@ -720,25 +726,20 @@ static PktOut *ssh2_gss_authpacket(Ssh ssh, Ssh_gss_ctx gss_ctx, static void ssh2_msg_unexpected(Ssh ssh, PktIn *pktin); static void ssh_unref_packet(PktIn *pkt); -struct PacketQueueNode { - struct PacketQueueNode *next, *prev; - PktIn *pkt; -}; - struct PacketQueue { - struct PacketQueueNode end; + PacketQueueNode end; }; static void pq_init(struct PacketQueue *pq) { pq->end.next = pq->end.prev = &pq->end; - pq->end.pkt = NULL; } static void pq_push(struct PacketQueue *pq, PktIn *pkt) { - struct PacketQueueNode *node = snew(struct PacketQueueNode); - node->pkt = pkt; + PacketQueueNode *node = &pkt->qnode; + assert(!node->next); + assert(!node->prev); node->next = &pq->end; node->prev = pq->end.prev; node->next->prev = node; @@ -747,8 +748,9 @@ static void pq_push(struct PacketQueue *pq, PktIn *pkt) static void pq_push_front(struct PacketQueue *pq, PktIn *pkt) { - struct PacketQueueNode *node = snew(struct PacketQueueNode); - node->pkt = pkt; + PacketQueueNode *node = &pkt->qnode; + assert(!node->next); + assert(!node->prev); node->prev = &pq->end; node->next = pq->end.next; node->next->prev = node; @@ -757,25 +759,22 @@ static void pq_push_front(struct PacketQueue *pq, PktIn *pkt) static PktIn *pq_peek(struct PacketQueue *pq) { - return pq->end.next->pkt; /* works even if next == &end, because - * end.pkt is NULL */ + if (pq->end.next == &pq->end) + return NULL; + return FROMFIELD(pq->end.next, PktIn, qnode); } static PktIn *pq_pop(struct PacketQueue *pq) { - PktIn *pkt; - struct PacketQueueNode *node; - - node = pq->end.next; + PacketQueueNode *node = pq->end.next; if (node == &pq->end) return NULL; - pkt = node->pkt; node->next->prev = node->prev; node->prev->next = node->next; - sfree(node); + node->prev = node->next = NULL; - return pkt; + return FROMFIELD(node, PktIn, qnode); } static void pq_clear(struct PacketQueue *pq) @@ -1527,6 +1526,7 @@ static void ssh1_rdpkt(Ssh ssh) * Allocate the packet to return, now we know its length. */ st->pktin = snew_plus(PktIn, st->biglen); + st->pktin->qnode.prev = st->pktin->qnode.next = NULL; st->pktin->refcount = 1; st->pktin->type = 0; @@ -1829,6 +1829,7 @@ static void ssh2_rdpkt(Ssh ssh) * Now transfer the data into an output packet. */ st->pktin = snew_plus(PktIn, st->maxlen); + st->pktin->qnode.prev = st->pktin->qnode.next = NULL; st->pktin->refcount = 1; st->pktin->type = 0; st->data = snew_plus_get_aux(st->pktin); @@ -1876,6 +1877,7 @@ static void ssh2_rdpkt(Ssh ssh) * Allocate the packet to return, now we know its length. */ st->pktin = snew_plus(PktIn, OUR_V2_PACKETLIMIT + st->maclen); + st->pktin->qnode.prev = st->pktin->qnode.next = NULL; st->pktin->refcount = 1; st->pktin->type = 0; st->data = snew_plus_get_aux(st->pktin); @@ -1947,6 +1949,7 @@ static void ssh2_rdpkt(Ssh ssh) */ st->maxlen = st->packetlen + st->maclen; st->pktin = snew_plus(PktIn, st->maxlen); + st->pktin->qnode.prev = st->pktin->qnode.next = NULL; st->pktin->refcount = 1; st->pktin->type = 0; st->data = snew_plus_get_aux(st->pktin); @@ -2098,6 +2101,7 @@ static void ssh2_bare_connection_rdpkt(Ssh ssh) * Allocate the packet to return, now we know its length. */ st->pktin = snew_plus(PktIn, st->packetlen); + st->pktin->qnode.prev = st->pktin->qnode.next = NULL; st->maxlen = 0; st->pktin->refcount = 1; st->data = snew_plus_get_aux(st->pktin); From 0df6303bb5f2aea6bec6bcc1454bd0971c0358e4 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Wed, 6 Jun 2018 20:05:13 +0100 Subject: [PATCH 365/607] Fix a valgrind error. rsa_ssh1_fingerprint will look at the input key's comment field, which I forgot to initialise to anything, even the NULL it should be. --- ssh.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ssh.c b/ssh.c index 3bac57d2..bc5ba682 100644 --- a/ssh.c +++ b/ssh.c @@ -4141,6 +4141,8 @@ static void do_ssh1_login(void *vctx) get_rsa_ssh1_pub(pktin, &s->servkey, RSA_SSH1_EXPONENT_FIRST); get_rsa_ssh1_pub(pktin, &s->hostkey, RSA_SSH1_EXPONENT_FIRST); + s->hostkey.comment = NULL; /* avoid confusing rsa_ssh1_fingerprint */ + /* * Log the host key fingerprint. */ From be6fed13fa53601aab04338f45770318efd35940 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Fri, 8 Jun 2018 19:07:47 +0100 Subject: [PATCH 366/607] Further void * / const fixes. Yet more of these that commits 7babe66a8 and 8d882756b didn't spot. I bet these still aren't the last, either. --- misc.c | 2 +- misc.h | 2 +- ssh.h | 6 +++--- sshccp.c | 12 ++++++++---- sshmd5.c | 8 +++++--- sshsh256.c | 13 ++++++++----- sshsha.c | 20 ++++++++++++-------- 7 files changed, 38 insertions(+), 25 deletions(-) diff --git a/misc.c b/misc.c index 36f27171..92890322 100644 --- a/misc.c +++ b/misc.c @@ -485,7 +485,7 @@ struct strbuf_impl { ((buf)->visible.s = (ptr), \ (buf)->visible.u = (unsigned char *)(buf)->visible.s) -char *strbuf_append(strbuf *buf_o, size_t len) +void *strbuf_append(strbuf *buf_o, size_t len) { struct strbuf_impl *buf = FROMFIELD(buf_o, struct strbuf_impl, visible); char *toret; diff --git a/misc.h b/misc.h index 4b830d99..35d9de6c 100644 --- a/misc.h +++ b/misc.h @@ -40,7 +40,7 @@ struct strbuf { }; strbuf *strbuf_new(void); void strbuf_free(strbuf *buf); -char *strbuf_append(strbuf *buf, size_t len); +void *strbuf_append(strbuf *buf, size_t len); char *strbuf_to_str(strbuf *buf); /* does free buf, but you must free result */ void strbuf_catf(strbuf *buf, const char *fmt, ...); void strbuf_catfv(strbuf *buf, const char *fmt, va_list ap); diff --git a/ssh.h b/ssh.h index 1c0f276c..0eaea9f2 100644 --- a/ssh.h +++ b/ssh.h @@ -350,10 +350,10 @@ struct ssh_mac { /* Passes in the cipher context */ void *(*make_context)(void *); void (*free_context)(void *); - void (*setkey) (void *, unsigned char *key); + void (*setkey) (void *, const void *key); /* whole-packet operations */ - void (*generate) (void *, unsigned char *blk, int len, unsigned long seq); - int (*verify) (void *, unsigned char *blk, int len, unsigned long seq); + void (*generate) (void *, void *blk, int len, unsigned long seq); + int (*verify) (void *, const void *blk, int len, unsigned long seq); /* partial-packet operations */ void (*start) (void *); BinarySink *(*sink) (void *); diff --git a/sshccp.c b/sshccp.c index 9345c6fa..04f1cc16 100644 --- a/sshccp.c +++ b/sshccp.c @@ -878,7 +878,7 @@ static void poly_free_context(void *ctx) /* Not allocated, just forwarded, no need to free */ } -static void poly_setkey(void *ctx, unsigned char *key) +static void poly_setkey(void *ctx, const void *key) { /* Uses the same context as ChaCha20, so ignore */ } @@ -948,7 +948,8 @@ static int poly_verresult(void *handle, unsigned char const *blk) } /* The generic poly operation used before generate and verify */ -static void poly_op(void *handle, unsigned char *blk, int len, unsigned long seq) +static void poly_op(void *handle, const unsigned char *blk, int len, + unsigned long seq) { struct ccp_context *ctx = (struct ccp_context *)handle; poly_start(ctx); @@ -957,14 +958,17 @@ static void poly_op(void *handle, unsigned char *blk, int len, unsigned long seq put_data(ctx, blk, len); } -static void poly_generate(void *handle, unsigned char *blk, int len, unsigned long seq) +static void poly_generate(void *handle, void *vblk, int len, unsigned long seq) { + unsigned char *blk = (unsigned char *)vblk; poly_op(handle, blk, len, seq); poly_genresult(handle, blk+len); } -static int poly_verify(void *handle, unsigned char *blk, int len, unsigned long seq) +static int poly_verify(void *handle, const void *vblk, int len, + unsigned long seq) { + const unsigned char *blk = (const unsigned char *)vblk; poly_op(handle, blk, len, seq); return poly_verresult(handle, blk+len); } diff --git a/sshmd5.c b/sshmd5.c index 5bd0ccb4..05f00d0b 100644 --- a/sshmd5.c +++ b/sshmd5.c @@ -261,7 +261,7 @@ void hmacmd5_key(void *handle, void const *keyv, int len) smemclr(foo, 64); /* burn the evidence */ } -static void hmacmd5_key_16(void *handle, unsigned char *key) +static void hmacmd5_key_16(void *handle, const void *key) { hmacmd5_key(handle, key, 16); } @@ -329,15 +329,17 @@ static void hmacmd5_do_hmac_ssh(void *handle, unsigned char const *blk, int len, hmacmd5_do_hmac_internal(handle, seqbuf, 4, blk, len, hmac); } -static void hmacmd5_generate(void *handle, unsigned char *blk, int len, +static void hmacmd5_generate(void *handle, void *vblk, int len, unsigned long seq) { + unsigned char *blk = (unsigned char *)vblk; hmacmd5_do_hmac_ssh(handle, blk, len, seq, blk + len); } -static int hmacmd5_verify(void *handle, unsigned char *blk, int len, +static int hmacmd5_verify(void *handle, const void *vblk, int len, unsigned long seq) { + const unsigned char *blk = (const unsigned char *)vblk; unsigned char correct[16]; hmacmd5_do_hmac_ssh(handle, blk, len, seq, correct); return smemeq(correct, blk + len, 16); diff --git a/sshsh256.c b/sshsh256.c index 0a0a9546..66752326 100644 --- a/sshsh256.c +++ b/sshsh256.c @@ -267,7 +267,8 @@ static void sha256_free_context(void *handle) sfree(handle); } -static void sha256_key_internal(void *handle, unsigned char *key, int len) +static void sha256_key_internal(void *handle, + const unsigned char *key, int len) { SHA256_State *keys = (SHA256_State *)handle; unsigned char foo[64]; @@ -288,7 +289,7 @@ static void sha256_key_internal(void *handle, unsigned char *key, int len) smemclr(foo, 64); /* burn the evidence */ } -static void sha256_key(void *handle, unsigned char *key) +static void sha256_key(void *handle, const void *key) { sha256_key_internal(handle, key, 32); } @@ -322,7 +323,7 @@ static void hmacsha256_genresult(void *handle, unsigned char *hmac) SHA256_Final(&s, hmac); } -static void sha256_do_hmac(void *handle, unsigned char *blk, int len, +static void sha256_do_hmac(void *handle, const unsigned char *blk, int len, unsigned long seq, unsigned char *hmac) { BinarySink *bs = hmacsha256_sink(handle); @@ -332,9 +333,10 @@ static void sha256_do_hmac(void *handle, unsigned char *blk, int len, hmacsha256_genresult(handle, hmac); } -static void sha256_generate(void *handle, unsigned char *blk, int len, +static void sha256_generate(void *handle, void *vblk, int len, unsigned long seq) { + unsigned char *blk = (unsigned char *)vblk; sha256_do_hmac(handle, blk, len, seq, blk + len); } @@ -345,9 +347,10 @@ static int hmacsha256_verresult(void *handle, unsigned char const *hmac) return smemeq(correct, hmac, 32); } -static int sha256_verify(void *handle, unsigned char *blk, int len, +static int sha256_verify(void *handle, const void *vblk, int len, unsigned long seq) { + const unsigned char *blk = (const unsigned char *)vblk; unsigned char correct[32]; sha256_do_hmac(handle, blk, len, seq, correct); return smemeq(correct, blk + len, 32); diff --git a/sshsha.c b/sshsha.c index ddcab81e..4b9d002f 100644 --- a/sshsha.c +++ b/sshsha.c @@ -294,7 +294,7 @@ static void sha1_free_context(void *handle) sfree(handle); } -static void sha1_key_internal(void *handle, unsigned char *key, int len) +static void sha1_key_internal(void *handle, const unsigned char *key, int len) { SHA_State *keys = (SHA_State *)handle; unsigned char foo[64]; @@ -315,12 +315,12 @@ static void sha1_key_internal(void *handle, unsigned char *key, int len) smemclr(foo, 64); /* burn the evidence */ } -static void sha1_key(void *handle, unsigned char *key) +static void sha1_key(void *handle, const void *key) { sha1_key_internal(handle, key, 20); } -static void sha1_key_buggy(void *handle, unsigned char *key) +static void sha1_key_buggy(void *handle, const void *key) { sha1_key_internal(handle, key, 16); } @@ -354,7 +354,7 @@ static void hmacsha1_genresult(void *handle, unsigned char *hmac) SHA_Final(&s, hmac); } -static void sha1_do_hmac(void *handle, unsigned char *blk, int len, +static void sha1_do_hmac(void *handle, const unsigned char *blk, int len, unsigned long seq, unsigned char *hmac) { BinarySink *bs = hmacsha1_sink(handle); @@ -364,9 +364,10 @@ static void sha1_do_hmac(void *handle, unsigned char *blk, int len, hmacsha1_genresult(handle, hmac); } -static void sha1_generate(void *handle, unsigned char *blk, int len, +static void sha1_generate(void *handle, void *vblk, int len, unsigned long seq) { + unsigned char *blk = (unsigned char *)vblk; sha1_do_hmac(handle, blk, len, seq, blk + len); } @@ -377,9 +378,10 @@ static int hmacsha1_verresult(void *handle, unsigned char const *hmac) return smemeq(correct, hmac, 20); } -static int sha1_verify(void *handle, unsigned char *blk, int len, +static int sha1_verify(void *handle, const void *vblk, int len, unsigned long seq) { + const unsigned char *blk = (const unsigned char *)vblk; unsigned char correct[20]; sha1_do_hmac(handle, blk, len, seq, correct); return smemeq(correct, blk + len, 20); @@ -392,9 +394,10 @@ static void hmacsha1_96_genresult(void *handle, unsigned char *hmac) memcpy(hmac, full, 12); } -static void sha1_96_generate(void *handle, unsigned char *blk, int len, +static void sha1_96_generate(void *handle, void *vblk, int len, unsigned long seq) { + unsigned char *blk = (unsigned char *)vblk; unsigned char full[20]; sha1_do_hmac(handle, blk, len, seq, full); memcpy(blk + len, full, 12); @@ -407,9 +410,10 @@ static int hmacsha1_96_verresult(void *handle, unsigned char const *hmac) return smemeq(correct, hmac, 12); } -static int sha1_96_verify(void *handle, unsigned char *blk, int len, +static int sha1_96_verify(void *handle, const void *vblk, int len, unsigned long seq) { + const unsigned char *blk = (const unsigned char *)vblk; unsigned char correct[20]; sha1_do_hmac(handle, blk, len, seq, correct); return smemeq(correct, blk + len, 12); From 734ada9b573393022888bb4338f8772af198515e Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 9 Jun 2018 07:52:28 +0100 Subject: [PATCH 367/607] gdb.py: add a 'memdump' command. This makes it easier for me to examine the contents of binary memory buffers, while debugging through code that does crypto or packet marshalling. --- contrib/gdb.py | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/contrib/gdb.py b/contrib/gdb.py index 14574bb2..a993cc89 100644 --- a/contrib/gdb.py +++ b/contrib/gdb.py @@ -35,3 +35,62 @@ def to_string(self): PuTTYBignumPrettyPrinter) gdb.printing.register_pretty_printer(None, rcpp) + +class MemDumpCommand(gdb.Command): + """Print a hex+ASCII dump of object EXP. + +EXP must be an expression whose value resides in memory. The +contents of the memory it occupies are printed in a standard hex +dump format, with each line showing an offset relative to the +address of EXP, then the hex byte values of the memory at that +offset, and then a translation into ASCII of the same bytes (with +values outside the printable ASCII range translated as '.'). + +To dump a number of bytes from a particular address, it's useful +to use the gdb expression extensions {TYPE} and @LENGTH. For +example, if 'ptr' and 'len' are variables giving an address and a +length in bytes, then the command + + memdump {char} ptr @ len + +will dump the range of memory described by those two variables.""" + + def __init__(self): + super(MemDumpCommand, self).__init__( + "memdump", gdb.COMMAND_DATA, gdb.COMPLETE_EXPRESSION) + + def invoke(self, cmdline, from_tty): + expr = gdb.parse_and_eval(cmdline) + try: + start, size = int(expr.address), expr.type.sizeof + except gdb.error as e: + sys.stderr.write(str(e)) + return + except (TypeError, AttributeError): + sys.stderr.write("expression must identify an object in memory") + return + + width = 16 + line_ptr_type = gdb.lookup_type( + "unsigned char").const().array(width).pointer() + + dumpaddr = 0 + while size > 0: + line = gdb.Value(start).cast(line_ptr_type).dereference() + thislinelen = min(size, width) + start += thislinelen + size -= thislinelen + + dumpline = [None, " "] + [" "] * width + [" "] + [""] * width + + dumpline[0] = "{:08x}".format(dumpaddr) + dumpaddr += thislinelen + + for i in range(thislinelen): + ch = int(line[i]) & 0xFF + dumpline[2+i] = " {:02x}".format(ch) + dumpline[3+width+i] = chr(ch) if 0x20 <= ch < 0x7F else "." + + sys.stdout.write("".join(dumpline) + "\n") + +MemDumpCommand() From 72c2b70736de1df2affd5ded566d38939d6564a6 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 9 Jun 2018 09:00:11 +0100 Subject: [PATCH 368/607] Make logblank_t a typedef. It seems especially silly for a structure whose name ends in _t to have to have the 'struct' prefix! --- defs.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/defs.h b/defs.h index 55468241..bfdf345d 100644 --- a/defs.h +++ b/defs.h @@ -62,6 +62,8 @@ typedef struct ptrlen { size_t len; } ptrlen; +typedef struct logblank_t logblank_t; + /* Do a compile-time type-check of 'to_check' (without evaluating it), * as a side effect of returning the value 'to_return'. Note that * although this macro double-*expands* to_return, it always From 8b98fea4ae2996df7185bed9128dcebc18929a1d Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 9 Jun 2018 09:01:07 +0100 Subject: [PATCH 369/607] New BinarySink function 'put_padding'. It is to put_data what memset is to memcpy. Several places in the code wanted it already, but not _quite_ enough for me to have written it with the rest of the BinarySink infrastructure originally. --- import.c | 3 +-- marshal.c | 11 +++++++++++ marshal.h | 5 +++++ ssh.c | 3 +-- sshpubk.c | 3 +-- 5 files changed, 19 insertions(+), 6 deletions(-) diff --git a/import.c b/import.c index 218670ee..e95883a0 100644 --- a/import.c +++ b/import.c @@ -1010,8 +1010,7 @@ int openssh_pem_write(const Filename *filename, struct ssh2_userkey *key, origlen = outblob->len; outlen = (origlen + 8) &~ 7; pad = outlen - origlen; - for (i = 0; i < pad; i++) - put_byte(outblob, pad); + put_padding(outblob, pad, pad); /* * Invent an iv. Then derive encryption key from passphrase diff --git a/marshal.c b/marshal.c index 76c7c05f..a8371b66 100644 --- a/marshal.c +++ b/marshal.c @@ -11,6 +11,17 @@ void BinarySink_put_data(BinarySink *bs, const void *data, size_t len) bs->write(bs, data, len); } +void BinarySink_put_padding(BinarySink *bs, unsigned char padbyte, size_t len) +{ + char buf[16]; + memset(buf, padbyte, sizeof(buf)); + while (len > 0) { + size_t thislen = len < sizeof(buf) ? len : sizeof(buf); + bs->write(bs, buf, thislen); + len -= thislen; + } +} + void BinarySink_put_byte(BinarySink *bs, unsigned char val) { bs->write(bs, &val, 1); diff --git a/marshal.h b/marshal.h index 90bb94ff..0debe82f 100644 --- a/marshal.h +++ b/marshal.h @@ -110,6 +110,10 @@ struct BinarySink { #define put_mp_ssh2(bs, val) \ BinarySink_put_mp_ssh2(BinarySink_UPCAST(bs), val) +/* Padding with a specified byte. */ +#define put_padding(bs, padbyte, len) \ + BinarySink_put_padding(BinarySink_UPCAST(bs), padbyte, len) + /* Fallback: just emit raw data bytes, using a syntax that matches the * rest of these macros. */ #define put_data(bs, val, len) \ @@ -126,6 +130,7 @@ struct BinarySink { * declaration(s) of their other parameter type(s) are in scope. */ void BinarySink_put_data(BinarySink *, const void *data, size_t len); +void BinarySink_put_padding(BinarySink *, unsigned char padbyte, size_t len); void BinarySink_put_byte(BinarySink *, unsigned char); void BinarySink_put_bool(BinarySink *, int); void BinarySink_put_uint16(BinarySink *, unsigned long); diff --git a/ssh.c b/ssh.c index bc5ba682..3980aa89 100644 --- a/ssh.c +++ b/ssh.c @@ -2803,8 +2803,7 @@ static void ssh2_add_sigblob(Ssh ssh, PktOut *pkt, strbuf *substr = strbuf_new(); put_data(substr, sigblob, sig_prefix_len); put_uint32(substr, mod_mp.len); - while (mod_mp.len-- > sig_mp.len) - put_byte(substr, 0); + put_padding(substr, mod_mp.len - sig_mp.len, 0); put_data(substr, sig_mp.ptr, sig_mp.len); put_stringsb(pkt, substr); return; diff --git a/sshpubk.c b/sshpubk.c index 3732a6f2..2144bc2c 100644 --- a/sshpubk.c +++ b/sshpubk.c @@ -356,8 +356,7 @@ int rsa_ssh1_savekey(const Filename *filename, struct RSAKey *key, * Now write zeros until the encrypted portion is a multiple of * 8 bytes. */ - while ((buf->len - estart) % 8) - put_byte(buf, 0); + put_padding(buf, (estart - buf->len) & 7, 0); /* * Now encrypt the encrypted portion. From ba7571291ab4552a1d587f39e295f8886fa9685b Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 9 Jun 2018 09:07:18 +0100 Subject: [PATCH 370/607] Move some ssh.c declarations into header files. ssh.c has been an unmanageably huge monolith of a source file for too long, and it's finally time I started breaking it up into smaller pieces. The first step is to move some declarations - basic types like packets and packet queues, standard constants, enums, and the coroutine system - into headers where other files can see them. --- ssh.c | 180 +++++--------------------------------------------------- ssh.h | 115 ++++++++++++++++++++++++++++++++++++ sshcr.h | 54 +++++++++++++++++ 3 files changed, 183 insertions(+), 166 deletions(-) create mode 100644 sshcr.h diff --git a/ssh.c b/ssh.c index 3980aa89..c01f55e6 100644 --- a/ssh.c +++ b/ssh.c @@ -15,6 +15,7 @@ #include "storage.h" #include "marshal.h" #include "ssh.h" +#include "sshcr.h" #ifndef NO_GSSAPI #include "sshgssc.h" #include "sshgss.h" @@ -25,26 +26,6 @@ #define GSS_CTXT_MAYFAIL (1<<3) /* Context may expire during handshake */ #endif -/* - * Packet type contexts, so that ssh2_pkt_type can correctly decode - * the ambiguous type numbers back into the correct type strings. - */ -typedef enum { - SSH2_PKTCTX_NOKEX, - SSH2_PKTCTX_DHGROUP, - SSH2_PKTCTX_DHGEX, - SSH2_PKTCTX_ECDHKEX, - SSH2_PKTCTX_GSSKEX, - SSH2_PKTCTX_RSAKEX -} Pkt_KCtx; -typedef enum { - SSH2_PKTCTX_NOAUTH, - SSH2_PKTCTX_PUBLICKEY, - SSH2_PKTCTX_PASSWORD, - SSH2_PKTCTX_GSSAPI, - SSH2_PKTCTX_KBDINTER -} Pkt_ACtx; - static const char *const ssh2_disconnect_reasons[] = { NULL, "host not allowed to connect", @@ -200,7 +181,7 @@ static unsigned long rekey_mins(int rekey_time, unsigned long def) #define translate(x) if (type == x) return #x #define translatek(x,ctx) if (type == x && (pkt_kctx == ctx)) return #x #define translatea(x,ctx) if (type == x && (pkt_actx == ctx)) return #x -static const char *ssh1_pkt_type(int type) +const char *ssh1_pkt_type(int type) { translate(SSH1_MSG_DISCONNECT); translate(SSH1_SMSG_PUBLIC_KEY); @@ -245,8 +226,7 @@ static const char *ssh1_pkt_type(int type) translate(SSH1_CMSG_AUTH_CCARD_RESPONSE); return "unknown"; } -static const char *ssh2_pkt_type(Pkt_KCtx pkt_kctx, Pkt_ACtx pkt_actx, - int type) +const char *ssh2_pkt_type(Pkt_KCtx pkt_kctx, Pkt_ACtx pkt_actx, int type) { translatea(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE,SSH2_PKTCTX_GSSAPI); translatea(SSH2_MSG_USERAUTH_GSSAPI_TOKEN,SSH2_PKTCTX_GSSAPI); @@ -313,57 +293,6 @@ enum { PKT_END, PKT_INT, PKT_CHAR, PKT_DATA, PKT_STR, PKT_BIGNUM, }; -/* - * Coroutine mechanics for the sillier bits of the code. If these - * macros look impenetrable to you, you might find it helpful to - * read - * - * https://www.chiark.greenend.org.uk/~sgtatham/coroutines.html - * - * which explains the theory behind these macros. - * - * In particular, if you are getting `case expression not constant' - * errors when building with MS Visual Studio, this is because MS's - * Edit and Continue debugging feature causes their compiler to - * violate ANSI C. To disable Edit and Continue debugging: - * - * - right-click ssh.c in the FileView - * - click Settings - * - select the C/C++ tab and the General category - * - under `Debug info:', select anything _other_ than `Program - * Database for Edit and Continue'. - */ -#define crBegin(v) { int *crLine = &v; switch(v) { case 0:; -#define crBeginState crBegin(s->crLine) -#define crStateP(t, v) \ - struct t *s; \ - if (!(v)) { s = (v) = snew(struct t); s->crLine = 0; } \ - s = (v); -#define crState(t) crStateP(t, ssh->t) -#define crFinish(z) } *crLine = 0; return (z); } -#define crFinishV } *crLine = 0; return; } -#define crFinishFree(z) } sfree(s); return (z); } -#define crFinishFreeV } sfree(s); return; } -#define crReturn(z) \ - do {\ - *crLine =__LINE__; return (z); case __LINE__:;\ - } while (0) -#define crReturnV \ - do {\ - *crLine=__LINE__; return; case __LINE__:;\ - } while (0) -#define crStop(z) do{ *crLine = 0; return (z); }while(0) -#define crStopV do{ *crLine = 0; return; }while(0) -#define crWaitUntil(c) do { crReturn(0); } while (!(c)) -#define crWaitUntilV(c) do { crReturnV; } while (!(c)) -#define crMaybeWaitUntil(c) do { while (!(c)) crReturn(0); } while (0) -#define crMaybeWaitUntilV(c) do { while (!(c)) crReturnV; } while (0) - -typedef struct PktIn PktIn; -typedef struct PktOut PktOut; - -static struct PktOut *ssh1_pkt_init(int pkt_type); -static struct PktOut *ssh2_pkt_init(int pkt_type); static void ssh_pkt_ensure(struct PktOut *, int length); static void ssh_pkt_adddata(struct PktOut *, const void *data, int len); static ptrlen ssh2_pkt_construct(Ssh, struct PktOut *); @@ -386,47 +315,6 @@ static void ssh1_login_input(Ssh ssh); static void ssh2_userauth_input(Ssh ssh); static void ssh2_connection_input(Ssh ssh); -/* - * Buffer management constants. There are several of these for - * various different purposes: - * - * - SSH1_BUFFER_LIMIT is the amount of backlog that must build up - * on a local data stream before we throttle the whole SSH - * connection (in SSH-1 only). Throttling the whole connection is - * pretty drastic so we set this high in the hope it won't - * happen very often. - * - * - SSH_MAX_BACKLOG is the amount of backlog that must build up - * on the SSH connection itself before we defensively throttle - * _all_ local data streams. This is pretty drastic too (though - * thankfully unlikely in SSH-2 since the window mechanism should - * ensure that the server never has any need to throttle its end - * of the connection), so we set this high as well. - * - * - OUR_V2_WINSIZE is the default window size we present on SSH-2 - * channels. - * - * - OUR_V2_BIGWIN is the window size we advertise for the only - * channel in a simple connection. It must be <= INT_MAX. - * - * - OUR_V2_MAXPKT is the official "maximum packet size" we send - * to the remote side. This actually has nothing to do with the - * size of the _packet_, but is instead a limit on the amount - * of data we're willing to receive in a single SSH2 channel - * data message. - * - * - OUR_V2_PACKETLIMIT is actually the maximum size of SSH - * _packet_ we're prepared to cope with. It must be a multiple - * of the cipher block size, and must be at least 35000. - */ - -#define SSH1_BUFFER_LIMIT 32768 -#define SSH_MAX_BACKLOG 32768 -#define OUR_V2_WINSIZE 16384 -#define OUR_V2_BIGWIN 0x7fffffff -#define OUR_V2_MAXPKT 0x4000UL -#define OUR_V2_PACKETLIMIT 0x9000UL - struct ssh_signkey_with_user_pref_id { const ssh_keyalg *alg; int id; @@ -670,40 +558,6 @@ struct ssh_portfwd { ((pf) ? (sfree((pf)->saddr), sfree((pf)->daddr), \ sfree((pf)->sserv), sfree((pf)->dserv)) : (void)0 ), sfree(pf) ) -typedef struct PacketQueueNode PacketQueueNode; -struct PacketQueueNode { - PacketQueueNode *next, *prev; -}; - -struct PktIn { - int refcount; - int type; - unsigned long sequence; /* SSH-2 incoming sequence number */ - long encrypted_len; /* for SSH-2 total-size counting */ - PacketQueueNode qnode; /* for linking this packet on to a queue */ - BinarySource_IMPLEMENTATION; -}; - -struct PktOut { - long prefix; /* bytes up to and including type field */ - long length; /* total bytes, including prefix */ - int type; - long forcepad; /* SSH-2: force padding to at least this length */ - unsigned char *data; /* allocated storage */ - long maxlen; /* amount of storage allocated for `data' */ - long encrypted_len; /* for SSH-2 total-size counting */ - - /* Extra metadata used in SSH packet logging mode, allowing us to - * log in the packet header line that the packet came from a - * connection-sharing downstream and what if anything unusual was - * done to it. The additional_log_text field is expected to be a - * static string - it will not be freed. */ - unsigned downstream_id; - const char *additional_log_text; - - BinarySink_IMPLEMENTATION; -}; - static void ssh1_protocol_setup(Ssh ssh); static void ssh2_protocol_setup(Ssh ssh); static void ssh2_bare_connection_protocol_setup(Ssh ssh); @@ -724,18 +578,13 @@ static PktOut *ssh2_gss_authpacket(Ssh ssh, Ssh_gss_ctx gss_ctx, const char *authtype); #endif static void ssh2_msg_unexpected(Ssh ssh, PktIn *pktin); -static void ssh_unref_packet(PktIn *pkt); - -struct PacketQueue { - PacketQueueNode end; -}; -static void pq_init(struct PacketQueue *pq) +void pq_init(struct PacketQueue *pq) { pq->end.next = pq->end.prev = &pq->end; } -static void pq_push(struct PacketQueue *pq, PktIn *pkt) +void pq_push(struct PacketQueue *pq, PktIn *pkt) { PacketQueueNode *node = &pkt->qnode; assert(!node->next); @@ -746,7 +595,7 @@ static void pq_push(struct PacketQueue *pq, PktIn *pkt) node->prev->next = node; } -static void pq_push_front(struct PacketQueue *pq, PktIn *pkt) +void pq_push_front(struct PacketQueue *pq, PktIn *pkt) { PacketQueueNode *node = &pkt->qnode; assert(!node->next); @@ -757,14 +606,14 @@ static void pq_push_front(struct PacketQueue *pq, PktIn *pkt) node->prev->next = node; } -static PktIn *pq_peek(struct PacketQueue *pq) +PktIn *pq_peek(struct PacketQueue *pq) { if (pq->end.next == &pq->end) return NULL; return FROMFIELD(pq->end.next, PktIn, qnode); } -static PktIn *pq_pop(struct PacketQueue *pq) +PktIn *pq_pop(struct PacketQueue *pq) { PacketQueueNode *node = pq->end.next; if (node == &pq->end) @@ -777,15 +626,14 @@ static PktIn *pq_pop(struct PacketQueue *pq) return FROMFIELD(node, PktIn, qnode); } -static void pq_clear(struct PacketQueue *pq) +void pq_clear(struct PacketQueue *pq) { PktIn *pkt; while ((pkt = pq_pop(pq)) != NULL) ssh_unref_packet(pkt); } -static int pq_empty_on_to_front_of(struct PacketQueue *src, - struct PacketQueue *dest) +int pq_empty_on_to_front_of(struct PacketQueue *src, struct PacketQueue *dest) { struct PacketQueueNode *srcfirst, *srclast; @@ -1373,13 +1221,13 @@ static void c_write_str(Ssh ssh, const char *buf) c_write(ssh, buf, strlen(buf)); } -static void ssh_unref_packet(PktIn *pkt) +void ssh_unref_packet(PktIn *pkt) { if (--pkt->refcount <= 0) sfree(pkt); } -static void ssh_free_pktout(PktOut *pkt) +void ssh_free_pktout(PktOut *pkt) { sfree(pkt->data); sfree(pkt); @@ -2347,7 +2195,7 @@ static void ssh_pkt_BinarySink_write(BinarySink *bs, ssh_pkt_adddata(pkt, data, len); } -static PktOut *ssh1_pkt_init(int pkt_type) +PktOut *ssh1_pkt_init(int pkt_type) { PktOut *pkt = ssh_new_packet(); pkt->length = 4 + 8; /* space for length + max padding */ @@ -2359,7 +2207,7 @@ static PktOut *ssh1_pkt_init(int pkt_type) return pkt; } -static PktOut *ssh2_pkt_init(int pkt_type) +PktOut *ssh2_pkt_init(int pkt_type) { PktOut *pkt = ssh_new_packet(); pkt->length = 5; /* space for packet length + padding length */ diff --git a/ssh.h b/ssh.h index 0eaea9f2..5e257324 100644 --- a/ssh.h +++ b/ssh.h @@ -22,6 +22,118 @@ void sshfwd_x11_sharing_handover(struct ssh_channel *c, const void *initial_data, int initial_len); void sshfwd_x11_is_local(struct ssh_channel *c); +/* + * Buffer management constants. There are several of these for + * various different purposes: + * + * - SSH1_BUFFER_LIMIT is the amount of backlog that must build up + * on a local data stream before we throttle the whole SSH + * connection (in SSH-1 only). Throttling the whole connection is + * pretty drastic so we set this high in the hope it won't + * happen very often. + * + * - SSH_MAX_BACKLOG is the amount of backlog that must build up + * on the SSH connection itself before we defensively throttle + * _all_ local data streams. This is pretty drastic too (though + * thankfully unlikely in SSH-2 since the window mechanism should + * ensure that the server never has any need to throttle its end + * of the connection), so we set this high as well. + * + * - OUR_V2_WINSIZE is the default window size we present on SSH-2 + * channels. + * + * - OUR_V2_BIGWIN is the window size we advertise for the only + * channel in a simple connection. It must be <= INT_MAX. + * + * - OUR_V2_MAXPKT is the official "maximum packet size" we send + * to the remote side. This actually has nothing to do with the + * size of the _packet_, but is instead a limit on the amount + * of data we're willing to receive in a single SSH2 channel + * data message. + * + * - OUR_V2_PACKETLIMIT is actually the maximum size of SSH + * _packet_ we're prepared to cope with. It must be a multiple + * of the cipher block size, and must be at least 35000. + */ + +#define SSH1_BUFFER_LIMIT 32768 +#define SSH_MAX_BACKLOG 32768 +#define OUR_V2_WINSIZE 16384 +#define OUR_V2_BIGWIN 0x7fffffff +#define OUR_V2_MAXPKT 0x4000UL +#define OUR_V2_PACKETLIMIT 0x9000UL + +typedef struct PacketQueueNode PacketQueueNode; +struct PacketQueueNode { + PacketQueueNode *next, *prev; +}; + +typedef struct PktIn { + int refcount; + int type; + unsigned long sequence; /* SSH-2 incoming sequence number */ + long encrypted_len; /* for SSH-2 total-size counting */ + PacketQueueNode qnode; /* for linking this packet on to a queue */ + BinarySource_IMPLEMENTATION; +} PktIn; + +typedef struct PktOut { + long prefix; /* bytes up to and including type field */ + long length; /* total bytes, including prefix */ + int type; + long forcepad; /* SSH-2: force padding to at least this length */ + unsigned char *data; /* allocated storage */ + long maxlen; /* amount of storage allocated for `data' */ + long encrypted_len; /* for SSH-2 total-size counting */ + + /* Extra metadata used in SSH packet logging mode, allowing us to + * log in the packet header line that the packet came from a + * connection-sharing downstream and what if anything unusual was + * done to it. The additional_log_text field is expected to be a + * static string - it will not be freed. */ + unsigned downstream_id; + const char *additional_log_text; + + BinarySink_IMPLEMENTATION; +} PktOut; + +typedef struct PacketQueue { + PacketQueueNode end; +} PacketQueue; + +void pq_init(struct PacketQueue *pq); +void pq_push(struct PacketQueue *pq, PktIn *pkt); +void pq_push_front(struct PacketQueue *pq, PktIn *pkt); +PktIn *pq_peek(struct PacketQueue *pq); +PktIn *pq_pop(struct PacketQueue *pq); +void pq_clear(struct PacketQueue *pq); +int pq_empty_on_to_front_of(struct PacketQueue *src, struct PacketQueue *dest); + +/* + * Packet type contexts, so that ssh2_pkt_type can correctly decode + * the ambiguous type numbers back into the correct type strings. + */ +typedef enum { + SSH2_PKTCTX_NOKEX, + SSH2_PKTCTX_DHGROUP, + SSH2_PKTCTX_DHGEX, + SSH2_PKTCTX_ECDHKEX, + SSH2_PKTCTX_GSSKEX, + SSH2_PKTCTX_RSAKEX +} Pkt_KCtx; +typedef enum { + SSH2_PKTCTX_NOAUTH, + SSH2_PKTCTX_PUBLICKEY, + SSH2_PKTCTX_PASSWORD, + SSH2_PKTCTX_GSSAPI, + SSH2_PKTCTX_KBDINTER +} Pkt_ACtx; + +PktOut *ssh1_pkt_init(int pkt_type); +PktOut *ssh2_pkt_init(int pkt_type); +void ssh_unref_packet(PktIn *pkt); +void ssh_free_pktout(PktOut *pkt); + extern Socket ssh_connection_sharing_init( const char *host, int port, Conf *conf, Ssh ssh, Plug sshplug, void **state); @@ -1048,6 +1160,9 @@ void platform_ssh_share_cleanup(const char *name); #define SSH2_EXTENDED_DATA_STDERR 1 /* 0x1 */ +const char *ssh1_pkt_type(int type); +const char *ssh2_pkt_type(Pkt_KCtx pkt_kctx, Pkt_ACtx pkt_actx, int type); + /* * Need this to warn about support for the original SSH-2 keyfile * format. diff --git a/sshcr.h b/sshcr.h new file mode 100644 index 00000000..18a31ff5 --- /dev/null +++ b/sshcr.h @@ -0,0 +1,54 @@ +/* + * Coroutine mechanics used in PuTTY's SSH code. + */ + +#ifndef PUTTY_SSHCR_H +#define PUTTY_SSHCR_H + +/* + * If these macros look impenetrable to you, you might find it helpful + * to read + * + * https://www.chiark.greenend.org.uk/~sgtatham/coroutines.html + * + * which explains the theory behind these macros. + * + * In particular, if you are getting `case expression not constant' + * errors when building with MS Visual Studio, this is because MS's + * Edit and Continue debugging feature causes their compiler to + * violate ANSI C. To disable Edit and Continue debugging: + * + * - right-click ssh.c in the FileView + * - click Settings + * - select the C/C++ tab and the General category + * - under `Debug info:', select anything _other_ than `Program + * Database for Edit and Continue'. + */ + +#define crBegin(v) { int *crLine = &v; switch(v) { case 0:; +#define crBeginState crBegin(s->crLine) +#define crStateP(t, v) \ + struct t *s; \ + if (!(v)) { s = (v) = snew(struct t); s->crLine = 0; } \ + s = (v); +#define crState(t) crStateP(t, ssh->t) +#define crFinish(z) } *crLine = 0; return (z); } +#define crFinishV } *crLine = 0; return; } +#define crFinishFree(z) } sfree(s); return (z); } +#define crFinishFreeV } sfree(s); return; } +#define crReturn(z) \ + do {\ + *crLine =__LINE__; return (z); case __LINE__:;\ + } while (0) +#define crReturnV \ + do {\ + *crLine=__LINE__; return; case __LINE__:;\ + } while (0) +#define crStop(z) do{ *crLine = 0; return (z); }while(0) +#define crStopV do{ *crLine = 0; return; }while(0) +#define crWaitUntil(c) do { crReturn(0); } while (!(c)) +#define crWaitUntilV(c) do { crReturnV; } while (!(c)) +#define crMaybeWaitUntil(c) do { while (!(c)) crReturn(0); } while (0) +#define crMaybeWaitUntilV(c) do { while (!(c)) crReturnV; } while (0) + +#endif /* PUTTY_SSHCR_H */ From 9e3522a97130ec4aec35a024482d694b3e935a05 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 9 Jun 2018 09:09:10 +0100 Subject: [PATCH 371/607] Use a bufchain for outgoing SSH wire data. This mirrors the use of one for incoming wire data: now when we send raw data (be it the initial greeting, or the output of binary packet construction), we put it on ssh->outgoing_data, and schedule a callback to transfer that into the socket. Partly this is in preparation for delegating the task of appending to that bufchain to a separate self-contained module that won't have direct access to the connection's Socket. But also, it has the very nice feature that I get to throw away the ssh_pkt_defer system completely! That was there so that we could construct more than one packet in rapid succession, concatenate them into a single blob, and pass that blob to the socket in one go so that the TCP headers couldn't contain any trace of where the boundary between them was. But now we don't need a separate function to do that: calling the ordinary packet-send routine twice in the same function before returning to the main event loop will have that effect _anyway_. --- ssh.c | 257 ++++++++++++++++------------------------------------------ 1 file changed, 72 insertions(+), 185 deletions(-) diff --git a/ssh.c b/ssh.c index c01f55e6..bdc91005 100644 --- a/ssh.c +++ b/ssh.c @@ -793,8 +793,6 @@ struct ssh_tag { PktOut **queue; int queuelen, queuesize; int queueing; - unsigned char *deferred_send_data; - int deferred_len, deferred_size; /* * Gross hack: pscp will try to start SFTP but fall back to @@ -858,6 +856,9 @@ struct ssh_tag { bufchain user_input; struct IdempotentCallback user_input_consumer; + bufchain outgoing_data; + struct IdempotentCallback outgoing_data_sender; + const char *rekey_reason; enum RekeyClass rekey_class; @@ -926,7 +927,7 @@ struct ssh_tag { * Track incoming and outgoing data sizes and time, for * size-based rekeys. */ - unsigned long incoming_data_size, outgoing_data_size, deferred_data_size; + unsigned long incoming_data_size, outgoing_data_size; unsigned long max_data_size; int kex_in_progress; unsigned long next_rekey, last_rekey; @@ -2059,28 +2060,11 @@ static int s_write(Ssh ssh, const void *data, int len) } static void s_wrpkt(Ssh ssh, PktOut *pkt) -{ - int len, backlog, offset; - len = s_wrpkt_prepare(ssh, pkt, &offset); - backlog = s_write(ssh, pkt->data + offset, len); - if (backlog > SSH_MAX_BACKLOG) - ssh_throttle_all(ssh, 1, backlog); - ssh_free_pktout(pkt); -} - -static void s_wrpkt_defer(Ssh ssh, PktOut *pkt) { int len, offset; len = s_wrpkt_prepare(ssh, pkt, &offset); - if (ssh->deferred_len + len > ssh->deferred_size) { - ssh->deferred_size = ssh->deferred_len + len + 128; - ssh->deferred_send_data = sresize(ssh->deferred_send_data, - ssh->deferred_size, - unsigned char); - } - memcpy(ssh->deferred_send_data + ssh->deferred_len, - pkt->data + offset, len); - ssh->deferred_len += len; + bufchain_add(&ssh->outgoing_data, pkt->data + offset, len); + queue_idempotent_callback(&ssh->outgoing_data_sender); ssh_free_pktout(pkt); } @@ -2141,16 +2125,6 @@ static void send_packet(Ssh ssh, int pkttype, ...) s_wrpkt(ssh, pkt); } -static void defer_packet(Ssh ssh, int pkttype, ...) -{ - PktOut *pkt; - va_list ap; - va_start(ap, pkttype); - pkt = construct_packet(ssh, pkttype, ap); - va_end(ap); - s_wrpkt_defer(ssh, pkt); -} - static int ssh_versioncmp(const char *a, const char *b) { char *ae, *be; @@ -2320,62 +2294,29 @@ static ptrlen ssh2_pkt_construct(Ssh ssh, PktOut *pkt) } /* - * Routines called from the main SSH code to send packets. There - * are quite a few of these, because we have two separate - * mechanisms for delaying the sending of packets: - * - * - In order to send an IGNORE message and a password message in - * a single fixed-length blob, we require the ability to - * concatenate the encrypted forms of those two packets _into_ a - * single blob and then pass it to our transport - * layer in one go. Hence, there's a deferment mechanism which - * works after packet encryption. - * - * - In order to avoid sending any connection-layer messages - * during repeat key exchange, we have to queue up any such - * outgoing messages _before_ they are encrypted (and in - * particular before they're allocated sequence numbers), and - * then send them once we've finished. - * - * I call these mechanisms `defer' and `queue' respectively, so as - * to distinguish them reasonably easily. - * - * The functions send_noqueue() and defer_noqueue() free the packet - * structure they are passed. Every outgoing packet goes through - * precisely one of these functions in its life; packets passed to - * ssh2_pkt_send() or ssh2_pkt_defer() either go straight to one of - * these or get queued, and then when the queue is later emptied - * the packets are all passed to defer_noqueue(). - * - * When using a CBC-mode cipher, it's necessary to ensure that an - * attacker can't provide data to be encrypted using an IV that they - * know. We ensure this by prefixing each packet that might contain - * user data with an SSH_MSG_IGNORE. This is done using the deferral - * mechanism, so in this case send_noqueue() ends up redirecting to - * defer_noqueue(). If you don't like this inefficiency, don't use - * CBC. - */ - -static void ssh2_pkt_defer_noqueue(Ssh, PktOut *, int); -static void ssh_pkt_defersend(Ssh); - -/* - * Send an SSH-2 packet immediately, without queuing or deferring. + * Send an SSH-2 packet immediately, without queuing. */ static void ssh2_pkt_send_noqueue(Ssh ssh, PktOut *pkt) { ptrlen data; - int backlog; - if (ssh->cscipher != NULL && (ssh->cscipher->flags & SSH_CIPHER_IS_CBC)) { - /* We need to send two packets, so use the deferral mechanism. */ - ssh2_pkt_defer_noqueue(ssh, pkt, FALSE); - ssh_pkt_defersend(ssh); - return; + if (ssh->cscipher != NULL && (ssh->cscipher->flags & SSH_CIPHER_IS_CBC) && + bufchain_size(&ssh->outgoing_data) != 0 && + !(ssh->remote_bugs & BUG_CHOKES_ON_SSH2_IGNORE)) { + /* + * When using a CBC-mode cipher in SSH-2, it's necessary to + * ensure that an attacker can't provide data to be encrypted + * using an IV that they know. We ensure this by prefixing + * each packet that might contain user data with an + * SSH_MSG_IGNORE. + */ + PktOut *ipkt = ssh2_pkt_init(SSH2_MSG_IGNORE); + put_stringz(ipkt, ""); + data = ssh2_pkt_construct(ssh, ipkt); + bufchain_add(&ssh->outgoing_data, data.ptr, data.len); } data = ssh2_pkt_construct(ssh, pkt); - backlog = s_write(ssh, data.ptr, data.len); - if (backlog > SSH_MAX_BACKLOG) - ssh_throttle_all(ssh, 1, backlog); + bufchain_add(&ssh->outgoing_data, data.ptr, data.len); + queue_idempotent_callback(&ssh->outgoing_data_sender); ssh->outgoing_data_size += pkt->encrypted_len; if (!ssh->kex_in_progress && @@ -2390,36 +2331,6 @@ static void ssh2_pkt_send_noqueue(Ssh ssh, PktOut *pkt) ssh_free_pktout(pkt); } -/* - * Defer an SSH-2 packet. - */ -static void ssh2_pkt_defer_noqueue(Ssh ssh, PktOut *pkt, int noignore) -{ - ptrlen data; - if (ssh->cscipher != NULL && (ssh->cscipher->flags & SSH_CIPHER_IS_CBC) && - ssh->deferred_len == 0 && !noignore && - !(ssh->remote_bugs & BUG_CHOKES_ON_SSH2_IGNORE)) { - /* - * Interpose an SSH_MSG_IGNORE to ensure that user data don't - * get encrypted with a known IV. - */ - PktOut *ipkt = ssh2_pkt_init(SSH2_MSG_IGNORE); - put_stringz(ipkt, ""); - ssh2_pkt_defer_noqueue(ssh, ipkt, TRUE); - } - data = ssh2_pkt_construct(ssh, pkt); - if (ssh->deferred_len + data.len > ssh->deferred_size) { - ssh->deferred_size = ssh->deferred_len + data.len + 128; - ssh->deferred_send_data = sresize(ssh->deferred_send_data, - ssh->deferred_size, - unsigned char); - } - memcpy(ssh->deferred_send_data + ssh->deferred_len, data.ptr, data.len); - ssh->deferred_len += data.len; - ssh->deferred_data_size += pkt->encrypted_len; - ssh_free_pktout(pkt); -} - /* * Queue an SSH-2 packet. */ @@ -2441,58 +2352,38 @@ static void ssh2_pkt_queue(Ssh ssh, PktOut *pkt) */ static void ssh2_pkt_send(Ssh ssh, PktOut *pkt) { - if (ssh->queueing) + if (ssh->queueing) { ssh2_pkt_queue(ssh, pkt); - else + } else { ssh2_pkt_send_noqueue(ssh, pkt); + } } -/* - * Either queue or defer a packet, depending on whether queueing is - * set. - */ -static void ssh2_pkt_defer(Ssh ssh, PktOut *pkt) +static void ssh_send_outgoing_data(void *ctx) { - if (ssh->queueing) - ssh2_pkt_queue(ssh, pkt); - else - ssh2_pkt_defer_noqueue(ssh, pkt, FALSE); -} + Ssh ssh = (Ssh)ctx; -/* - * Send the whole deferred data block constructed by - * ssh2_pkt_defer() or SSH-1's defer_packet(). - * - * The expected use of the defer mechanism is that you call - * ssh2_pkt_defer() a few times, then call ssh_pkt_defersend(). If - * not currently queueing, this simply sets up deferred_send_data - * and then sends it. If we _are_ currently queueing, the calls to - * ssh2_pkt_defer() put the deferred packets on to the queue - * instead, and therefore ssh_pkt_defersend() has no deferred data - * to send. Hence, there's no need to make it conditional on - * ssh->queueing. - */ -static void ssh_pkt_defersend(Ssh ssh) -{ - int backlog; - backlog = s_write(ssh, ssh->deferred_send_data, ssh->deferred_len); - ssh->deferred_len = ssh->deferred_size = 0; - sfree(ssh->deferred_send_data); - ssh->deferred_send_data = NULL; - if (backlog > SSH_MAX_BACKLOG) - ssh_throttle_all(ssh, 1, backlog); + while (bufchain_size(&ssh->outgoing_data) > 0) { + void *data; + int len, backlog; - if (ssh->version == 2) { - ssh->outgoing_data_size += ssh->deferred_data_size; - ssh->deferred_data_size = 0; - if (!ssh->kex_in_progress && - !ssh->bare_connection && - ssh->max_data_size != 0 && + bufchain_prefix(&ssh->outgoing_data, &data, &len); + backlog = s_write(ssh, data, len); + bufchain_consume(&ssh->outgoing_data, len); + + ssh->outgoing_data_size += len; + if (ssh->version == 2 && !ssh->kex_in_progress && + !ssh->bare_connection && ssh->max_data_size != 0 && ssh->outgoing_data_size > ssh->max_data_size) { ssh->rekey_reason = "too much data sent"; ssh->rekey_class = RK_NORMAL; queue_idempotent_callback(&ssh->ssh2_transport_icb); } + + if (backlog > SSH_MAX_BACKLOG) { + ssh_throttle_all(ssh, 1, backlog); + return; + } } } @@ -2518,26 +2409,27 @@ static void ssh2_pkt_send_with_padding(Ssh ssh, PktOut *pkt, int padsize) #endif { /* - * If we can't do that, however, an alternative approach is - * to use the pkt_defer mechanism to bundle the packet - * tightly together with an SSH_MSG_IGNORE such that their - * combined length is a constant. So first we construct the - * final form of this packet and defer its sending. + * If we can't do that, however, an alternative approach is to + * bundle the packet tightly together with an SSH_MSG_IGNORE + * such that their combined length is a constant. So first we + * construct the final form of this packet and append it to + * the outgoing_data bufchain... */ - ssh2_pkt_defer(ssh, pkt); + ssh2_pkt_send(ssh, pkt); /* - * Now construct an SSH_MSG_IGNORE which includes a string - * that's an exact multiple of the cipher block size. (If - * the cipher is NULL so that the block size is - * unavailable, we don't do this trick at all, because we - * gain nothing by it.) + * ... but before we return from this function (triggering a + * call to the outgoing_data_sender), we also construct an + * SSH_MSG_IGNORE which includes a string that's an exact + * multiple of the cipher block size. (If the cipher is NULL + * so that the block size is unavailable, we don't do this + * trick at all, because we gain nothing by it.) */ if (ssh->cscipher && !(ssh->remote_bugs & BUG_CHOKES_ON_SSH2_IGNORE)) { int stringlen, i; - stringlen = (256 - ssh->deferred_len); + stringlen = (256 - bufchain_size(&ssh->outgoing_data)); stringlen += ssh->cscipher->blksize - 1; stringlen -= (stringlen % ssh->cscipher->blksize); if (ssh->cscomp) { @@ -2559,16 +2451,13 @@ static void ssh2_pkt_send_with_padding(Ssh ssh, PktOut *pkt, int padsize) put_byte(substr, random_byte()); put_stringsb(pkt, substr); } - ssh2_pkt_defer(ssh, pkt); + ssh2_pkt_send(ssh, pkt); } - ssh_pkt_defersend(ssh); } } /* - * Send all queued SSH-2 packets. We send them by means of - * ssh2_pkt_defer_noqueue(), in case they included a pair of - * packets that needed to be lumped together. + * Send all queued SSH-2 packets. */ static void ssh2_pkt_queuesend(Ssh ssh) { @@ -2577,10 +2466,8 @@ static void ssh2_pkt_queuesend(Ssh ssh) assert(!ssh->queueing); for (i = 0; i < ssh->queuelen; i++) - ssh2_pkt_defer_noqueue(ssh, ssh->queue[i], FALSE); + ssh2_pkt_send_noqueue(ssh, ssh->queue[i]); ssh->queuelen = 0; - - ssh_pkt_defersend(ssh); } #if 0 @@ -2913,7 +2800,8 @@ static void ssh_send_verstring(Ssh ssh, const char *protoname, char *svers) logeventf(ssh, "We claim version: %.*s", strcspn(verstring, "\015\012"), verstring); - s_write(ssh, verstring, strlen(verstring)); + bufchain_add(&ssh->outgoing_data, verstring, strlen(verstring)); + queue_idempotent_callback(&ssh->outgoing_data_sender); sfree(verstring); } @@ -4826,9 +4714,9 @@ static void do_ssh1_login(void *vctx) for (i = bottom; i <= top; i++) { if (i == pwlen) { - defer_packet(ssh, s->pwpkt_type, - PKT_STR,s->cur_prompt->prompts[0]->result, - PKT_END); + send_packet(ssh, s->pwpkt_type, + PKT_STR, s->cur_prompt->prompts[0]->result, + PKT_END); } else { for (j = 0; j < i; j++) { do { @@ -4836,12 +4724,11 @@ static void do_ssh1_login(void *vctx) } while (randomstr[j] == '\0'); } randomstr[i] = '\0'; - defer_packet(ssh, SSH1_MSG_IGNORE, - PKT_STR, randomstr, PKT_END); + send_packet(ssh, SSH1_MSG_IGNORE, + PKT_STR, randomstr, PKT_END); } } logevent("Sending password with camouflage packets"); - ssh_pkt_defersend(ssh); sfree(randomstr); } else if (!(ssh->remote_bugs & BUG_NEEDS_SSH1_PLAIN_PASSWORD)) { @@ -11898,9 +11785,6 @@ static const char *ssh_init(void *frontend_handle, void **backend_handle, ssh->eof_needed = FALSE; ssh->ldisc = NULL; ssh->logctx = NULL; - ssh->deferred_send_data = NULL; - ssh->deferred_len = 0; - ssh->deferred_size = 0; ssh->fallback_cmd = 0; ssh->pkt_kctx = SSH2_PKTCTX_NOKEX; ssh->pkt_actx = SSH2_PKTCTX_NOAUTH; @@ -11954,6 +11838,10 @@ static const char *ssh_init(void *frontend_handle, void **backend_handle, ssh->user_input_consumer.fn = ssh_process_user_input; ssh->user_input_consumer.ctx = ssh; ssh->user_input_consumer.queued = FALSE; + bufchain_init(&ssh->outgoing_data); + ssh->outgoing_data_sender.fn = ssh_send_outgoing_data; + ssh->outgoing_data_sender.ctx = ssh; + ssh->outgoing_data_sender.queued = FALSE; ssh->current_user_input_fn = NULL; ssh->pending_newkeys = FALSE; ssh->rekey_reason = NULL; @@ -12010,8 +11898,7 @@ static const char *ssh_init(void *frontend_handle, void **backend_handle, ssh->pinger = NULL; - ssh->incoming_data_size = ssh->outgoing_data_size = - ssh->deferred_data_size = 0L; + ssh->incoming_data_size = ssh->outgoing_data_size = 0L; ssh->max_data_size = parse_blocksize(conf_get_str(ssh->conf, CONF_ssh_rekey_data)); ssh->kex_in_progress = FALSE; @@ -12120,7 +12007,6 @@ static void ssh_free(void *handle) freetree234(ssh->rportfwds); ssh->rportfwds = NULL; } - sfree(ssh->deferred_send_data); if (ssh->x11disp) x11_free_display(ssh->x11disp); while ((auth = delpos234(ssh->x11authtree, 0)) != NULL) @@ -12132,6 +12018,7 @@ static void ssh_free(void *handle) sfree(ssh->do_ssh2_userauth_state); sfree(ssh->do_ssh2_connection_state); bufchain_clear(&ssh->incoming_data); + bufchain_clear(&ssh->outgoing_data); sfree(ssh->incoming_data_eof_message); pq_clear(&ssh->pq_full); pq_clear(&ssh->pq_ssh1_login); From 679fa90dfef62153f95816d703a48495546410c7 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 9 Jun 2018 09:09:10 +0100 Subject: [PATCH 372/607] Move binary packet protocols and censoring out of ssh.c. sshbpp.h now defines a classoid that encapsulates both directions of an SSH binary packet protocol - that is, a system for reading a bufchain of incoming data and turning it into a stream of PktIn, and another system for taking a PktOut and turning it into data on an outgoing bufchain. The state structure in each of those files contains everything that used to be in the 'rdpkt2_state' structure and its friends, and also quite a lot of bits and pieces like cipher and MAC states that used to live in the main Ssh structure. One minor effect of this layer separation is that I've had to extend the packet dispatch table by one, because the BPP layer can no longer directly trigger sending of SSH_MSG_UNIMPLEMENTED for a message too short to have a type byte. Instead, I extend the PktIn type field to use an out-of-range value to encode that, and the easiest way to make that trigger an UNIMPLEMENTED message is to have the dispatch table contain an entry for it. (That's a system that may come in useful again - I was also wondering about inventing a fake type code to indicate network EOF, so that that could be propagated through the layers and be handled by whichever one currently knew best how to respond.) I've also moved the packet-censoring code into its own pair of files, partly because I was going to want to do that anyway sooner or later, and mostly because it's called from the BPP code, and the SSH-2 version in particular has to be called from both the main SSH-2 BPP and the bare unencrypted protocol used for connection sharing. While I was at it, I took the opportunity to merge the outgoing and incoming censor functions, so that the parts that were common between them (e.g. CHANNEL_DATA messages look the same in both directions) didn't need to be repeated. --- Recipe | 3 +- ssh.c | 1721 ++++++++++-------------------------------------- ssh.h | 24 +- ssh1bpp.c | 280 ++++++++ ssh1censor.c | 76 +++ ssh2bpp-bare.c | 160 +++++ ssh2bpp.c | 613 +++++++++++++++++ ssh2censor.c | 107 +++ sshbpp.h | 54 ++ 9 files changed, 1659 insertions(+), 1379 deletions(-) create mode 100644 ssh1bpp.c create mode 100644 ssh1censor.c create mode 100644 ssh2bpp-bare.c create mode 100644 ssh2bpp.c create mode 100644 ssh2censor.c create mode 100644 sshbpp.h diff --git a/Recipe b/Recipe index c76b14f7..1b84885b 100644 --- a/Recipe +++ b/Recipe @@ -250,7 +250,8 @@ GTKMAIN = gtkmain cmdline NONSSH = telnet raw rlogin ldisc pinger # SSH back end (putty, plink, pscp, psftp). -SSH = ssh sshcrc sshdes sshmd5 sshrsa sshrand sshsha sshblowf +SSH = ssh ssh1bpp ssh2bpp ssh2bpp-bare ssh1censor ssh2censor + + sshcrc sshdes sshmd5 sshrsa sshrand sshsha sshblowf + sshdh sshcrcda sshpubk sshzlib sshdss x11fwd portfwd + sshaes sshccp sshsh256 sshsh512 sshbn wildcard pinger ssharcf + sshgssc pgssapi sshshare sshecc aqsync marshal nullplug diff --git a/ssh.c b/ssh.c index bdc91005..919b2321 100644 --- a/ssh.c +++ b/ssh.c @@ -16,6 +16,7 @@ #include "marshal.h" #include "ssh.h" #include "sshcr.h" +#include "sshbpp.h" #ifndef NO_GSSAPI #include "sshgssc.h" #include "sshgss.h" @@ -295,9 +296,7 @@ enum { static void ssh_pkt_ensure(struct PktOut *, int length); static void ssh_pkt_adddata(struct PktOut *, const void *data, int len); -static ptrlen ssh2_pkt_construct(Ssh, struct PktOut *); static void ssh2_pkt_send(Ssh, struct PktOut *); -static void ssh2_pkt_send_noqueue(Ssh, struct PktOut *); static void do_ssh1_login(void *vctx); static void do_ssh2_userauth(void *vctx); static void ssh2_connection_setup(Ssh ssh); @@ -651,31 +650,6 @@ int pq_empty_on_to_front_of(struct PacketQueue *src, struct PacketQueue *dest) return TRUE; } -struct rdpkt1_state_tag { - long len, pad, biglen, length, maxlen; - unsigned char *data; - unsigned long realcrc, gotcrc; - int chunk; - PktIn *pktin; -}; - -struct rdpkt2_state_tag { - long len, pad, payload, packetlen, maclen, length, maxlen; - unsigned char *buf; - size_t bufsize; - unsigned char *data; - int cipherblk; - unsigned long incoming_sequence; - PktIn *pktin; -}; - -struct rdpkt2_bare_state_tag { - long packetlen, maxlen; - unsigned char *data; - unsigned long incoming_sequence; - PktIn *pktin; -}; - struct queued_handler; struct queued_handler { int msg1, msg2; @@ -729,28 +703,18 @@ struct ssh_tag { void *logctx; unsigned char session_key[32]; - int v1_compressing; int v1_remote_protoflags; int v1_local_protoflags; int agentfwd_enabled; int X11_fwd_enabled; int remote_bugs; - const struct ssh_cipher *cipher; - void *v1_cipher_ctx; - void *crcda_ctx; - const struct ssh2_cipher *cscipher, *sccipher; - void *cs_cipher_ctx, *sc_cipher_ctx; - const struct ssh_mac *csmac, *scmac; - int csmac_etm, scmac_etm; - void *cs_mac_ctx, *sc_mac_ctx; - BinarySink *sc_mac_bs; - const struct ssh_compress *cscomp, *sccomp; - void *cs_comp_ctx, *sc_comp_ctx; const struct ssh_kex *kex; const ssh_keyalg *hostkey_alg; char *hostkey_str; /* string representation, for easy checking in rekeys */ unsigned char v2_session_id[SSH2_KEX_MAX_HASH_LEN]; int v2_session_id_len; + int v2_cbc_ignore_workaround; + int v2_out_cipherblksize; void *kex_ctx; int bare_connection; @@ -804,9 +768,6 @@ struct ssh_tag { bufchain banner; /* accumulates banners during do_ssh2_userauth */ - Pkt_KCtx pkt_kctx; - Pkt_ACtx pkt_actx; - struct X11Display *x11disp; struct X11FakeAuth *x11auth; tree234 *x11authtree; @@ -816,11 +777,7 @@ struct ssh_tag { int overall_bufsize; int throttled_all; int v1_stdout_throttling; - unsigned long v2_outgoing_sequence; - int ssh1_rdpkt_crstate; - int ssh2_rdpkt_crstate; - int ssh2_bare_rdpkt_crstate; int do_ssh1_connection_crstate; void *do_ssh_init_state; @@ -862,9 +819,8 @@ struct ssh_tag { const char *rekey_reason; enum RekeyClass rekey_class; - struct rdpkt1_state_tag rdpkt1_state; - struct rdpkt2_state_tag rdpkt2_state; - struct rdpkt2_bare_state_tag rdpkt2_bare_state; + PacketLogSettings pls; + BinaryPacketProtocol *bpp; void (*general_packet_processing)(Ssh ssh, PktIn *pkt); void (*current_incoming_data_fn) (Ssh ssh); @@ -878,12 +834,6 @@ struct ssh_tag { */ Conf *conf; - /* - * Values cached out of conf so as to avoid the tree234 lookup - * cost every time they're used. - */ - int logomitdata; - /* * Dynamically allocated username string created during SSH * login. Stored in here rather than in the coroutine state so @@ -909,7 +859,7 @@ struct ssh_tag { * Dispatch table for packet types that we may have to deal * with at any time. */ - handler_fn_t packet_dispatch[256]; + handler_fn_t packet_dispatch[SSH_MAX_MSG]; /* * Queues of one-off handler functions for success/failure @@ -933,13 +883,6 @@ struct ssh_tag { unsigned long next_rekey, last_rekey; const char *deferred_rekey_reason; - /* - * Inhibit processing of incoming raw data into packets while - * we're still waiting for a NEWKEYS message to complete and fill - * in the new details of how that should be done. - */ - int pending_newkeys; - /* * Fully qualified host name, which we need if doing GSSAPI. */ @@ -997,7 +940,7 @@ static const char *ssh_pkt_type(Ssh ssh, int type) if (ssh->version == 1) return ssh1_pkt_type(type); else - return ssh2_pkt_type(ssh->pkt_kctx, ssh->pkt_actx, type); + return ssh2_pkt_type(ssh->pls.kctx, ssh->pls.actx, type); } #define logevent(s) logevent(ssh->frontend, s) @@ -1236,819 +1179,20 @@ void ssh_free_pktout(PktOut *pkt) static void ssh_pkt_BinarySink_write(BinarySink *bs, const void *data, size_t len); -static PktOut *ssh_new_packet(void) +PktOut *ssh_new_packet(void) { PktOut *pkt = snew(PktOut); BinarySink_INIT(pkt, ssh_pkt_BinarySink_write); pkt->data = NULL; + pkt->length = 0; pkt->maxlen = 0; + pkt->downstream_id = 0; + pkt->additional_log_text = NULL; return pkt; } -static void ssh1_log_incoming_packet(Ssh ssh, const PktIn *pkt) -{ - int nblanks = 0; - struct logblank_t blanks[4]; - ptrlen str; - BinarySource src[1]; - - BinarySource_BARE_INIT(src, BinarySource_UPCAST(pkt)->data, - BinarySource_UPCAST(pkt)->len); - - if (ssh->logomitdata && - (pkt->type == SSH1_SMSG_STDOUT_DATA || - pkt->type == SSH1_SMSG_STDERR_DATA || - pkt->type == SSH1_MSG_CHANNEL_DATA)) { - /* "Session data" packets - omit the data string. */ - if (pkt->type == SSH1_MSG_CHANNEL_DATA) - get_uint32(src); /* skip channel id */ - str = get_string(src); - if (!get_err(src)) { - blanks[nblanks].offset = src->pos - str.len; - blanks[nblanks].type = PKTLOG_OMIT; - blanks[nblanks].len = str.len; - nblanks++; - } - } - log_packet(ssh->logctx, PKT_INCOMING, pkt->type, ssh1_pkt_type(pkt->type), - src->data, src->len, nblanks, blanks, NULL, 0, NULL); -} - -static void ssh1_log_outgoing_packet(Ssh ssh, const PktOut *pkt) -{ - int nblanks = 0; - struct logblank_t blanks[4]; - ptrlen str; - BinarySource src[1]; - - BinarySource_BARE_INIT(src, pkt->data + pkt->prefix, - pkt->length - pkt->prefix); - - if (ssh->logomitdata && - (pkt->type == SSH1_CMSG_STDIN_DATA || - pkt->type == SSH1_MSG_CHANNEL_DATA)) { - /* "Session data" packets - omit the data string. */ - if (pkt->type == SSH1_MSG_CHANNEL_DATA) - get_uint32(src); /* skip channel id */ - str = get_string(src); - if (!get_err(src)) { - blanks[nblanks].offset = src->pos - str.len; - blanks[nblanks].type = PKTLOG_OMIT; - blanks[nblanks].len = str.len; - nblanks++; - } - } - - if ((pkt->type == SSH1_CMSG_AUTH_PASSWORD || - pkt->type == SSH1_CMSG_AUTH_TIS_RESPONSE || - pkt->type == SSH1_CMSG_AUTH_CCARD_RESPONSE) && - conf_get_int(ssh->conf, CONF_logomitpass)) { - /* If this is a password or similar packet, blank the password(s). */ - blanks[nblanks].offset = 0; - blanks[nblanks].len = pkt->length; - blanks[nblanks].type = PKTLOG_BLANK; - nblanks++; - } else if (pkt->type == SSH1_CMSG_X11_REQUEST_FORWARDING && - conf_get_int(ssh->conf, CONF_logomitpass)) { - /* - * If this is an X forwarding request packet, blank the fake - * auth data. - * - * Note that while we blank the X authentication data here, we - * don't take any special action to blank the start of an X11 - * channel, so using MIT-MAGIC-COOKIE-1 and actually opening - * an X connection without having session blanking enabled is - * likely to leak your cookie into the log. - */ - get_string(src); /* skip protocol name */ - str = get_string(src); - if (!get_err(src)) { - blanks[nblanks].offset = src->pos - str.len; - blanks[nblanks].type = PKTLOG_BLANK; - blanks[nblanks].len = str.len; - nblanks++; - } - } - - log_packet(ssh->logctx, PKT_OUTGOING, pkt->data[12], - ssh1_pkt_type(pkt->data[12]), - src->data, src->len, nblanks, blanks, NULL, 0, NULL); -} - -/* - * Collect incoming data in the incoming packet buffer. - * Decipher and verify the packet when it is completely read. - * Update the *data and *datalen variables. - * Return a Packet structure when a packet is completed. - */ -static void ssh1_rdpkt(Ssh ssh) -{ - struct rdpkt1_state_tag *st = &ssh->rdpkt1_state; - - crBegin(ssh->ssh1_rdpkt_crstate); - - while (1) { - st->maxlen = 0; - st->length = 0; - - { - unsigned char lenbuf[4]; - crMaybeWaitUntilV(bufchain_try_fetch_consume( - &ssh->incoming_data, lenbuf, 4)); - st->len = toint(GET_32BIT_MSB_FIRST(lenbuf)); - } - - st->pad = 8 - (st->len % 8); - st->biglen = st->len + st->pad; - st->length = st->len - 5; - - if (st->biglen < 0) { - bombout(("Extremely large packet length from server suggests" - " data stream corruption")); - ssh_unref_packet(st->pktin); - crStopV; - } - - /* - * Allocate the packet to return, now we know its length. - */ - st->pktin = snew_plus(PktIn, st->biglen); - st->pktin->qnode.prev = st->pktin->qnode.next = NULL; - st->pktin->refcount = 1; - st->pktin->type = 0; - - st->maxlen = st->biglen; - st->data = snew_plus_get_aux(st->pktin); - - crMaybeWaitUntilV(bufchain_try_fetch_consume( - &ssh->incoming_data, st->data, st->biglen)); - - if (ssh->cipher && detect_attack(ssh->crcda_ctx, st->data, - st->biglen, NULL)) { - bombout(("Network attack (CRC compensation) detected!")); - ssh_unref_packet(st->pktin); - crStopV; - } - - if (ssh->cipher) - ssh->cipher->decrypt(ssh->v1_cipher_ctx, st->data, st->biglen); - - st->realcrc = crc32_compute(st->data, st->biglen - 4); - st->gotcrc = GET_32BIT(st->data + st->biglen - 4); - if (st->gotcrc != st->realcrc) { - bombout(("Incorrect CRC received on packet")); - ssh_unref_packet(st->pktin); - crStopV; - } - - if (ssh->v1_compressing) { - unsigned char *decompblk; - int decomplen; - if (!zlib_decompress_block(ssh->sc_comp_ctx, - st->data + st->pad, st->length + 1, - &decompblk, &decomplen)) { - bombout(("Zlib decompression encountered invalid data")); - ssh_unref_packet(st->pktin); - crStopV; - } - - if (st->maxlen < st->pad + decomplen) { - PktIn *old_pktin = st->pktin; - - st->maxlen = st->pad + decomplen; - st->pktin = snew_plus(PktIn, st->maxlen); - *st->pktin = *old_pktin; /* structure copy */ - st->data = snew_plus_get_aux(st->pktin); - - smemclr(old_pktin, st->biglen); - sfree(old_pktin); - } - - memcpy(st->data + st->pad, decompblk, decomplen); - sfree(decompblk); - st->length = decomplen - 1; - } - - /* - * Now we can find the bounds of the semantic content of the - * packet, and the initial type byte. - */ - st->pktin->type = st->data[st->pad]; - BinarySource_INIT(st->pktin, st->data + st->pad + 1, st->length); - - if (ssh->logctx) - ssh1_log_incoming_packet(ssh, st->pktin); - - /* - * Mild layer violation: if the message is a DISCONNECT, we - * should unset the close_expected flag, because now we _do_ - * expect the server to close the network connection - * afterwards. That way, the more informative connection_fatal - * message for the disconnect itself won't fight with 'Server - * unexpectedly closed network connection'. - */ - if (st->pktin->type == SSH1_MSG_DISCONNECT) { - ssh->clean_exit = FALSE; - ssh->close_expected = TRUE; - ssh->disconnect_message_seen = TRUE; - } - - pq_push(&ssh->pq_full, st->pktin); - queue_idempotent_callback(&ssh->pq_full_consumer); - } - crFinishV; -} - -static void ssh2_log_incoming_packet(Ssh ssh, const PktIn *pkt) -{ - int nblanks = 0; - struct logblank_t blanks[4]; - ptrlen str; - BinarySource src[1]; - - BinarySource_BARE_INIT(src, BinarySource_UPCAST(pkt)->data, - BinarySource_UPCAST(pkt)->len); - - if (ssh->logomitdata && - (pkt->type == SSH2_MSG_CHANNEL_DATA || - pkt->type == SSH2_MSG_CHANNEL_EXTENDED_DATA)) { - /* "Session data" packets - omit the data string. */ - get_uint32(src); /* skip channel id */ - if (pkt->type == SSH2_MSG_CHANNEL_EXTENDED_DATA) - get_uint32(src); /* skip extended data type */ - str = get_string(src); - if (!get_err(src)) { - blanks[nblanks].offset = src->pos - str.len; - blanks[nblanks].type = PKTLOG_OMIT; - blanks[nblanks].len = str.len; - nblanks++; - } - } - - log_packet(ssh->logctx, PKT_INCOMING, pkt->type, - ssh2_pkt_type(ssh->pkt_kctx, ssh->pkt_actx, pkt->type), - src->data, src->len, nblanks, blanks, &pkt->sequence, - 0, NULL); -} - -static void ssh2_log_outgoing_packet(Ssh ssh, const PktOut *pkt) -{ - int nblanks = 0; - struct logblank_t blanks[4]; - ptrlen str; - BinarySource src[1]; - - BinarySource_BARE_INIT(src, pkt->data + pkt->prefix, - pkt->length - pkt->prefix); - - if (ssh->logomitdata && - (pkt->type == SSH2_MSG_CHANNEL_DATA || - pkt->type == SSH2_MSG_CHANNEL_EXTENDED_DATA)) { - /* "Session data" packets - omit the data string. */ - get_uint32(src); /* skip channel id */ - if (pkt->type == SSH2_MSG_CHANNEL_EXTENDED_DATA) - get_uint32(src); /* skip extended data type */ - str = get_string(src); - if (!get_err(src)) { - blanks[nblanks].offset = src->pos - str.len; - blanks[nblanks].type = PKTLOG_OMIT; - blanks[nblanks].len = str.len; - nblanks++; - } - } - - if (pkt->type == SSH2_MSG_USERAUTH_REQUEST && - conf_get_int(ssh->conf, CONF_logomitpass)) { - /* If this is a password packet, blank the password(s). */ - get_string(src); /* username */ - get_string(src); /* service name */ - str = get_string(src); /* auth method */ - if (ptrlen_eq_string(str, "password")) { - get_bool(src); - /* Blank the password field. */ - str = get_string(src); - if (!get_err(src)) { - blanks[nblanks].offset = src->pos - str.len; - blanks[nblanks].type = PKTLOG_BLANK; - blanks[nblanks].len = str.len; - nblanks++; - /* If there's another password field beyond it (change of - * password), blank that too. */ - str = get_string(src); - if (!get_err(src)) - blanks[nblanks-1].len = src->pos - blanks[nblanks].offset; - } - } - } else if (ssh->pkt_actx == SSH2_PKTCTX_KBDINTER && - pkt->type == SSH2_MSG_USERAUTH_INFO_RESPONSE && - conf_get_int(ssh->conf, CONF_logomitpass)) { - /* If this is a keyboard-interactive response packet, blank - * the responses. */ - get_uint32(src); - blanks[nblanks].offset = src->pos; - blanks[nblanks].type = PKTLOG_BLANK; - do { - str = get_string(src); - } while (!get_err(src)); - blanks[nblanks].len = src->pos - blanks[nblanks].offset; - nblanks++; - } else if (pkt->type == SSH2_MSG_CHANNEL_REQUEST && - conf_get_int(ssh->conf, CONF_logomitpass)) { - /* - * If this is an X forwarding request packet, blank the fake - * auth data. - * - * Note that while we blank the X authentication data here, we - * don't take any special action to blank the start of an X11 - * channel, so using MIT-MAGIC-COOKIE-1 and actually opening - * an X connection without having session blanking enabled is - * likely to leak your cookie into the log. - */ - get_uint32(src); - str = get_string(src); - if (ptrlen_eq_string(str, "x11-req")) { - get_bool(src); - get_bool(src); - get_string(src); - str = get_string(src); - if (!get_err(src)) { - blanks[nblanks].offset = src->pos - str.len; - blanks[nblanks].type = PKTLOG_BLANK; - blanks[nblanks].len = str.len; - nblanks++; - } - } - } - - log_packet(ssh->logctx, PKT_OUTGOING, pkt->data[5], - ssh2_pkt_type(ssh->pkt_kctx, ssh->pkt_actx, pkt->data[5]), - src->data, src->len, nblanks, blanks, - &ssh->v2_outgoing_sequence, - pkt->downstream_id, pkt->additional_log_text); -} - -static void ssh2_rdpkt(Ssh ssh) -{ - struct rdpkt2_state_tag *st = &ssh->rdpkt2_state; - - crBegin(ssh->ssh2_rdpkt_crstate); - - st->buf = NULL; - st->bufsize = 0; - - while (1) { - st->maxlen = 0; - st->length = 0; - if (ssh->sccipher) - st->cipherblk = ssh->sccipher->blksize; - else - st->cipherblk = 8; - if (st->cipherblk < 8) - st->cipherblk = 8; - st->maclen = ssh->scmac ? ssh->scmac->len : 0; - - if (ssh->sccipher && (ssh->sccipher->flags & SSH_CIPHER_IS_CBC) && - ssh->scmac && !ssh->scmac_etm) { - /* - * When dealing with a CBC-mode cipher, we want to avoid the - * possibility of an attacker's tweaking the ciphertext stream - * so as to cause us to feed the same block to the block - * cipher more than once and thus leak information - * (VU#958563). The way we do this is not to take any - * decisions on the basis of anything we've decrypted until - * we've verified it with a MAC. That includes the packet - * length, so we just read data and check the MAC repeatedly, - * and when the MAC passes, see if the length we've got is - * plausible. - * - * This defence is unnecessary in OpenSSH ETM mode, because - * the whole point of ETM mode is that the attacker can't - * tweak the ciphertext stream at all without the MAC - * detecting it before we decrypt anything. - */ - - /* - * Make sure we have buffer space for a maximum-size packet. - */ - int buflimit = OUR_V2_PACKETLIMIT + st->maclen; - if (st->bufsize < buflimit) { - st->bufsize = buflimit; - st->buf = sresize(st->buf, st->bufsize, unsigned char); - } - - /* Read an amount corresponding to the MAC. */ - crMaybeWaitUntilV(bufchain_try_fetch_consume( - &ssh->incoming_data, st->buf, st->maclen)); - - st->packetlen = 0; - ssh->scmac->start(ssh->sc_mac_ctx); - ssh->sc_mac_bs = ssh->scmac->sink(ssh->sc_mac_ctx); - put_uint32(ssh->sc_mac_bs, st->incoming_sequence); - - for (;;) { /* Once around this loop per cipher block. */ - /* Read another cipher-block's worth, and tack it onto the end. */ - crMaybeWaitUntilV(bufchain_try_fetch_consume( - &ssh->incoming_data, - st->buf + (st->packetlen + st->maclen), - st->cipherblk)); - /* Decrypt one more block (a little further back in the stream). */ - ssh->sccipher->decrypt(ssh->sc_cipher_ctx, - st->buf + st->packetlen, - st->cipherblk); - /* Feed that block to the MAC. */ - put_data(ssh->sc_mac_bs, - st->buf + st->packetlen, st->cipherblk); - st->packetlen += st->cipherblk; - /* See if that gives us a valid packet. */ - if (ssh->scmac->verresult(ssh->sc_mac_ctx, - st->buf + st->packetlen) && - ((st->len = toint(GET_32BIT(st->buf))) == - st->packetlen-4)) - break; - if (st->packetlen >= OUR_V2_PACKETLIMIT) { - bombout(("No valid incoming packet found")); - crStopV; - } - } - st->maxlen = st->packetlen + st->maclen; - - /* - * Now transfer the data into an output packet. - */ - st->pktin = snew_plus(PktIn, st->maxlen); - st->pktin->qnode.prev = st->pktin->qnode.next = NULL; - st->pktin->refcount = 1; - st->pktin->type = 0; - st->data = snew_plus_get_aux(st->pktin); - memcpy(st->data, st->buf, st->maxlen); - } else if (ssh->scmac && ssh->scmac_etm) { - if (st->bufsize < 4) { - st->bufsize = 4; - st->buf = sresize(st->buf, st->bufsize, unsigned char); - } - - /* - * OpenSSH encrypt-then-MAC mode: the packet length is - * unencrypted, unless the cipher supports length encryption. - */ - crMaybeWaitUntilV(bufchain_try_fetch_consume( - &ssh->incoming_data, st->buf, 4)); - - /* Cipher supports length decryption, so do it */ - if (ssh->sccipher && (ssh->sccipher->flags & SSH_CIPHER_SEPARATE_LENGTH)) { - /* Keep the packet the same though, so the MAC passes */ - unsigned char len[4]; - memcpy(len, st->buf, 4); - ssh->sccipher->decrypt_length(ssh->sc_cipher_ctx, len, 4, st->incoming_sequence); - st->len = toint(GET_32BIT(len)); - } else { - st->len = toint(GET_32BIT(st->buf)); - } - - /* - * _Completely_ silly lengths should be stomped on before they - * do us any more damage. - */ - if (st->len < 0 || st->len > OUR_V2_PACKETLIMIT || - st->len % st->cipherblk != 0) { - bombout(("Incoming packet length field was garbled")); - crStopV; - } - - /* - * So now we can work out the total packet length. - */ - st->packetlen = st->len + 4; - - /* - * Allocate the packet to return, now we know its length. - */ - st->pktin = snew_plus(PktIn, OUR_V2_PACKETLIMIT + st->maclen); - st->pktin->qnode.prev = st->pktin->qnode.next = NULL; - st->pktin->refcount = 1; - st->pktin->type = 0; - st->data = snew_plus_get_aux(st->pktin); - memcpy(st->data, st->buf, 4); - - /* - * Read the remainder of the packet. - */ - crMaybeWaitUntilV(bufchain_try_fetch_consume( - &ssh->incoming_data, st->data + 4, - st->packetlen + st->maclen - 4)); - - /* - * Check the MAC. - */ - if (ssh->scmac - && !ssh->scmac->verify(ssh->sc_mac_ctx, st->data, - st->len + 4, st->incoming_sequence)) { - bombout(("Incorrect MAC received on packet")); - ssh_unref_packet(st->pktin); - crStopV; - } - - /* Decrypt everything between the length field and the MAC. */ - if (ssh->sccipher) - ssh->sccipher->decrypt(ssh->sc_cipher_ctx, - st->data + 4, st->packetlen - 4); - } else { - if (st->bufsize < st->cipherblk) { - st->bufsize = st->cipherblk; - st->buf = sresize(st->buf, st->bufsize, unsigned char); - } - - /* - * Acquire and decrypt the first block of the packet. This will - * contain the length and padding details. - */ - crMaybeWaitUntilV(bufchain_try_fetch_consume( - &ssh->incoming_data, - st->buf, st->cipherblk)); - - if (ssh->sccipher) - ssh->sccipher->decrypt(ssh->sc_cipher_ctx, - st->buf, st->cipherblk); - - /* - * Now get the length figure. - */ - st->len = toint(GET_32BIT(st->buf)); - - /* - * _Completely_ silly lengths should be stomped on before they - * do us any more damage. - */ - if (st->len < 0 || st->len > OUR_V2_PACKETLIMIT || - (st->len + 4) % st->cipherblk != 0) { - bombout(("Incoming packet was garbled on decryption")); - ssh_unref_packet(st->pktin); - crStopV; - } - - /* - * So now we can work out the total packet length. - */ - st->packetlen = st->len + 4; - - /* - * Allocate the packet to return, now we know its length. - */ - st->maxlen = st->packetlen + st->maclen; - st->pktin = snew_plus(PktIn, st->maxlen); - st->pktin->qnode.prev = st->pktin->qnode.next = NULL; - st->pktin->refcount = 1; - st->pktin->type = 0; - st->data = snew_plus_get_aux(st->pktin); - memcpy(st->data, st->buf, st->cipherblk); - - /* - * Read and decrypt the remainder of the packet. - */ - crMaybeWaitUntilV(bufchain_try_fetch_consume( - &ssh->incoming_data, - st->data + st->cipherblk, - st->packetlen + st->maclen - st->cipherblk)); - - /* Decrypt everything _except_ the MAC. */ - if (ssh->sccipher) - ssh->sccipher->decrypt(ssh->sc_cipher_ctx, - st->data + st->cipherblk, - st->packetlen - st->cipherblk); - - /* - * Check the MAC. - */ - if (ssh->scmac - && !ssh->scmac->verify(ssh->sc_mac_ctx, st->data, - st->len + 4, st->incoming_sequence)) { - bombout(("Incorrect MAC received on packet")); - ssh_unref_packet(st->pktin); - crStopV; - } - } - /* Get and sanity-check the amount of random padding. */ - st->pad = st->data[4]; - if (st->pad < 4 || st->len - st->pad < 1) { - bombout(("Invalid padding length on received packet")); - ssh_unref_packet(st->pktin); - crStopV; - } - /* - * This enables us to deduce the payload length. - */ - st->payload = st->len - st->pad - 1; - - st->length = st->payload + 5; - st->pktin->encrypted_len = st->packetlen; - - st->pktin->sequence = st->incoming_sequence++; - - st->length = st->packetlen - st->pad; - assert(st->length >= 0); - - /* - * Decompress packet payload. - */ - { - unsigned char *newpayload; - int newlen; - if (ssh->sccomp && - ssh->sccomp->decompress(ssh->sc_comp_ctx, - st->data + 5, st->length - 5, - &newpayload, &newlen)) { - if (st->maxlen < newlen + 5) { - PktIn *old_pktin = st->pktin; - - st->maxlen = newlen + 5; - st->pktin = snew_plus(PktIn, st->maxlen); - *st->pktin = *old_pktin; /* structure copy */ - st->data = snew_plus_get_aux(st->pktin); - - smemclr(old_pktin, st->packetlen + st->maclen); - sfree(old_pktin); - } - st->length = 5 + newlen; - memcpy(st->data + 5, newpayload, newlen); - sfree(newpayload); - } - } - - /* - * RFC 4253 doesn't explicitly say that completely empty packets - * with no type byte are forbidden, so treat them as deserving - * an SSH_MSG_UNIMPLEMENTED. - */ - if (st->length <= 5) { /* == 5 we hope, but robustness */ - ssh2_msg_something_unimplemented(ssh, st->pktin); - crStopV; - } - - /* - * Now we can identify the semantic content of the packet, - * and also the initial type byte. - */ - st->pktin->type = st->data[5]; - st->length -= 6; - assert(st->length >= 0); /* one last double-check */ - BinarySource_INIT(st->pktin, st->data + 6, st->length); - - if (ssh->logctx) - ssh2_log_incoming_packet(ssh, st->pktin); - - /* - * Mild layer violation: if the message is a DISCONNECT, we - * should unset the close_expected flag, because now we _do_ - * expect the server to close the network connection - * afterwards. That way, the more informative connection_fatal - * message for the disconnect itself won't fight with 'Server - * unexpectedly closed network connection'. - */ - if (st->pktin->type == SSH2_MSG_DISCONNECT) { - ssh->clean_exit = FALSE; - ssh->close_expected = TRUE; - ssh->disconnect_message_seen = TRUE; - } - - pq_push(&ssh->pq_full, st->pktin); - queue_idempotent_callback(&ssh->pq_full_consumer); - if (st->pktin->type == SSH2_MSG_NEWKEYS) { - /* Mild layer violation: in this situation we must suspend - * processing of the input byte stream in order to ensure - * that the transport code has processed NEWKEYS and - * installed the new cipher. */ - ssh->pending_newkeys = TRUE; - crReturnV; - } - } - crFinishV; -} - -static void ssh2_bare_connection_rdpkt(Ssh ssh) -{ - struct rdpkt2_bare_state_tag *st = &ssh->rdpkt2_bare_state; - - crBegin(ssh->ssh2_bare_rdpkt_crstate); - - while (1) { - /* Read the length field. */ - { - unsigned char lenbuf[4]; - crMaybeWaitUntilV(bufchain_try_fetch_consume( - &ssh->incoming_data, lenbuf, 4)); - st->packetlen = toint(GET_32BIT_MSB_FIRST(lenbuf)); - } - - if (st->packetlen <= 0 || st->packetlen >= OUR_V2_PACKETLIMIT) { - bombout(("Invalid packet length received")); - crStopV; - } - - /* - * Allocate the packet to return, now we know its length. - */ - st->pktin = snew_plus(PktIn, st->packetlen); - st->pktin->qnode.prev = st->pktin->qnode.next = NULL; - st->maxlen = 0; - st->pktin->refcount = 1; - st->data = snew_plus_get_aux(st->pktin); - - st->pktin->encrypted_len = st->packetlen; - - st->pktin->sequence = st->incoming_sequence++; - - /* - * Read the remainder of the packet. - */ - crMaybeWaitUntilV(bufchain_try_fetch_consume( - &ssh->incoming_data, st->data, st->packetlen)); - - /* - * The data we just read is precisely the initial type byte - * followed by the packet payload. - */ - st->pktin->type = st->data[0]; - BinarySource_INIT(st->pktin, st->data + 1, st->packetlen - 1); - - /* - * Log incoming packet, possibly omitting sensitive fields. - */ - if (ssh->logctx) - ssh2_log_incoming_packet(ssh, st->pktin); - - /* - * Mild layer violation: if the message is a DISCONNECT, we - * should unset the close_expected flag, because now we _do_ - * expect the server to close the network connection - * afterwards. That way, the more informative connection_fatal - * message for the disconnect itself won't fight with 'Server - * unexpectedly closed network connection'. - */ - if (st->pktin->type == SSH2_MSG_DISCONNECT) { - ssh->clean_exit = FALSE; - ssh->close_expected = TRUE; - ssh->disconnect_message_seen = TRUE; - } - - pq_push(&ssh->pq_full, st->pktin); - queue_idempotent_callback(&ssh->pq_full_consumer); - } - crFinishV; -} - -static int s_wrpkt_prepare(Ssh ssh, PktOut *pkt, int *offset_p) -{ - int pad, biglen, i, pktoffs; - unsigned long crc; -#ifdef __SC__ - /* - * XXX various versions of SC (including 8.8.4) screw up the - * register allocation in this function and use the same register - * (D6) for len and as a temporary, with predictable results. The - * following sledgehammer prevents this. - */ - volatile -#endif - int len; - - if (ssh->logctx) - ssh1_log_outgoing_packet(ssh, pkt); - - if (ssh->v1_compressing) { - unsigned char *compblk; - int complen; - zlib_compress_block(ssh->cs_comp_ctx, - pkt->data + 12, pkt->length - 12, - &compblk, &complen); - ssh_pkt_ensure(pkt, complen + 2); /* just in case it's got bigger */ - memcpy(pkt->data + 12, compblk, complen); - sfree(compblk); - pkt->length = complen + 12; - } - - ssh_pkt_ensure(pkt, pkt->length + 4); /* space for CRC */ - pkt->length += 4; - len = pkt->length - 4 - 8; /* len(type+data+CRC) */ - pad = 8 - (len % 8); - pktoffs = 8 - pad; - biglen = len + pad; /* len(padding+type+data+CRC) */ - - for (i = pktoffs; i < 4+8; i++) - pkt->data[i] = random_byte(); - crc = crc32_compute(pkt->data + pktoffs + 4, biglen - 4); /* all ex len */ - PUT_32BIT(pkt->data + pktoffs + 4 + biglen - 4, crc); - PUT_32BIT(pkt->data + pktoffs, len); - - if (ssh->cipher) - ssh->cipher->encrypt(ssh->v1_cipher_ctx, - pkt->data + pktoffs + 4, biglen); - - if (offset_p) *offset_p = pktoffs; - return biglen + 4; /* len(length+padding+type+data+CRC) */ -} - static int s_write(Ssh ssh, const void *data, int len) { if (len && ssh->logctx) @@ -2059,15 +1203,6 @@ static int s_write(Ssh ssh, const void *data, int len) return sk_write(ssh->s, data, len); } -static void s_wrpkt(Ssh ssh, PktOut *pkt) -{ - int len, offset; - len = s_wrpkt_prepare(ssh, pkt, &offset); - bufchain_add(&ssh->outgoing_data, pkt->data + offset, len); - queue_idempotent_callback(&ssh->outgoing_data_sender); - ssh_free_pktout(pkt); -} - /* * Construct a SSH-1 packet with the specified contents. * (This all-at-once interface used to be the only one, but now SSH-1 @@ -2079,7 +1214,7 @@ static PktOut *construct_packet(Ssh ssh, int pkttype, va_list ap) Bignum bn; PktOut *pkt; - pkt = ssh1_pkt_init(pkttype); + pkt = ssh_bpp_new_pktout(ssh->bpp, pkttype); while ((argtype = va_arg(ap, int)) != PKT_END) { unsigned char *argp, argchar; @@ -2115,6 +1250,26 @@ static PktOut *construct_packet(Ssh ssh, int pkttype, va_list ap) return pkt; } +static void ssh_pkt_write(Ssh ssh, PktOut *pkt) +{ + if (ssh->version == 2 && ssh->v2_cbc_ignore_workaround && + bufchain_size(&ssh->outgoing_data) != 0) { + /* + * When using a CBC-mode cipher in SSH-2, it's necessary to + * ensure that an attacker can't provide data to be encrypted + * using an IV that they know. We ensure this by prefixing + * each packet that might contain user data with an + * SSH_MSG_IGNORE. + */ + PktOut *ipkt = ssh_bpp_new_pktout(ssh->bpp, SSH2_MSG_IGNORE); + put_stringz(ipkt, ""); + ssh_bpp_format_packet(ssh->bpp, pkt); + } + + ssh_bpp_format_packet(ssh->bpp, pkt); + queue_idempotent_callback(&ssh->outgoing_data_sender); +} + static void send_packet(Ssh ssh, int pkttype, ...) { PktOut *pkt; @@ -2122,7 +1277,7 @@ static void send_packet(Ssh ssh, int pkttype, ...) va_start(ap, pkttype); pkt = construct_packet(ssh, pkttype, ap); va_end(ap); - s_wrpkt(ssh, pkt); + ssh_pkt_write(ssh, pkt); } static int ssh_versioncmp(const char *a, const char *b) @@ -2169,168 +1324,6 @@ static void ssh_pkt_BinarySink_write(BinarySink *bs, ssh_pkt_adddata(pkt, data, len); } -PktOut *ssh1_pkt_init(int pkt_type) -{ - PktOut *pkt = ssh_new_packet(); - pkt->length = 4 + 8; /* space for length + max padding */ - put_byte(pkt, pkt_type); - pkt->prefix = pkt->length; - pkt->type = pkt_type; - pkt->downstream_id = 0; - pkt->additional_log_text = NULL; - return pkt; -} - -PktOut *ssh2_pkt_init(int pkt_type) -{ - PktOut *pkt = ssh_new_packet(); - pkt->length = 5; /* space for packet length + padding length */ - pkt->forcepad = 0; - pkt->type = pkt_type; - put_byte(pkt, (unsigned char) pkt_type); - pkt->prefix = pkt->length; - pkt->downstream_id = 0; - pkt->additional_log_text = NULL; - return pkt; -} - -/* - * Construct an SSH-2 final-form packet: compress it, encrypt it, put - * the MAC on it. Return a slice of pkt->data giving the final packet - * in ready-to-send form. - */ -static ptrlen ssh2_pkt_construct(Ssh ssh, PktOut *pkt) -{ - int cipherblk, maclen, padding, unencrypted_prefix, i; - - if (ssh->logctx) - ssh2_log_outgoing_packet(ssh, pkt); - - if (ssh->bare_connection) { - /* - * Trivial packet construction for the bare connection - * protocol. - */ - long start = pkt->prefix - 1; - long length = pkt->length - start; - assert(start >= 4); - PUT_32BIT(pkt->data + start - 4, length); - ssh->v2_outgoing_sequence++; /* only for diagnostics, really */ - return make_ptrlen(pkt->data + start - 4, length + 4); - } - - /* - * Compress packet payload. - */ - { - unsigned char *newpayload; - int newlen; - if (ssh->cscomp && - ssh->cscomp->compress(ssh->cs_comp_ctx, pkt->data + 5, - pkt->length - 5, - &newpayload, &newlen)) { - pkt->length = 5; - put_data(pkt, newpayload, newlen); - sfree(newpayload); - } - } - - /* - * Add padding. At least four bytes, and must also bring total - * length (minus MAC) up to a multiple of the block size. - * If pkt->forcepad is set, make sure the packet is at least that size - * after padding. - */ - cipherblk = ssh->cscipher ? ssh->cscipher->blksize : 8; /* block size */ - cipherblk = cipherblk < 8 ? 8 : cipherblk; /* or 8 if blksize < 8 */ - padding = 4; - unencrypted_prefix = (ssh->csmac && ssh->csmac_etm) ? 4 : 0; - if (pkt->length + padding < pkt->forcepad) - padding = pkt->forcepad - pkt->length; - padding += - (cipherblk - (pkt->length - unencrypted_prefix + padding) % cipherblk) - % cipherblk; - assert(padding <= 255); - maclen = ssh->csmac ? ssh->csmac->len : 0; - ssh_pkt_ensure(pkt, pkt->length + padding + maclen); - pkt->data[4] = padding; - for (i = 0; i < padding; i++) - pkt->data[pkt->length + i] = random_byte(); - PUT_32BIT(pkt->data, pkt->length + padding - 4); - - /* Encrypt length if the scheme requires it */ - if (ssh->cscipher && (ssh->cscipher->flags & SSH_CIPHER_SEPARATE_LENGTH)) { - ssh->cscipher->encrypt_length(ssh->cs_cipher_ctx, pkt->data, 4, - ssh->v2_outgoing_sequence); - } - - if (ssh->csmac && ssh->csmac_etm) { - /* - * OpenSSH-defined encrypt-then-MAC protocol. - */ - if (ssh->cscipher) - ssh->cscipher->encrypt(ssh->cs_cipher_ctx, - pkt->data + 4, pkt->length + padding - 4); - ssh->csmac->generate(ssh->cs_mac_ctx, pkt->data, - pkt->length + padding, - ssh->v2_outgoing_sequence); - } else { - /* - * SSH-2 standard protocol. - */ - if (ssh->csmac) - ssh->csmac->generate(ssh->cs_mac_ctx, pkt->data, - pkt->length + padding, - ssh->v2_outgoing_sequence); - if (ssh->cscipher) - ssh->cscipher->encrypt(ssh->cs_cipher_ctx, - pkt->data, pkt->length + padding); - } - - ssh->v2_outgoing_sequence++; /* whether or not we MACed */ - pkt->encrypted_len = pkt->length + padding; - - return make_ptrlen(pkt->data, pkt->length + padding + maclen); -} - -/* - * Send an SSH-2 packet immediately, without queuing. - */ -static void ssh2_pkt_send_noqueue(Ssh ssh, PktOut *pkt) -{ - ptrlen data; - if (ssh->cscipher != NULL && (ssh->cscipher->flags & SSH_CIPHER_IS_CBC) && - bufchain_size(&ssh->outgoing_data) != 0 && - !(ssh->remote_bugs & BUG_CHOKES_ON_SSH2_IGNORE)) { - /* - * When using a CBC-mode cipher in SSH-2, it's necessary to - * ensure that an attacker can't provide data to be encrypted - * using an IV that they know. We ensure this by prefixing - * each packet that might contain user data with an - * SSH_MSG_IGNORE. - */ - PktOut *ipkt = ssh2_pkt_init(SSH2_MSG_IGNORE); - put_stringz(ipkt, ""); - data = ssh2_pkt_construct(ssh, ipkt); - bufchain_add(&ssh->outgoing_data, data.ptr, data.len); - } - data = ssh2_pkt_construct(ssh, pkt); - bufchain_add(&ssh->outgoing_data, data.ptr, data.len); - queue_idempotent_callback(&ssh->outgoing_data_sender); - - ssh->outgoing_data_size += pkt->encrypted_len; - if (!ssh->kex_in_progress && - !ssh->bare_connection && - ssh->max_data_size != 0 && - ssh->outgoing_data_size > ssh->max_data_size) { - ssh->rekey_reason = "too much data sent"; - ssh->rekey_class = RK_NORMAL; - queue_idempotent_callback(&ssh->ssh2_transport_icb); - } - - ssh_free_pktout(pkt); -} - /* * Queue an SSH-2 packet. */ @@ -2355,7 +1348,7 @@ static void ssh2_pkt_send(Ssh ssh, PktOut *pkt) if (ssh->queueing) { ssh2_pkt_queue(ssh, pkt); } else { - ssh2_pkt_send_noqueue(ssh, pkt); + ssh_pkt_write(ssh, pkt); } } @@ -2415,7 +1408,7 @@ static void ssh2_pkt_send_with_padding(Ssh ssh, PktOut *pkt, int padsize) * construct the final form of this packet and append it to * the outgoing_data bufchain... */ - ssh2_pkt_send(ssh, pkt); + ssh_pkt_write(ssh, pkt); /* * ... but before we return from this function (triggering a @@ -2425,33 +1418,30 @@ static void ssh2_pkt_send_with_padding(Ssh ssh, PktOut *pkt, int padsize) * so that the block size is unavailable, we don't do this * trick at all, because we gain nothing by it.) */ - if (ssh->cscipher && - !(ssh->remote_bugs & BUG_CHOKES_ON_SSH2_IGNORE)) { + if (!(ssh->remote_bugs & BUG_CHOKES_ON_SSH2_IGNORE)) { int stringlen, i; stringlen = (256 - bufchain_size(&ssh->outgoing_data)); - stringlen += ssh->cscipher->blksize - 1; - stringlen -= (stringlen % ssh->cscipher->blksize); - if (ssh->cscomp) { - /* - * Temporarily disable actual compression, so we - * can guarantee to get this string exactly the - * length we want it. The compression-disabling - * routine should return an integer indicating how - * many bytes we should adjust our string length - * by. - */ - stringlen -= - ssh->cscomp->disable_compression(ssh->cs_comp_ctx); - } - pkt = ssh2_pkt_init(SSH2_MSG_IGNORE); + stringlen += ssh->v2_out_cipherblksize - 1; + stringlen -= (stringlen % ssh->v2_out_cipherblksize); + + /* + * Temporarily disable actual compression, so we can + * guarantee to get this string exactly the length we want + * it. The compression-disabling routine should return an + * integer indicating how many bytes we should adjust our + * string length by. + */ + stringlen -= ssh2_bpp_temporarily_disable_compression(ssh->bpp); + + pkt = ssh_bpp_new_pktout(ssh->bpp, SSH2_MSG_IGNORE); { strbuf *substr = strbuf_new(); for (i = 0; i < stringlen; i++) put_byte(substr, random_byte()); put_stringsb(pkt, substr); } - ssh2_pkt_send(ssh, pkt); + ssh_pkt_write(ssh, pkt); } } } @@ -2466,7 +1456,7 @@ static void ssh2_pkt_queuesend(Ssh ssh) assert(!ssh->queueing); for (i = 0; i < ssh->queuelen; i++) - ssh2_pkt_send_noqueue(ssh, ssh->queue[i]); + ssh_pkt_write(ssh, ssh->queue[i]); ssh->queuelen = 0; } @@ -2805,6 +1795,36 @@ static void ssh_send_verstring(Ssh ssh, const char *protoname, char *svers) sfree(verstring); } +static void ssh_feed_to_bpp(Ssh ssh) +{ + PacketQueueNode *prev_tail = ssh->pq_full.end.prev; + + assert(ssh->bpp); + ssh_bpp_handle_input(ssh->bpp); + + if (ssh->bpp->error) { + bomb_out(ssh, ssh->bpp->error); /* also frees the error string */ + return; + } + + if (ssh->bpp->seen_disconnect) { + /* + * If we've seen a DISCONNECT message, we should unset the + * close_expected flag, because now we _do_ expect the server + * to close the network connection afterwards. That way, the + * more informative connection_fatal message for the + * disconnect itself won't fight with 'Server unexpectedly + * closed network connection'. + */ + ssh->clean_exit = FALSE; + ssh->close_expected = TRUE; + ssh->disconnect_message_seen = TRUE; + } + + if (ssh->pq_full.end.prev != prev_tail) + queue_idempotent_callback(&ssh->pq_full_consumer); +} + static void do_ssh_init(Ssh ssh) { static const char protoname[] = "SSH-"; @@ -2863,7 +1883,6 @@ static void do_ssh_init(Ssh ssh) ssh->session_started = TRUE; ssh->agentfwd_enabled = FALSE; - ssh->rdpkt2_state.incoming_sequence = 0; /* * Now read the rest of the greeting line. @@ -2958,16 +1977,21 @@ static void do_ssh_init(Ssh ssh) */ ssh2_protocol_setup(ssh); ssh->general_packet_processing = ssh2_general_packet_processing; - ssh->current_incoming_data_fn = ssh2_rdpkt; ssh->current_user_input_fn = NULL; } else { /* * Initialise SSH-1 protocol. */ ssh1_protocol_setup(ssh); - ssh->current_incoming_data_fn = ssh1_rdpkt; ssh->current_user_input_fn = ssh1_login_input; } + ssh->bpp->out_raw = &ssh->outgoing_data; + ssh->bpp->in_raw = &ssh->incoming_data; + ssh->bpp->in_pq = &ssh->pq_full; + ssh->bpp->pls = &ssh->pls; + ssh->bpp->logctx = ssh->logctx; + ssh->current_incoming_data_fn = ssh_feed_to_bpp; + queue_idempotent_callback(&ssh->incoming_data_consumer); queue_idempotent_callback(&ssh->user_input_consumer); if (ssh->version == 2) @@ -3081,7 +2105,6 @@ static void do_ssh_connection_init(Ssh ssh) s->vstring[strcspn(s->vstring, "\015\012")] = '\0';/* remove EOL chars */ ssh->agentfwd_enabled = FALSE; - ssh->rdpkt2_bare_state.incoming_sequence = 0; logeventf(ssh, "Server version: %s", s->vstring); ssh_detect_bugs(ssh, s->vstring); @@ -3116,7 +2139,12 @@ static void do_ssh_connection_init(Ssh ssh) * Initialise bare connection protocol. */ ssh2_bare_connection_protocol_setup(ssh); - ssh->current_incoming_data_fn = ssh2_bare_connection_rdpkt; + ssh->bpp->out_raw = &ssh->outgoing_data; + ssh->bpp->in_raw = &ssh->incoming_data; + ssh->bpp->in_pq = &ssh->pq_full; + ssh->bpp->pls = &ssh->pls; + ssh->bpp->logctx = ssh->logctx; + ssh->current_incoming_data_fn = ssh_feed_to_bpp; queue_idempotent_callback(&ssh->incoming_data_consumer); ssh->current_user_input_fn = ssh2_connection_input; queue_idempotent_callback(&ssh->user_input_consumer); @@ -3149,7 +2177,7 @@ static void ssh_process_incoming_data(void *ctx) if (ssh->state == SSH_STATE_CLOSED) return; - if (!ssh->frozen && !ssh->pending_newkeys) + if (!ssh->frozen) ssh->current_incoming_data_fn(ssh); if (ssh->state == SSH_STATE_CLOSED) /* yes, check _again_ */ @@ -3748,11 +2776,11 @@ static void ssh_disconnect(Ssh ssh, const char *client_reason, send_packet(ssh, SSH1_MSG_DISCONNECT, PKT_STR, wire_reason, PKT_END); } else if (ssh->version == 2) { - PktOut *pktout = ssh2_pkt_init(SSH2_MSG_DISCONNECT); + PktOut *pktout = ssh_bpp_new_pktout(ssh->bpp, SSH2_MSG_DISCONNECT); put_uint32(pktout, code); put_stringz(pktout, wire_reason); put_stringz(pktout, "en"); /* language tag */ - ssh2_pkt_send_noqueue(ssh, pktout); + ssh_pkt_write(ssh, pktout); } } ssh->close_expected = TRUE; @@ -4079,15 +3107,14 @@ static void do_ssh1_login(void *vctx) sfree(s->rsabuf); - ssh->cipher = (s->cipher_type == SSH_CIPHER_BLOWFISH ? &ssh_blowfish_ssh1 : - s->cipher_type == SSH_CIPHER_DES ? &ssh_des : - &ssh_3des); - ssh->v1_cipher_ctx = ssh->cipher->make_context(); - ssh->cipher->sesskey(ssh->v1_cipher_ctx, ssh->session_key); - logeventf(ssh, "Initialised %s encryption", ssh->cipher->text_name); - - ssh->crcda_ctx = crcda_make_context(); - logevent("Installing CRC compensation attack detector"); + { + const struct ssh_cipher *cipher = + (s->cipher_type == SSH_CIPHER_BLOWFISH ? &ssh_blowfish_ssh1 : + s->cipher_type == SSH_CIPHER_DES ? &ssh_des : + &ssh_3des); + ssh1_bpp_new_cipher(ssh->bpp, cipher, ssh->session_key); + logeventf(ssh, "Initialised %s encryption", cipher->text_name); + } if (s->servkey.modulus) { sfree(s->servkey.modulus); @@ -4798,7 +3825,7 @@ static void do_ssh1_login(void *vctx) /* Set up for the next phase */ { int i; - for (i = 0; i < 256; i++) + for (i = 0; i < SSH_MAX_MSG; i++) if (ssh->packet_dispatch[i] == ssh1_coro_wrapper_initial) ssh->packet_dispatch[i] = ssh1_coro_wrapper_session; ssh->current_user_input_fn = ssh1_connection_input; @@ -4824,7 +3851,7 @@ static void ssh_channel_try_eof(struct ssh_channel *c) c->closes |= CLOSES_SENT_EOF; } else { PktOut *pktout; - pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_EOF); + pktout = ssh_bpp_new_pktout(ssh->bpp, SSH2_MSG_CHANNEL_EOF); put_uint32(pktout, c->remoteid); ssh2_pkt_send(ssh, pktout); c->closes |= CLOSES_SENT_EOF; @@ -5203,7 +4230,8 @@ static void ssh_setup_portfwd(Ssh ssh, Conf *conf) * to make on it are rejected. */ } else { - pktout = ssh2_pkt_init(SSH2_MSG_GLOBAL_REQUEST); + pktout = ssh_bpp_new_pktout( + ssh->bpp, SSH2_MSG_GLOBAL_REQUEST); put_stringz(pktout, "cancel-tcpip-forward"); put_bool(pktout, 0);/* _don't_ want reply */ if (epf->saddr) { @@ -5330,7 +4358,8 @@ static void ssh_setup_portfwd(Ssh ssh, Conf *conf) ssh_rportfwd_succfail, pf); } else { PktOut *pktout; - pktout = ssh2_pkt_init(SSH2_MSG_GLOBAL_REQUEST); + pktout = ssh_bpp_new_pktout( + ssh->bpp, SSH2_MSG_GLOBAL_REQUEST); put_stringz(pktout, "tcpip-forward"); put_bool(pktout, 1);/* want reply */ put_stringz(pktout, pf->shost); @@ -5730,7 +4759,7 @@ static void do_ssh1_connection(void *vctx) ssh->ospeed = 38400; ssh->ispeed = 38400; /* last-resort defaults */ sscanf(conf_get_str(ssh->conf, CONF_termspeed), "%d,%d", &ssh->ospeed, &ssh->ispeed); /* Send the pty request. */ - pkt = ssh1_pkt_init(SSH1_CMSG_REQUEST_PTY); + pkt = ssh_bpp_new_pktout(ssh->bpp, SSH1_CMSG_REQUEST_PTY); put_stringz(pkt, conf_get_str(ssh->conf, CONF_termtype)); put_uint32(pkt, ssh->term_height); put_uint32(pkt, ssh->term_width); @@ -5742,7 +4771,7 @@ static void do_ssh1_connection(void *vctx) put_byte(pkt, SSH1_TTY_OP_OSPEED); put_uint32(pkt, ssh->ospeed); put_byte(pkt, SSH_TTY_OP_END); - s_wrpkt(ssh, pkt); + ssh_pkt_write(ssh, pkt); ssh->state = SSH_STATE_INTERMED; crMaybeWaitUntilV((pktin = pq_pop(&ssh->pq_ssh1_connection)) != NULL); if (pktin->type != SSH1_SMSG_SUCCESS @@ -5771,12 +4800,8 @@ static void do_ssh1_connection(void *vctx) } else if (pktin->type == SSH1_SMSG_FAILURE) { c_write_str(ssh, "Server refused to compress\r\n"); } - logevent("Started compression"); - ssh->v1_compressing = TRUE; - ssh->cs_comp_ctx = zlib_compress_init(); - logevent("Initialised zlib (RFC1950) compression"); - ssh->sc_comp_ctx = zlib_decompress_init(); - logevent("Initialised zlib (RFC1950) decompression"); + logevent("Started zlib (RFC1950) compression"); + ssh1_bpp_start_compression(ssh->bpp); } /* @@ -5895,10 +4920,12 @@ static void ssh1_protocol_setup(Ssh ssh) { int i; + ssh->bpp = ssh1_bpp_new(); + /* * Most messages are handled by the main protocol routine. */ - for (i = 0; i < 256; i++) + for (i = 0; i < SSH_MAX_MSG; i++) ssh->packet_dispatch[i] = ssh1_coro_wrapper_initial; /* @@ -5965,8 +4992,8 @@ static void add_to_commasep(strbuf *buf, const char *data) /* * SSH-2 key derivation (RFC 4253 section 7.2). */ -static unsigned char *ssh2_mkkey(Ssh ssh, Bignum K, unsigned char *H, - char chr, int keylen) +static void ssh2_mkkey(Ssh ssh, strbuf *out, Bignum K, unsigned char *H, + char chr, int keylen) { const struct ssh_hash *h = ssh->kex->hash; int keylen_padded; @@ -5975,12 +5002,22 @@ static unsigned char *ssh2_mkkey(Ssh ssh, Bignum K, unsigned char *H, BinarySink *bs; if (keylen == 0) - return NULL; + return; - /* Round up to the next multiple of hash length. */ + /* + * Round the requested amount of key material up to a multiple of + * the length of the hash we're using to make it. This makes life + * simpler because then we can just write each hash output block + * straight into the output buffer without fiddling about + * truncating the last one. Since it's going into a strbuf, and + * strbufs are always smemclr()ed on free, there's no need to + * worry about leaving extra potentially-sensitive data in memory + * that the caller didn't ask for. + */ keylen_padded = ((keylen + h->hlen - 1) / h->hlen) * h->hlen; - key = snewn(keylen_padded, unsigned char); + out->len = 0; + key = strbuf_append(out, keylen_padded); /* First hlen bytes. */ s = h->init(); @@ -6010,14 +5047,6 @@ static unsigned char *ssh2_mkkey(Ssh ssh, Bignum K, unsigned char *H, h->free(s); } - - /* Now clear any extra bytes of key material beyond the length - * we're officially returning, because the caller won't know to - * smemclr those. */ - if (keylen_padded > keylen) - smemclr(key + keylen, keylen_padded - keylen); - - return key; } /* @@ -6211,13 +5240,12 @@ static void do_ssh2_transport(void *vctx) int kex_init_value, kex_reply_value; const struct ssh_mac *const *maclist; int nmacs; - const struct ssh2_cipher *cscipher_tobe; - const struct ssh2_cipher *sccipher_tobe; - const struct ssh_mac *csmac_tobe; - const struct ssh_mac *scmac_tobe; - int csmac_etm_tobe, scmac_etm_tobe; - const struct ssh_compress *cscomp_tobe; - const struct ssh_compress *sccomp_tobe; + struct { + const struct ssh2_cipher *cipher; + const struct ssh_mac *mac; + int etm_mode; + const struct ssh_compress *comp; + } in, out; ptrlen hostkeydata, sigdata; char *keystr, *fingerprint; ssh_key *hkey; /* actual host key */ @@ -6261,9 +5289,9 @@ static void do_ssh2_transport(void *vctx) crBeginState; - s->cscipher_tobe = s->sccipher_tobe = NULL; - s->csmac_tobe = s->scmac_tobe = NULL; - s->cscomp_tobe = s->sccomp_tobe = NULL; + s->in.cipher = s->out.cipher = NULL; + s->in.mac = s->out.mac = NULL; + s->in.comp = s->out.comp = NULL; s->got_session_id = FALSE; s->userauth_succeeded = FALSE; @@ -6328,7 +5356,7 @@ static void do_ssh2_transport(void *vctx) } #endif - ssh->pkt_kctx = SSH2_PKTCTX_NOKEX; + ssh->pls.kctx = SSH2_PKTCTX_NOKEX; { int i, j, k, warn; struct kexinit_algorithm *alg; @@ -6616,7 +5644,7 @@ static void do_ssh2_transport(void *vctx) /* * Construct and send our key exchange packet. */ - s->pktout = ssh2_pkt_init(SSH2_MSG_KEXINIT); + s->pktout = ssh_bpp_new_pktout(ssh->bpp, SSH2_MSG_KEXINIT); for (i = 0; i < 16; i++) put_byte(s->pktout, (unsigned char) random_byte()); for (i = 0; i < NKEXLIST; i++) { @@ -6641,7 +5669,7 @@ static void do_ssh2_transport(void *vctx) s->our_kexinit = snewn(s->our_kexinitlen, unsigned char); memcpy(s->our_kexinit, s->pktout->data + 5, s->our_kexinitlen); - ssh2_pkt_send_noqueue(ssh, s->pktout); + ssh_pkt_write(ssh, s->pktout); crMaybeWaitUntilV((pktin = pq_pop(&ssh->pq_ssh2_transport)) != NULL); @@ -6659,12 +5687,9 @@ static void do_ssh2_transport(void *vctx) } ssh->kex = NULL; ssh->hostkey_alg = NULL; - s->cscipher_tobe = NULL; - s->sccipher_tobe = NULL; - s->csmac_tobe = NULL; - s->scmac_tobe = NULL; - s->cscomp_tobe = NULL; - s->sccomp_tobe = NULL; + s->in.cipher = s->out.cipher = NULL; + s->in.mac = s->out.mac = NULL; + s->in.comp = s->out.comp = NULL; s->warn_kex = s->warn_hk = FALSE; s->warn_cscipher = s->warn_sccipher = FALSE; @@ -6682,16 +5707,16 @@ static void do_ssh2_transport(void *vctx) * particular MAC, then just select that, and don't even * bother looking through the server's KEXINIT string for * MACs. */ - if (i == KEXLIST_CSMAC && s->cscipher_tobe && - s->cscipher_tobe->required_mac) { - s->csmac_tobe = s->cscipher_tobe->required_mac; - s->csmac_etm_tobe = !!(s->csmac_tobe->etm_name); + if (i == KEXLIST_CSMAC && s->out.cipher && + s->out.cipher->required_mac) { + s->out.mac = s->out.cipher->required_mac; + s->out.etm_mode = !!(s->out.mac->etm_name); goto matched; } - if (i == KEXLIST_SCMAC && s->sccipher_tobe && - s->sccipher_tobe->required_mac) { - s->scmac_tobe = s->sccipher_tobe->required_mac; - s->scmac_etm_tobe = !!(s->scmac_tobe->etm_name); + if (i == KEXLIST_SCMAC && s->in.cipher && + s->in.cipher->required_mac) { + s->in.mac = s->in.cipher->required_mac; + s->in.etm_mode = !!(s->in.mac->etm_name); goto matched; } @@ -6723,21 +5748,21 @@ static void do_ssh2_transport(void *vctx) ssh->hostkey_alg = alg->u.hk.hostkey; s->warn_hk = alg->u.hk.warn; } else if (i == KEXLIST_CSCIPHER) { - s->cscipher_tobe = alg->u.cipher.cipher; + s->out.cipher = alg->u.cipher.cipher; s->warn_cscipher = alg->u.cipher.warn; } else if (i == KEXLIST_SCCIPHER) { - s->sccipher_tobe = alg->u.cipher.cipher; + s->in.cipher = alg->u.cipher.cipher; s->warn_sccipher = alg->u.cipher.warn; } else if (i == KEXLIST_CSMAC) { - s->csmac_tobe = alg->u.mac.mac; - s->csmac_etm_tobe = alg->u.mac.etm; + s->out.mac = alg->u.mac.mac; + s->out.etm_mode = alg->u.mac.etm; } else if (i == KEXLIST_SCMAC) { - s->scmac_tobe = alg->u.mac.mac; - s->scmac_etm_tobe = alg->u.mac.etm; + s->in.mac = alg->u.mac.mac; + s->in.etm_mode = alg->u.mac.etm; } else if (i == KEXLIST_CSCOMP) { - s->cscomp_tobe = alg->u.comp; + s->out.comp = alg->u.comp; } else if (i == KEXLIST_SCCOMP) { - s->sccomp_tobe = alg->u.comp; + s->in.comp = alg->u.comp; } goto matched; } @@ -6883,7 +5908,7 @@ static void do_ssh2_transport(void *vctx) ssh_set_frozen(ssh, 1); s->dlgret = askalg(ssh->frontend, "client-to-server cipher", - s->cscipher_tobe->name, + s->out.cipher->name, ssh_dialog_callback, ssh); if (s->dlgret < 0) { ssh->user_response = -1; @@ -6902,7 +5927,7 @@ static void do_ssh2_transport(void *vctx) ssh_set_frozen(ssh, 1); s->dlgret = askalg(ssh->frontend, "server-to-client cipher", - s->sccipher_tobe->name, + s->in.cipher->name, ssh_dialog_callback, ssh); if (s->dlgret < 0) { ssh->user_response = -1; @@ -6930,8 +5955,8 @@ static void do_ssh2_transport(void *vctx) { int csbits, scbits; - csbits = s->cscipher_tobe ? s->cscipher_tobe->real_keybits : 0; - scbits = s->sccipher_tobe ? s->sccipher_tobe->real_keybits : 0; + csbits = s->out.cipher ? s->out.cipher->real_keybits : 0; + scbits = s->in.cipher ? s->in.cipher->real_keybits : 0; s->nbits = (csbits > scbits ? csbits : scbits); } /* The keys only have hlen-bit entropy, since they're based on @@ -6945,7 +5970,7 @@ static void do_ssh2_transport(void *vctx) */ if (dh_is_gex(ssh->kex)) { logevent("Doing Diffie-Hellman group exchange"); - ssh->pkt_kctx = SSH2_PKTCTX_DHGEX; + ssh->pls.kctx = SSH2_PKTCTX_DHGEX; /* * Work out how big a DH group we will need to allow that * much data. @@ -6956,15 +5981,17 @@ static void do_ssh2_transport(void *vctx) if (s->pbits > DH_MAX_SIZE) s->pbits = DH_MAX_SIZE; if ((ssh->remote_bugs & BUG_SSH2_OLDGEX)) { - s->pktout = ssh2_pkt_init(SSH2_MSG_KEX_DH_GEX_REQUEST_OLD); + s->pktout = ssh_bpp_new_pktout( + ssh->bpp, SSH2_MSG_KEX_DH_GEX_REQUEST_OLD); put_uint32(s->pktout, s->pbits); } else { - s->pktout = ssh2_pkt_init(SSH2_MSG_KEX_DH_GEX_REQUEST); + s->pktout = ssh_bpp_new_pktout( + ssh->bpp, SSH2_MSG_KEX_DH_GEX_REQUEST); put_uint32(s->pktout, DH_MIN_SIZE); put_uint32(s->pktout, s->pbits); put_uint32(s->pktout, DH_MAX_SIZE); } - ssh2_pkt_send_noqueue(ssh, s->pktout); + ssh_pkt_write(ssh, s->pktout); crMaybeWaitUntilV((pktin = pq_pop(&ssh->pq_ssh2_transport)) != NULL); if (pktin->type != SSH2_MSG_KEX_DH_GEX_GROUP) { @@ -6983,7 +6010,7 @@ static void do_ssh2_transport(void *vctx) s->kex_init_value = SSH2_MSG_KEX_DH_GEX_INIT; s->kex_reply_value = SSH2_MSG_KEX_DH_GEX_REPLY; } else { - ssh->pkt_kctx = SSH2_PKTCTX_DHGROUP; + ssh->pls.kctx = SSH2_PKTCTX_DHGROUP; ssh->kex_ctx = dh_setup_group(ssh->kex); s->kex_init_value = SSH2_MSG_KEXDH_INIT; s->kex_reply_value = SSH2_MSG_KEXDH_REPLY; @@ -6998,9 +6025,9 @@ static void do_ssh2_transport(void *vctx) */ set_busy_status(ssh->frontend, BUSY_CPU); /* this can take a while */ s->e = dh_create_e(ssh->kex_ctx, s->nbits * 2); - s->pktout = ssh2_pkt_init(s->kex_init_value); + s->pktout = ssh_bpp_new_pktout(ssh->bpp, s->kex_init_value); put_mp_ssh2(s->pktout, s->e); - ssh2_pkt_send_noqueue(ssh, s->pktout); + ssh_pkt_write(ssh, s->pktout); set_busy_status(ssh->frontend, BUSY_WAITING); /* wait for server */ crMaybeWaitUntilV((pktin = pq_pop(&ssh->pq_ssh2_transport)) != NULL); @@ -7055,7 +6082,7 @@ static void do_ssh2_transport(void *vctx) logeventf(ssh, "Doing ECDH key exchange with curve %s and hash %s", ssh_ecdhkex_curve_textname(ssh->kex), ssh->kex->hash->text_name); - ssh->pkt_kctx = SSH2_PKTCTX_ECDHKEX; + ssh->pls.kctx = SSH2_PKTCTX_ECDHKEX; s->eckey = ssh_ecdhkex_newkey(ssh->kex); if (!s->eckey) { @@ -7063,14 +6090,14 @@ static void do_ssh2_transport(void *vctx) crStopV; } - s->pktout = ssh2_pkt_init(SSH2_MSG_KEX_ECDH_INIT); + s->pktout = ssh_bpp_new_pktout(ssh->bpp, SSH2_MSG_KEX_ECDH_INIT); { strbuf *pubpoint = strbuf_new(); ssh_ecdhkex_getpublic(s->eckey, BinarySink_UPCAST(pubpoint)); put_stringsb(s->pktout, pubpoint); } - ssh2_pkt_send_noqueue(ssh, s->pktout); + ssh_pkt_write(ssh, s->pktout); crMaybeWaitUntilV((pktin = pq_pop(&ssh->pq_ssh2_transport)) != NULL); if (pktin->type != SSH2_MSG_KEX_ECDH_REPLY) { @@ -7112,7 +6139,7 @@ static void do_ssh2_transport(void *vctx) } else if (ssh->kex->main_type == KEXTYPE_GSS) { ptrlen data; - ssh->pkt_kctx = SSH2_PKTCTX_GSSKEX; + ssh->pls.kctx = SSH2_PKTCTX_GSSKEX; s->init_token_sent = 0; s->complete_rcvd = 0; s->hkey = NULL; @@ -7129,8 +6156,8 @@ static void do_ssh2_transport(void *vctx) { int csbits, scbits; - csbits = s->cscipher_tobe->real_keybits; - scbits = s->sccipher_tobe->real_keybits; + csbits = s->out.cipher->real_keybits; + scbits = s->in.cipher->real_keybits; s->nbits = (csbits > scbits ? csbits : scbits); } /* The keys only have hlen-bit entropy, since they're based on @@ -7146,11 +6173,11 @@ static void do_ssh2_transport(void *vctx) s->pbits = 512 << ((s->nbits - 1) / 64); logeventf(ssh, "Doing GSSAPI (with Kerberos V5) Diffie-Hellman " "group exchange, with minimum %d bits", s->pbits); - s->pktout = ssh2_pkt_init(SSH2_MSG_KEXGSS_GROUPREQ); + s->pktout = ssh_bpp_new_pktout(ssh->bpp, SSH2_MSG_KEXGSS_GROUPREQ); put_uint32(s->pktout, s->pbits); /* min */ put_uint32(s->pktout, s->pbits); /* preferred */ put_uint32(s->pktout, s->pbits * 2); /* max */ - ssh2_pkt_send_noqueue(ssh, s->pktout); + ssh_pkt_write(ssh, s->pktout); crMaybeWaitUntilV( (pktin = pq_pop(&ssh->pq_ssh2_transport)) != NULL); @@ -7232,7 +6259,7 @@ static void do_ssh2_transport(void *vctx) if (!s->init_token_sent) { s->init_token_sent = 1; - s->pktout = ssh2_pkt_init(SSH2_MSG_KEXGSS_INIT); + s->pktout = ssh_bpp_new_pktout(ssh->bpp, SSH2_MSG_KEXGSS_INIT); if (s->gss_sndtok.length == 0) { bombout(("GSSAPI key exchange failed:" " no initial context token")); @@ -7241,14 +6268,15 @@ static void do_ssh2_transport(void *vctx) put_string(s->pktout, s->gss_sndtok.value, s->gss_sndtok.length); put_mp_ssh2(s->pktout, s->e); - ssh2_pkt_send_noqueue(ssh, s->pktout); + ssh_pkt_write(ssh, s->pktout); ssh->gsslib->free_tok(ssh->gsslib, &s->gss_sndtok); logevent("GSSAPI key exchange initialised"); } else if (s->gss_sndtok.length != 0) { - s->pktout = ssh2_pkt_init(SSH2_MSG_KEXGSS_CONTINUE); + s->pktout = ssh_bpp_new_pktout( + ssh->bpp, SSH2_MSG_KEXGSS_CONTINUE); put_string(s->pktout, s->gss_sndtok.value, s->gss_sndtok.length); - ssh2_pkt_send_noqueue(ssh, s->pktout); + ssh_pkt_write(ssh, s->pktout); ssh->gsslib->free_tok(ssh->gsslib, &s->gss_sndtok); } @@ -7366,7 +6394,7 @@ static void do_ssh2_transport(void *vctx) assert(ssh->kex->main_type == KEXTYPE_RSA); logeventf(ssh, "Doing RSA key exchange with hash %s", ssh->kex->hash->text_name); - ssh->pkt_kctx = SSH2_PKTCTX_RSAKEX; + ssh->pls.kctx = SSH2_PKTCTX_RSAKEX; /* * RSA key exchange. First expect a KEXRSA_PUBKEY packet * from the server. @@ -7431,9 +6459,9 @@ static void do_ssh2_transport(void *vctx) /* * And send it off in a return packet. */ - s->pktout = ssh2_pkt_init(SSH2_MSG_KEXRSA_SECRET); + s->pktout = ssh_bpp_new_pktout(ssh->bpp, SSH2_MSG_KEXRSA_SECRET); put_string(s->pktout, outstr, outstrlen); - ssh2_pkt_send_noqueue(ssh, s->pktout); + ssh_pkt_write(ssh, s->pktout); put_string(ssh->exhash_bs, outstr, outstrlen); @@ -7750,71 +6778,65 @@ static void do_ssh2_transport(void *vctx) /* * Send SSH2_MSG_NEWKEYS. */ - s->pktout = ssh2_pkt_init(SSH2_MSG_NEWKEYS); - ssh2_pkt_send_noqueue(ssh, s->pktout); + s->pktout = ssh_bpp_new_pktout(ssh->bpp, SSH2_MSG_NEWKEYS); + ssh_pkt_write(ssh, s->pktout); ssh->outgoing_data_size = 0; /* start counting from here */ /* * We've sent client NEWKEYS, so create and initialise * client-to-server session keys. */ - if (ssh->cs_cipher_ctx) - ssh->cscipher->free_context(ssh->cs_cipher_ctx); - ssh->cscipher = s->cscipher_tobe; - if (ssh->cscipher) ssh->cs_cipher_ctx = ssh->cscipher->make_context(); - - if (ssh->cs_mac_ctx) - ssh->csmac->free_context(ssh->cs_mac_ctx); - ssh->csmac = s->csmac_tobe; - ssh->csmac_etm = s->csmac_etm_tobe; - if (ssh->csmac) - ssh->cs_mac_ctx = ssh->csmac->make_context(ssh->cs_cipher_ctx); - - if (ssh->cs_comp_ctx) - ssh->cscomp->compress_cleanup(ssh->cs_comp_ctx); - ssh->cscomp = s->cscomp_tobe; - ssh->cs_comp_ctx = ssh->cscomp->compress_init(); + { + strbuf *cipher_key = strbuf_new(); + strbuf *cipher_iv = strbuf_new(); + strbuf *mac_key = strbuf_new(); + + if (s->out.cipher) { + ssh2_mkkey(ssh, cipher_iv, s->K, s->exchange_hash, 'A', + s->out.cipher->blksize); + ssh2_mkkey(ssh, cipher_key, s->K, s->exchange_hash, 'C', + s->out.cipher->padded_keybytes); + } + if (s->out.mac) { + ssh2_mkkey(ssh, mac_key, s->K, s->exchange_hash, 'E', + s->out.mac->keylen); + } - /* - * Set IVs on client-to-server keys. Here we use the exchange - * hash from the _first_ key exchange. - */ - if (ssh->cscipher) { - unsigned char *key; - - key = ssh2_mkkey(ssh, s->K, s->exchange_hash, 'C', - ssh->cscipher->padded_keybytes); - ssh->cscipher->setkey(ssh->cs_cipher_ctx, key); - smemclr(key, ssh->cscipher->padded_keybytes); - sfree(key); - - key = ssh2_mkkey(ssh, s->K, s->exchange_hash, 'A', - ssh->cscipher->blksize); - ssh->cscipher->setiv(ssh->cs_cipher_ctx, key); - smemclr(key, ssh->cscipher->blksize); - sfree(key); - } - if (ssh->csmac) { - unsigned char *key; - - key = ssh2_mkkey(ssh, s->K, s->exchange_hash, 'E', - ssh->csmac->keylen); - ssh->csmac->setkey(ssh->cs_mac_ctx, key); - smemclr(key, ssh->csmac->keylen); - sfree(key); - } - - if (ssh->cscipher) - logeventf(ssh, "Initialised %.200s client->server encryption", - ssh->cscipher->text_name); - if (ssh->csmac) - logeventf(ssh, "Initialised %.200s client->server MAC algorithm%s%s", - ssh->csmac->text_name, - ssh->csmac_etm ? " (in ETM mode)" : "", - ssh->cscipher->required_mac ? " (required by cipher)" : ""); - if (ssh->cscomp->text_name) - logeventf(ssh, "Initialised %s compression", - ssh->cscomp->text_name); + ssh2_bpp_new_outgoing_crypto( + ssh->bpp, + s->out.cipher, cipher_key->u, cipher_iv->u, + s->out.mac, s->out.etm_mode, mac_key->u, + s->out.comp); + + /* + * Remember some details we'll need later for making other + * policy decisions based on the crypto we've just + * initialised. + */ + ssh->v2_cbc_ignore_workaround = ( + s->out.cipher && + (s->out.cipher->flags & SSH_CIPHER_IS_CBC) && + !(ssh->remote_bugs & BUG_CHOKES_ON_SSH2_IGNORE)); + ssh->v2_out_cipherblksize = s->out.cipher->blksize; + + strbuf_free(cipher_key); + strbuf_free(cipher_iv); + strbuf_free(mac_key); + } + + if (s->out.cipher) + logeventf(ssh, "Initialised %.200s client->server encryption", + s->out.cipher->text_name); + if (s->out.mac) + logeventf(ssh, "Initialised %.200s client->server" + " MAC algorithm%s%s", + s->out.mac->text_name, + s->out.etm_mode ? " (in ETM mode)" : "", + (s->out.cipher->required_mac ? + " (required by cipher)" : "")); + if (s->out.comp->text_name) + logeventf(ssh, "Initialised %s compression", + s->out.comp->text_name); /* * Now our end of the key exchange is complete, we can send all @@ -7831,72 +6853,52 @@ static void do_ssh2_transport(void *vctx) bombout(("expected new-keys packet from server")); crStopV; } - ssh->pending_newkeys = FALSE; /* resume processing incoming data */ ssh->incoming_data_size = 0; /* start counting from here */ /* * We've seen server NEWKEYS, so create and initialise * server-to-client session keys. */ - if (ssh->sc_cipher_ctx) - ssh->sccipher->free_context(ssh->sc_cipher_ctx); - if (s->sccipher_tobe) { - ssh->sccipher = s->sccipher_tobe; - ssh->sc_cipher_ctx = ssh->sccipher->make_context(); - } + { + strbuf *cipher_key = strbuf_new(); + strbuf *cipher_iv = strbuf_new(); + strbuf *mac_key = strbuf_new(); + + if (s->in.cipher) { + ssh2_mkkey(ssh, cipher_iv, s->K, s->exchange_hash, 'B', + s->in.cipher->blksize); + ssh2_mkkey(ssh, cipher_key, s->K, s->exchange_hash, 'D', + s->in.cipher->padded_keybytes); + } + if (s->in.mac) { + ssh2_mkkey(ssh, mac_key, s->K, s->exchange_hash, 'F', + s->in.mac->keylen); + } - if (ssh->sc_mac_ctx) - ssh->scmac->free_context(ssh->sc_mac_ctx); - if (s->scmac_tobe) { - ssh->scmac = s->scmac_tobe; - ssh->scmac_etm = s->scmac_etm_tobe; - ssh->sc_mac_ctx = ssh->scmac->make_context(ssh->sc_cipher_ctx); - } + ssh2_bpp_new_incoming_crypto( + ssh->bpp, + s->in.cipher, cipher_key->u, cipher_iv->u, + s->in.mac, s->in.etm_mode, mac_key->u, + s->in.comp); - if (ssh->sc_comp_ctx) - ssh->sccomp->decompress_cleanup(ssh->sc_comp_ctx); - ssh->sccomp = s->sccomp_tobe; - ssh->sc_comp_ctx = ssh->sccomp->decompress_init(); + strbuf_free(cipher_key); + strbuf_free(cipher_iv); + strbuf_free(mac_key); + } - /* - * Set IVs on server-to-client keys. Here we use the exchange - * hash from the _first_ key exchange. - */ - if (ssh->sccipher) { - unsigned char *key; - - key = ssh2_mkkey(ssh, s->K, s->exchange_hash, 'D', - ssh->sccipher->padded_keybytes); - ssh->sccipher->setkey(ssh->sc_cipher_ctx, key); - smemclr(key, ssh->sccipher->padded_keybytes); - sfree(key); - - key = ssh2_mkkey(ssh, s->K, s->exchange_hash, 'B', - ssh->sccipher->blksize); - ssh->sccipher->setiv(ssh->sc_cipher_ctx, key); - smemclr(key, ssh->sccipher->blksize); - sfree(key); - } - if (ssh->scmac) { - unsigned char *key; - - key = ssh2_mkkey(ssh, s->K, s->exchange_hash, 'F', - ssh->scmac->keylen); - ssh->scmac->setkey(ssh->sc_mac_ctx, key); - smemclr(key, ssh->scmac->keylen); - sfree(key); - } - if (ssh->sccipher) - logeventf(ssh, "Initialised %.200s server->client encryption", - ssh->sccipher->text_name); - if (ssh->scmac) - logeventf(ssh, "Initialised %.200s server->client MAC algorithm%s%s", - ssh->scmac->text_name, - ssh->scmac_etm ? " (in ETM mode)" : "", - ssh->sccipher->required_mac ? " (required by cipher)" : ""); - if (ssh->sccomp->text_name) - logeventf(ssh, "Initialised %s decompression", - ssh->sccomp->text_name); + if (s->in.cipher) + logeventf(ssh, "Initialised %.200s server->client encryption", + s->in.cipher->text_name); + if (s->in.mac) + logeventf(ssh, "Initialised %.200s server->client" + " MAC algorithm%s%s", + s->in.mac->text_name, + s->in.etm_mode ? " (in ETM mode)" : "", + (s->in.cipher->required_mac ? + " (required by cipher)" : "")); + if (s->in.comp->text_name) + logeventf(ssh, "Initialised %s decompression", + s->in.comp->text_name); /* * Free shared secret. @@ -8068,7 +7070,7 @@ static int ssh2_try_send(struct ssh_channel *c) len = c->v.v2.remwindow; if ((unsigned)len > c->v.v2.remmaxpkt) len = c->v.v2.remmaxpkt; - pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_DATA); + pktout = ssh_bpp_new_pktout(ssh->bpp, SSH2_MSG_CHANNEL_DATA); put_uint32(pktout, c->remoteid); put_string(pktout, data, len); ssh2_pkt_send(ssh, pktout); @@ -8162,7 +7164,7 @@ static PktOut *ssh2_chanopen_init(struct ssh_channel *c, { PktOut *pktout; - pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_OPEN); + pktout = ssh_bpp_new_pktout(c->ssh->bpp, SSH2_MSG_CHANNEL_OPEN); put_stringz(pktout, type); put_uint32(pktout, c->localid); put_uint32(pktout, c->v.v2.locwindow);/* our window size */ @@ -8212,7 +7214,7 @@ static PktOut *ssh2_chanreq_init(struct ssh_channel *c, PktOut *pktout; assert(!(c->closes & (CLOSES_SENT_CLOSE | CLOSES_RCVD_CLOSE))); - pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST); + pktout = ssh_bpp_new_pktout(c->ssh->bpp, SSH2_MSG_CHANNEL_REQUEST); put_uint32(pktout, c->remoteid); put_stringz(pktout, type); put_bool(pktout, handler != NULL); @@ -8312,7 +7314,7 @@ static void ssh2_set_window(struct ssh_channel *c, int newwin) c->v.v2.remlocwin = newwin; c->v.v2.throttle_state = THROTTLED; } - pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_WINDOW_ADJUST); + pktout = ssh_bpp_new_pktout(ssh->bpp, SSH2_MSG_CHANNEL_WINDOW_ADJUST); put_uint32(pktout, c->remoteid); put_uint32(pktout, newwin - c->v.v2.locwindow); ssh2_pkt_send(ssh, pktout); @@ -8603,7 +7605,7 @@ static void ssh2_channel_check_close(struct ssh_channel *c) * means the channel is in final wind-up. But we haven't sent * CLOSE, so let's do so now. */ - pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_CLOSE); + pktout = ssh_bpp_new_pktout(ssh->bpp, SSH2_MSG_CHANNEL_CLOSE); put_uint32(pktout, c->remoteid); ssh2_pkt_send(ssh, pktout); c->closes |= CLOSES_SENT_EOF | CLOSES_SENT_CLOSE; @@ -9012,7 +8014,7 @@ static void ssh2_msg_channel_request(Ssh ssh, PktIn *pktin) reply = SSH2_MSG_CHANNEL_FAILURE; } if (want_reply) { - pktout = ssh2_pkt_init(reply); + pktout = ssh_bpp_new_pktout(ssh->bpp, reply); put_uint32(pktout, c->remoteid); ssh2_pkt_send(ssh, pktout); } @@ -9033,7 +8035,7 @@ static void ssh2_msg_global_request(Ssh ssh, PktIn *pktin) * want_reply. */ if (want_reply) { - pktout = ssh2_pkt_init(SSH2_MSG_REQUEST_FAILURE); + pktout = ssh_bpp_new_pktout(ssh->bpp, SSH2_MSG_REQUEST_FAILURE); ssh2_pkt_send(ssh, pktout); } } @@ -9171,7 +8173,7 @@ static void ssh2_msg_channel_open(Ssh ssh, PktIn *pktin) c->remoteid = remid; c->halfopen = FALSE; if (error) { - pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_OPEN_FAILURE); + pktout = ssh_bpp_new_pktout(ssh->bpp, SSH2_MSG_CHANNEL_OPEN_FAILURE); put_uint32(pktout, c->remoteid); put_uint32(pktout, SSH2_OPEN_CONNECT_FAILED); put_stringz(pktout, error); @@ -9187,7 +8189,8 @@ static void ssh2_msg_channel_open(Ssh ssh, PktIn *pktin) c->v.v2.locwindow = c->v.v2.locmaxwin = c->v.v2.remlocwin = our_winsize_override; } - pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION); + pktout = ssh_bpp_new_pktout( + ssh->bpp, SSH2_MSG_CHANNEL_OPEN_CONFIRMATION); put_uint32(pktout, c->remoteid); put_uint32(pktout, c->localid); put_uint32(pktout, c->v.v2.locwindow); @@ -9561,7 +8564,7 @@ static void do_ssh2_userauth(void *vctx) /* * Request userauth protocol, and await a response to it. */ - s->pktout = ssh2_pkt_init(SSH2_MSG_SERVICE_REQUEST); + s->pktout = ssh_bpp_new_pktout(ssh->bpp, SSH2_MSG_SERVICE_REQUEST); put_stringz(s->pktout, "ssh-userauth"); ssh2_pkt_send(ssh, s->pktout); crMaybeWaitUntilV((pktin = pq_pop(&ssh->pq_ssh2_userauth)) != NULL); @@ -9572,7 +8575,7 @@ static void do_ssh2_userauth(void *vctx) /* * Request connection protocol directly, without authentication. */ - s->pktout = ssh2_pkt_init(SSH2_MSG_SERVICE_REQUEST); + s->pktout = ssh_bpp_new_pktout(ssh->bpp, SSH2_MSG_SERVICE_REQUEST); put_stringz(s->pktout, "ssh-connection"); ssh2_pkt_send(ssh, s->pktout); crMaybeWaitUntilV((pktin = pq_pop(&ssh->pq_ssh2_userauth)) != NULL); @@ -9809,9 +8812,9 @@ static void do_ssh2_userauth(void *vctx) * just in case it succeeds, and (b) so that we know what * authentication methods we can usefully try next. */ - ssh->pkt_actx = SSH2_PKTCTX_NOAUTH; + ssh->pls.actx = SSH2_PKTCTX_NOAUTH; - s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST); + s->pktout = ssh_bpp_new_pktout(ssh->bpp, SSH2_MSG_USERAUTH_REQUEST); put_stringz(s->pktout, ssh->username); put_stringz(s->pktout, "ssh-connection");/* service requested */ put_stringz(s->pktout, "none"); /* method */ @@ -9976,7 +8979,7 @@ static void do_ssh2_userauth(void *vctx) #endif } - ssh->pkt_actx = SSH2_PKTCTX_NOAUTH; + ssh->pls.actx = SSH2_PKTCTX_NOAUTH; #ifndef NO_GSSAPI if (s->can_gssapi_keyex_auth && !s->tried_gssapi_keyex_auth) { @@ -9985,7 +8988,7 @@ static void do_ssh2_userauth(void *vctx) s->type = AUTH_TYPE_GSSAPI; s->tried_gssapi_keyex_auth = TRUE; - ssh->pkt_actx = SSH2_PKTCTX_GSSAPI; + ssh->pls.actx = SSH2_PKTCTX_GSSAPI; if (ssh->gsslib->gsslogmsg) logevent(ssh->gsslib->gsslogmsg); @@ -10007,7 +9010,7 @@ static void do_ssh2_userauth(void *vctx) * Attempt public-key authentication using a key from Pageant. */ - ssh->pkt_actx = SSH2_PKTCTX_PUBLICKEY; + ssh->pls.actx = SSH2_PKTCTX_PUBLICKEY; logeventf(ssh, "Trying Pageant key #%d", s->keyi); @@ -10021,7 +9024,8 @@ static void do_ssh2_userauth(void *vctx) } /* See if server will accept it */ - s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST); + s->pktout = ssh_bpp_new_pktout( + ssh->bpp, SSH2_MSG_USERAUTH_REQUEST); put_stringz(s->pktout, ssh->username); put_stringz(s->pktout, "ssh-connection"); /* service requested */ @@ -10056,7 +9060,8 @@ static void do_ssh2_userauth(void *vctx) * Server is willing to accept the key. * Construct a SIGN_REQUEST. */ - s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST); + s->pktout = ssh_bpp_new_pktout( + ssh->bpp, SSH2_MSG_USERAUTH_REQUEST); put_stringz(s->pktout, ssh->username); put_stringz(s->pktout, "ssh-connection"); /* service requested */ @@ -10131,7 +9136,7 @@ static void do_ssh2_userauth(void *vctx) struct ssh2_userkey *key; /* not live over crReturn */ char *passphrase; /* not live over crReturn */ - ssh->pkt_actx = SSH2_PKTCTX_PUBLICKEY; + ssh->pls.actx = SSH2_PKTCTX_PUBLICKEY; s->tried_pubkey_config = TRUE; @@ -10141,7 +9146,8 @@ static void do_ssh2_userauth(void *vctx) * First, offer the public blob to see if the server is * willing to accept it. */ - s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST); + s->pktout = ssh_bpp_new_pktout( + ssh->bpp, SSH2_MSG_USERAUTH_REQUEST); put_stringz(s->pktout, ssh->username); put_stringz(s->pktout, "ssh-connection"); /* service requested */ @@ -10251,7 +9257,8 @@ static void do_ssh2_userauth(void *vctx) * has announced that it's willing to accept it. * Hallelujah. Generate a signature and send it. */ - s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST); + s->pktout = ssh_bpp_new_pktout( + ssh->bpp, SSH2_MSG_USERAUTH_REQUEST); put_stringz(s->pktout, ssh->username); put_stringz(s->pktout, "ssh-connection"); /* service requested */ @@ -10306,14 +9313,15 @@ static void do_ssh2_userauth(void *vctx) s->type = AUTH_TYPE_GSSAPI; s->tried_gssapi = TRUE; - ssh->pkt_actx = SSH2_PKTCTX_GSSAPI; + ssh->pls.actx = SSH2_PKTCTX_GSSAPI; if (ssh->gsslib->gsslogmsg) logevent(ssh->gsslib->gsslogmsg); /* Sending USERAUTH_REQUEST with "gssapi-with-mic" method */ logeventf(ssh, "Trying gssapi-with-mic..."); - s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST); + s->pktout = ssh_bpp_new_pktout( + ssh->bpp, SSH2_MSG_USERAUTH_REQUEST); put_stringz(s->pktout, ssh->username); put_stringz(s->pktout, "ssh-connection"); put_stringz(s->pktout, "gssapi-with-mic"); @@ -10419,7 +9427,8 @@ static void do_ssh2_userauth(void *vctx) */ if (s->gss_sndtok.length != 0) { s->pktout = - ssh2_pkt_init(SSH2_MSG_USERAUTH_GSSAPI_TOKEN); + ssh_bpp_new_pktout( + ssh->bpp, SSH2_MSG_USERAUTH_GSSAPI_TOKEN); put_string(s->pktout, s->gss_sndtok.value, s->gss_sndtok.length); ssh2_pkt_send(ssh, s->pktout); @@ -10464,9 +9473,10 @@ static void do_ssh2_userauth(void *vctx) s->type = AUTH_TYPE_KEYBOARD_INTERACTIVE; - ssh->pkt_actx = SSH2_PKTCTX_KBDINTER; + ssh->pls.actx = SSH2_PKTCTX_KBDINTER; - s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST); + s->pktout = ssh_bpp_new_pktout( + ssh->bpp, SSH2_MSG_USERAUTH_REQUEST); put_stringz(s->pktout, ssh->username); put_stringz(s->pktout, "ssh-connection"); /* service requested */ @@ -10588,7 +9598,8 @@ static void do_ssh2_userauth(void *vctx) /* * Send the response(s) to the server. */ - s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_INFO_RESPONSE); + s->pktout = ssh_bpp_new_pktout( + ssh->bpp, SSH2_MSG_USERAUTH_INFO_RESPONSE); put_uint32(s->pktout, s->num_prompts); for (i=0; i < s->num_prompts; i++) { put_stringz(s->pktout, @@ -10623,7 +9634,7 @@ static void do_ssh2_userauth(void *vctx) */ int changereq_first_time; /* not live over crReturn */ - ssh->pkt_actx = SSH2_PKTCTX_PASSWORD; + ssh->pls.actx = SSH2_PKTCTX_PASSWORD; s->cur_prompt = new_prompts(ssh->frontend); s->cur_prompt->to_server = TRUE; @@ -10675,7 +9686,8 @@ static void do_ssh2_userauth(void *vctx) * probably doesn't have much to worry about from * people who find out how long their password is! */ - s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST); + s->pktout = ssh_bpp_new_pktout( + ssh->bpp, SSH2_MSG_USERAUTH_REQUEST); put_stringz(s->pktout, ssh->username); put_stringz(s->pktout, "ssh-connection"); /* service requested */ @@ -10807,7 +9819,8 @@ static void do_ssh2_userauth(void *vctx) * Send the new password (along with the old one). * (see above for padding rationale) */ - s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST); + s->pktout = ssh_bpp_new_pktout( + ssh->bpp, SSH2_MSG_USERAUTH_REQUEST); put_stringz(s->pktout, ssh->username); put_stringz(s->pktout, "ssh-connection"); /* service requested */ @@ -11297,7 +10310,7 @@ static void ssh2_msg_transport(Ssh ssh, PktIn *pktin) static void ssh2_msg_unexpected(Ssh ssh, PktIn *pktin) { char *buf = dupprintf("Server protocol violation: unexpected %s packet", - ssh2_pkt_type(ssh->pkt_kctx, ssh->pkt_actx, + ssh2_pkt_type(ssh->pls.kctx, ssh->pls.actx, pktin->type)); ssh_disconnect(ssh, NULL, buf, SSH2_DISCONNECT_PROTOCOL_ERROR, FALSE); sfree(buf); @@ -11306,13 +10319,13 @@ static void ssh2_msg_unexpected(Ssh ssh, PktIn *pktin) static void ssh2_msg_something_unimplemented(Ssh ssh, PktIn *pktin) { PktOut *pktout; - pktout = ssh2_pkt_init(SSH2_MSG_UNIMPLEMENTED); + pktout = ssh_bpp_new_pktout(ssh->bpp, SSH2_MSG_UNIMPLEMENTED); put_uint32(pktout, pktin->sequence); /* * UNIMPLEMENTED messages MUST appear in the same order as the * messages they respond to. Hence, never queue them. */ - ssh2_pkt_send_noqueue(ssh, pktout); + ssh_pkt_write(ssh, pktout); } /* @@ -11322,6 +10335,8 @@ static void ssh2_protocol_setup(Ssh ssh) { int i; + ssh->bpp = ssh2_bpp_new(); + #ifndef NO_GSSAPI /* Load and pick the highest GSS library on the preference list. */ if (!ssh->gsslibs) @@ -11353,7 +10368,7 @@ static void ssh2_protocol_setup(Ssh ssh) /* * Most messages cause SSH2_MSG_UNIMPLEMENTED. */ - for (i = 0; i < 256; i++) + for (i = 0; i < SSH_MAX_MSG; i++) ssh->packet_dispatch[i] = ssh2_msg_something_unimplemented; /* @@ -11409,10 +10424,12 @@ static void ssh2_bare_connection_protocol_setup(Ssh ssh) { int i; + ssh->bpp = ssh2_bare_bpp_new(); + /* * Most messages cause SSH2_MSG_UNIMPLEMENTED. */ - for (i = 0; i < 256; i++) + for (i = 0; i < SSH_MAX_MSG; i++) ssh->packet_dispatch[i] = ssh2_msg_something_unimplemented; /* @@ -11475,9 +10492,9 @@ static PktOut *ssh2_gss_authpacket(Ssh ssh, Ssh_gss_ctx gss_ctx, /* Now we can build the real packet */ if (strcmp(authtype, "gssapi-with-mic") == 0) { - p = ssh2_pkt_init(SSH2_MSG_USERAUTH_GSSAPI_MIC); + p = ssh_bpp_new_pktout(ssh->bpp, SSH2_MSG_USERAUTH_GSSAPI_MIC); } else { - p = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST); + p = ssh_bpp_new_pktout(ssh->bpp, SSH2_MSG_USERAUTH_REQUEST); put_stringz(p, ssh->username); put_stringz(p, "ssh-connection"); put_stringz(p, authtype); @@ -11736,7 +10753,8 @@ static void ssh2_general_packet_processing(Ssh ssh, PktIn *pktin) static void ssh_cache_conf_values(Ssh ssh) { - ssh->logomitdata = conf_get_int(ssh->conf, CONF_logomitdata); + ssh->pls.omit_passwords = conf_get_int(ssh->conf, CONF_logomitpass); + ssh->pls.omit_data = conf_get_int(ssh->conf, CONF_logomitdata); } /* @@ -11757,21 +10775,6 @@ static const char *ssh_init(void *frontend_handle, void **backend_handle, ssh_cache_conf_values(ssh); ssh->version = 0; /* when not ready yet */ ssh->s = NULL; - ssh->cipher = NULL; - ssh->v1_cipher_ctx = NULL; - ssh->crcda_ctx = NULL; - ssh->cscipher = NULL; - ssh->cs_cipher_ctx = NULL; - ssh->sccipher = NULL; - ssh->sc_cipher_ctx = NULL; - ssh->csmac = NULL; - ssh->cs_mac_ctx = NULL; - ssh->scmac = NULL; - ssh->sc_mac_ctx = NULL; - ssh->cscomp = NULL; - ssh->cs_comp_ctx = NULL; - ssh->sccomp = NULL; - ssh->sc_comp_ctx = NULL; ssh->kex = NULL; ssh->kex_ctx = NULL; ssh->hostkey_alg = NULL; @@ -11786,17 +10789,13 @@ static const char *ssh_init(void *frontend_handle, void **backend_handle, ssh->ldisc = NULL; ssh->logctx = NULL; ssh->fallback_cmd = 0; - ssh->pkt_kctx = SSH2_PKTCTX_NOKEX; - ssh->pkt_actx = SSH2_PKTCTX_NOAUTH; + ssh->pls.kctx = SSH2_PKTCTX_NOKEX; + ssh->pls.actx = SSH2_PKTCTX_NOAUTH; ssh->x11disp = NULL; ssh->x11auth = NULL; ssh->x11authtree = newtree234(x11_authcmp); - ssh->v1_compressing = FALSE; - ssh->v2_outgoing_sequence = 0; - ssh->ssh1_rdpkt_crstate = 0; - ssh->ssh2_rdpkt_crstate = 0; - ssh->ssh2_bare_rdpkt_crstate = 0; - ssh->rdpkt2_state.buf = NULL; + ssh->v2_cbc_ignore_workaround = FALSE; + ssh->bpp = NULL; ssh->do_ssh1_connection_crstate = 0; ssh->do_ssh_init_state = NULL; ssh->do_ssh_connection_init_state = NULL; @@ -11843,7 +10842,6 @@ static const char *ssh_init(void *frontend_handle, void **backend_handle, ssh->outgoing_data_sender.ctx = ssh; ssh->outgoing_data_sender.queued = FALSE; ssh->current_user_input_fn = NULL; - ssh->pending_newkeys = FALSE; ssh->rekey_reason = NULL; ssh->rekey_class = RK_INITIAL; ssh->v_c = NULL; @@ -11934,37 +10932,10 @@ static void ssh_free(void *handle) struct X11FakeAuth *auth; int need_random_unref; - if (ssh->v1_cipher_ctx) - ssh->cipher->free_context(ssh->v1_cipher_ctx); - if (ssh->cs_cipher_ctx) - ssh->cscipher->free_context(ssh->cs_cipher_ctx); - if (ssh->sc_cipher_ctx) - ssh->sccipher->free_context(ssh->sc_cipher_ctx); - if (ssh->cs_mac_ctx) - ssh->csmac->free_context(ssh->cs_mac_ctx); - if (ssh->sc_mac_ctx) - ssh->scmac->free_context(ssh->sc_mac_ctx); - if (ssh->cs_comp_ctx) { - if (ssh->cscomp) - ssh->cscomp->compress_cleanup(ssh->cs_comp_ctx); - else - zlib_compress_cleanup(ssh->cs_comp_ctx); - } - if (ssh->sc_comp_ctx) { - if (ssh->sccomp) - ssh->sccomp->decompress_cleanup(ssh->sc_comp_ctx); - else - zlib_decompress_cleanup(ssh->sc_comp_ctx); - } if (ssh->kex_ctx) dh_cleanup(ssh->kex_ctx); sfree(ssh->savedhost); - if (ssh->rdpkt2_state.buf) { - smemclr(ssh->rdpkt2_state.buf, ssh->rdpkt2_state.bufsize); - sfree(ssh->rdpkt2_state.buf); - } - while (ssh->queuelen-- > 0) ssh_free_pktout(ssh->queue[ssh->queuelen]); sfree(ssh->queue); @@ -12011,6 +10982,8 @@ static void ssh_free(void *handle) x11_free_display(ssh->x11disp); while ((auth = delpos234(ssh->x11authtree, 0)) != NULL) x11_free_fake_auth(auth); + if (ssh->bpp) + ssh_bpp_free(ssh->bpp); freetree234(ssh->x11authtree); sfree(ssh->do_ssh_init_state); sfree(ssh->do_ssh1_login_state); @@ -12032,10 +11005,6 @@ static void ssh_free(void *handle) sfree(ssh->fullhostname); sfree(ssh->hostkey_str); sfree(ssh->specials); - if (ssh->crcda_ctx) { - crcda_free_context(ssh->crcda_ctx); - ssh->crcda_ctx = NULL; - } if (ssh->s) ssh_do_close(ssh, TRUE); expire_timer_context(ssh); @@ -12353,9 +11322,9 @@ static void ssh_special(void *handle, Telnet_Special code) send_packet(ssh, SSH1_MSG_IGNORE, PKT_STR, "", PKT_END); } else { if (!(ssh->remote_bugs & BUG_CHOKES_ON_SSH2_IGNORE)) { - pktout = ssh2_pkt_init(SSH2_MSG_IGNORE); + pktout = ssh_bpp_new_pktout(ssh->bpp, SSH2_MSG_IGNORE); put_stringz(pktout, ""); - ssh2_pkt_send_noqueue(ssh, pktout); + ssh_pkt_write(ssh, pktout); } } } else if (code == TS_REKEY) { @@ -12457,7 +11426,7 @@ void ssh_send_packet_from_downstream(Ssh ssh, unsigned id, int type, { PktOut *pkt; - pkt = ssh2_pkt_init(type); + pkt = ssh_bpp_new_pktout(ssh->bpp, type); pkt->downstream_id = id; pkt->additional_log_text = additional_log_text; put_data(pkt, data, datalen); diff --git a/ssh.h b/ssh.h index 5e257324..f00c7e99 100644 --- a/ssh.h +++ b/ssh.h @@ -129,8 +129,21 @@ typedef enum { SSH2_PKTCTX_KBDINTER } Pkt_ACtx; -PktOut *ssh1_pkt_init(int pkt_type); -PktOut *ssh2_pkt_init(int pkt_type); +typedef struct PacketLogSettings { + int omit_passwords, omit_data; + Pkt_KCtx kctx; + Pkt_ACtx actx; +} PacketLogSettings; + +#define MAX_BLANKS 4 /* no packet needs more censored sections than this */ +int ssh1_censor_packet( + const PacketLogSettings *pls, int type, int sender_is_client, + ptrlen pkt, logblank_t *blanks); +int ssh2_censor_packet( + const PacketLogSettings *pls, int type, int sender_is_client, + ptrlen pkt, logblank_t *blanks); + +PktOut *ssh_new_packet(void); void ssh_unref_packet(PktIn *pkt); void ssh_free_pktout(PktOut *pkt); @@ -1106,6 +1119,13 @@ void platform_ssh_share_cleanup(const char *name); #define SSH2_MSG_USERAUTH_GSSAPI_ERRTOK 65 #define SSH2_MSG_USERAUTH_GSSAPI_MIC 66 +/* Virtual packet type, for packets too short to even have a type */ +#define SSH_MSG_NO_TYPE_CODE 0x100 + +/* Given that virtual packet types exist, this is how big the dispatch + * table has to be */ +#define SSH_MAX_MSG 0x101 + /* * SSH-1 agent messages. */ diff --git a/ssh1bpp.c b/ssh1bpp.c new file mode 100644 index 00000000..a00c4d3c --- /dev/null +++ b/ssh1bpp.c @@ -0,0 +1,280 @@ +/* + * Binary packet protocol for SSH-1. + */ + +#include + +#include "putty.h" +#include "ssh.h" +#include "sshbpp.h" +#include "sshcr.h" + +struct ssh1_bpp_state { + int crState; + long len, pad, biglen, length, maxlen; + unsigned char *data; + unsigned long realcrc, gotcrc; + int chunk; + PktIn *pktin; + + const struct ssh_cipher *cipher; + void *cipher_ctx; + + void *crcda_ctx; + + void *compctx, *decompctx; + + BinaryPacketProtocol bpp; +}; + +static void ssh1_bpp_free(BinaryPacketProtocol *bpp); +static void ssh1_bpp_handle_input(BinaryPacketProtocol *bpp); +static PktOut *ssh1_bpp_new_pktout(int type); +static void ssh1_bpp_format_packet(BinaryPacketProtocol *bpp, PktOut *pkt); + +const struct BinaryPacketProtocolVtable ssh1_bpp_vtable = { + ssh1_bpp_free, + ssh1_bpp_handle_input, + ssh1_bpp_new_pktout, + ssh1_bpp_format_packet, +}; + +BinaryPacketProtocol *ssh1_bpp_new(void) +{ + struct ssh1_bpp_state *s = snew(struct ssh1_bpp_state); + memset(s, 0, sizeof(*s)); + s->bpp.vt = &ssh1_bpp_vtable; + return &s->bpp; +} + +static void ssh1_bpp_free(BinaryPacketProtocol *bpp) +{ + struct ssh1_bpp_state *s = FROMFIELD(bpp, struct ssh1_bpp_state, bpp); + if (s->cipher) + s->cipher->free_context(s->cipher_ctx); + if (s->compctx) + zlib_compress_cleanup(s->compctx); + if (s->decompctx) + zlib_decompress_cleanup(s->decompctx); + if (s->crcda_ctx) + crcda_free_context(s->crcda_ctx); + if (s->pktin) + ssh_unref_packet(s->pktin); + sfree(s); +} + +void ssh1_bpp_new_cipher(BinaryPacketProtocol *bpp, + const struct ssh_cipher *cipher, + const void *session_key) +{ + struct ssh1_bpp_state *s; + assert(bpp->vt == &ssh1_bpp_vtable); + s = FROMFIELD(bpp, struct ssh1_bpp_state, bpp); + + assert(!s->cipher); + + s->cipher = cipher; + if (s->cipher) { + s->cipher_ctx = cipher->make_context(); + cipher->sesskey(s->cipher_ctx, session_key); + + assert(!s->crcda_ctx); + s->crcda_ctx = crcda_make_context(); + } +} + +void ssh1_bpp_start_compression(BinaryPacketProtocol *bpp) +{ + struct ssh1_bpp_state *s; + assert(bpp->vt == &ssh1_bpp_vtable); + s = FROMFIELD(bpp, struct ssh1_bpp_state, bpp); + + assert(!s->compctx); + assert(!s->decompctx); + + s->compctx = zlib_compress_init(); + s->decompctx = zlib_decompress_init(); +} + +static void ssh1_bpp_handle_input(BinaryPacketProtocol *bpp) +{ + struct ssh1_bpp_state *s = FROMFIELD(bpp, struct ssh1_bpp_state, bpp); + + crBegin(s->crState); + + while (1) { + s->maxlen = 0; + s->length = 0; + + { + unsigned char lenbuf[4]; + crMaybeWaitUntilV(bufchain_try_fetch_consume( + bpp->in_raw, lenbuf, 4)); + s->len = toint(GET_32BIT_MSB_FIRST(lenbuf)); + } + + if (s->len < 0 || s->len > 262144) { /* SSH1.5-mandated max size */ + s->bpp.error = dupprintf( + "Extremely large packet length from server suggests" + " data stream corruption"); + crStopV; + } + + s->pad = 8 - (s->len % 8); + s->biglen = s->len + s->pad; + s->length = s->len - 5; + + /* + * Allocate the packet to return, now we know its length. + */ + s->pktin = snew_plus(PktIn, s->biglen); + s->pktin->qnode.prev = s->pktin->qnode.next = NULL; + s->pktin->refcount = 1; + s->pktin->type = 0; + + s->maxlen = s->biglen; + s->data = snew_plus_get_aux(s->pktin); + + crMaybeWaitUntilV(bufchain_try_fetch_consume( + bpp->in_raw, s->data, s->biglen)); + + if (s->cipher && detect_attack(s->crcda_ctx, + s->data, s->biglen, NULL)) { + s->bpp.error = dupprintf( + "Network attack (CRC compensation) detected!"); + crStopV; + } + + if (s->cipher) + s->cipher->decrypt(s->cipher_ctx, s->data, s->biglen); + + s->realcrc = crc32_compute(s->data, s->biglen - 4); + s->gotcrc = GET_32BIT(s->data + s->biglen - 4); + if (s->gotcrc != s->realcrc) { + s->bpp.error = dupprintf( + "Incorrect CRC received on packet"); + crStopV; + } + + if (s->decompctx) { + unsigned char *decompblk; + int decomplen; + if (!zlib_decompress_block(s->decompctx, + s->data + s->pad, s->length + 1, + &decompblk, &decomplen)) { + s->bpp.error = dupprintf( + "Zlib decompression encountered invalid data"); + crStopV; + } + + if (s->maxlen < s->pad + decomplen) { + PktIn *old_pktin = s->pktin; + + s->maxlen = s->pad + decomplen; + s->pktin = snew_plus(PktIn, s->maxlen); + *s->pktin = *old_pktin; /* structure copy */ + s->data = snew_plus_get_aux(s->pktin); + + smemclr(old_pktin, s->biglen); + sfree(old_pktin); + } + + memcpy(s->data + s->pad, decompblk, decomplen); + sfree(decompblk); + s->length = decomplen - 1; + } + + /* + * Now we can find the bounds of the semantic content of the + * packet, and the initial type byte. + */ + s->data += s->pad; + s->pktin->type = *s->data++; + BinarySource_INIT(s->pktin, s->data, s->length); + + if (s->bpp.logctx) { + logblank_t blanks[MAX_BLANKS]; + int nblanks = ssh1_censor_packet( + s->bpp.pls, s->pktin->type, FALSE, + make_ptrlen(s->data, s->length), blanks); + log_packet(s->bpp.logctx, PKT_INCOMING, s->pktin->type, + ssh1_pkt_type(s->pktin->type), + get_ptr(s->pktin), get_avail(s->pktin), nblanks, blanks, + NULL, 0, NULL); + } + + pq_push(s->bpp.in_pq, s->pktin); + + { + int type = s->pktin->type; + s->pktin = NULL; + + if (type == SSH1_MSG_DISCONNECT) + s->bpp.seen_disconnect = TRUE; + } + } + crFinishV; +} + +static PktOut *ssh1_bpp_new_pktout(int pkt_type) +{ + PktOut *pkt = ssh_new_packet(); + pkt->length = 4 + 8; /* space for length + max padding */ + put_byte(pkt, pkt_type); + pkt->prefix = pkt->length; + pkt->type = pkt_type; + pkt->downstream_id = 0; + pkt->additional_log_text = NULL; + return pkt; +} + +static void ssh1_bpp_format_packet(BinaryPacketProtocol *bpp, PktOut *pkt) +{ + struct ssh1_bpp_state *s = FROMFIELD(bpp, struct ssh1_bpp_state, bpp); + int pad, biglen, i, pktoffs; + unsigned long crc; + int len; + + if (s->bpp.logctx) { + ptrlen pktdata = make_ptrlen(pkt->data + pkt->prefix, + pkt->length - pkt->prefix); + logblank_t blanks[MAX_BLANKS]; + int nblanks = ssh1_censor_packet( + s->bpp.pls, pkt->type, TRUE, pktdata, blanks); + log_packet(s->bpp.logctx, PKT_OUTGOING, pkt->type, + ssh1_pkt_type(pkt->type), + pktdata.ptr, pktdata.len, nblanks, blanks, + NULL, 0, NULL); + } + + if (s->compctx) { + unsigned char *compblk; + int complen; + zlib_compress_block(s->compctx, pkt->data + 12, pkt->length - 12, + &compblk, &complen); + /* Replace the uncompressed packet data with the compressed + * version. */ + pkt->length = 12; + put_data(pkt, compblk, complen); + sfree(compblk); + } + + put_uint32(pkt, 0); /* space for CRC */ + len = pkt->length - 4 - 8; /* len(type+data+CRC) */ + pad = 8 - (len % 8); + pktoffs = 8 - pad; + biglen = len + pad; /* len(padding+type+data+CRC) */ + + for (i = pktoffs; i < 4+8; i++) + pkt->data[i] = random_byte(); + crc = crc32_compute(pkt->data + pktoffs + 4, + biglen - 4); /* all ex len */ + PUT_32BIT(pkt->data + pktoffs + 4 + biglen - 4, crc); + PUT_32BIT(pkt->data + pktoffs, len); + + if (s->cipher) + s->cipher->encrypt(s->cipher_ctx, pkt->data + pktoffs + 4, biglen); + + bufchain_add(s->bpp.out_raw, pkt->data + pktoffs, + biglen + 4); /* len(length+padding+type+data+CRC) */ +} diff --git a/ssh1censor.c b/ssh1censor.c new file mode 100644 index 00000000..755ce3d8 --- /dev/null +++ b/ssh1censor.c @@ -0,0 +1,76 @@ +/* + * Packet-censoring code for SSH-1, used to identify sensitive fields + * like passwords so that the logging system can avoid writing them + * into log files. + */ + +#include + +#include "putty.h" +#include "ssh.h" + +int ssh1_censor_packet( + const PacketLogSettings *pls, int type, int sender_is_client, + ptrlen pkt, logblank_t *blanks) +{ + int nblanks = 0; + ptrlen str; + BinarySource src[1]; + + BinarySource_BARE_INIT(src, pkt.ptr, pkt.len); + + if (pls->omit_data && + (type == SSH1_SMSG_STDOUT_DATA || + type == SSH1_SMSG_STDERR_DATA || + type == SSH1_CMSG_STDIN_DATA || + type == SSH1_MSG_CHANNEL_DATA)) { + /* "Session data" packets - omit the data string. */ + if (type == SSH1_MSG_CHANNEL_DATA) + get_uint32(src); /* skip channel id */ + str = get_string(src); + if (!get_err(src)) { + assert(nblanks < MAX_BLANKS); + blanks[nblanks].offset = src->pos - str.len; + blanks[nblanks].type = PKTLOG_OMIT; + blanks[nblanks].len = str.len; + nblanks++; + } + } + + if (sender_is_client && pls->omit_passwords) { + if (type == SSH1_CMSG_AUTH_PASSWORD || + type == SSH1_CMSG_AUTH_TIS_RESPONSE || + type == SSH1_CMSG_AUTH_CCARD_RESPONSE) { + /* If this is a password or similar packet, blank the + * password(s). */ + assert(nblanks < MAX_BLANKS); + blanks[nblanks].offset = 0; + blanks[nblanks].len = pkt.len; + blanks[nblanks].type = PKTLOG_BLANK; + nblanks++; + } else if (type == SSH1_CMSG_X11_REQUEST_FORWARDING) { + /* + * If this is an X forwarding request packet, blank the + * fake auth data. + * + * Note that while we blank the X authentication data + * here, we don't take any special action to blank the + * start of an X11 channel, so using MIT-MAGIC-COOKIE-1 + * and actually opening an X connection without having + * session blanking enabled is likely to leak your cookie + * into the log. + */ + get_string(src); /* skip protocol name */ + str = get_string(src); + if (!get_err(src)) { + assert(nblanks < MAX_BLANKS); + blanks[nblanks].offset = src->pos - str.len; + blanks[nblanks].type = PKTLOG_BLANK; + blanks[nblanks].len = str.len; + nblanks++; + } + } + } + + return nblanks; +} diff --git a/ssh2bpp-bare.c b/ssh2bpp-bare.c new file mode 100644 index 00000000..270c0118 --- /dev/null +++ b/ssh2bpp-bare.c @@ -0,0 +1,160 @@ +/* + * Trivial binary packet protocol for the 'bare' ssh-connection + * protocol used in PuTTY's SSH-2 connection sharing system. + */ + +#include + +#include "putty.h" +#include "ssh.h" +#include "sshbpp.h" +#include "sshcr.h" + +struct ssh2_bare_bpp_state { + int crState; + long packetlen, maxlen; + unsigned char *data; + unsigned long incoming_sequence, outgoing_sequence; + PktIn *pktin; + + BinaryPacketProtocol bpp; +}; + +static void ssh2_bare_bpp_free(BinaryPacketProtocol *bpp); +static void ssh2_bare_bpp_handle_input(BinaryPacketProtocol *bpp); +static PktOut *ssh2_bare_bpp_new_pktout(int type); +static void ssh2_bare_bpp_format_packet(BinaryPacketProtocol *bpp, PktOut *); + +const struct BinaryPacketProtocolVtable ssh2_bare_bpp_vtable = { + ssh2_bare_bpp_free, + ssh2_bare_bpp_handle_input, + ssh2_bare_bpp_new_pktout, + ssh2_bare_bpp_format_packet, +}; + +BinaryPacketProtocol *ssh2_bare_bpp_new(void) +{ + struct ssh2_bare_bpp_state *s = snew(struct ssh2_bare_bpp_state); + memset(s, 0, sizeof(*s)); + s->bpp.vt = &ssh2_bare_bpp_vtable; + return &s->bpp; +} + +static void ssh2_bare_bpp_free(BinaryPacketProtocol *bpp) +{ + struct ssh2_bare_bpp_state *s = + FROMFIELD(bpp, struct ssh2_bare_bpp_state, bpp); + if (s->pktin) + ssh_unref_packet(s->pktin); + sfree(s); +} + +static void ssh2_bare_bpp_handle_input(BinaryPacketProtocol *bpp) +{ + struct ssh2_bare_bpp_state *s = + FROMFIELD(bpp, struct ssh2_bare_bpp_state, bpp); + + crBegin(s->crState); + + while (1) { + /* Read the length field. */ + { + unsigned char lenbuf[4]; + crMaybeWaitUntilV(bufchain_try_fetch_consume( + s->bpp.in_raw, lenbuf, 4)); + s->packetlen = toint(GET_32BIT_MSB_FIRST(lenbuf)); + } + + if (s->packetlen <= 0 || s->packetlen >= (long)OUR_V2_PACKETLIMIT) { + s->bpp.error = dupstr("Invalid packet length received"); + crStopV; + } + + /* + * Allocate the packet to return, now we know its length. + */ + s->pktin = snew_plus(PktIn, s->packetlen); + s->pktin->qnode.prev = s->pktin->qnode.next = NULL; + s->maxlen = 0; + s->pktin->refcount = 1; + s->data = snew_plus_get_aux(s->pktin); + + s->pktin->encrypted_len = s->packetlen; + + s->pktin->sequence = s->incoming_sequence++; + + /* + * Read the remainder of the packet. + */ + crMaybeWaitUntilV(bufchain_try_fetch_consume( + s->bpp.in_raw, s->data, s->packetlen)); + + /* + * The data we just read is precisely the initial type byte + * followed by the packet payload. + */ + s->pktin->type = s->data[0]; + s->data++; + s->packetlen--; + BinarySource_INIT(s->pktin, s->data, s->packetlen); + + /* + * Log incoming packet, possibly omitting sensitive fields. + */ + if (s->bpp.logctx) { + logblank_t blanks[MAX_BLANKS]; + int nblanks = ssh2_censor_packet( + s->bpp.pls, s->pktin->type, FALSE, + make_ptrlen(s->data, s->packetlen), blanks); + log_packet(s->bpp.logctx, PKT_INCOMING, s->pktin->type, + ssh2_pkt_type(s->bpp.pls->kctx, s->bpp.pls->actx, + s->pktin->type), + get_ptr(s->pktin), get_avail(s->pktin), nblanks, blanks, + &s->pktin->sequence, 0, NULL); + } + + pq_push(s->bpp.in_pq, s->pktin); + + { + int type = s->pktin->type; + s->pktin = NULL; + + if (type == SSH2_MSG_DISCONNECT) + s->bpp.seen_disconnect = TRUE; + } + } + crFinishV; +} + +static PktOut *ssh2_bare_bpp_new_pktout(int pkt_type) +{ + PktOut *pkt = ssh_new_packet(); + pkt->length = 4; /* space for packet length */ + pkt->type = pkt_type; + put_byte(pkt, pkt_type); + return pkt; +} + +static void ssh2_bare_bpp_format_packet(BinaryPacketProtocol *bpp, PktOut *pkt) +{ + struct ssh2_bare_bpp_state *s = + FROMFIELD(bpp, struct ssh2_bare_bpp_state, bpp); + + if (s->bpp.logctx) { + ptrlen pktdata = make_ptrlen(pkt->data + 5, pkt->length - 5); + logblank_t blanks[MAX_BLANKS]; + int nblanks = ssh2_censor_packet( + s->bpp.pls, pkt->type, TRUE, pktdata, blanks); + log_packet(s->bpp.logctx, PKT_OUTGOING, pkt->type, + ssh2_pkt_type(s->bpp.pls->kctx, s->bpp.pls->actx, + pkt->type), + pktdata.ptr, pktdata.len, nblanks, blanks, + &s->outgoing_sequence, + pkt->downstream_id, pkt->additional_log_text); + } + + s->outgoing_sequence++; /* only for diagnostics, really */ + + PUT_32BIT(pkt->data, pkt->length - 4); + bufchain_add(s->bpp.out_raw, pkt->data, pkt->length); +} diff --git a/ssh2bpp.c b/ssh2bpp.c new file mode 100644 index 00000000..da0ac900 --- /dev/null +++ b/ssh2bpp.c @@ -0,0 +1,613 @@ +/* + * Binary packet protocol for SSH-2. + */ + +#include + +#include "putty.h" +#include "ssh.h" +#include "sshbpp.h" +#include "sshcr.h" + +struct ssh2_bpp_direction { + unsigned long sequence; + const struct ssh2_cipher *cipher; + void *cipher_ctx; + const struct ssh_mac *mac; + int etm_mode; + void *mac_ctx; + const struct ssh_compress *comp; + void *comp_ctx; +}; + +struct ssh2_bpp_state { + int crState; + long len, pad, payload, packetlen, maclen, length, maxlen; + unsigned char *buf; + size_t bufsize; + unsigned char *data; + unsigned cipherblk; + PktIn *pktin; + BinarySink *sc_mac_bs; + + struct ssh2_bpp_direction in, out; + int pending_newkeys; + + BinaryPacketProtocol bpp; +}; + +static void ssh2_bpp_free(BinaryPacketProtocol *bpp); +static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp); +static PktOut *ssh2_bpp_new_pktout(int type); +static void ssh2_bpp_format_packet(BinaryPacketProtocol *bpp, PktOut *pkt); + +const struct BinaryPacketProtocolVtable ssh2_bpp_vtable = { + ssh2_bpp_free, + ssh2_bpp_handle_input, + ssh2_bpp_new_pktout, + ssh2_bpp_format_packet, +}; + +BinaryPacketProtocol *ssh2_bpp_new(void) +{ + struct ssh2_bpp_state *s = snew(struct ssh2_bpp_state); + memset(s, 0, sizeof(*s)); + s->bpp.vt = &ssh2_bpp_vtable; + return &s->bpp; +} + +static void ssh2_bpp_free(BinaryPacketProtocol *bpp) +{ + struct ssh2_bpp_state *s = FROMFIELD(bpp, struct ssh2_bpp_state, bpp); + sfree(s->buf); + if (s->out.cipher_ctx) + s->out.cipher->free_context(s->out.cipher_ctx); + if (s->out.mac_ctx) + s->out.mac->free_context(s->out.mac_ctx); + if (s->out.comp_ctx) + s->out.comp->compress_cleanup(s->out.comp_ctx); + if (s->in.cipher_ctx) + s->in.cipher->free_context(s->in.cipher_ctx); + if (s->in.mac_ctx) + s->in.mac->free_context(s->in.mac_ctx); + if (s->in.comp_ctx) + s->in.comp->decompress_cleanup(s->in.comp_ctx); + if (s->pktin) + ssh_unref_packet(s->pktin); + sfree(s); +} + +void ssh2_bpp_new_outgoing_crypto( + BinaryPacketProtocol *bpp, + const struct ssh2_cipher *cipher, const void *ckey, const void *iv, + const struct ssh_mac *mac, int etm_mode, const void *mac_key, + const struct ssh_compress *compression) +{ + struct ssh2_bpp_state *s; + assert(bpp->vt == &ssh2_bpp_vtable); + s = FROMFIELD(bpp, struct ssh2_bpp_state, bpp); + + if (s->out.cipher_ctx) + s->out.cipher->free_context(s->out.cipher_ctx); + if (s->out.mac_ctx) + s->out.mac->free_context(s->out.mac_ctx); + if (s->out.comp_ctx) + s->out.comp->compress_cleanup(s->out.comp_ctx); + + s->out.cipher = cipher; + if (cipher) { + s->out.cipher_ctx = cipher->make_context(); + cipher->setkey(s->out.cipher_ctx, ckey); + cipher->setiv(s->out.cipher_ctx, iv); + } + s->out.mac = mac; + s->out.etm_mode = etm_mode; + if (mac) { + s->out.mac_ctx = mac->make_context(s->out.cipher_ctx); + mac->setkey(s->out.mac_ctx, mac_key); + } + + s->out.comp = compression; + /* out_comp is always non-NULL, because no compression is + * indicated by ssh_comp_none. So compress_init always exists, but + * it may return a null out_comp_ctx. */ + s->out.comp_ctx = compression->compress_init(); +} + +void ssh2_bpp_new_incoming_crypto( + BinaryPacketProtocol *bpp, + const struct ssh2_cipher *cipher, const void *ckey, const void *iv, + const struct ssh_mac *mac, int etm_mode, const void *mac_key, + const struct ssh_compress *compression) +{ + struct ssh2_bpp_state *s; + assert(bpp->vt == &ssh2_bpp_vtable); + s = FROMFIELD(bpp, struct ssh2_bpp_state, bpp); + + if (s->in.cipher_ctx) + s->in.cipher->free_context(s->in.cipher_ctx); + if (s->in.mac_ctx) + s->in.mac->free_context(s->in.mac_ctx); + if (s->in.comp_ctx) + s->in.comp->decompress_cleanup(s->in.comp_ctx); + + s->in.cipher = cipher; + if (cipher) { + s->in.cipher_ctx = cipher->make_context(); + cipher->setkey(s->in.cipher_ctx, ckey); + cipher->setiv(s->in.cipher_ctx, iv); + } + s->in.mac = mac; + s->in.etm_mode = etm_mode; + if (mac) { + s->in.mac_ctx = mac->make_context(s->in.cipher_ctx); + mac->setkey(s->in.mac_ctx, mac_key); + } + + s->in.comp = compression; + /* out_comp is always non-NULL, because no compression is + * indicated by ssh_comp_none. So compress_init always exists, but + * it may return a null out_comp_ctx. */ + s->in.comp_ctx = compression->compress_init(); + + /* Clear the pending_newkeys flag, so that handle_input below will + * start consuming the input data again. */ + s->pending_newkeys = FALSE; +} + +static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp) +{ + struct ssh2_bpp_state *s = FROMFIELD(bpp, struct ssh2_bpp_state, bpp); + + crBegin(s->crState); + + while (1) { + s->maxlen = 0; + s->length = 0; + if (s->in.cipher) + s->cipherblk = s->in.cipher->blksize; + else + s->cipherblk = 8; + if (s->cipherblk < 8) + s->cipherblk = 8; + s->maclen = s->in.mac ? s->in.mac->len : 0; + + if (s->in.cipher && (s->in.cipher->flags & SSH_CIPHER_IS_CBC) && + s->in.mac && !s->in.etm_mode) { + /* + * When dealing with a CBC-mode cipher, we want to avoid the + * possibility of an attacker's tweaking the ciphertext stream + * so as to cause us to feed the same block to the block + * cipher more than once and thus leak information + * (VU#958563). The way we do this is not to take any + * decisions on the basis of anything we've decrypted until + * we've verified it with a MAC. That includes the packet + * length, so we just read data and check the MAC repeatedly, + * and when the MAC passes, see if the length we've got is + * plausible. + * + * This defence is unnecessary in OpenSSH ETM mode, because + * the whole point of ETM mode is that the attacker can't + * tweak the ciphertext stream at all without the MAC + * detecting it before we decrypt anything. + */ + + /* + * Make sure we have buffer space for a maximum-size packet. + */ + unsigned buflimit = OUR_V2_PACKETLIMIT + s->maclen; + if (s->bufsize < buflimit) { + s->bufsize = buflimit; + s->buf = sresize(s->buf, s->bufsize, unsigned char); + } + + /* Read an amount corresponding to the MAC. */ + crMaybeWaitUntilV(bufchain_try_fetch_consume( + s->bpp.in_raw, s->buf, s->maclen)); + + s->packetlen = 0; + s->in.mac->start(s->in.mac_ctx); + s->sc_mac_bs = s->in.mac->sink(s->in.mac_ctx); + put_uint32(s->sc_mac_bs, s->in.sequence); + + for (;;) { /* Once around this loop per cipher block. */ + /* Read another cipher-block's worth, and tack it on to + * the end. */ + crMaybeWaitUntilV(bufchain_try_fetch_consume( + s->bpp.in_raw, + s->buf + (s->packetlen + s->maclen), + s->cipherblk)); + /* Decrypt one more block (a little further back in + * the stream). */ + s->in.cipher->decrypt( + s->in.cipher_ctx, + s->buf + s->packetlen, s->cipherblk); + + /* Feed that block to the MAC. */ + put_data(s->sc_mac_bs, + s->buf + s->packetlen, s->cipherblk); + s->packetlen += s->cipherblk; + + /* See if that gives us a valid packet. */ + if (s->in.mac->verresult( + s->in.mac_ctx, s->buf + s->packetlen) && + ((s->len = toint(GET_32BIT(s->buf))) == + s->packetlen-4)) + break; + if (s->packetlen >= (long)OUR_V2_PACKETLIMIT) { + s->bpp.error = dupprintf( + "No valid incoming packet found"); + crStopV; + } + } + s->maxlen = s->packetlen + s->maclen; + + /* + * Now transfer the data into an output packet. + */ + s->pktin = snew_plus(PktIn, s->maxlen); + s->pktin->qnode.prev = s->pktin->qnode.next = NULL; + s->pktin->refcount = 1; + s->pktin->type = 0; + s->data = snew_plus_get_aux(s->pktin); + memcpy(s->data, s->buf, s->maxlen); + } else if (s->in.mac && s->in.etm_mode) { + if (s->bufsize < 4) { + s->bufsize = 4; + s->buf = sresize(s->buf, s->bufsize, unsigned char); + } + + /* + * OpenSSH encrypt-then-MAC mode: the packet length is + * unencrypted, unless the cipher supports length encryption. + */ + crMaybeWaitUntilV(bufchain_try_fetch_consume( + s->bpp.in_raw, s->buf, 4)); + + /* Cipher supports length decryption, so do it */ + if (s->in.cipher && + (s->in.cipher->flags & SSH_CIPHER_SEPARATE_LENGTH)) { + /* Keep the packet the same though, so the MAC passes */ + unsigned char len[4]; + memcpy(len, s->buf, 4); + s->in.cipher->decrypt_length( + s->in.cipher_ctx, len, 4, s->in.sequence); + s->len = toint(GET_32BIT(len)); + } else { + s->len = toint(GET_32BIT(s->buf)); + } + + /* + * _Completely_ silly lengths should be stomped on before they + * do us any more damage. + */ + if (s->len < 0 || s->len > (long)OUR_V2_PACKETLIMIT || + s->len % s->cipherblk != 0) { + s->bpp.error = dupprintf( + "Incoming packet length field was garbled"); + crStopV; + } + + /* + * So now we can work out the total packet length. + */ + s->packetlen = s->len + 4; + + /* + * Allocate the packet to return, now we know its length. + */ + s->pktin = snew_plus(PktIn, OUR_V2_PACKETLIMIT + s->maclen); + s->pktin->qnode.prev = s->pktin->qnode.next = NULL; + s->pktin->refcount = 1; + s->pktin->type = 0; + s->data = snew_plus_get_aux(s->pktin); + memcpy(s->data, s->buf, 4); + + /* + * Read the remainder of the packet. + */ + crMaybeWaitUntilV(bufchain_try_fetch_consume( + s->bpp.in_raw, s->data + 4, + s->packetlen + s->maclen - 4)); + + /* + * Check the MAC. + */ + if (s->in.mac && !s->in.mac->verify( + s->in.mac_ctx, s->data, s->len + 4, s->in.sequence)) { + s->bpp.error = dupprintf("Incorrect MAC received on packet"); + crStopV; + } + + /* Decrypt everything between the length field and the MAC. */ + if (s->in.cipher) + s->in.cipher->decrypt( + s->in.cipher_ctx, s->data + 4, s->packetlen - 4); + } else { + if (s->bufsize < s->cipherblk) { + s->bufsize = s->cipherblk; + s->buf = sresize(s->buf, s->bufsize, unsigned char); + } + + /* + * Acquire and decrypt the first block of the packet. This will + * contain the length and padding details. + */ + crMaybeWaitUntilV(bufchain_try_fetch_consume( + s->bpp.in_raw, s->buf, s->cipherblk)); + + if (s->in.cipher) + s->in.cipher->decrypt( + s->in.cipher_ctx, s->buf, s->cipherblk); + + /* + * Now get the length figure. + */ + s->len = toint(GET_32BIT(s->buf)); + + /* + * _Completely_ silly lengths should be stomped on before they + * do us any more damage. + */ + if (s->len < 0 || s->len > (long)OUR_V2_PACKETLIMIT || + (s->len + 4) % s->cipherblk != 0) { + s->bpp.error = dupprintf( + "Incoming packet was garbled on decryption"); + crStopV; + } + + /* + * So now we can work out the total packet length. + */ + s->packetlen = s->len + 4; + + /* + * Allocate the packet to return, now we know its length. + */ + s->maxlen = s->packetlen + s->maclen; + s->pktin = snew_plus(PktIn, s->maxlen); + s->pktin->qnode.prev = s->pktin->qnode.next = NULL; + s->pktin->refcount = 1; + s->pktin->type = 0; + s->data = snew_plus_get_aux(s->pktin); + memcpy(s->data, s->buf, s->cipherblk); + + /* + * Read and decrypt the remainder of the packet. + */ + crMaybeWaitUntilV(bufchain_try_fetch_consume( + s->bpp.in_raw, s->data + s->cipherblk, + s->packetlen + s->maclen - s->cipherblk)); + + /* Decrypt everything _except_ the MAC. */ + if (s->in.cipher) + s->in.cipher->decrypt( + s->in.cipher_ctx, + s->data + s->cipherblk, s->packetlen - s->cipherblk); + + /* + * Check the MAC. + */ + if (s->in.mac && !s->in.mac->verify( + s->in.mac_ctx, s->data, s->len + 4, s->in.sequence)) { + s->bpp.error = dupprintf("Incorrect MAC received on packet"); + crStopV; + } + } + /* Get and sanity-check the amount of random padding. */ + s->pad = s->data[4]; + if (s->pad < 4 || s->len - s->pad < 1) { + s->bpp.error = dupprintf( + "Invalid padding length on received packet"); + crStopV; + } + /* + * This enables us to deduce the payload length. + */ + s->payload = s->len - s->pad - 1; + + s->length = s->payload + 5; + s->pktin->encrypted_len = s->packetlen; + + s->pktin->sequence = s->in.sequence++; + + s->length = s->packetlen - s->pad; + assert(s->length >= 0); + + /* + * Decompress packet payload. + */ + { + unsigned char *newpayload; + int newlen; + if (s->in.comp && s->in.comp->decompress( + s->in.comp_ctx, s->data + 5, s->length - 5, + &newpayload, &newlen)) { + if (s->maxlen < newlen + 5) { + PktIn *old_pktin = s->pktin; + + s->maxlen = newlen + 5; + s->pktin = snew_plus(PktIn, s->maxlen); + *s->pktin = *old_pktin; /* structure copy */ + s->data = snew_plus_get_aux(s->pktin); + + smemclr(old_pktin, s->packetlen + s->maclen); + sfree(old_pktin); + } + s->length = 5 + newlen; + memcpy(s->data + 5, newpayload, newlen); + sfree(newpayload); + } + } + + /* + * Now we can identify the semantic content of the packet, + * and also the initial type byte. + */ + if (s->length <= 5) { /* == 5 we hope, but robustness */ + /* + * RFC 4253 doesn't explicitly say that completely empty + * packets with no type byte are forbidden. We handle them + * here by giving them a type code larger than 0xFF, which + * will be picked up at the next layer and trigger + * SSH_MSG_UNIMPLEMENTED. + */ + s->pktin->type = SSH_MSG_NO_TYPE_CODE; + s->length = 0; + BinarySource_INIT(s->pktin, s->data + 5, 0); + } else { + s->pktin->type = s->data[5]; + s->length -= 6; + BinarySource_INIT(s->pktin, s->data + 6, s->length); + } + + if (s->bpp.logctx) { + logblank_t blanks[MAX_BLANKS]; + int nblanks = ssh2_censor_packet( + s->bpp.pls, s->pktin->type, FALSE, + make_ptrlen(s->data, s->length), blanks); + log_packet(s->bpp.logctx, PKT_INCOMING, s->pktin->type, + ssh2_pkt_type(s->bpp.pls->kctx, s->bpp.pls->actx, + s->pktin->type), + get_ptr(s->pktin), get_avail(s->pktin), nblanks, blanks, + &s->pktin->sequence, 0, NULL); + } + + pq_push(s->bpp.in_pq, s->pktin); + + { + int type = s->pktin->type; + s->pktin = NULL; + + if (type == SSH2_MSG_DISCONNECT) + s->bpp.seen_disconnect = TRUE; + if (type == SSH2_MSG_NEWKEYS) { + /* + * Mild layer violation: in this situation we must + * suspend processing of the input byte stream until + * the transport layer has initialised the new keys by + * calling ssh2_bpp_new_incoming_crypto above. + */ + s->pending_newkeys = TRUE; + crWaitUntilV(!s->pending_newkeys); + } + } + } + crFinishV; +} + +int ssh2_bpp_temporarily_disable_compression(BinaryPacketProtocol *bpp) +{ + struct ssh2_bpp_state *s; + assert(bpp->vt == &ssh2_bpp_vtable); + s = FROMFIELD(bpp, struct ssh2_bpp_state, bpp); + + if (!s->out.comp || !s->out.comp_ctx) + return 0; + + return s->out.comp->disable_compression(s->out.comp_ctx); +} + +static PktOut *ssh2_bpp_new_pktout(int pkt_type) +{ + PktOut *pkt = ssh_new_packet(); + pkt->length = 5; /* space for packet length + padding length */ + pkt->forcepad = 0; + pkt->type = pkt_type; + put_byte(pkt, pkt_type); + pkt->prefix = pkt->length; + return pkt; +} + +static void ssh2_bpp_format_packet(BinaryPacketProtocol *bpp, PktOut *pkt) +{ + struct ssh2_bpp_state *s = FROMFIELD(bpp, struct ssh2_bpp_state, bpp); + int origlen, cipherblk, maclen, padding, unencrypted_prefix, i; + + if (s->bpp.logctx) { + ptrlen pktdata = make_ptrlen(pkt->data + pkt->prefix, + pkt->length - pkt->prefix); + logblank_t blanks[MAX_BLANKS]; + int nblanks = ssh2_censor_packet( + s->bpp.pls, pkt->type, TRUE, pktdata, blanks); + log_packet(s->bpp.logctx, PKT_OUTGOING, pkt->type, + ssh2_pkt_type(s->bpp.pls->kctx, s->bpp.pls->actx, + pkt->type), + pktdata.ptr, pktdata.len, nblanks, blanks, &s->out.sequence, + pkt->downstream_id, pkt->additional_log_text); + } + + /* + * Compress packet payload. + */ + { + unsigned char *newpayload; + int newlen; + if (s->out.comp && s->out.comp->compress( + s->out.comp_ctx, pkt->data + 5, pkt->length - 5, + &newpayload, &newlen)) { + pkt->length = 5; + put_data(pkt, newpayload, newlen); + sfree(newpayload); + } + } + + /* + * Add padding. At least four bytes, and must also bring total + * length (minus MAC) up to a multiple of the block size. + * If pkt->forcepad is set, make sure the packet is at least that size + * after padding. + */ + cipherblk = s->out.cipher ? s->out.cipher->blksize : 8; + cipherblk = cipherblk < 8 ? 8 : cipherblk; /* or 8 if blksize < 8 */ + padding = 4; + unencrypted_prefix = (s->out.mac && s->out.etm_mode) ? 4 : 0; + if (pkt->length + padding < pkt->forcepad) + padding = pkt->forcepad - pkt->length; + padding += + (cipherblk - (pkt->length - unencrypted_prefix + padding) % cipherblk) + % cipherblk; + assert(padding <= 255); + maclen = s->out.mac ? s->out.mac->len : 0; + origlen = pkt->length; + for (i = 0; i < padding; i++) + put_byte(pkt, random_byte()); + pkt->data[4] = padding; + PUT_32BIT(pkt->data, origlen + padding - 4); + + /* Encrypt length if the scheme requires it */ + if (s->out.cipher && + (s->out.cipher->flags & SSH_CIPHER_SEPARATE_LENGTH)) { + s->out.cipher->encrypt_length(s->out.cipher_ctx, pkt->data, 4, + s->out.sequence); + } + + put_padding(pkt, 0, maclen); + + if (s->out.mac && s->out.etm_mode) { + /* + * OpenSSH-defined encrypt-then-MAC protocol. + */ + if (s->out.cipher) + s->out.cipher->encrypt(s->out.cipher_ctx, + pkt->data + 4, origlen + padding - 4); + s->out.mac->generate(s->out.mac_ctx, pkt->data, origlen + padding, + s->out.sequence); + } else { + /* + * SSH-2 standard protocol. + */ + if (s->out.mac) + s->out.mac->generate( + s->out.mac_ctx, pkt->data, origlen + padding, + s->out.sequence); + if (s->out.cipher) + s->out.cipher->encrypt(s->out.cipher_ctx, + pkt->data, origlen + padding); + } + + s->out.sequence++; /* whether or not we MACed */ + pkt->encrypted_len = origlen + padding; + + bufchain_add(s->bpp.out_raw, pkt->data, pkt->length); +} diff --git a/ssh2censor.c b/ssh2censor.c new file mode 100644 index 00000000..3d13589d --- /dev/null +++ b/ssh2censor.c @@ -0,0 +1,107 @@ +/* + * Packet-censoring code for SSH-2, used to identify sensitive fields + * like passwords so that the logging system can avoid writing them + * into log files. + */ + +#include + +#include "putty.h" +#include "ssh.h" + +int ssh2_censor_packet( + const PacketLogSettings *pls, int type, int sender_is_client, + ptrlen pkt, logblank_t *blanks) +{ + int nblanks = 0; + ptrlen str; + BinarySource src[1]; + + BinarySource_BARE_INIT(src, pkt.ptr, pkt.len); + + if (pls->omit_data && + (type == SSH2_MSG_CHANNEL_DATA || + type == SSH2_MSG_CHANNEL_EXTENDED_DATA)) { + /* "Session data" packets - omit the data string. */ + get_uint32(src); /* skip channel id */ + if (type == SSH2_MSG_CHANNEL_EXTENDED_DATA) + get_uint32(src); /* skip extended data type */ + str = get_string(src); + if (!get_err(src)) { + assert(nblanks < MAX_BLANKS); + blanks[nblanks].offset = src->pos - str.len; + blanks[nblanks].type = PKTLOG_OMIT; + blanks[nblanks].len = str.len; + nblanks++; + } + } + + if (sender_is_client && pls->omit_passwords) { + if (type == SSH2_MSG_USERAUTH_REQUEST) { + /* If this is a password packet, blank the password(s). */ + get_string(src); /* username */ + get_string(src); /* service name */ + str = get_string(src); /* auth method */ + if (ptrlen_eq_string(str, "password")) { + get_bool(src); + /* Blank the password field. */ + str = get_string(src); + if (!get_err(src)) { + assert(nblanks < MAX_BLANKS); + blanks[nblanks].offset = src->pos - str.len; + blanks[nblanks].type = PKTLOG_BLANK; + blanks[nblanks].len = str.len; + nblanks++; + /* If there's another password field beyond it + * (change of password), blank that too. */ + str = get_string(src); + if (!get_err(src)) + blanks[nblanks-1].len = + src->pos - blanks[nblanks].offset; + } + } + } else if (pls->actx == SSH2_PKTCTX_KBDINTER && + type == SSH2_MSG_USERAUTH_INFO_RESPONSE) { + /* If this is a keyboard-interactive response packet, + * blank the responses. */ + get_uint32(src); + assert(nblanks < MAX_BLANKS); + blanks[nblanks].offset = src->pos; + blanks[nblanks].type = PKTLOG_BLANK; + do { + str = get_string(src); + } while (!get_err(src)); + blanks[nblanks].len = src->pos - blanks[nblanks].offset; + nblanks++; + } else if (type == SSH2_MSG_CHANNEL_REQUEST) { + /* + * If this is an X forwarding request packet, blank the + * fake auth data. + * + * Note that while we blank the X authentication data + * here, we don't take any special action to blank the + * start of an X11 channel, so using MIT-MAGIC-COOKIE-1 + * and actually opening an X connection without having + * session blanking enabled is likely to leak your cookie + * into the log. + */ + get_uint32(src); + str = get_string(src); + if (ptrlen_eq_string(str, "x11-req")) { + get_bool(src); + get_bool(src); + get_string(src); + str = get_string(src); + if (!get_err(src)) { + assert(nblanks < MAX_BLANKS); + blanks[nblanks].offset = src->pos - str.len; + blanks[nblanks].type = PKTLOG_BLANK; + blanks[nblanks].len = str.len; + nblanks++; + } + } + } + } + + return nblanks; +} diff --git a/sshbpp.h b/sshbpp.h new file mode 100644 index 00000000..cf1a528d --- /dev/null +++ b/sshbpp.h @@ -0,0 +1,54 @@ +/* + * Abstraction of the binary packet protocols used in SSH. + */ + +#ifndef PUTTY_SSHBPP_H +#define PUTTY_SSHBPP_H + +typedef struct BinaryPacketProtocol BinaryPacketProtocol; + +struct BinaryPacketProtocolVtable { + void (*free)(BinaryPacketProtocol *); + void (*handle_input)(BinaryPacketProtocol *); + PktOut *(*new_pktout)(int type); + void (*format_packet)(BinaryPacketProtocol *, PktOut *); +}; + +struct BinaryPacketProtocol { + const struct BinaryPacketProtocolVtable *vt; + bufchain *in_raw, *out_raw; + PacketQueue *in_pq; + PacketLogSettings *pls; + void *logctx; + + int seen_disconnect; + char *error; +}; + +#define ssh_bpp_free(bpp) ((bpp)->vt->free(bpp)) +#define ssh_bpp_handle_input(bpp) ((bpp)->vt->handle_input(bpp)) +#define ssh_bpp_new_pktout(bpp, type) ((bpp)->vt->new_pktout(type)) +#define ssh_bpp_format_packet(bpp, pkt) ((bpp)->vt->format_packet(bpp, pkt)) + +BinaryPacketProtocol *ssh1_bpp_new(void); +void ssh1_bpp_new_cipher(BinaryPacketProtocol *bpp, + const struct ssh_cipher *cipher, + const void *session_key); +void ssh1_bpp_start_compression(BinaryPacketProtocol *bpp); + +BinaryPacketProtocol *ssh2_bpp_new(void); +void ssh2_bpp_new_outgoing_crypto( + BinaryPacketProtocol *bpp, + const struct ssh2_cipher *cipher, const void *ckey, const void *iv, + const struct ssh_mac *mac, int etm_mode, const void *mac_key, + const struct ssh_compress *compression); +void ssh2_bpp_new_incoming_crypto( + BinaryPacketProtocol *bpp, + const struct ssh2_cipher *cipher, const void *ckey, const void *iv, + const struct ssh_mac *mac, int etm_mode, const void *mac_key, + const struct ssh_compress *compression); +int ssh2_bpp_temporarily_disable_compression(BinaryPacketProtocol *bpp); + +BinaryPacketProtocol *ssh2_bare_bpp_new(void); + +#endif /* PUTTY_SSHBPP_H */ From 93afcf02af7a68d736b487d9665aca741a3d5e0b Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 9 Jun 2018 09:59:58 +0100 Subject: [PATCH 373/607] Remove the SSH-1 variadic send_packet() system. Now we have the new marshalling system, I think it's outlived its usefulness, because the new system allows us to directly express various things (e.g. uint16 and non-zero-terminated strings) that were actually _more_ awkward to do via the variadic interface. So here's a rewrite that removes send_packet(), and replaces all its call sites with something that matches our SSH-2 packet construction idioms. This diff actually _reduces_ the number of lines of code in ssh.c. Since the variadic system was trying to save code by centralising things, that seems like the best possible evidence that it wasn't pulling its weight! --- ssh.c | 340 ++++++++++++++++++++++++++-------------------------------- 1 file changed, 153 insertions(+), 187 deletions(-) diff --git a/ssh.c b/ssh.c index 919b2321..9f8d0314 100644 --- a/ssh.c +++ b/ssh.c @@ -1203,53 +1203,6 @@ static int s_write(Ssh ssh, const void *data, int len) return sk_write(ssh->s, data, len); } -/* - * Construct a SSH-1 packet with the specified contents. - * (This all-at-once interface used to be the only one, but now SSH-1 - * packets can also be constructed incrementally.) - */ -static PktOut *construct_packet(Ssh ssh, int pkttype, va_list ap) -{ - int argtype; - Bignum bn; - PktOut *pkt; - - pkt = ssh_bpp_new_pktout(ssh->bpp, pkttype); - - while ((argtype = va_arg(ap, int)) != PKT_END) { - unsigned char *argp, argchar; - char *sargp; - unsigned long argint; - int arglen; - switch (argtype) { - /* Actual fields in the packet */ - case PKT_INT: - argint = va_arg(ap, int); - put_uint32(pkt, argint); - break; - case PKT_CHAR: - argchar = (unsigned char) va_arg(ap, int); - put_byte(pkt, argchar); - break; - case PKT_DATA: - argp = va_arg(ap, unsigned char *); - arglen = va_arg(ap, int); - put_data(pkt, argp, arglen); - break; - case PKT_STR: - sargp = va_arg(ap, char *); - put_stringz(pkt, sargp); - break; - case PKT_BIGNUM: - bn = va_arg(ap, Bignum); - put_mp_ssh1(pkt, bn); - break; - } - } - - return pkt; -} - static void ssh_pkt_write(Ssh ssh, PktOut *pkt) { if (ssh->version == 2 && ssh->v2_cbc_ignore_workaround && @@ -1270,16 +1223,6 @@ static void ssh_pkt_write(Ssh ssh, PktOut *pkt) queue_idempotent_callback(&ssh->outgoing_data_sender); } -static void send_packet(Ssh ssh, int pkttype, ...) -{ - PktOut *pkt; - va_list ap; - va_start(ap, pkttype); - pkt = construct_packet(ssh, pkttype, ap); - va_end(ap); - ssh_pkt_write(ssh, pkt); -} - static int ssh_versioncmp(const char *a, const char *b) { char *ae, *be; @@ -2773,8 +2716,9 @@ static void ssh_disconnect(Ssh ssh, const char *client_reason, error = dupstr("Disconnected"); if (wire_reason) { if (ssh->version == 1) { - send_packet(ssh, SSH1_MSG_DISCONNECT, PKT_STR, wire_reason, - PKT_END); + PktOut *pktout = ssh_bpp_new_pktout(ssh->bpp, SSH1_MSG_DISCONNECT); + put_stringz(pktout, wire_reason); + ssh_pkt_write(ssh, pktout); } else if (ssh->version == 2) { PktOut *pktout = ssh_bpp_new_pktout(ssh->bpp, SSH2_MSG_DISCONNECT); put_uint32(pktout, code); @@ -2853,6 +2797,7 @@ static void do_ssh1_login(void *vctx) { Ssh ssh = (Ssh)vctx; PktIn *pktin; + PktOut *pkt; int i, j, ret; ptrlen pl; @@ -3096,12 +3041,13 @@ static void do_ssh1_login(void *vctx) break; } - send_packet(ssh, SSH1_CMSG_SESSION_KEY, - PKT_CHAR, s->cipher_type, - PKT_DATA, s->cookie, 8, - PKT_CHAR, (s->len * 8) >> 8, PKT_CHAR, (s->len * 8) & 0xFF, - PKT_DATA, s->rsabuf, s->len, - PKT_INT, ssh->v1_local_protoflags, PKT_END); + pkt = ssh_bpp_new_pktout(ssh->bpp, SSH1_CMSG_SESSION_KEY); + put_byte(pkt, s->cipher_type); + put_data(pkt, s->cookie, 8); + put_uint16(pkt, s->len * 8); + put_data(pkt, s->rsabuf, s->len); + put_uint32(pkt, ssh->v1_local_protoflags); + ssh_pkt_write(ssh, pkt); logevent("Trying to enable encryption..."); @@ -3173,7 +3119,10 @@ static void do_ssh1_login(void *vctx) free_prompts(s->cur_prompt); } - send_packet(ssh, SSH1_CMSG_USER, PKT_STR, ssh->username, PKT_END); + pkt = ssh_bpp_new_pktout(ssh->bpp, SSH1_CMSG_USER); + put_stringz(pkt, ssh->username); + ssh_pkt_write(ssh, pkt); + { char *userlog = dupprintf("Sent username \"%s\"", ssh->username); logevent(userlog); @@ -3305,8 +3254,9 @@ static void do_ssh1_login(void *vctx) continue; } logeventf(ssh, "Trying Pageant key #%d", s->keyi); - send_packet(ssh, SSH1_CMSG_AUTH_RSA, - PKT_BIGNUM, s->key.modulus, PKT_END); + pkt = ssh_bpp_new_pktout(ssh->bpp, SSH1_CMSG_AUTH_RSA); + put_mp_ssh1(pkt, s->key.modulus); + ssh_pkt_write(ssh, pkt); crMaybeWaitUntilV((pktin = pq_pop(&ssh->pq_ssh1_login)) != NULL); if (pktin->type != SSH1_SMSG_AUTH_RSA_CHALLENGE) { @@ -3351,9 +3301,10 @@ static void do_ssh1_login(void *vctx) if (ret) { if (ret[4] == SSH1_AGENT_RSA_RESPONSE) { logevent("Sending Pageant's response"); - send_packet(ssh, SSH1_CMSG_AUTH_RSA_RESPONSE, - PKT_DATA, ret + 5, 16, - PKT_END); + pkt = ssh_bpp_new_pktout(ssh->bpp, + SSH1_CMSG_AUTH_RSA_RESPONSE); + put_data(pkt, ret + 5, 16); + ssh_pkt_write(ssh, pkt); sfree(ret); crMaybeWaitUntilV( (pktin = pq_pop(&ssh->pq_ssh1_login)) @@ -3487,8 +3438,9 @@ static void do_ssh1_login(void *vctx) /* * Send a public key attempt. */ - send_packet(ssh, SSH1_CMSG_AUTH_RSA, - PKT_BIGNUM, s->key.modulus, PKT_END); + pkt = ssh_bpp_new_pktout(ssh->bpp, SSH1_CMSG_AUTH_RSA); + put_mp_ssh1(pkt, s->key.modulus); + ssh_pkt_write(ssh, pkt); crMaybeWaitUntilV((pktin = pq_pop(&ssh->pq_ssh1_login)) != NULL); @@ -3524,8 +3476,10 @@ static void do_ssh1_login(void *vctx) put_data(&md5c, s->session_id, 16); MD5Final(buffer, &md5c); - send_packet(ssh, SSH1_CMSG_AUTH_RSA_RESPONSE, - PKT_DATA, buffer, 16, PKT_END); + pkt = ssh_bpp_new_pktout( + ssh->bpp, SSH1_CMSG_AUTH_RSA_RESPONSE); + put_data(pkt, buffer, 16); + ssh_pkt_write(ssh, pkt); freebn(challenge); freebn(response); @@ -3558,7 +3512,8 @@ static void do_ssh1_login(void *vctx) !s->tis_auth_refused) { s->pwpkt_type = SSH1_CMSG_AUTH_TIS_RESPONSE; logevent("Requested TIS authentication"); - send_packet(ssh, SSH1_CMSG_AUTH_TIS, PKT_END); + pkt = ssh_bpp_new_pktout(ssh->bpp, SSH1_CMSG_AUTH_TIS); + ssh_pkt_write(ssh, pkt); crMaybeWaitUntilV((pktin = pq_pop(&ssh->pq_ssh1_login)) != NULL); if (pktin->type != SSH1_SMSG_AUTH_TIS_CHALLENGE) { logevent("TIS authentication declined"); @@ -3600,7 +3555,8 @@ static void do_ssh1_login(void *vctx) !s->ccard_auth_refused) { s->pwpkt_type = SSH1_CMSG_AUTH_CCARD_RESPONSE; logevent("Requested CryptoCard authentication"); - send_packet(ssh, SSH1_CMSG_AUTH_CCARD, PKT_END); + pkt = ssh_bpp_new_pktout(ssh->bpp, SSH1_CMSG_AUTH_CCARD); + ssh_pkt_write(ssh, pkt); crMaybeWaitUntilV((pktin = pq_pop(&ssh->pq_ssh1_login)) != NULL); if (pktin->type != SSH1_SMSG_AUTH_CCARD_CHALLENGE) { logevent("CryptoCard authentication declined"); @@ -3724,7 +3680,6 @@ static void do_ssh1_login(void *vctx) * we can use the primary defence. */ int bottom, top, pwlen, i; - char *randomstr; pwlen = strlen(s->cur_prompt->prompts[0]->result); if (pwlen < 16) { @@ -3737,26 +3692,22 @@ static void do_ssh1_login(void *vctx) assert(pwlen >= bottom && pwlen <= top); - randomstr = snewn(top + 1, char); - for (i = bottom; i <= top; i++) { if (i == pwlen) { - send_packet(ssh, s->pwpkt_type, - PKT_STR, s->cur_prompt->prompts[0]->result, - PKT_END); + pkt = ssh_bpp_new_pktout(ssh->bpp, s->pwpkt_type); + put_stringz(pkt, s->cur_prompt->prompts[0]->result); + ssh_pkt_write(ssh, pkt); } else { - for (j = 0; j < i; j++) { - do { - randomstr[j] = random_byte(); - } while (randomstr[j] == '\0'); - } - randomstr[i] = '\0'; - send_packet(ssh, SSH1_MSG_IGNORE, - PKT_STR, randomstr, PKT_END); + strbuf *random_data = strbuf_new(); + for (j = 0; j < i; j++) + put_byte(random_data, random_byte()); + + pkt = ssh_bpp_new_pktout(ssh->bpp, SSH1_MSG_IGNORE); + put_stringsb(pkt, random_data); + ssh_pkt_write(ssh, pkt); } } logevent("Sending password with camouflage packets"); - sfree(randomstr); } else if (!(ssh->remote_bugs & BUG_NEEDS_SSH1_PLAIN_PASSWORD)) { /* @@ -3764,42 +3715,30 @@ static void do_ssh1_login(void *vctx) * but can deal with padded passwords, so we * can use the secondary defence. */ - char string[64]; - char *ss; - int len; - - len = strlen(s->cur_prompt->prompts[0]->result); - if (len < sizeof(string)) { - ss = string; - strcpy(string, s->cur_prompt->prompts[0]->result); - len++; /* cover the zero byte */ - while (len < sizeof(string)) { - string[len++] = (char) random_byte(); - } - } else { - ss = s->cur_prompt->prompts[0]->result; - } + strbuf *padded_pw = strbuf_new(); + logevent("Sending length-padded password"); - send_packet(ssh, s->pwpkt_type, - PKT_INT, len, PKT_DATA, ss, len, - PKT_END); + pkt = ssh_bpp_new_pktout(ssh->bpp, s->pwpkt_type); + put_asciz(padded_pw, s->cur_prompt->prompts[0]->result); + do { + put_byte(padded_pw, random_byte()); + } while (padded_pw->len % 64 != 0); + put_stringsb(pkt, padded_pw); + ssh_pkt_write(ssh, pkt); } else { /* * The server is believed unable to cope with * any of our password camouflage methods. */ - int len; - len = strlen(s->cur_prompt->prompts[0]->result); logevent("Sending unpadded password"); - send_packet(ssh, s->pwpkt_type, - PKT_INT, len, - PKT_DATA, s->cur_prompt->prompts[0]->result, len, - PKT_END); + pkt = ssh_bpp_new_pktout(ssh->bpp, s->pwpkt_type); + put_stringz(pkt, s->cur_prompt->prompts[0]->result); + ssh_pkt_write(ssh, pkt); } } else { - send_packet(ssh, s->pwpkt_type, - PKT_STR, s->cur_prompt->prompts[0]->result, - PKT_END); + pkt = ssh_bpp_new_pktout(ssh->bpp, s->pwpkt_type); + put_stringz(pkt, s->cur_prompt->prompts[0]->result); + ssh_pkt_write(ssh, pkt); } logevent("Sent password"); free_prompts(s->cur_prompt); @@ -3838,6 +3777,7 @@ static void do_ssh1_login(void *vctx) static void ssh_channel_try_eof(struct ssh_channel *c) { Ssh ssh = c->ssh; + PktOut *pktout; assert(c->pending_eof); /* precondition for calling us */ if (c->halfopen) return; /* can't close: not even opened yet */ @@ -3846,11 +3786,11 @@ static void ssh_channel_try_eof(struct ssh_channel *c) c->pending_eof = FALSE; /* we're about to send it */ if (ssh->version == 1) { - send_packet(ssh, SSH1_MSG_CHANNEL_CLOSE, PKT_INT, c->remoteid, - PKT_END); + pktout = ssh_bpp_new_pktout(ssh->bpp, SSH1_MSG_CHANNEL_CLOSE); + put_uint32(pktout, c->remoteid); + ssh_pkt_write(ssh, pktout); c->closes |= CLOSES_SENT_EOF; } else { - PktOut *pktout; pktout = ssh_bpp_new_pktout(ssh->bpp, SSH2_MSG_CHANNEL_EOF); put_uint32(pktout, c->remoteid); ssh2_pkt_send(ssh, pktout); @@ -4339,6 +4279,8 @@ static void ssh_setup_portfwd(Ssh ssh, Conf *conf) epf->daddr, epf->dport); sfree(pf); } else { + PktOut *pktout; + logeventf(ssh, "Requesting remote port %s" " forward to %s", sportdesc, dportdesc); @@ -4348,16 +4290,16 @@ static void ssh_setup_portfwd(Ssh ssh, Conf *conf) pf->pfrec = epf; if (ssh->version == 1) { - send_packet(ssh, SSH1_CMSG_PORT_FORWARD_REQUEST, - PKT_INT, epf->sport, - PKT_STR, epf->daddr, - PKT_INT, epf->dport, - PKT_END); + pktout = ssh_bpp_new_pktout( + ssh->bpp, SSH1_CMSG_PORT_FORWARD_REQUEST); + put_uint32(pktout, epf->sport); + put_stringz(pktout, epf->daddr); + put_uint32(pktout, epf->dport); + ssh_pkt_write(ssh, pktout); ssh_queue_handler(ssh, SSH1_SMSG_SUCCESS, SSH1_SMSG_FAILURE, ssh_rportfwd_succfail, pf); } else { - PktOut *pktout; pktout = ssh_bpp_new_pktout( ssh->bpp, SSH2_MSG_GLOBAL_REQUEST); put_stringz(pktout, "tcpip-forward"); @@ -4401,13 +4343,15 @@ static void ssh1_smsg_x11_open(Ssh ssh, PktIn *pktin) /* Remote side is trying to open a channel to talk to our * X-Server. Give them back a local channel number. */ struct ssh_channel *c; + PktOut *pkt; int remoteid = get_uint32(pktin); logevent("Received X11 connect request"); /* Refuse if X11 forwarding is disabled. */ if (!ssh->X11_fwd_enabled) { - send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_FAILURE, - PKT_INT, remoteid, PKT_END); + pkt = ssh_bpp_new_pktout(ssh->bpp, SSH1_MSG_CHANNEL_OPEN_FAILURE); + put_uint32(pkt, remoteid); + ssh_pkt_write(ssh, pkt); logevent("Rejected X11 connect request"); } else { c = snew(struct ssh_channel); @@ -4418,9 +4362,10 @@ static void ssh1_smsg_x11_open(Ssh ssh, PktIn *pktin) c->remoteid = remoteid; c->halfopen = FALSE; c->type = CHAN_X11; /* identify channel type */ - send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_CONFIRMATION, - PKT_INT, c->remoteid, PKT_INT, - c->localid, PKT_END); + pkt = ssh_bpp_new_pktout(ssh->bpp, SSH1_MSG_CHANNEL_OPEN_CONFIRMATION); + put_uint32(pkt, c->remoteid); + put_uint32(pkt, c->localid); + ssh_pkt_write(ssh, pkt); logevent("Opened X11 forward channel"); } } @@ -4430,12 +4375,14 @@ static void ssh1_smsg_agent_open(Ssh ssh, PktIn *pktin) /* Remote side is trying to open a channel to talk to our * agent. Give them back a local channel number. */ struct ssh_channel *c; + PktOut *pkt; int remoteid = toint(get_uint32(pktin)); /* Refuse if agent forwarding is disabled. */ if (!ssh->agentfwd_enabled) { - send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_FAILURE, - PKT_INT, remoteid, PKT_END); + pkt = ssh_bpp_new_pktout(ssh->bpp, SSH1_MSG_CHANNEL_OPEN_FAILURE); + put_uint32(pkt, remoteid); + ssh_pkt_write(ssh, pkt); } else { c = snew(struct ssh_channel); c->ssh = ssh; @@ -4445,9 +4392,10 @@ static void ssh1_smsg_agent_open(Ssh ssh, PktIn *pktin) c->type = CHAN_AGENT; /* identify channel type */ c->u.a.pending = NULL; bufchain_init(&c->u.a.inbuffer); - send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_CONFIRMATION, - PKT_INT, c->remoteid, PKT_INT, c->localid, - PKT_END); + pkt = ssh_bpp_new_pktout(ssh->bpp, SSH1_MSG_CHANNEL_OPEN_CONFIRMATION); + put_uint32(pkt, c->remoteid); + put_uint32(pkt, c->localid); + ssh_pkt_write(ssh, pkt); } } @@ -4456,6 +4404,7 @@ static void ssh1_msg_port_open(Ssh ssh, PktIn *pktin) /* Remote side is trying to open a channel to talk to a * forwarded port. Give them back a local channel number. */ struct ssh_rportfwd pf, *pfp; + PktOut *pkt; int remoteid; int port; ptrlen host; @@ -4472,8 +4421,9 @@ static void ssh1_msg_port_open(Ssh ssh, PktIn *pktin) if (pfp == NULL) { logeventf(ssh, "Rejected remote port open request for %s:%d", pf.dhost, port); - send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_FAILURE, - PKT_INT, remoteid, PKT_END); + pkt = ssh_bpp_new_pktout(ssh->bpp, SSH1_MSG_CHANNEL_OPEN_FAILURE); + put_uint32(pkt, remoteid); + ssh_pkt_write(ssh, pkt); } else { struct ssh_channel *c = snew(struct ssh_channel); c->ssh = ssh; @@ -4486,16 +4436,19 @@ static void ssh1_msg_port_open(Ssh ssh, PktIn *pktin) logeventf(ssh, "Port open failed: %s", err); sfree(err); sfree(c); - send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_FAILURE, - PKT_INT, remoteid, PKT_END); + pkt = ssh_bpp_new_pktout(ssh->bpp, SSH1_MSG_CHANNEL_OPEN_FAILURE); + put_uint32(pkt, remoteid); + ssh_pkt_write(ssh, pkt); } else { ssh_channel_init(c); c->remoteid = remoteid; c->halfopen = FALSE; c->type = CHAN_SOCKDATA; /* identify channel type */ - send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_CONFIRMATION, - PKT_INT, c->remoteid, PKT_INT, - c->localid, PKT_END); + pkt = ssh_bpp_new_pktout( + ssh->bpp, SSH1_MSG_CHANNEL_OPEN_CONFIRMATION); + put_uint32(pkt, c->remoteid); + put_uint32(pkt, c->localid); + ssh_pkt_write(ssh, pkt); logevent("Forwarded port opened successfully"); } } @@ -4569,8 +4522,10 @@ static void ssh1_msg_channel_close(Ssh ssh, PktIn *pktin) if (!((CLOSES_SENT_EOF | CLOSES_RCVD_EOF) & ~c->closes) && !(c->closes & CLOSES_SENT_CLOSE)) { - send_packet(ssh, SSH1_MSG_CHANNEL_CLOSE_CONFIRMATION, - PKT_INT, c->remoteid, PKT_END); + PktOut *pkt = ssh_bpp_new_pktout( + ssh->bpp, SSH1_MSG_CHANNEL_CLOSE_CONFIRMATION); + put_uint32(pkt, c->remoteid); + ssh_pkt_write(ssh, pkt); c->closes |= CLOSES_SENT_CLOSE; } @@ -4635,9 +4590,11 @@ static void ssh1_msg_channel_data(Ssh ssh, PktIn *pktin) static void ssh1_smsg_exit_status(Ssh ssh, PktIn *pktin) { + PktOut *pkt; ssh->exitcode = get_uint32(pktin); logeventf(ssh, "Server sent command exit status %d", ssh->exitcode); - send_packet(ssh, SSH1_CMSG_EXIT_CONFIRMATION, PKT_END); + pkt = ssh_bpp_new_pktout(ssh->bpp, SSH1_CMSG_EXIT_CONFIRMATION); + ssh_pkt_write(ssh, pkt); /* * In case `helpful' firewalls or proxies tack * extra human-readable text on the end of the @@ -4673,6 +4630,7 @@ static void do_ssh1_connection(void *vctx) { Ssh ssh = (Ssh)vctx; PktIn *pktin; + PktOut *pkt; crBegin(ssh->do_ssh1_connection_crstate); @@ -4692,7 +4650,8 @@ static void do_ssh1_connection(void *vctx) if (ssh_agent_forwarding_permitted(ssh)) { logevent("Requesting agent forwarding"); - send_packet(ssh, SSH1_CMSG_AGENT_REQUEST_FORWARDING, PKT_END); + pkt = ssh_bpp_new_pktout(ssh->bpp, SSH1_CMSG_AGENT_REQUEST_FORWARDING); + ssh_pkt_write(ssh, pkt); crMaybeWaitUntilV((pktin = pq_pop(&ssh->pq_ssh1_connection)) != NULL); if (pktin->type != SSH1_SMSG_SUCCESS && pktin->type != SSH1_SMSG_FAILURE) { @@ -4721,18 +4680,13 @@ static void do_ssh1_connection(void *vctx) ssh->x11auth->disp = ssh->x11disp; logevent("Requesting X11 forwarding"); - if (ssh->v1_local_protoflags & SSH1_PROTOFLAG_SCREEN_NUMBER) { - send_packet(ssh, SSH1_CMSG_X11_REQUEST_FORWARDING, - PKT_STR, ssh->x11auth->protoname, - PKT_STR, ssh->x11auth->datastring, - PKT_INT, ssh->x11disp->screennum, - PKT_END); - } else { - send_packet(ssh, SSH1_CMSG_X11_REQUEST_FORWARDING, - PKT_STR, ssh->x11auth->protoname, - PKT_STR, ssh->x11auth->datastring, - PKT_END); - } + pkt = ssh_bpp_new_pktout( + ssh->bpp, SSH1_CMSG_X11_REQUEST_FORWARDING); + put_stringz(pkt, ssh->x11auth->protoname); + put_stringz(pkt, ssh->x11auth->datastring); + if (ssh->v1_local_protoflags & SSH1_PROTOFLAG_SCREEN_NUMBER) + put_uint32(pkt, ssh->x11disp->screennum); + ssh_pkt_write(ssh, pkt); crMaybeWaitUntilV((pktin = pq_pop(&ssh->pq_ssh1_connection)) != NULL); if (pktin->type != SSH1_SMSG_SUCCESS @@ -4791,7 +4745,9 @@ static void do_ssh1_connection(void *vctx) } if (conf_get_int(ssh->conf, CONF_compression)) { - send_packet(ssh, SSH1_CMSG_REQUEST_COMPRESSION, PKT_INT, 6, PKT_END); + pkt = ssh_bpp_new_pktout(ssh->bpp, SSH1_CMSG_REQUEST_COMPRESSION); + put_uint32(pkt, 6); /* gzip compression level */ + ssh_pkt_write(ssh, pkt); crMaybeWaitUntilV((pktin = pq_pop(&ssh->pq_ssh1_connection)) != NULL); if (pktin->type != SSH1_SMSG_SUCCESS && pktin->type != SSH1_SMSG_FAILURE) { @@ -4819,10 +4775,14 @@ static void do_ssh1_connection(void *vctx) cmd = conf_get_str(ssh->conf, CONF_remote_cmd2); ssh->fallback_cmd = TRUE; } - if (*cmd) - send_packet(ssh, SSH1_CMSG_EXEC_CMD, PKT_STR, cmd, PKT_END); - else - send_packet(ssh, SSH1_CMSG_EXEC_SHELL, PKT_END); + if (*cmd) { + pkt = ssh_bpp_new_pktout(ssh->bpp, SSH1_CMSG_EXEC_CMD); + put_stringz(pkt, cmd); + ssh_pkt_write(ssh, pkt); + } else { + pkt = ssh_bpp_new_pktout(ssh->bpp, SSH1_CMSG_EXEC_SHELL); + ssh_pkt_write(ssh, pkt); + } logevent("Started session"); } @@ -4861,9 +4821,9 @@ static void do_ssh1_connection(void *vctx) bufchain_prefix(&ssh->user_input, &data, &len); if (len > 512) len = 512; - send_packet(ssh, SSH1_CMSG_STDIN_DATA, - PKT_INT, len, PKT_DATA, data, len, - PKT_END); + pkt = ssh_bpp_new_pktout(ssh->bpp, SSH1_CMSG_STDIN_DATA); + put_string(pkt, data, len); + ssh_pkt_write(ssh, pkt); bufchain_consume(&ssh->user_input, len); } crReturnV; @@ -7037,11 +6997,10 @@ static int ssh_send_channel_data(struct ssh_channel *c, const char *buf, bufchain_add(&c->v.v2.outbuffer, buf, len); return ssh2_try_send(c); } else { - send_packet(c->ssh, SSH1_MSG_CHANNEL_DATA, - PKT_INT, c->remoteid, - PKT_INT, len, - PKT_DATA, buf, len, - PKT_END); + PktOut *pkt = ssh_bpp_new_pktout(c->ssh->bpp, SSH1_MSG_CHANNEL_DATA); + put_uint32(pkt, c->remoteid); + put_string(pkt, buf, len); + ssh_pkt_write(c->ssh, pkt); /* * In SSH-1 we can return 0 here - implying that channels are * never individually throttled - because the only @@ -11164,10 +11123,12 @@ static void ssh_size(void *handle, int width, int height) case SSH_STATE_SESSION: if (!conf_get_int(ssh->conf, CONF_nopty)) { if (ssh->version == 1) { - send_packet(ssh, SSH1_CMSG_WINDOW_SIZE, - PKT_INT, ssh->term_height, - PKT_INT, ssh->term_width, - PKT_INT, 0, PKT_INT, 0, PKT_END); + pktout = ssh_bpp_new_pktout(ssh->bpp, SSH1_CMSG_WINDOW_SIZE); + put_uint32(pktout, ssh->term_height); + put_uint32(pktout, ssh->term_width); + put_uint32(pktout, 0); + put_uint32(pktout, 0); + ssh_pkt_write(ssh, pktout); } else if (ssh->mainchan) { pktout = ssh2_chanreq_init(ssh->mainchan, "window-change", NULL, NULL); @@ -11308,7 +11269,8 @@ static void ssh_special(void *handle, Telnet_Special code) return; } if (ssh->version == 1) { - send_packet(ssh, SSH1_CMSG_EOF, PKT_END); + pktout = ssh_bpp_new_pktout(ssh->bpp, SSH1_CMSG_EOF); + ssh_pkt_write(ssh, pktout); } else if (ssh->mainchan) { sshfwd_write_eof(ssh->mainchan); ssh->send_ok = 0; /* now stop trying to read from stdin */ @@ -11318,8 +11280,11 @@ static void ssh_special(void *handle, Telnet_Special code) if (ssh->state == SSH_STATE_CLOSED || ssh->state == SSH_STATE_PREPACKET) return; if (ssh->version == 1) { - if (!(ssh->remote_bugs & BUG_CHOKES_ON_SSH1_IGNORE)) - send_packet(ssh, SSH1_MSG_IGNORE, PKT_STR, "", PKT_END); + if (!(ssh->remote_bugs & BUG_CHOKES_ON_SSH1_IGNORE)) { + pktout = ssh_bpp_new_pktout(ssh->bpp, SSH1_MSG_IGNORE); + put_stringz(pktout, ""); + ssh_pkt_write(ssh, pktout); + } } else { if (!(ssh->remote_bugs & BUG_CHOKES_ON_SSH2_IGNORE)) { pktout = ssh_bpp_new_pktout(ssh->bpp, SSH2_MSG_IGNORE); @@ -11468,12 +11433,13 @@ void ssh_send_port_open(void *channel, const char *hostname, int port, logeventf(ssh, "Opening connection to %s:%d for %s", hostname, port, org); if (ssh->version == 1) { - send_packet(ssh, SSH1_MSG_PORT_OPEN, - PKT_INT, c->localid, - PKT_STR, hostname, - PKT_INT, port, - /* PKT_STR, , */ - PKT_END); + pktout = ssh_bpp_new_pktout(ssh->bpp, SSH1_MSG_PORT_OPEN); + put_uint32(pktout, c->localid); + put_stringz(pktout, hostname); + put_uint32(pktout, port); + /* originator string would go here, but we didn't specify + * SSH_PROTOFLAG_HOST_IN_FWD_OPEN */ + ssh_pkt_write(ssh, pktout); } else { pktout = ssh2_chanopen_init(c, "direct-tcpip"); { From 281d317ab9f37210b9340cce6d7725cf7c9acf27 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Wed, 13 Jun 2018 19:42:19 +0100 Subject: [PATCH 374/607] Make put_padding() have a consistent argument order. Thanks to Alex Landau for pointing out that commit 8b98fea4a introduced two uses of it with the arguments one way round and one with them the other way round. (Plus a fourth use where it doesn't matter, because the padding at the end of the encrypted blob of an OpenSSH PEM private key consists of n bytes with value n. :-) On the basis of majority vote, I've switched the order in the function definition to match the two of the three call sites that expressed the same opinion, and fixed the third. --- marshal.c | 2 +- marshal.h | 6 +++--- ssh2bpp.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/marshal.c b/marshal.c index a8371b66..f0612a85 100644 --- a/marshal.c +++ b/marshal.c @@ -11,7 +11,7 @@ void BinarySink_put_data(BinarySink *bs, const void *data, size_t len) bs->write(bs, data, len); } -void BinarySink_put_padding(BinarySink *bs, unsigned char padbyte, size_t len) +void BinarySink_put_padding(BinarySink *bs, size_t len, unsigned char padbyte) { char buf[16]; memset(buf, padbyte, sizeof(buf)); diff --git a/marshal.h b/marshal.h index 0debe82f..2aa0301a 100644 --- a/marshal.h +++ b/marshal.h @@ -111,8 +111,8 @@ struct BinarySink { BinarySink_put_mp_ssh2(BinarySink_UPCAST(bs), val) /* Padding with a specified byte. */ -#define put_padding(bs, padbyte, len) \ - BinarySink_put_padding(BinarySink_UPCAST(bs), padbyte, len) +#define put_padding(bs, len, padbyte) \ + BinarySink_put_padding(BinarySink_UPCAST(bs), len, padbyte) /* Fallback: just emit raw data bytes, using a syntax that matches the * rest of these macros. */ @@ -130,7 +130,7 @@ struct BinarySink { * declaration(s) of their other parameter type(s) are in scope. */ void BinarySink_put_data(BinarySink *, const void *data, size_t len); -void BinarySink_put_padding(BinarySink *, unsigned char padbyte, size_t len); +void BinarySink_put_padding(BinarySink *, size_t len, unsigned char padbyte); void BinarySink_put_byte(BinarySink *, unsigned char); void BinarySink_put_bool(BinarySink *, int); void BinarySink_put_uint16(BinarySink *, unsigned long); diff --git a/ssh2bpp.c b/ssh2bpp.c index da0ac900..0ea1f793 100644 --- a/ssh2bpp.c +++ b/ssh2bpp.c @@ -582,7 +582,7 @@ static void ssh2_bpp_format_packet(BinaryPacketProtocol *bpp, PktOut *pkt) s->out.sequence); } - put_padding(pkt, 0, maclen); + put_padding(pkt, maclen, 0); if (s->out.mac && s->out.etm_mode) { /* From ba5e56cd1b448ac7d97e2d8d7cb9eafab66a45b9 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Wed, 13 Jun 2018 19:44:44 +0100 Subject: [PATCH 375/607] Add a missing check of outgoing_data. When the whole SSH connection is throttled and then unthrottled, we need to requeue the callback that transfers data to the Socket from the new outgoing_data queue introduced in commit 9e3522a97. The user-visible effect of this missing call was that outgoing SFTP transactions would lock up, because in SFTP mode we enable the "simple@putty.projects.tartarus.org" mode and essentially turn off the per-channel window management, so throttling of the whole connection becomes the main source of back-pressure. --- ssh.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/ssh.c b/ssh.c index 9f8d0314..7df6b509 100644 --- a/ssh.c +++ b/ssh.c @@ -2310,11 +2310,14 @@ static void ssh_sent(Plug plug, int bufsize) { Ssh ssh = FROMFIELD(plug, struct ssh_tag, plugvt); /* - * If the send backlog on the SSH socket itself clears, we - * should unthrottle the whole world if it was throttled. + * If the send backlog on the SSH socket itself clears, we should + * unthrottle the whole world if it was throttled, and also resume + * sending our bufchain of queued wire data. */ - if (bufsize < SSH_MAX_BACKLOG) + if (bufsize < SSH_MAX_BACKLOG) { ssh_throttle_all(ssh, 0, bufsize); + queue_idempotent_callback(&ssh->outgoing_data_sender); + } } static void ssh_hostport_setup(const char *host, int port, Conf *conf, From d4304f1b7b3f5e4c02f373977f9f7fe172d4f5fd Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Fri, 15 Jun 2018 19:08:05 +0100 Subject: [PATCH 376/607] Fix cut and paste goof in SSH-2 compression support. The new SSH-2 BPP has two functions ssh2_bpp_new_outgoing_crypto and ssh2_bpp_new_incoming_crypto, which (due to general symmetry) are _almost_ identical, except that the code that sets up the compression context in the two directions has to call compress_init in the former and decompress_init in the latter. Except that it called compress_init in both, so compression in SSH-2 has been completely broken for a week. How embarrassing. I _remember_ thinking that I'd better make sure to change that one call between the two, but apparently it fell out of my head before I committed. --- ssh2bpp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ssh2bpp.c b/ssh2bpp.c index 0ea1f793..11f5d08b 100644 --- a/ssh2bpp.c +++ b/ssh2bpp.c @@ -145,10 +145,10 @@ void ssh2_bpp_new_incoming_crypto( } s->in.comp = compression; - /* out_comp is always non-NULL, because no compression is + /* in_comp is always non-NULL, because no compression is * indicated by ssh_comp_none. So compress_init always exists, but - * it may return a null out_comp_ctx. */ - s->in.comp_ctx = compression->compress_init(); + * it may return a null in_comp_ctx. */ + s->in.comp_ctx = compression->decompress_init(); /* Clear the pending_newkeys flag, so that handle_input below will * start consuming the input data again. */ From 20e8fdece39dd1d680c0feb8eb1432e18c81ade2 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 16 Jun 2018 14:44:10 +0100 Subject: [PATCH 377/607] Stop saying we'll try compression later, if it is later. On the post-userauth rekey, when we're specifically rekeying in order to turn on delayed compression, we shouldn't write the Event Log "Server supports delayed compression; will try this later" message that we did in the original key exchange. At this point, it _is_ later, and we're about to turn on compression right now! --- ssh.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ssh.c b/ssh.c index 7df6b509..dbc23c09 100644 --- a/ssh.c +++ b/ssh.c @@ -5731,7 +5731,8 @@ static void do_ssh2_transport(void *vctx) } if ((i == KEXLIST_CSCOMP || i == KEXLIST_SCCOMP) && in_commasep_string(alg->u.comp->delayed_name, - str.ptr, str.len)) + str.ptr, str.len) && + !s->userauth_succeeded) s->pending_compression = TRUE; /* try this later */ } bombout(("Couldn't agree a %s (available: %.*s)", From fecd42858c3fb4abd5b9c9dae1d456141820d244 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 8 Jul 2018 15:29:41 +0100 Subject: [PATCH 378/607] winpgnt.c: put all file-mapping code in one function. Previously, the code to recover and memory-map the file-mapping object Pageant uses for its IPC, and the code to convey its contents to and from the cross-platform agent code, were widely separated, with the former living in the WM_COPYDATA handler in the window procedure, and the latter in answer_msg. Now all of that code lives in answer_filemapping_message; WndProc only handles the _window message_ contents - i.e. ensures the WM_COPYDATA message has the right dwData id and that its lpData contains an ASCIZ string - and answer_filemapping_message goes all the way from that file-mapping object name to calling pageant_handle_msg. While I'm here, I've also tidied up the code so that it uses the 'goto cleanup' idiom rather than nesting everything inconveniently deeply, and arranged that if anything goes wrong then we at least _construct_ an error message (although as yet we don't use that for anything unless we're compiled with DEBUG_IPC enabled). --- windows/winpgnt.c | 315 +++++++++++++++++++++++++--------------------- 1 file changed, 170 insertions(+), 145 deletions(-) diff --git a/windows/winpgnt.c b/windows/winpgnt.c index 9c57a2d6..7aa61c79 100644 --- a/windows/winpgnt.c +++ b/windows/winpgnt.c @@ -380,59 +380,6 @@ void keylist_update(void) } } -struct PageantReply { - char buf[AGENT_MAX_MSGLEN - 4]; - int len, overflowed; - BinarySink_IMPLEMENTATION; -}; - -static void pageant_reply_BinarySink_write( - BinarySink *bs, const void *data, size_t len) -{ - struct PageantReply *rep = BinarySink_DOWNCAST(bs, struct PageantReply); - if (!rep->overflowed && len <= sizeof(rep->buf) - rep->len) { - memcpy(rep->buf + rep->len, data, len); - rep->len += len; - } else { - rep->overflowed = TRUE; - } -} - -static void answer_msg(void *msgv) -{ - unsigned char *msg = (unsigned char *)msgv; - unsigned msglen; - struct PageantReply reply; - - reply.len = 0; - reply.overflowed = FALSE; - BinarySink_INIT(&reply, pageant_reply_BinarySink_write); - - msglen = GET_32BIT(msg); - if (msglen > AGENT_MAX_MSGLEN) { - pageant_failure_msg(BinarySink_UPCAST(&reply), - "incoming length field too large", NULL, NULL); - } else { - pageant_handle_msg(BinarySink_UPCAST(&reply), - msg + 4, msglen, NULL, NULL); - if (reply.len > AGENT_MAX_MSGLEN) { - reply.len = 0; - reply.overflowed = FALSE; - pageant_failure_msg(BinarySink_UPCAST(&reply), - "output would exceed max msglen", NULL, NULL); - } - } - - /* - * Windows Pageant answers messages in place, by overwriting the - * input message buffer. - */ - assert(4 + reply.len <= AGENT_MAX_MSGLEN); - PUT_32BIT(msg, reply.len); - memcpy(msg + 4, reply.buf, reply.len); - smemclr(reply.buf, sizeof(reply.buf)); -} - static void win_add_keyfile(Filename *filename) { char *err; @@ -829,6 +776,168 @@ PSID get_default_sid(void) } #endif +struct PageantReply { + char buf[AGENT_MAX_MSGLEN - 4]; + int len, overflowed; + BinarySink_IMPLEMENTATION; +}; + +static void pageant_reply_BinarySink_write( + BinarySink *bs, const void *data, size_t len) +{ + struct PageantReply *rep = BinarySink_DOWNCAST(bs, struct PageantReply); + if (!rep->overflowed && len <= sizeof(rep->buf) - rep->len) { + memcpy(rep->buf + rep->len, data, len); + rep->len += len; + } else { + rep->overflowed = TRUE; + } +} + +static char *answer_filemapping_message(const char *mapname) +{ + HANDLE maphandle = INVALID_HANDLE_VALUE; + void *mapaddr = NULL; + char *err = NULL; + unsigned char *msg; + unsigned msglen; + struct PageantReply reply; + +#ifndef NO_SECURITY + PSID mapsid = NULL; + PSID expectedsid = NULL; + PSID expectedsid_bc = NULL; + PSECURITY_DESCRIPTOR psd = NULL; +#endif + +#ifdef DEBUG_IPC + debug(("mapname = \"%s\"\n", mapname)); +#endif + + maphandle = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, mapname); + if (maphandle == NULL || maphandle == INVALID_HANDLE_VALUE) { + err = dupprintf("OpenFileMapping(\"%s\"): %s", + mapname, win_strerror(GetLastError())); + goto cleanup; + } + +#ifdef DEBUG_IPC + debug(("maphandle = %p\n", maphandle)); +#endif + +#ifndef NO_SECURITY + if (has_security) { + DWORD retd; + + if ((expectedsid = get_user_sid()) == NULL) { + err = dupstr("unable to get user SID"); + goto cleanup; + } + + if ((expectedsid_bc = get_default_sid()) == NULL) { + err = dupstr("unable to get default SID"); + goto cleanup; + } + + if ((retd = p_GetSecurityInfo( + maphandle, SE_KERNEL_OBJECT, OWNER_SECURITY_INFORMATION, + &mapsid, NULL, NULL, NULL, &psd) != ERROR_SUCCESS)) { + err = dupprintf("unable to get owner of file mapping: " + "GetSecurityInfo returned: %s", + win_strerror(retd)); + goto cleanup; + } + +#ifdef DEBUG_IPC + { + LPTSTR ours, ours2, theirs; + ConvertSidToStringSid(mapsid, &theirs); + ConvertSidToStringSid(expectedsid, &ours); + ConvertSidToStringSid(expectedsid_bc, &ours2); + debug(("got sids:\n oursnew=%s\n oursold=%s\n" + " theirs=%s\n", ours, ours2, theirs)); + LocalFree(ours); + LocalFree(ours2); + LocalFree(theirs); + } +#endif + + if (!EqualSid(mapsid, expectedsid) && + !EqualSid(mapsid, expectedsid_bc)) { + err = dupstr("wrong owning SID of file mapping"); + goto cleanup; + } + } else +#endif /* NO_SECURITY */ + { +#ifdef DEBUG_IPC + debug(("security APIs not present\n")); +#endif + } + + mapaddr = MapViewOfFile(maphandle, FILE_MAP_WRITE, 0, 0, 0); + if (!mapaddr) { + err = dupprintf("unable to obtain view of file mapping: %s", + win_strerror(GetLastError())); + goto cleanup; + } + +#ifdef DEBUG_IPC + debug(("mapped address = %p\n", mapaddr)); +#endif + + msglen = GET_32BIT((unsigned char *)mapaddr); + +#ifdef DEBUG_IPC + debug(("msg length=%08x, msg type=%02x\n", + msglen, (unsigned)((unsigned char *) mapaddr)[4])); +#endif + + reply.len = 0; + reply.overflowed = FALSE; + BinarySink_INIT(&reply, pageant_reply_BinarySink_write); + + if (msglen > AGENT_MAX_MSGLEN - 4) { + pageant_failure_msg(BinarySink_UPCAST(&reply), + "incoming length field too large", NULL, NULL); + } else { + pageant_handle_msg(BinarySink_UPCAST(&reply), + msg + 4, msglen, NULL, NULL); + if (reply.overflowed || reply.len > AGENT_MAX_MSGLEN - 4) { + reply.len = 0; + reply.overflowed = FALSE; + pageant_failure_msg(BinarySink_UPCAST(&reply), + "output would overflow message buffer", + NULL, NULL); + } + } + + if (reply.len > AGENT_MAX_MSGLEN - 4) { + err = dupstr("even error-message output overflows buffer"); + goto cleanup; + } + + /* + * Windows Pageant answers messages in place, by overwriting the + * input message buffer. + */ + assert(4 + reply.len <= AGENT_MAX_MSGLEN); + PUT_32BIT(msg, reply.len); + memcpy(msg + 4, reply.buf, reply.len); + smemclr(reply.buf, sizeof(reply.buf)); + + cleanup: + /* expectedsid has the lifetime of the program, so we don't free it */ + sfree(expectedsid_bc); + if (psd) + LocalFree(psd); + if (mapaddr) + UnmapViewOfFile(mapaddr); + if (maphandle != NULL && maphandle != INVALID_HANDLE_VALUE) + CloseHandle(maphandle); + return err; +} + static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { @@ -971,14 +1080,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, case WM_COPYDATA: { COPYDATASTRUCT *cds; - char *mapname; - void *p; - HANDLE filemap; -#ifndef NO_SECURITY - PSID mapowner, ourself, ourself2; -#endif - PSECURITY_DESCRIPTOR psd = NULL; - int ret = 0; + char *mapname, *err; cds = (COPYDATASTRUCT *) lParam; if (cds->dwData != AGENT_COPYDATA_ID) @@ -986,92 +1088,15 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, mapname = (char *) cds->lpData; if (mapname[cds->cbData - 1] != '\0') return 0; /* failure to be ASCIZ! */ + err = answer_filemapping_message(mapname); + if (err) { #ifdef DEBUG_IPC - debug(("mapname is :%s:\n", mapname)); -#endif - filemap = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, mapname); -#ifdef DEBUG_IPC - debug(("filemap is %p\n", filemap)); -#endif - if (filemap != NULL && filemap != INVALID_HANDLE_VALUE) { -#ifndef NO_SECURITY - int rc; - if (has_security) { - if ((ourself = get_user_sid()) == NULL) { -#ifdef DEBUG_IPC - debug(("couldn't get user SID\n")); -#endif - CloseHandle(filemap); - return 0; - } - - if ((ourself2 = get_default_sid()) == NULL) { -#ifdef DEBUG_IPC - debug(("couldn't get default SID\n")); + debug(("IPC failed: %s\n", err)); #endif - CloseHandle(filemap); - return 0; - } - - if ((rc = p_GetSecurityInfo(filemap, SE_KERNEL_OBJECT, - OWNER_SECURITY_INFORMATION, - &mapowner, NULL, NULL, NULL, - &psd) != ERROR_SUCCESS)) { -#ifdef DEBUG_IPC - debug(("couldn't get owner info for filemap: %d\n", - rc)); -#endif - CloseHandle(filemap); - sfree(ourself2); - return 0; - } -#ifdef DEBUG_IPC - { - LPTSTR ours, ours2, theirs; - ConvertSidToStringSid(mapowner, &theirs); - ConvertSidToStringSid(ourself, &ours); - ConvertSidToStringSid(ourself2, &ours2); - debug(("got sids:\n oursnew=%s\n oursold=%s\n" - " theirs=%s\n", ours, ours2, theirs)); - LocalFree(ours); - LocalFree(ours2); - LocalFree(theirs); - } -#endif - if (!EqualSid(mapowner, ourself) && - !EqualSid(mapowner, ourself2)) { - CloseHandle(filemap); - LocalFree(psd); - sfree(ourself2); - return 0; /* security ID mismatch! */ - } -#ifdef DEBUG_IPC - debug(("security stuff matched\n")); -#endif - LocalFree(psd); - sfree(ourself2); - } else { -#ifdef DEBUG_IPC - debug(("security APIs not present\n")); -#endif - } -#endif - p = MapViewOfFile(filemap, FILE_MAP_WRITE, 0, 0, 0); -#ifdef DEBUG_IPC - debug(("p is %p\n", p)); - { - int i; - for (i = 0; i < 5; i++) - debug(("p[%d]=%02x\n", i, - ((unsigned char *) p)[i])); - } -#endif - answer_msg(p); - ret = 1; - UnmapViewOfFile(p); - } - CloseHandle(filemap); - return ret; + sfree(err); + return 0; + } + return 1; } } From ac51a712b3abf82277c086fdc76a99e5cdee5c13 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 8 Jul 2018 16:46:32 +0100 Subject: [PATCH 379/607] winpgnt.c: handle arbitrarily large file mappings. I heard recently that at least one third-party client of Pageant exists, and that it's used to generate signatures to use with TLS client certificates. Apparently the signature scheme is compatible, but TLS tends to need signatures over more data than will fit in AGENT_MAX_MSGLEN. Before the BinarySink refactor in commit b6cbad89f, this was OK because the Windows Pageant IPC didn't check the size of the _input_ message against AGENT_MAX_MSGLEN, only the output one. But then we started checking both, so that third-party TLS client started failing. Now we use VirtualQuery to find out the actual size of the file mapping we've been passed, and our only requirement is that the input and output messages should both fit in _that_. So TLS should work again, and also, other clients should be able to retrieve longer lists of public keys if they pass a larger file mapping. One side effect of this change is that Pageant's reply message is now written directly into the shared-memory region. Previously, it was written into a separate buffer and then memcpy()ed over after pageant_handle_msg returned, but now the buffer is variable-size, it seems to me to make more sense to avoid that extra not-entirely controlled malloc. So I've done one very small reordering of statements in the cross-platform pageant_handle_msg(), which fixes the only case I could find where that function started writing its output before it had finished using the contents of the input buffer. --- pageant.c | 4 ++-- windows/winpgnt.c | 59 +++++++++++++++++++++++++++++++++-------------- 2 files changed, 44 insertions(+), 19 deletions(-) diff --git a/pageant.c b/pageant.c index 5c3efb13..f12694de 100644 --- a/pageant.c +++ b/pageant.c @@ -339,11 +339,11 @@ void pageant_handle_msg(BinarySink *bs, return; } - put_byte(bs, SSH2_AGENT_SIGN_RESPONSE); - signature = strbuf_new(); ssh_key_sign(key->key, sigdata.ptr, sigdata.len, BinarySink_UPCAST(signature)); + + put_byte(bs, SSH2_AGENT_SIGN_RESPONSE); put_stringsb(bs, signature); plog(logctx, logfn, "reply: SSH2_AGENT_SIGN_RESPONSE"); diff --git a/windows/winpgnt.c b/windows/winpgnt.c index 7aa61c79..2325692c 100644 --- a/windows/winpgnt.c +++ b/windows/winpgnt.c @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -777,8 +778,9 @@ PSID get_default_sid(void) #endif struct PageantReply { - char buf[AGENT_MAX_MSGLEN - 4]; - int len, overflowed; + char *buf; + size_t size, len; + int overflowed; BinarySink_IMPLEMENTATION; }; @@ -786,7 +788,7 @@ static void pageant_reply_BinarySink_write( BinarySink *bs, const void *data, size_t len) { struct PageantReply *rep = BinarySink_DOWNCAST(bs, struct PageantReply); - if (!rep->overflowed && len <= sizeof(rep->buf) - rep->len) { + if (!rep->overflowed && len <= rep->size - rep->len) { memcpy(rep->buf + rep->len, data, len); rep->len += len; } else { @@ -799,7 +801,7 @@ static char *answer_filemapping_message(const char *mapname) HANDLE maphandle = INVALID_HANDLE_VALUE; void *mapaddr = NULL; char *err = NULL; - unsigned char *msg; + size_t mapsize; unsigned msglen; struct PageantReply reply; @@ -810,6 +812,8 @@ static char *answer_filemapping_message(const char *mapname) PSECURITY_DESCRIPTOR psd = NULL; #endif + reply.buf = NULL; + #ifdef DEBUG_IPC debug(("mapname = \"%s\"\n", mapname)); #endif @@ -886,6 +890,31 @@ static char *answer_filemapping_message(const char *mapname) debug(("mapped address = %p\n", mapaddr)); #endif + { + MEMORY_BASIC_INFORMATION mbi; + size_t mbiSize = VirtualQuery(mapaddr, &mbi, sizeof(mbi)); + if (mbiSize == 0) { + err = dupprintf("unable to query view of file mapping: %s", + win_strerror(GetLastError())); + goto cleanup; + } + if (mbiSize < (offsetof(MEMORY_BASIC_INFORMATION, RegionSize) + + sizeof(mbi.RegionSize))) { + err = dupstr("VirtualQuery returned too little data to get " + "region size"); + goto cleanup; + } + + mapsize = mbi.RegionSize; + } +#ifdef DEBUG_IPC + debug(("region size = %zd\n", mapsize)); +#endif + if (mapsize < 5) { + err = dupstr("mapping smaller than smallest possible request"); + goto cleanup; + } + msglen = GET_32BIT((unsigned char *)mapaddr); #ifdef DEBUG_IPC @@ -893,17 +922,19 @@ static char *answer_filemapping_message(const char *mapname) msglen, (unsigned)((unsigned char *) mapaddr)[4])); #endif + reply.buf = (char *)mapaddr + 4; + reply.size = mapsize - 4; reply.len = 0; reply.overflowed = FALSE; BinarySink_INIT(&reply, pageant_reply_BinarySink_write); - if (msglen > AGENT_MAX_MSGLEN - 4) { + if (msglen > mapsize - 4) { pageant_failure_msg(BinarySink_UPCAST(&reply), "incoming length field too large", NULL, NULL); } else { pageant_handle_msg(BinarySink_UPCAST(&reply), - msg + 4, msglen, NULL, NULL); - if (reply.overflowed || reply.len > AGENT_MAX_MSGLEN - 4) { + (unsigned char *)mapaddr + 4, msglen, NULL, NULL); + if (reply.overflowed) { reply.len = 0; reply.overflowed = FALSE; pageant_failure_msg(BinarySink_UPCAST(&reply), @@ -912,19 +943,13 @@ static char *answer_filemapping_message(const char *mapname) } } - if (reply.len > AGENT_MAX_MSGLEN - 4) { - err = dupstr("even error-message output overflows buffer"); + if (reply.overflowed) { + err = dupstr("even failure message overflows buffer"); goto cleanup; } - /* - * Windows Pageant answers messages in place, by overwriting the - * input message buffer. - */ - assert(4 + reply.len <= AGENT_MAX_MSGLEN); - PUT_32BIT(msg, reply.len); - memcpy(msg + 4, reply.buf, reply.len); - smemclr(reply.buf, sizeof(reply.buf)); + /* Write in the initial length field, and we're done. */ + PUT_32BIT(((unsigned char *)mapaddr), reply.len); cleanup: /* expectedsid has the lifetime of the program, so we don't free it */ From 98528db25a9df211141b8711a3756ee2b6ea26e9 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 8 Jul 2018 17:04:12 +0100 Subject: [PATCH 380/607] Raise AGENT_MAX_MSGLEN to 256Kb. That's the same value as in the OpenSSH source code, so it should be large enough that anyone needing to sign a larger message will have other problems too. --- pageant.h | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/pageant.h b/pageant.h index 551c2a36..26263129 100644 --- a/pageant.h +++ b/pageant.h @@ -5,12 +5,11 @@ #include /* - * FIXME: it would be nice not to have this arbitrary limit. It's - * currently needed because the Windows Pageant IPC system needs an - * upper bound known to the client, but it's also reused as a basic - * sanity check on incoming messages' length fields. + * Upper limit on length of any agent message. Used as a basic sanity + * check on messages' length fields, and used by the Windows Pageant + * client IPC to decide how large a file mapping to allocate. */ -#define AGENT_MAX_MSGLEN 8192 +#define AGENT_MAX_MSGLEN 262144 typedef void (*pageant_logfn_t)(void *logctx, const char *fmt, va_list ap); From daa086fe73d667a92de8b380d78302bdad827b85 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Mon, 9 Jul 2018 07:18:08 +0100 Subject: [PATCH 381/607] winpgnt.c: fix an outdated error message. I just spotted it while I was looking through this module anyway. It was using %.100s to prevent an sprintf buffer overflow, which hasn't been necessary since I switched everything over to dupprintf, and also it was printing the integer value of GetLastError() without using my convenient translation wrapper win_strerror. --- windows/winpgnt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/windows/winpgnt.c b/windows/winpgnt.c index 2325692c..3734ab17 100644 --- a/windows/winpgnt.c +++ b/windows/winpgnt.c @@ -1136,8 +1136,8 @@ void spawn_cmd(const char *cmdline, const char *args, int show) if (ShellExecute(NULL, _T("open"), cmdline, args, NULL, show) <= (HINSTANCE) 32) { char *msg; - msg = dupprintf("Failed to run \"%.100s\", Error: %d", cmdline, - (int)GetLastError()); + msg = dupprintf("Failed to run \"%s\": %s", cmdline, + win_strerror(GetLastError())); MessageBox(NULL, msg, APPNAME, MB_OK | MB_ICONEXCLAMATION); sfree(msg); } From d4abff521a7cba4c703fbe0bdbaa3b9607c0ac24 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Mon, 9 Jul 2018 20:59:36 +0100 Subject: [PATCH 382/607] Reinstate calls to ssh_free_pktout! I think ever since commit 679fa90df last month, PuTTY has been forgetting to free any of its outgoing packet structures after turning them into their encrypted wire format. And apparently no users of the development snapshots have noticed - including me! --- ssh1bpp.c | 2 ++ ssh2bpp-bare.c | 2 ++ ssh2bpp.c | 2 ++ 3 files changed, 6 insertions(+) diff --git a/ssh1bpp.c b/ssh1bpp.c index a00c4d3c..5b0f119b 100644 --- a/ssh1bpp.c +++ b/ssh1bpp.c @@ -277,4 +277,6 @@ static void ssh1_bpp_format_packet(BinaryPacketProtocol *bpp, PktOut *pkt) bufchain_add(s->bpp.out_raw, pkt->data + pktoffs, biglen + 4); /* len(length+padding+type+data+CRC) */ + + ssh_free_pktout(pkt); } diff --git a/ssh2bpp-bare.c b/ssh2bpp-bare.c index 270c0118..bdf49a21 100644 --- a/ssh2bpp-bare.c +++ b/ssh2bpp-bare.c @@ -157,4 +157,6 @@ static void ssh2_bare_bpp_format_packet(BinaryPacketProtocol *bpp, PktOut *pkt) PUT_32BIT(pkt->data, pkt->length - 4); bufchain_add(s->bpp.out_raw, pkt->data, pkt->length); + + ssh_free_pktout(pkt); } diff --git a/ssh2bpp.c b/ssh2bpp.c index 11f5d08b..ef007024 100644 --- a/ssh2bpp.c +++ b/ssh2bpp.c @@ -610,4 +610,6 @@ static void ssh2_bpp_format_packet(BinaryPacketProtocol *bpp, PktOut *pkt) pkt->encrypted_len = origlen + padding; bufchain_add(s->bpp.out_raw, pkt->data, pkt->length); + + ssh_free_pktout(pkt); } From 445fa12da70b901a37a56779bb4179fe72156db1 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Tue, 10 Jul 2018 21:04:32 +0100 Subject: [PATCH 383/607] Fix duplicate packets in CBC mode. Yesterday's reinstatement of ssh_free_pktout revealed - via valgrind spotting the use-after-free - that the code that prefixed sensible packets with IV-muddling SSH_MSG_IGNOREs was actually sending a second copy of the sensible packet in place of the IGNORE, due to a typo. --- ssh.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssh.c b/ssh.c index dbc23c09..dd564c92 100644 --- a/ssh.c +++ b/ssh.c @@ -1216,7 +1216,7 @@ static void ssh_pkt_write(Ssh ssh, PktOut *pkt) */ PktOut *ipkt = ssh_bpp_new_pktout(ssh->bpp, SSH2_MSG_IGNORE); put_stringz(ipkt, ""); - ssh_bpp_format_packet(ssh->bpp, pkt); + ssh_bpp_format_packet(ssh->bpp, ipkt); } ssh_bpp_format_packet(ssh->bpp, pkt); From bcb94f966e4aeca2a9619b87dfe96d546fde16c6 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Tue, 10 Jul 2018 21:27:43 +0100 Subject: [PATCH 384/607] Make compression functions return void. The return value wasn't used to indicate failure; it only indicated whether any compression was being done at all or whether the compression method was ssh_comp_none, and we can tell the latter just as well by the fact that its init function returns a null context pointer. --- ssh.c | 10 +++++++--- ssh.h | 8 ++++---- ssh2bpp.c | 20 +++++++++----------- sshzlib.c | 6 ++---- 4 files changed, 22 insertions(+), 22 deletions(-) diff --git a/ssh.c b/ssh.c index dd564c92..369fbf35 100644 --- a/ssh.c +++ b/ssh.c @@ -341,8 +341,12 @@ static void *ssh_comp_none_init(void) static void ssh_comp_none_cleanup(void *handle) { } -static int ssh_comp_none_block(void *handle, unsigned char *block, int len, - unsigned char **outblock, int *outlen) +static void ssh_comp_none_block(void *handle, unsigned char *block, int len, + unsigned char **outblock, int *outlen) +{ +} +static int ssh_decomp_none_block(void *handle, unsigned char *block, int len, + unsigned char **outblock, int *outlen) { return 0; } @@ -353,7 +357,7 @@ static int ssh_comp_none_disable(void *handle) const static struct ssh_compress ssh_comp_none = { "none", NULL, ssh_comp_none_init, ssh_comp_none_cleanup, ssh_comp_none_block, - ssh_comp_none_init, ssh_comp_none_cleanup, ssh_comp_none_block, + ssh_comp_none_init, ssh_comp_none_cleanup, ssh_decomp_none_block, ssh_comp_none_disable, NULL }; extern const struct ssh_compress ssh_zlib; diff --git a/ssh.h b/ssh.h index f00c7e99..5620af02 100644 --- a/ssh.h +++ b/ssh.h @@ -560,8 +560,8 @@ struct ssh_compress { const char *delayed_name; void *(*compress_init) (void); void (*compress_cleanup) (void *); - int (*compress) (void *, unsigned char *block, int len, - unsigned char **outblock, int *outlen); + void (*compress) (void *, unsigned char *block, int len, + unsigned char **outblock, int *outlen); void *(*decompress_init) (void); void (*decompress_cleanup) (void *); int (*decompress) (void *, unsigned char *block, int len, @@ -981,8 +981,8 @@ void *zlib_compress_init(void); void zlib_compress_cleanup(void *); void *zlib_decompress_init(void); void zlib_decompress_cleanup(void *); -int zlib_compress_block(void *, unsigned char *block, int len, - unsigned char **outblock, int *outlen); +void zlib_compress_block(void *, unsigned char *block, int len, + unsigned char **outblock, int *outlen); int zlib_decompress_block(void *, unsigned char *block, int len, unsigned char **outblock, int *outlen); diff --git a/ssh2bpp.c b/ssh2bpp.c index ef007024..e6e9975f 100644 --- a/ssh2bpp.c +++ b/ssh2bpp.c @@ -537,19 +537,17 @@ static void ssh2_bpp_format_packet(BinaryPacketProtocol *bpp, PktOut *pkt) pkt->downstream_id, pkt->additional_log_text); } - /* - * Compress packet payload. - */ - { + if (s->out.comp && s->out.comp_ctx) { unsigned char *newpayload; int newlen; - if (s->out.comp && s->out.comp->compress( - s->out.comp_ctx, pkt->data + 5, pkt->length - 5, - &newpayload, &newlen)) { - pkt->length = 5; - put_data(pkt, newpayload, newlen); - sfree(newpayload); - } + /* + * Compress packet payload. + */ + s->out.comp->compress(s->out.comp_ctx, pkt->data + 5, pkt->length - 5, + &newpayload, &newlen); + pkt->length = 5; + put_data(pkt, newpayload, newlen); + sfree(newpayload); } /* diff --git a/sshzlib.c b/sshzlib.c index 855ddd86..290e6fe4 100644 --- a/sshzlib.c +++ b/sshzlib.c @@ -679,8 +679,8 @@ static int zlib_disable_compression(void *handle) return n; } -int zlib_compress_block(void *handle, unsigned char *block, int len, - unsigned char **outblock, int *outlen) +void zlib_compress_block(void *handle, unsigned char *block, int len, + unsigned char **outblock, int *outlen) { struct LZ77Context *ectx = (struct LZ77Context *)handle; struct Outbuf *out = (struct Outbuf *) ectx->userdata; @@ -796,8 +796,6 @@ int zlib_compress_block(void *handle, unsigned char *block, int len, *outblock = out->outbuf; *outlen = out->outlen; - - return 1; } /* ---------------------------------------------------------------------- From 20a9bd5642ac66ae1190069989d33c5fcefe5672 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Mon, 9 Jul 2018 20:30:11 +0100 Subject: [PATCH 385/607] Move password-packet padding into the BPP module. Now when we construct a packet containing sensitive data, we just set a field saying '... and make it take up at least this much space, to disguise its true size', and nothing in the rest of the system worries about that flag until ssh2bpp.c acts on it. Also, I've changed the strategy for doing the padding. Previously, we were following the real packet with an SSH_MSG_IGNORE to make up the size. But that was only a partial defence: it works OK against passive traffic analysis, but an attacker proxying the TCP stream and dribbling it out one byte at a time could still have found out the size of the real packet by noting when the dribbled data provoked a response. Now I put the SSH_MSG_IGNORE _first_, which should defeat that attack. But that in turn doesn't work when we're doing compression, because we can't predict the compressed sizes accurately enough to make that strategy sensible. Fortunately, compression provides an alternative strategy anyway: if we've got zlib turned on when we send one of these sensitive packets, then we can pad out the compressed zlib data as much as we like by adding empty RFC1951 blocks (effectively chaining ZLIB_PARTIAL_FLUSHes). So both strategies should now be dribble-proof. --- ssh.c | 87 ++++--------------------- ssh.h | 8 +-- ssh1bpp.c | 2 +- ssh2bpp.c | 108 ++++++++++++++++++++++++------ sshbpp.h | 1 - sshzlib.c | 192 ++++++++++++++---------------------------------------- 6 files changed, 152 insertions(+), 246 deletions(-) diff --git a/ssh.c b/ssh.c index 369fbf35..4c237e31 100644 --- a/ssh.c +++ b/ssh.c @@ -342,7 +342,8 @@ static void ssh_comp_none_cleanup(void *handle) { } static void ssh_comp_none_block(void *handle, unsigned char *block, int len, - unsigned char **outblock, int *outlen) + unsigned char **outblock, int *outlen, + int minlen) { } static int ssh_decomp_none_block(void *handle, unsigned char *block, int len, @@ -350,15 +351,11 @@ static int ssh_decomp_none_block(void *handle, unsigned char *block, int len, { return 0; } -static int ssh_comp_none_disable(void *handle) -{ - return 0; -} const static struct ssh_compress ssh_comp_none = { "none", NULL, ssh_comp_none_init, ssh_comp_none_cleanup, ssh_comp_none_block, ssh_comp_none_init, ssh_comp_none_cleanup, ssh_decomp_none_block, - ssh_comp_none_disable, NULL + NULL }; extern const struct ssh_compress ssh_zlib; const static struct ssh_compress *const compressions[] = { @@ -1327,72 +1324,6 @@ static void ssh_send_outgoing_data(void *ctx) } } -/* - * Send a packet whose length needs to be disguised (typically - * passwords or keyboard-interactive responses). - */ -static void ssh2_pkt_send_with_padding(Ssh ssh, PktOut *pkt, int padsize) -{ -#if 0 - if (0) { - /* - * The simplest way to do this is to adjust the - * variable-length padding field in the outgoing packet. - * - * Currently compiled out, because some Cisco SSH servers - * don't like excessively padded packets (bah, why's it - * always Cisco?) - */ - pkt->forcepad = padsize; - ssh2_pkt_send(ssh, pkt); - } else -#endif - { - /* - * If we can't do that, however, an alternative approach is to - * bundle the packet tightly together with an SSH_MSG_IGNORE - * such that their combined length is a constant. So first we - * construct the final form of this packet and append it to - * the outgoing_data bufchain... - */ - ssh_pkt_write(ssh, pkt); - - /* - * ... but before we return from this function (triggering a - * call to the outgoing_data_sender), we also construct an - * SSH_MSG_IGNORE which includes a string that's an exact - * multiple of the cipher block size. (If the cipher is NULL - * so that the block size is unavailable, we don't do this - * trick at all, because we gain nothing by it.) - */ - if (!(ssh->remote_bugs & BUG_CHOKES_ON_SSH2_IGNORE)) { - int stringlen, i; - - stringlen = (256 - bufchain_size(&ssh->outgoing_data)); - stringlen += ssh->v2_out_cipherblksize - 1; - stringlen -= (stringlen % ssh->v2_out_cipherblksize); - - /* - * Temporarily disable actual compression, so we can - * guarantee to get this string exactly the length we want - * it. The compression-disabling routine should return an - * integer indicating how many bytes we should adjust our - * string length by. - */ - stringlen -= ssh2_bpp_temporarily_disable_compression(ssh->bpp); - - pkt = ssh_bpp_new_pktout(ssh->bpp, SSH2_MSG_IGNORE); - { - strbuf *substr = strbuf_new(); - for (i = 0; i < stringlen; i++) - put_byte(substr, random_byte()); - put_stringsb(pkt, substr); - } - ssh_pkt_write(ssh, pkt); - } - } -} - /* * Send all queued SSH-2 packets. */ @@ -9563,7 +9494,8 @@ static void do_ssh2_userauth(void *vctx) } /* - * Send the response(s) to the server. + * Send the response(s) to the server, padding + * them to disguise their true length. */ s->pktout = ssh_bpp_new_pktout( ssh->bpp, SSH2_MSG_USERAUTH_INFO_RESPONSE); @@ -9572,7 +9504,8 @@ static void do_ssh2_userauth(void *vctx) put_stringz(s->pktout, s->cur_prompt->prompts[i]->result); } - ssh2_pkt_send_with_padding(ssh, s->pktout, 256); + s->pktout->minlen = 256; + ssh2_pkt_send(ssh, s->pktout); /* * Free the prompts structure from this iteration. @@ -9661,7 +9594,8 @@ static void do_ssh2_userauth(void *vctx) put_stringz(s->pktout, "password"); put_bool(s->pktout, FALSE); put_stringz(s->pktout, s->password); - ssh2_pkt_send_with_padding(ssh, s->pktout, 256); + s->pktout->minlen = 256; + ssh2_pkt_send(ssh, s->pktout); logevent("Sent password"); s->type = AUTH_TYPE_PASSWORD; @@ -9797,7 +9731,8 @@ static void do_ssh2_userauth(void *vctx) put_stringz(s->pktout, s->cur_prompt->prompts[1]->result); free_prompts(s->cur_prompt); - ssh2_pkt_send_with_padding(ssh, s->pktout, 256); + s->pktout->minlen = 256; + ssh2_pkt_send(ssh, s->pktout); logevent("Sent new password"); /* diff --git a/ssh.h b/ssh.h index 5620af02..99ff5b73 100644 --- a/ssh.h +++ b/ssh.h @@ -81,7 +81,7 @@ typedef struct PktOut { long prefix; /* bytes up to and including type field */ long length; /* total bytes, including prefix */ int type; - long forcepad; /* SSH-2: force padding to at least this length */ + long minlen; /* SSH-2: ensure wire length is at least this */ unsigned char *data; /* allocated storage */ long maxlen; /* amount of storage allocated for `data' */ long encrypted_len; /* for SSH-2 total-size counting */ @@ -561,12 +561,12 @@ struct ssh_compress { void *(*compress_init) (void); void (*compress_cleanup) (void *); void (*compress) (void *, unsigned char *block, int len, - unsigned char **outblock, int *outlen); + unsigned char **outblock, int *outlen, + int minlen); void *(*decompress_init) (void); void (*decompress_cleanup) (void *); int (*decompress) (void *, unsigned char *block, int len, unsigned char **outblock, int *outlen); - int (*disable_compression) (void *); const char *text_name; }; @@ -982,7 +982,7 @@ void zlib_compress_cleanup(void *); void *zlib_decompress_init(void); void zlib_decompress_cleanup(void *); void zlib_compress_block(void *, unsigned char *block, int len, - unsigned char **outblock, int *outlen); + unsigned char **outblock, int *outlen, int minlen); int zlib_decompress_block(void *, unsigned char *block, int len, unsigned char **outblock, int *outlen); diff --git a/ssh1bpp.c b/ssh1bpp.c index 5b0f119b..7f5b72f6 100644 --- a/ssh1bpp.c +++ b/ssh1bpp.c @@ -251,7 +251,7 @@ static void ssh1_bpp_format_packet(BinaryPacketProtocol *bpp, PktOut *pkt) unsigned char *compblk; int complen; zlib_compress_block(s->compctx, pkt->data + 12, pkt->length - 12, - &compblk, &complen); + &compblk, &complen, 0); /* Replace the uncompressed packet data with the compressed * version. */ pkt->length = 12; diff --git a/ssh2bpp.c b/ssh2bpp.c index e6e9975f..007ab735 100644 --- a/ssh2bpp.c +++ b/ssh2bpp.c @@ -496,32 +496,19 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp) crFinishV; } -int ssh2_bpp_temporarily_disable_compression(BinaryPacketProtocol *bpp) -{ - struct ssh2_bpp_state *s; - assert(bpp->vt == &ssh2_bpp_vtable); - s = FROMFIELD(bpp, struct ssh2_bpp_state, bpp); - - if (!s->out.comp || !s->out.comp_ctx) - return 0; - - return s->out.comp->disable_compression(s->out.comp_ctx); -} - static PktOut *ssh2_bpp_new_pktout(int pkt_type) { PktOut *pkt = ssh_new_packet(); pkt->length = 5; /* space for packet length + padding length */ - pkt->forcepad = 0; + pkt->minlen = 0; pkt->type = pkt_type; put_byte(pkt, pkt_type); pkt->prefix = pkt->length; return pkt; } -static void ssh2_bpp_format_packet(BinaryPacketProtocol *bpp, PktOut *pkt) +static void ssh2_bpp_format_packet_inner(struct ssh2_bpp_state *s, PktOut *pkt) { - struct ssh2_bpp_state *s = FROMFIELD(bpp, struct ssh2_bpp_state, bpp); int origlen, cipherblk, maclen, padding, unencrypted_prefix, i; if (s->bpp.logctx) { @@ -537,14 +524,29 @@ static void ssh2_bpp_format_packet(BinaryPacketProtocol *bpp, PktOut *pkt) pkt->downstream_id, pkt->additional_log_text); } + cipherblk = s->out.cipher ? s->out.cipher->blksize : 8; + cipherblk = cipherblk < 8 ? 8 : cipherblk; /* or 8 if blksize < 8 */ + if (s->out.comp && s->out.comp_ctx) { unsigned char *newpayload; - int newlen; + int minlen, newlen; + /* * Compress packet payload. */ + minlen = pkt->minlen; + if (minlen) { + /* + * Work out how much compressed data we need (at least) to + * make the overall packet length come to pkt->minlen. + */ + if (s->out.mac) + minlen -= s->out.mac->len; + minlen -= 8; /* length field + min padding */ + } + s->out.comp->compress(s->out.comp_ctx, pkt->data + 5, pkt->length - 5, - &newpayload, &newlen); + &newpayload, &newlen, minlen); pkt->length = 5; put_data(pkt, newpayload, newlen); sfree(newpayload); @@ -556,12 +558,8 @@ static void ssh2_bpp_format_packet(BinaryPacketProtocol *bpp, PktOut *pkt) * If pkt->forcepad is set, make sure the packet is at least that size * after padding. */ - cipherblk = s->out.cipher ? s->out.cipher->blksize : 8; - cipherblk = cipherblk < 8 ? 8 : cipherblk; /* or 8 if blksize < 8 */ padding = 4; unencrypted_prefix = (s->out.mac && s->out.etm_mode) ? 4 : 0; - if (pkt->length + padding < pkt->forcepad) - padding = pkt->forcepad - pkt->length; padding += (cipherblk - (pkt->length - unencrypted_prefix + padding) % cipherblk) % cipherblk; @@ -607,6 +605,74 @@ static void ssh2_bpp_format_packet(BinaryPacketProtocol *bpp, PktOut *pkt) s->out.sequence++; /* whether or not we MACed */ pkt->encrypted_len = origlen + padding; +} + +static void ssh2_bpp_format_packet(BinaryPacketProtocol *bpp, PktOut *pkt) +{ + struct ssh2_bpp_state *s = FROMFIELD(bpp, struct ssh2_bpp_state, bpp); + + if (pkt->minlen > 0 && !(s->out.comp && s->out.comp_ctx)) { + /* + * If we've been told to pad the packet out to a given minimum + * length, but we're not compressing (and hence can't get the + * compression to do the padding by pointlessly opening and + * closing zlib blocks), then our other strategy is to precede + * this message with an SSH_MSG_IGNORE that makes it up to the + * right length. + * + * A third option in principle, and the most obviously + * sensible, would be to set the explicit padding field in the + * packet to more than its minimum value. Sadly, that turns + * out to break some servers (our institutional memory thinks + * Cisco in particular) and so we abandoned that idea shortly + * after trying it. + */ + + /* + * Calculate the length we expect the real packet to have. + */ + int block, length; + PktOut *ignore_pkt; + + block = s->out.cipher ? s->out.cipher->blksize : 0; + if (block < 8) + block = 8; + length = pkt->length; + length += 4; /* minimum 4 byte padding */ + length += block-1; + length -= (length % block); + if (s->out.mac) + length += s->out.mac->len; + + if (length < pkt->minlen) { + /* + * We need an ignore message. Calculate its length. + */ + length = pkt->minlen - length; + + /* + * And work backwards from that to the length of the + * contained string. + */ + if (s->out.mac) + length -= s->out.mac->len; + length -= 8; /* length field + min padding */ + length -= 5; /* type code + string length prefix */ + + if (length < 0) + length = 0; + + ignore_pkt = ssh2_bpp_new_pktout(SSH2_MSG_IGNORE); + put_uint32(ignore_pkt, length); + while (length-- > 0) + put_byte(ignore_pkt, random_byte()); + ssh2_bpp_format_packet_inner(s, ignore_pkt); + bufchain_add(s->bpp.out_raw, ignore_pkt->data, ignore_pkt->length); + ssh_free_pktout(ignore_pkt); + } + } + + ssh2_bpp_format_packet_inner(s, pkt); bufchain_add(s->bpp.out_raw, pkt->data, pkt->length); ssh_free_pktout(pkt); diff --git a/sshbpp.h b/sshbpp.h index cf1a528d..5ec3c6ce 100644 --- a/sshbpp.h +++ b/sshbpp.h @@ -47,7 +47,6 @@ void ssh2_bpp_new_incoming_crypto( const struct ssh2_cipher *cipher, const void *ckey, const void *iv, const struct ssh_mac *mac, int etm_mode, const void *mac_key, const struct ssh_compress *compression); -int ssh2_bpp_temporarily_disable_compression(BinaryPacketProtocol *bpp); BinaryPacketProtocol *ssh2_bare_bpp_new(void); diff --git a/sshzlib.c b/sshzlib.c index 290e6fe4..17550477 100644 --- a/sshzlib.c +++ b/sshzlib.c @@ -374,7 +374,6 @@ struct Outbuf { unsigned long outbits; int noutbits; int firstblock; - int comp_disabled; }; static void outbits(struct Outbuf *out, unsigned long bits, int nbits) @@ -502,14 +501,6 @@ static void zlib_literal(struct LZ77Context *ectx, unsigned char c) { struct Outbuf *out = (struct Outbuf *) ectx->userdata; - if (out->comp_disabled) { - /* - * We're in an uncompressed block, so just output the byte. - */ - outbits(out, c, 8); - return; - } - if (c <= 143) { /* 0 through 143 are 8 bits long starting at 00110000. */ outbits(out, mirrorbytes[0x30 + c], 8); @@ -525,8 +516,6 @@ static void zlib_match(struct LZ77Context *ectx, int distance, int len) int i, j, k; struct Outbuf *out = (struct Outbuf *) ectx->userdata; - assert(!out->comp_disabled); - while (len > 0) { int thislen; @@ -623,7 +612,6 @@ void *zlib_compress_init(void) out = snew(struct Outbuf); out->outbits = out->noutbits = 0; out->firstblock = 1; - out->comp_disabled = FALSE; ectx->userdata = out; return ectx; @@ -637,50 +625,9 @@ void zlib_compress_cleanup(void *handle) sfree(ectx); } -/* - * Turn off actual LZ77 analysis for one block, to facilitate - * construction of a precise-length IGNORE packet. Returns the - * length adjustment (which is only valid for packets < 65536 - * bytes, but that seems reasonable enough). - */ -static int zlib_disable_compression(void *handle) -{ - struct LZ77Context *ectx = (struct LZ77Context *)handle; - struct Outbuf *out = (struct Outbuf *) ectx->userdata; - int n; - - out->comp_disabled = TRUE; - - n = 0; - /* - * If this is the first block, we will start by outputting two - * header bytes, and then three bits to begin an uncompressed - * block. This will cost three bytes (because we will start on - * a byte boundary, this is certain). - */ - if (out->firstblock) { - n = 3; - } else { - /* - * Otherwise, we will output seven bits to close the - * previous static block, and _then_ three bits to begin an - * uncompressed block, and then flush the current byte. - * This may cost two bytes or three, depending on noutbits. - */ - n += (out->noutbits + 10) / 8; - } - - /* - * Now we output four bytes for the length / ~length pair in - * the uncompressed block. - */ - n += 4; - - return n; -} - void zlib_compress_block(void *handle, unsigned char *block, int len, - unsigned char **outblock, int *outlen) + unsigned char **outblock, int *outlen, + int minlen) { struct LZ77Context *ectx = (struct LZ77Context *)handle; struct Outbuf *out = (struct Outbuf *) ectx->userdata; @@ -702,98 +649,58 @@ void zlib_compress_block(void *handle, unsigned char *block, int len, } else in_block = TRUE; - if (out->comp_disabled) { - if (in_block) - outbits(out, 0, 7); /* close static block */ - - while (len > 0) { - int blen = (len < 65535 ? len : 65535); - - /* - * Start a Deflate (RFC1951) uncompressed block. We - * transmit a zero bit (BFINAL=0), followed by two more - * zero bits (BTYPE=00). Of course these are in the - * wrong order (00 0), not that it matters. - */ - outbits(out, 0, 3); - - /* - * Output zero bits to align to a byte boundary. - */ - if (out->noutbits) - outbits(out, 0, 8 - out->noutbits); - - /* - * Output the block length, and then its one's - * complement. They're little-endian, so all we need to - * do is pass them straight to outbits() with bit count - * 16. - */ - outbits(out, blen, 16); - outbits(out, blen ^ 0xFFFF, 16); - - /* - * Do the `compression': we need to pass the data to - * lz77_compress so that it will be taken into account - * for subsequent (distance,length) pairs. But - * lz77_compress is passed FALSE, which means it won't - * actually find (or even look for) any matches; so - * every character will be passed straight to - * zlib_literal which will spot out->comp_disabled and - * emit in the uncompressed format. - */ - lz77_compress(ectx, block, blen, FALSE); + if (!in_block) { + /* + * Start a Deflate (RFC1951) fixed-trees block. We + * transmit a zero bit (BFINAL=0), followed by a zero + * bit and a one bit (BTYPE=01). Of course these are in + * the wrong order (01 0). + */ + outbits(out, 2, 3); + } - len -= blen; - block += blen; - } - outbits(out, 2, 3); /* open new block */ - } else { - if (!in_block) { - /* - * Start a Deflate (RFC1951) fixed-trees block. We - * transmit a zero bit (BFINAL=0), followed by a zero - * bit and a one bit (BTYPE=01). Of course these are in - * the wrong order (01 0). - */ - outbits(out, 2, 3); - } + /* + * Do the compression. + */ + lz77_compress(ectx, block, len, TRUE); - /* - * Do the compression. - */ - lz77_compress(ectx, block, len, TRUE); + /* + * End the block (by transmitting code 256, which is + * 0000000 in fixed-tree mode), and transmit some empty + * blocks to ensure we have emitted the byte containing the + * last piece of genuine data. There are three ways we can + * do this: + * + * - Minimal flush. Output end-of-block and then open a + * new static block. This takes 9 bits, which is + * guaranteed to flush out the last genuine code in the + * closed block; but allegedly zlib can't handle it. + * + * - Zlib partial flush. Output EOB, open and close an + * empty static block, and _then_ open the new block. + * This is the best zlib can handle. + * + * - Zlib sync flush. Output EOB, then an empty + * _uncompressed_ block (000, then sync to byte + * boundary, then send bytes 00 00 FF FF). Then open the + * new block. + * + * For the moment, we will use Zlib partial flush. + */ + outbits(out, 0, 7); /* close block */ + outbits(out, 2, 3 + 7); /* empty static block */ + outbits(out, 2, 3); /* open new block */ - /* - * End the block (by transmitting code 256, which is - * 0000000 in fixed-tree mode), and transmit some empty - * blocks to ensure we have emitted the byte containing the - * last piece of genuine data. There are three ways we can - * do this: - * - * - Minimal flush. Output end-of-block and then open a - * new static block. This takes 9 bits, which is - * guaranteed to flush out the last genuine code in the - * closed block; but allegedly zlib can't handle it. - * - * - Zlib partial flush. Output EOB, open and close an - * empty static block, and _then_ open the new block. - * This is the best zlib can handle. - * - * - Zlib sync flush. Output EOB, then an empty - * _uncompressed_ block (000, then sync to byte - * boundary, then send bytes 00 00 FF FF). Then open the - * new block. - * - * For the moment, we will use Zlib partial flush. - */ - outbits(out, 0, 7); /* close block */ - outbits(out, 2, 3 + 7); /* empty static block */ - outbits(out, 2, 3); /* open new block */ + /* + * If we've been asked to pad out the compressed data until it's + * at least a given length, do so by emitting further empty static + * blocks. + */ + while (out->outlen < minlen) { + outbits(out, 0, 7); /* close block */ + outbits(out, 2, 3); /* open new static block */ } - out->comp_disabled = FALSE; - *outblock = out->outbuf; *outlen = out->outlen; } @@ -1391,7 +1298,6 @@ const struct ssh_compress ssh_zlib = { zlib_decompress_init, zlib_decompress_cleanup, zlib_decompress_block, - zlib_disable_compression, "zlib (RFC1950)" }; From 9f6b59fa2e02527d5b3b6faca627f27d5fba245d Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Thu, 16 Aug 2018 19:01:36 +0100 Subject: [PATCH 386/607] Fix platform field in Windows on Arm installers. I had previously left the platform field (in line 7 of the installer database's SummaryInformation table) set at "x86" instead of any value you might expect such as "Arm" or "Arm64", because I found that an MSI file with either of the latter values was rejected by WoA's msiexec as invalid. It turns out this is because I _also_ needed to upgrade the installer database schema version to a higher value than I even knew existed: apparently the problem is that those platform fields aren't present in the older schema. A test confirms that this works. Unfortunately, WiX 3 doesn't actually know _how_ to write MSIs with those platform values. But that's OK, because diffing the x86 and x64 MSIs against each other suggested that there were basically no other changes in the database tables - so I can just generate the installer as if for x64, and then rewrite that one field after installer construction using GNOME msitools to take apart the binary file structure and put it back together. (Those are the same tools I'm using as part of my system for running WiX on Linux in the first place.) This commit introduces a script to do that post-hoc bodging, and calls it from Buildscr. I've also changed over the choice of Program Files folder for the Arm installers so that it's ProgramFiles64Folder instead of ProgramFilesFolder - so now the Windows on Arm installer doesn't incongruously default to installing in C:\Program Files (x86)! --- Buildscr | 9 ++++-- windows/installer.wxs | 9 ++++-- windows/msiplatform.py | 63 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 76 insertions(+), 5 deletions(-) create mode 100755 windows/msiplatform.py diff --git a/Buildscr b/Buildscr index 08be3ec6..12ff2fcf 100644 --- a/Buildscr +++ b/Buildscr @@ -199,8 +199,13 @@ ifneq "$(cross_winsigncode)" "" in putty/windows do $(cross_winsigncode) -N -i h # Build a WiX MSI installer, for each of build32 and build64. in putty/windows with wixonlinux do candle -arch x86 -dRealPlatform=x86 -dDllOk=yes -dBuilddir=build32/ -dWinver="$(Winver)" -dPuttytextver="$(Puttytextver)" installer.wxs && light -ext WixUIExtension -ext WixUtilExtension -sval installer.wixobj -o installer32.msi -spdb in putty/windows with wixonlinux do candle -arch x64 -dRealPlatform=x64 -dDllOk=yes -dBuilddir=build64/ -dWinver="$(Winver)" -dPuttytextver="$(Puttytextver)" installer.wxs && light -ext WixUIExtension -ext WixUtilExtension -sval installer.wixobj -o installer64.msi -spdb -in putty/windows with wixonlinux do candle -arch x86 -dRealPlatform=Arm -dDllOk=no -dBuilddir=abuild32/ -dWinver="$(Winver)" -dPuttytextver="$(Puttytextver)" installer.wxs && light -ext WixUIExtension -ext WixUtilExtension -sval installer.wixobj -o installera32.msi -spdb -in putty/windows with wixonlinux do candle -arch x86 -dRealPlatform=Arm64 -dDllOk=no -dBuilddir=abuild64/ -dWinver="$(Winver)" -dPuttytextver="$(Puttytextver)" installer.wxs && light -ext WixUIExtension -ext WixUtilExtension -sval installer.wixobj -o installera64.msi -spdb +in putty/windows with wixonlinux do candle -arch x64 -dRealPlatform=Arm -dDllOk=no -dBuilddir=abuild32/ -dWinver="$(Winver)" -dPuttytextver="$(Puttytextver)" installer.wxs && light -ext WixUIExtension -ext WixUtilExtension -sval installer.wixobj -o installera32.msi -spdb +in putty/windows with wixonlinux do candle -arch x64 -dRealPlatform=Arm64 -dDllOk=no -dBuilddir=abuild64/ -dWinver="$(Winver)" -dPuttytextver="$(Puttytextver)" installer.wxs && light -ext WixUIExtension -ext WixUtilExtension -sval installer.wixobj -o installera64.msi -spdb + +# Bodge the platform fields for the Windows on Arm installers, since +# WiX 3 doesn't understand Arm platform names itself. +in putty/windows do ./msiplatform.py installera32.msi Arm +in putty/windows do ./msiplatform.py installera64.msi Arm64 # Sign the Windows installers. ifneq "$(cross_winsigncode)" "" in putty/windows do $(cross_winsigncode) -i https://www.chiark.greenend.org.uk/~sgtatham/putty/ -n "PuTTY Installer" installer32.msi installer64.msi installera32.msi installera64.msi diff --git a/windows/installer.wxs b/windows/installer.wxs index 47da2c9e..005d7e03 100644 --- a/windows/installer.wxs +++ b/windows/installer.wxs @@ -5,17 +5,20 @@ - - - + + + + + + diff --git a/windows/msiplatform.py b/windows/msiplatform.py new file mode 100755 index 00000000..eea4272f --- /dev/null +++ b/windows/msiplatform.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python + +import argparse +import os +import tempfile +import shutil +import subprocess +import pipes + +def run(command, verbose): + if verbose: + sys.stdout.write("$ {}\n".format(" ".join( + pipes.quote(word) for word in command))) + out = subprocess.check_output(command) + if verbose: + sys.stdout.write("".join( + "> {}\n".format(line) for line in out.splitlines())) + +def set_platform(msi, platform, verbose): + run(["msidump", "-t", msi], verbose) + + summary_stream = "_SummaryInformation.idt" + + with open(summary_stream) as fh: + lines = [line.rstrip("\r\n").split("\t") + for line in iter(fh.readline, "")] + + for line in lines[3:]: + if line[0] == "7": + line[1] = ";".join([platform] + line[1].split(";", 1)[1:]) + + with open(summary_stream, "w") as fh: + for line in lines: + fh.write("\t".join(line) + "\r\n") + + run(["msibuild", msi, "-i", summary_stream], verbose) + +def main(): + parser = argparse.ArgumentParser( + description='Change the platform field of an MSI installer package.') + parser.add_argument("msi", help="MSI installer file.") + parser.add_argument("platform", help="New value for the platform field.") + parser.add_argument("-v", "--verbose", action="store_true", + help="Log what this script is doing.") + parser.add_argument("-k", "--keep", action="store_true", + help="Don't delete the temporary working directory.") + args = parser.parse_args() + + msi = os.path.abspath(args.msi) + msidir = os.path.dirname(msi) + try: + tempdir = tempfile.mkdtemp(dir=msidir) + os.chdir(tempdir) + set_platform(msi, args.platform, args.verbose) + finally: + if args.keep: + sys.stdout.write( + "Retained temporary directory {}\n".format(tempdir)) + else: + shutil.rmtree(tempdir) + +if __name__ == '__main__': + main() From 6c924ba862475b83fcdeaaa43d8516c59b0c79a1 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 25 Aug 2018 14:36:25 +0100 Subject: [PATCH 387/607] GPG key rollover. This commit adds the new ids and fingerprints in the keys appendix of the manual, and moves the old ones down into the historic-keys section. I've tweaked a few pieces of wording for ongoing use, so that they don't imply a specific number of past key rollovers. The -pgpfp option in all the tools now shows the new Master Key fingerprint and the previous (2015) one. I've adjusted all the uses of the #defines in putty.h so that future rollovers should only have to modify the #defines themselves. Most importantly, sign.sh bakes in the ids of the current release and snapshot keys, so that snapshots will automatically be signed with the new snapshot key and the -r option will invoke the new release key. --- doc/pgpkeys.but | 91 ++++++++++++++++++++++++++++------------------ putty.h | 16 ++++---- sign.sh | 4 +- unix/uxmisc.c | 10 ++--- windows/wincons.c | 10 ++--- windows/winutils.c | 10 ++--- 6 files changed, 81 insertions(+), 60 deletions(-) diff --git a/doc/pgpkeys.but b/doc/pgpkeys.but index 71143af2..85008c88 100644 --- a/doc/pgpkeys.but +++ b/doc/pgpkeys.but @@ -53,31 +53,25 @@ The current issue of those keys are available for download from the PuTTY website, and are also available on PGP keyservers using the key IDs listed below. -\dt \W{https://www.chiark.greenend.org.uk/~sgtatham/putty/keys/master-2015.asc}{\s{Master Key}} +\dt \W{https://www.chiark.greenend.org.uk/~sgtatham/putty/keys/master-2018.asc}{\s{Master Key} (2018)} -\dd RSA, 4096-bit. Key ID: \cw{4096R/04676F7C} (long version: -\cw{4096R/AB585DC604676F7C}). Fingerprint: -\cw{440D\_E3B5\_B7A1\_CA85\_B3CC\_\_1718\_AB58\_5DC6\_0467\_6F7C} +\dd RSA, 4096-bit. Key ID: \cw{76BC7FE4EBFD2D9E}. Fingerprint: +\cw{24E1\_B1C5\_75EA\_3C9F\_F752\_\_A922\_76BC\_7FE4\_EBFD\_2D9E} -\dt \W{https://www.chiark.greenend.org.uk/~sgtatham/putty/keys/release-2015.asc}{\s{Release Key}} +\dt \W{https://www.chiark.greenend.org.uk/~sgtatham/putty/keys/release-2018.asc}{\s{Release Key} (2018)} -\dd RSA, 2048-bit. Key ID: \cw{2048R/B43434E4} (long version: -\cw{2048R/9DFE2648B43434E4}). Fingerprint: -\cw{0054\_DDAA\_8ADA\_15D2\_768A\_\_6DE7\_9DFE\_2648\_B434\_34E4} +\dd RSA, 3072-bit. Key ID: \cw{6289A25F4AE8DA82}. Fingerprint: +\cw{E273\_94AC\_A3F9\_D904\_9522\_\_E054\_6289\_A25F\_4AE8\_DA82} -\dt \W{https://www.chiark.greenend.org.uk/~sgtatham/putty/keys/contact-2016.asc}{\s{Secure Contact Key}} +\dt \W{https://www.chiark.greenend.org.uk/~sgtatham/putty/keys/snapshot-2018.asc}{\s{Snapshot Key} (2018)} -\dd RSA, 2048-bit. Main key ID: \cw{2048R/8A0AF00B} (long version: -\cw{2048R/C4FCAAD08A0AF00B}). Encryption subkey ID: -\cw{2048R/50C2CF5C} (long version: \cw{2048R/9EB39CC150C2CF5C}). -Fingerprint: -\cw{8A26\_250E\_763F\_E359\_75F3\_\_118F\_C4FC\_AAD0\_8A0A\_F00B} +\dd RSA, 3072-bit. Key ID: \cw{38BA7229B7588FD1}. Fingerprint: +\cw{C92B\_52E9\_9AB6\_1DDA\_33DB\_\_2B7A\_38BA\_7229\_B758\_8FD1} -\dt \W{https://www.chiark.greenend.org.uk/~sgtatham/putty/keys/snapshot-2015.asc}{\s{Snapshot Key}} +\dt \W{https://www.chiark.greenend.org.uk/~sgtatham/putty/keys/contact-2018.asc}{\s{Secure Contact Key} (2018)} -\dd RSA, 2048-bit. Key ID: \cw{2048R/D15F7E8A} (long version: -\cw{2048R/EEF20295D15F7E8A}). Fingerprint: -\cw{0A3B\_0048\_FE49\_9B67\_A234\_\_FEB6\_EEF2\_0295\_D15F\_7E8A} +\dd RSA, 3072-bit. Key ID: \cw{657D487977F95C98}. Fingerprint: +\cw{A680\_0082\_2998\_6E46\_22CA\_\_0E43\_657D\_4879\_77F9\_5C98} \H{pgpkeys-security} Security details @@ -156,28 +150,53 @@ once. \H{pgpkeys-rollover} Key rollover -Our current keys were generated in September 2015, except for the -Secure Contact Key which was generated in February 2016 (we didn't -think of it until later). +Our current keys were generated in August 2018. + +Each new Master Key is signed with the old one, to show that it really +is owned by the same people and not substituted by an attacker. -Prior to that, we had a much older set of keys generated in 2000. For -each of the key types above (other than the Secure Contact Key), we -provided both an RSA key \e{and} a DSA key (because at the time we -generated them, RSA was not in practice available to everyone, due to -export restrictions). +Each new Master Key also signs the previous Release Keys, in case +you're trying to verify the signatures on a release prior to the +rollover and can find a chain of trust to those keys from any of the +people who have signed our new Master Key. -The new Master Key is signed with both of the old ones, to show that -it really is owned by the same people and not substituted by an -attacker. Also, we have retrospectively signed the old Release Keys -with the new Master Key, in case you're trying to verify the -signatures on a release prior to the rollover and can find a chain of -trust to those keys from any of the people who have signed our new -Master Key. +Each release is signed with the Release Key that was current at the +time of release. We don't go back and re-sign old releases with newly +generated keys. -Future releases will be signed with the up-to-date keys shown above. -Releases prior to the rollover are signed with the old Release Keys. +The details of all previous keys are given here. + +\s{Key generated in 2016} (when we first introduced the Secure Contact Key) + +\dt \W{https://www.chiark.greenend.org.uk/~sgtatham/putty/keys/contact-2016.asc}{\s{Secure Contact Key} (2016)} + +\dd RSA, 2048-bit. Main key ID: \cw{2048R/8A0AF00B} (long version: +\cw{2048R/C4FCAAD08A0AF00B}). Encryption subkey ID: +\cw{2048R/50C2CF5C} (long version: \cw{2048R/9EB39CC150C2CF5C}). +Fingerprint: +\cw{8A26\_250E\_763F\_E359\_75F3\_\_118F\_C4FC\_AAD0\_8A0A\_F00B} + +\s{Keys generated in the 2015 rollover} + +\dt \W{https://www.chiark.greenend.org.uk/~sgtatham/putty/keys/master-2015.asc}{\s{Master Key} (2015)} + +\dd RSA, 4096-bit. Key ID: \cw{4096R/04676F7C} (long version: +\cw{4096R/AB585DC604676F7C}). Fingerprint: +\cw{440D\_E3B5\_B7A1\_CA85\_B3CC\_\_1718\_AB58\_5DC6\_0467\_6F7C} + +\dt \W{https://www.chiark.greenend.org.uk/~sgtatham/putty/keys/release-2015.asc}{\s{Release Key} (2015)} + +\dd RSA, 2048-bit. Key ID: \cw{2048R/B43434E4} (long version: +\cw{2048R/9DFE2648B43434E4}). Fingerprint: +\cw{0054\_DDAA\_8ADA\_15D2\_768A\_\_6DE7\_9DFE\_2648\_B434\_34E4} + +\dt \W{https://www.chiark.greenend.org.uk/~sgtatham/putty/keys/snapshot-2015.asc}{\s{Snapshot Key} (2015)} + +\dd RSA, 2048-bit. Key ID: \cw{2048R/D15F7E8A} (long version: +\cw{2048R/EEF20295D15F7E8A}). Fingerprint: +\cw{0A3B\_0048\_FE49\_9B67\_A234\_\_FEB6\_EEF2\_0295\_D15F\_7E8A} -For completeness, those old keys are given here: +\s{Original keys generated in 2000} (two sets, RSA and DSA) \dt \W{https://www.chiark.greenend.org.uk/~sgtatham/putty/keys/master-rsa.asc}{\s{Master Key} (original RSA)} diff --git a/putty.h b/putty.h index fb9a2d55..844c6fa1 100644 --- a/putty.h +++ b/putty.h @@ -30,15 +30,17 @@ #define MAX_TICK_MINS (INT_MAX / (60 * TICKSPERSEC)) /* - * Fingerprints of the PGP master keys that can be used to establish a trust - * path between an executable and other files. + * Fingerprints of the current and previous PGP master keys, to + * establish a trust path between an executable and other files. */ -#define PGP_MASTER_KEY_FP \ +#define PGP_MASTER_KEY_YEAR "2018" +#define PGP_MASTER_KEY_DETAILS "RSA, 4096-bit" +#define PGP_MASTER_KEY_FP \ + "24E1 B1C5 75EA 3C9F F752 A922 76BC 7FE4 EBFD 2D9E" +#define PGP_PREV_MASTER_KEY_YEAR "2015" +#define PGP_PREV_MASTER_KEY_DETAILS "RSA, 4096-bit" +#define PGP_PREV_MASTER_KEY_FP \ "440D E3B5 B7A1 CA85 B3CC 1718 AB58 5DC6 0467 6F7C" -#define PGP_RSA_MASTER_KEY_FP \ - "8F 15 97 DA 25 30 AB 0D 88 D1 92 54 11 CF 0C 4C" -#define PGP_DSA_MASTER_KEY_FP \ - "313C 3E76 4B74 C2C5 F2AE 83A8 4F5E 6DF5 6A93 B34E" /* Three attribute types: * The ATTRs (normal attributes) are stored with the characters in diff --git a/sign.sh b/sign.sh index 8dbdb613..bece850a 100755 --- a/sign.sh +++ b/sign.sh @@ -9,14 +9,14 @@ set -e -keyname=EEF20295D15F7E8A +keyname=38BA7229B7588FD1 preliminary=false while :; do case "$1" in -r) shift - keyname=9DFE2648B43434E4 + keyname=6289A25F4AE8DA82 ;; -p) shift diff --git a/unix/uxmisc.c b/unix/uxmisc.c index c478856b..320a6c9e 100644 --- a/unix/uxmisc.c +++ b/unix/uxmisc.c @@ -158,12 +158,12 @@ void pgp_fingerprints(void) "one. See the manual for more information.\n" "(Note: these fingerprints have nothing to do with SSH!)\n" "\n" - "PuTTY Master Key as of 2015 (RSA, 4096-bit):\n" + "PuTTY Master Key as of " PGP_MASTER_KEY_YEAR + " (" PGP_MASTER_KEY_DETAILS "):\n" " " PGP_MASTER_KEY_FP "\n\n" - "Original PuTTY Master Key (RSA, 1024-bit):\n" - " " PGP_RSA_MASTER_KEY_FP "\n" - "Original PuTTY Master Key (DSA, 1024-bit):\n" - " " PGP_DSA_MASTER_KEY_FP "\n", stdout); + "Previous Master Key (" PGP_PREV_MASTER_KEY_YEAR + ", " PGP_PREV_MASTER_KEY_DETAILS "):\n" + " " PGP_PREV_MASTER_KEY_FP "\n", stdout); } /* diff --git a/windows/wincons.c b/windows/wincons.c index e315f64a..4827ddbd 100644 --- a/windows/wincons.c +++ b/windows/wincons.c @@ -327,12 +327,12 @@ void pgp_fingerprints(void) "one. See the manual for more information.\n" "(Note: these fingerprints have nothing to do with SSH!)\n" "\n" - "PuTTY Master Key as of 2015 (RSA, 4096-bit):\n" + "PuTTY Master Key as of " PGP_MASTER_KEY_YEAR + " (" PGP_MASTER_KEY_DETAILS "):\n" " " PGP_MASTER_KEY_FP "\n\n" - "Original PuTTY Master Key (RSA, 1024-bit):\n" - " " PGP_RSA_MASTER_KEY_FP "\n" - "Original PuTTY Master Key (DSA, 1024-bit):\n" - " " PGP_DSA_MASTER_KEY_FP "\n", stdout); + "Previous Master Key (" PGP_PREV_MASTER_KEY_YEAR + ", " PGP_PREV_MASTER_KEY_DETAILS "):\n" + " " PGP_PREV_MASTER_KEY_FP "\n", stdout); } void console_provide_logctx(void *logctx) diff --git a/windows/winutils.c b/windows/winutils.c index 31b98d18..58614966 100644 --- a/windows/winutils.c +++ b/windows/winutils.c @@ -142,12 +142,12 @@ void pgp_fingerprints(void) "one. See the manual for more information.\n" "(Note: these fingerprints have nothing to do with SSH!)\n" "\n" - "PuTTY Master Key as of 2015 (RSA, 4096-bit):\n" + "PuTTY Master Key as of " PGP_MASTER_KEY_YEAR + " (" PGP_MASTER_KEY_DETAILS "):\n" " " PGP_MASTER_KEY_FP "\n\n" - "Original PuTTY Master Key (RSA, 1024-bit):\n" - " " PGP_RSA_MASTER_KEY_FP "\n" - "Original PuTTY Master Key (DSA, 1024-bit):\n" - " " PGP_DSA_MASTER_KEY_FP, + "Previous Master Key (" PGP_PREV_MASTER_KEY_YEAR + ", " PGP_PREV_MASTER_KEY_DETAILS "):\n" + " " PGP_PREV_MASTER_KEY_FP, "PGP fingerprints", MB_ICONINFORMATION | MB_OK, HELPCTXID(pgp_fingerprints)); } From 566d4826f4115006b2bfaf5210649a7935cb3c00 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Wed, 12 Sep 2018 08:55:39 +0100 Subject: [PATCH 388/607] testback.c: add some missing 'const'. This source file isn't actually built as part of even a test binary, so it hasn't been kept up to date with internal API changes. But it might still come in useful in the future (I think its original purpose was to substitute for a normal backend in order to test the GUI side of a new PuTTY port before the network side was written), so I'll at least try to carry on keeping it updated. --- testback.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/testback.c b/testback.c index 752ec4ca..a84caee0 100644 --- a/testback.c +++ b/testback.c @@ -32,15 +32,15 @@ #include "putty.h" -static const char *null_init(void *, void **, Conf *, char *, int, char **, - int, int); -static const char *loop_init(void *, void **, Conf *, char *, int, char **, - int, int); +static const char *null_init(void *, void **, Conf *, const char *, int, + char **, int, int); +static const char *loop_init(void *, void **, Conf *, const char *, int, + char **, int, int); static void null_free(void *); static void loop_free(void *); static void null_reconfig(void *, Conf *); -static int null_send(void *, char *, int); -static int loop_send(void *, char *, int); +static int null_send(void *, const char *, int); +static int loop_send(void *, const char *, int); static int null_sendbuffer(void *); static void null_size(void *, int, int); static void null_special(void *, Telnet_Special); @@ -73,14 +73,14 @@ struct loop_state { }; static const char *null_init(void *frontend_handle, void **backend_handle, - Conf *conf, char *host, int port, + Conf *conf, const char *host, int port, char **realhost, int nodelay, int keepalive) { return NULL; } static const char *loop_init(void *frontend_handle, void **backend_handle, - Conf *conf, char *host, int port, + Conf *conf, const char *host, int port, char **realhost, int nodelay, int keepalive) { struct loop_state *st = snew(struct loop_state); @@ -104,12 +104,12 @@ static void null_reconfig(void *handle, Conf *conf) { } -static int null_send(void *handle, char *buf, int len) { +static int null_send(void *handle, const char *buf, int len) { return 0; } -static int loop_send(void *handle, char *buf, int len) { +static int loop_send(void *handle, const char *buf, int len) { struct loop_state *st = handle; return from_backend(st->term, 0, buf, len); From e72e8ebe59439e373c336c84d44d214fdc5476f0 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Tue, 11 Sep 2018 15:02:59 +0100 Subject: [PATCH 389/607] Expose the Ldisc structure tag throughout the code. That's one fewer anonymous 'void *' which might be accidentally confused with some other pointer type if I misremember the order of function arguments. While I'm here, I've made its pointer-nature explicit - that is, 'Ldisc' is now a typedef for the structure type itself rather than a pointer to it. A stylistic change only, but it feels more natural to me these days for a thing you're going to eventually pass to a 'free' function. --- defs.h | 2 ++ fuzzterm.c | 4 ++-- ldisc.c | 28 +++++++++++----------------- ldisc.h | 4 ++-- ldiscucs.c | 6 ++---- pscp.c | 2 +- psftp.c | 2 +- putty.h | 16 ++++++++-------- raw.c | 2 +- rlogin.c | 2 +- ssh.c | 4 ++-- telnet.c | 4 ++-- terminal.h | 2 +- testback.c | 4 ++-- unix/gtkwin.c | 2 +- unix/uxpty.c | 2 +- unix/uxser.c | 2 +- windows/window.c | 2 +- windows/winser.c | 2 +- 19 files changed, 43 insertions(+), 49 deletions(-) diff --git a/defs.h b/defs.h index bfdf345d..f1d73fb5 100644 --- a/defs.h +++ b/defs.h @@ -44,6 +44,8 @@ typedef struct SockAddr_tag *SockAddr; typedef struct Socket_vtable Socket_vtable; typedef struct Plug_vtable Plug_vtable; +typedef struct Ldisc_tag Ldisc; + /* Note indirection: for historical reasons (it used to be closer to * the OS socket type), the type that most code uses for a socket is * 'Socket', not 'Socket *'. So an implementation of Socket or Plug diff --git a/fuzzterm.c b/fuzzterm.c index 21246069..cdefb0d9 100644 --- a/fuzzterm.c +++ b/fuzzterm.c @@ -71,8 +71,8 @@ void set_title(void *frontend, char *t) { } void set_icon(void *frontend, char *t) { } void set_sbar(void *frontend, int a, int b, int c) { } -void ldisc_send(void *handle, const void *buf, int len, int interactive) {} -void ldisc_echoedit_update(void *handle) {} +void ldisc_send(Ldisc *ldisc, const void *buf, int len, int interactive) {} +void ldisc_echoedit_update(Ldisc *ldisc) {} Context get_ctx(void *frontend) { static char x; diff --git a/ldisc.c b/ldisc.c index 06c5e90f..ba90e1d0 100644 --- a/ldisc.c +++ b/ldisc.c @@ -22,12 +22,12 @@ (ldisc->back->ldisc(ldisc->backhandle, LD_EDIT) || \ term_ldisc(ldisc->term, LD_EDIT)))) -static void c_write(Ldisc ldisc, const void *buf, int len) +static void c_write(Ldisc *ldisc, const void *buf, int len) { from_backend(ldisc->frontend, 0, buf, len); } -static int plen(Ldisc ldisc, unsigned char c) +static int plen(Ldisc *ldisc, unsigned char c) { if ((c >= 32 && c <= 126) || (c >= 160 && !in_utf(ldisc->term))) return 1; @@ -42,7 +42,7 @@ static int plen(Ldisc ldisc, unsigned char c) return 4; /* hex representation */ } -static void pwrite(Ldisc ldisc, unsigned char c) +static void pwrite(Ldisc *ldisc, unsigned char c) { if ((c >= 32 && c <= 126) || (!in_utf(ldisc->term) && c >= 0xA0) || @@ -60,7 +60,7 @@ static void pwrite(Ldisc ldisc, unsigned char c) } } -static int char_start(Ldisc ldisc, unsigned char c) +static int char_start(Ldisc *ldisc, unsigned char c) { if (in_utf(ldisc->term)) return (c < 0x80 || c >= 0xC0); @@ -68,7 +68,7 @@ static int char_start(Ldisc ldisc, unsigned char c) return 1; } -static void bsb(Ldisc ldisc, int n) +static void bsb(Ldisc *ldisc, int n) { while (n--) c_write(ldisc, "\010 \010", 3); @@ -77,11 +77,11 @@ static void bsb(Ldisc ldisc, int n) #define CTRL(x) (x^'@') #define KCTRL(x) ((x^'@') | 0x100) -void *ldisc_create(Conf *conf, Terminal *term, +Ldisc *ldisc_create(Conf *conf, Terminal *term, Backend *back, void *backhandle, void *frontend) { - Ldisc ldisc = snew(struct ldisc_tag); + Ldisc *ldisc = snew(Ldisc); ldisc->buf = NULL; ldisc->buflen = 0; @@ -104,10 +104,8 @@ void *ldisc_create(Conf *conf, Terminal *term, return ldisc; } -void ldisc_configure(void *handle, Conf *conf) +void ldisc_configure(Ldisc *ldisc, Conf *conf) { - Ldisc ldisc = (Ldisc) handle; - ldisc->telnet_keyboard = conf_get_int(conf, CONF_telnet_keyboard); ldisc->telnet_newline = conf_get_int(conf, CONF_telnet_newline); ldisc->protocol = conf_get_int(conf, CONF_protocol); @@ -115,10 +113,8 @@ void ldisc_configure(void *handle, Conf *conf) ldisc->localedit = conf_get_int(conf, CONF_localedit); } -void ldisc_free(void *handle) +void ldisc_free(Ldisc *ldisc) { - Ldisc ldisc = (Ldisc) handle; - if (ldisc->term) ldisc->term->ldisc = NULL; if (ldisc->back) @@ -128,16 +124,14 @@ void ldisc_free(void *handle) sfree(ldisc); } -void ldisc_echoedit_update(void *handle) +void ldisc_echoedit_update(Ldisc *ldisc) { - Ldisc ldisc = (Ldisc) handle; frontend_echoedit_update(ldisc->frontend, ECHOING, EDITING); } -void ldisc_send(void *handle, const void *vbuf, int len, int interactive) +void ldisc_send(Ldisc *ldisc, const void *vbuf, int len, int interactive) { const char *buf = (const char *)vbuf; - Ldisc ldisc = (Ldisc) handle; int keyflag = 0; assert(ldisc->term); diff --git a/ldisc.h b/ldisc.h index 5dbe2a76..44f5772f 100644 --- a/ldisc.h +++ b/ldisc.h @@ -8,7 +8,7 @@ #ifndef PUTTY_LDISC_H #define PUTTY_LDISC_H -typedef struct ldisc_tag { +struct Ldisc_tag { Terminal *term; Backend *back; void *backhandle; @@ -21,6 +21,6 @@ typedef struct ldisc_tag { char *buf; int buflen, bufsiz, quotenext; -} *Ldisc; +}; #endif /* PUTTY_LDISC_H */ diff --git a/ldiscucs.c b/ldiscucs.c index 1634bc43..6c943a09 100644 --- a/ldiscucs.c +++ b/ldiscucs.c @@ -12,10 +12,9 @@ #include "terminal.h" #include "ldisc.h" -void lpage_send(void *handle, +void lpage_send(Ldisc *ldisc, int codepage, const char *buf, int len, int interactive) { - Ldisc ldisc = (Ldisc)handle; wchar_t *widebuffer = 0; int widesize = 0; int wclen; @@ -34,9 +33,8 @@ void lpage_send(void *handle, sfree(widebuffer); } -void luni_send(void *handle, const wchar_t *widebuf, int len, int interactive) +void luni_send(Ldisc *ldisc, const wchar_t *widebuf, int len, int interactive) { - Ldisc ldisc = (Ldisc)handle; int ratio = (in_utf(ldisc->term))?3:1; char *linebuffer; int linesize; diff --git a/pscp.c b/pscp.c index 22cbf57e..964e2443 100644 --- a/pscp.c +++ b/pscp.c @@ -60,7 +60,7 @@ const char *const appname = "PSCP"; */ #define MAX_SCP_BUFSIZE 16384 -void ldisc_echoedit_update(void *handle) { } +void ldisc_echoedit_update(Ldisc *ldisc) { } static void tell_char(FILE *stream, char c) { diff --git a/psftp.c b/psftp.c index 46eeeb40..b28c0976 100644 --- a/psftp.c +++ b/psftp.c @@ -2483,7 +2483,7 @@ void connection_fatal(void *frontend, const char *fmt, ...) cleanup_exit(1); } -void ldisc_echoedit_update(void *handle) { } +void ldisc_echoedit_update(Ldisc *ldisc) { } /* * In psftp, all agent requests should be synchronous, so this is a diff --git a/putty.h b/putty.h index 844c6fa1..042f66c5 100644 --- a/putty.h +++ b/putty.h @@ -461,7 +461,7 @@ struct backend_tag { * may be lost. */ int (*sendok) (void *handle); int (*ldisc) (void *handle, int); - void (*provide_ldisc) (void *handle, void *ldisc); + void (*provide_ldisc) (void *handle, Ldisc *ldisc); void (*provide_logctx) (void *handle, void *logctx); /* * back->unthrottle() tells the back end that the front end @@ -1174,18 +1174,18 @@ extern Backend ssh_backend; /* * Exports from ldisc.c. */ -void *ldisc_create(Conf *, Terminal *, Backend *, void *, void *); -void ldisc_configure(void *, Conf *); -void ldisc_free(void *); -void ldisc_send(void *handle, const void *buf, int len, int interactive); -void ldisc_echoedit_update(void *handle); +Ldisc *ldisc_create(Conf *, Terminal *, Backend *, void *, void *); +void ldisc_configure(Ldisc *, Conf *); +void ldisc_free(Ldisc *); +void ldisc_send(Ldisc *, const void *buf, int len, int interactive); +void ldisc_echoedit_update(Ldisc *); /* * Exports from ldiscucs.c. */ -void lpage_send(void *, int codepage, const char *buf, int len, +void lpage_send(Ldisc *, int codepage, const char *buf, int len, int interactive); -void luni_send(void *, const wchar_t * widebuf, int len, int interactive); +void luni_send(Ldisc *, const wchar_t * widebuf, int len, int interactive); /* * Exports from sshrand.c. diff --git a/raw.c b/raw.c index 67d34601..58a500c7 100644 --- a/raw.c +++ b/raw.c @@ -274,7 +274,7 @@ static int raw_ldisc(void *handle, int option) return 0; } -static void raw_provide_ldisc(void *handle, void *ldisc) +static void raw_provide_ldisc(void *handle, Ldisc *ldisc) { /* This is a stub. */ } diff --git a/rlogin.c b/rlogin.c index 9156340c..7f9093e4 100644 --- a/rlogin.c +++ b/rlogin.c @@ -366,7 +366,7 @@ static int rlogin_ldisc(void *handle, int option) return 0; } -static void rlogin_provide_ldisc(void *handle, void *ldisc) +static void rlogin_provide_ldisc(void *handle, Ldisc *ldisc) { /* This is a stub. */ } diff --git a/ssh.c b/ssh.c index 4c237e31..d02b7321 100644 --- a/ssh.c +++ b/ssh.c @@ -700,7 +700,7 @@ struct ssh_tag { const Plug_vtable *plugvt; - void *ldisc; + Ldisc *ldisc; void *logctx; unsigned char session_key[32]; @@ -11428,7 +11428,7 @@ static int ssh_ldisc(void *handle, int option) return FALSE; } -static void ssh_provide_ldisc(void *handle, void *ldisc) +static void ssh_provide_ldisc(void *handle, Ldisc *ldisc) { Ssh ssh = (Ssh) handle; ssh->ldisc = ldisc; diff --git a/telnet.c b/telnet.c index 6fe509dc..0f958b50 100644 --- a/telnet.c +++ b/telnet.c @@ -175,7 +175,7 @@ typedef struct telnet_tag { int closed_on_socket_error; void *frontend; - void *ldisc; + Ldisc *ldisc; int term_width, term_height; int opt_states[NUM_OPTS]; @@ -1059,7 +1059,7 @@ static int telnet_ldisc(void *handle, int option) return FALSE; } -static void telnet_provide_ldisc(void *handle, void *ldisc) +static void telnet_provide_ldisc(void *handle, Ldisc *ldisc) { Telnet telnet = (Telnet) handle; telnet->ldisc = ldisc; diff --git a/terminal.h b/terminal.h index ba4a07f6..3eb60939 100644 --- a/terminal.h +++ b/terminal.h @@ -230,7 +230,7 @@ struct terminal_tag { void (*resize_fn)(void *, int, int); void *resize_ctx; - void *ldisc; + Ldisc *ldisc; void *frontend; diff --git a/testback.c b/testback.c index a84caee0..d84c77db 100644 --- a/testback.c +++ b/testback.c @@ -49,7 +49,7 @@ static int null_connected(void *); static int null_exitcode(void *); static int null_sendok(void *); static int null_ldisc(void *, int); -static void null_provide_ldisc(void *, void *); +static void null_provide_ldisc(void *, Ldisc *); static void null_provide_logctx(void *, void *); static void null_unthrottle(void *, int); static int null_cfg_info(void *); @@ -157,7 +157,7 @@ static int null_ldisc(void *handle, int option) { return 0; } -static void null_provide_ldisc (void *handle, void *ldisc) { +static void null_provide_ldisc (void *handle, Ldisc *ldisc) { } diff --git a/unix/gtkwin.c b/unix/gtkwin.c index 5b84c7c9..e28146b4 100644 --- a/unix/gtkwin.c +++ b/unix/gtkwin.c @@ -158,7 +158,7 @@ struct gui_data { char *wintitle; char *icontitle; int master_fd, master_func_id; - void *ldisc; + Ldisc *ldisc; Backend *back; void *backhandle; Terminal *term; diff --git a/unix/uxpty.c b/unix/uxpty.c index 7aaad8ac..9df61532 100644 --- a/unix/uxpty.c +++ b/unix/uxpty.c @@ -1206,7 +1206,7 @@ static int pty_ldisc(void *handle, int option) return 0; /* neither editing nor echoing */ } -static void pty_provide_ldisc(void *handle, void *ldisc) +static void pty_provide_ldisc(void *handle, Ldisc *ldisc) { /* Pty pty = (Pty)handle; */ /* This is a stub. */ diff --git a/unix/uxser.c b/unix/uxser.c index e77f797a..558cf015 100644 --- a/unix/uxser.c +++ b/unix/uxser.c @@ -544,7 +544,7 @@ static int serial_ldisc(void *handle, int option) return 0; } -static void serial_provide_ldisc(void *handle, void *ldisc) +static void serial_provide_ldisc(void *handle, Ldisc *ldisc) { /* This is a stub. */ } diff --git a/windows/window.c b/windows/window.c index 1a7bb472..80b94201 100644 --- a/windows/window.c +++ b/windows/window.c @@ -125,7 +125,7 @@ static int caret_x = -1, caret_y = -1; static int kbd_codepage; -static void *ldisc; +static Ldisc *ldisc; static Backend *back; static void *backhandle; diff --git a/windows/winser.c b/windows/winser.c index 976f8955..2dd45fac 100644 --- a/windows/winser.c +++ b/windows/winser.c @@ -409,7 +409,7 @@ static int serial_ldisc(void *handle, int option) return 0; } -static void serial_provide_ldisc(void *handle, void *ldisc) +static void serial_provide_ldisc(void *handle, Ldisc *ldisc) { /* This is a stub. */ } From 3814a5cee87e759568f53df4497d48d61e66cf84 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Tue, 11 Sep 2018 15:17:16 +0100 Subject: [PATCH 390/607] Make 'LogContext' a typedef visible throughout the code. Same principle again - the more of these structures have globally visible tags (even if the structure contents are still opaque in most places), the fewer of them I can mistake for each other. --- cmdgen.c | 2 +- defs.h | 1 + logging.c | 40 ++++++++++++++++------------------------ pscp.c | 2 +- psftp.c | 2 +- putty.h | 24 ++++++++++++------------ raw.c | 2 +- rlogin.c | 2 +- ssh.c | 4 ++-- sshbpp.h | 2 +- telnet.c | 2 +- terminal.c | 2 +- terminal.h | 2 +- testback.c | 4 ++-- unix/gtkwin.c | 2 +- unix/uxcons.c | 2 +- unix/uxpgnt.c | 2 +- unix/uxplink.c | 2 +- unix/uxpty.c | 2 +- unix/uxser.c | 2 +- windows/wincons.c | 2 +- windows/winser.c | 2 +- windows/winstuff.h | 2 +- 23 files changed, 51 insertions(+), 58 deletions(-) diff --git a/cmdgen.c b/cmdgen.c index 7cf920f3..034b9154 100644 --- a/cmdgen.c +++ b/cmdgen.c @@ -116,7 +116,7 @@ void nonfatal(const char *p, ...) /* * Stubs to let everything else link sensibly. */ -void log_eventlog(void *handle, const char *event) +void log_eventlog(LogContext *logctx, const char *event) { } char *x_get_default(const char *key) diff --git a/defs.h b/defs.h index f1d73fb5..45b56d60 100644 --- a/defs.h +++ b/defs.h @@ -45,6 +45,7 @@ typedef struct Socket_vtable Socket_vtable; typedef struct Plug_vtable Plug_vtable; typedef struct Ldisc_tag Ldisc; +typedef struct LogContext_tag LogContext; /* Note indirection: for historical reasons (it used to be closer to * the OS socket type), the type that most code uses for a socket is diff --git a/logging.c b/logging.c index 41c5b257..75c457e3 100644 --- a/logging.c +++ b/logging.c @@ -12,7 +12,7 @@ #include "putty.h" /* log session to file stuff ... */ -struct LogContext { +struct LogContext_tag { FILE *lgfp; enum { L_CLOSED, L_OPENING, L_OPEN, L_ERROR } state; bufchain queue; @@ -31,7 +31,7 @@ static Filename *xlatlognam(Filename *s, char *hostname, int port, * isn't open, buffering data if it's in the process of being * opened asynchronously, etc. */ -static void logwrite(struct LogContext *ctx, void *data, int len) +static void logwrite(LogContext *ctx, void *data, int len) { /* * In state L_CLOSED, we call logfopen, which will set the state @@ -59,7 +59,7 @@ static void logwrite(struct LogContext *ctx, void *data, int len) * Convenience wrapper on logwrite() which printf-formats the * string. */ -static void logprintf(struct LogContext *ctx, const char *fmt, ...) +static void logprintf(LogContext *ctx, const char *fmt, ...) { va_list ap; char *data; @@ -75,16 +75,16 @@ static void logprintf(struct LogContext *ctx, const char *fmt, ...) /* * Flush any open log file. */ -void logflush(void *handle) { - struct LogContext *ctx = (struct LogContext *)handle; +void logflush(LogContext *ctx) +{ if (ctx->logtype > 0) if (ctx->state == L_OPEN) fflush(ctx->lgfp); } -static void logfopen_callback(void *handle, int mode) +static void logfopen_callback(void *vctx, int mode) { - struct LogContext *ctx = (struct LogContext *)handle; + LogContext *ctx = (LogContext *)vctx; char buf[256], *event; struct tm tm; const char *fmode; @@ -160,9 +160,8 @@ static void logfopen_callback(void *handle, int mode) * file and asking the user whether they want to append, overwrite * or cancel logging. */ -void logfopen(void *handle) +void logfopen(LogContext *ctx) { - struct LogContext *ctx = (struct LogContext *)handle; struct tm tm; int mode; @@ -199,9 +198,8 @@ void logfopen(void *handle) logfopen_callback(ctx, mode); /* open the file */ } -void logfclose(void *handle) +void logfclose(LogContext *ctx) { - struct LogContext *ctx = (struct LogContext *)handle; if (ctx->lgfp) { fclose(ctx->lgfp); ctx->lgfp = NULL; @@ -212,9 +210,8 @@ void logfclose(void *handle) /* * Log session traffic. */ -void logtraffic(void *handle, unsigned char c, int logmode) +void logtraffic(LogContext *ctx, unsigned char c, int logmode) { - struct LogContext *ctx = (struct LogContext *)handle; if (ctx->logtype > 0) { if (ctx->logtype == logmode) logwrite(ctx, &c, 1); @@ -230,9 +227,8 @@ void logtraffic(void *handle, unsigned char c, int logmode) * platforms. Platforms which don't have a meaningful stderr can * just avoid defining FLAG_STDERR. */ -void log_eventlog(void *handle, const char *event) +void log_eventlog(LogContext *ctx, const char *event) { - struct LogContext *ctx = (struct LogContext *)handle; if ((flags & FLAG_STDERR) && (flags & FLAG_VERBOSE)) { fprintf(stderr, "%s\n", event); fflush(stderr); @@ -252,13 +248,12 @@ void log_eventlog(void *handle, const char *event) * If n_blanks != 0, blank or omit some parts. * Set of blanking areas must be in increasing order. */ -void log_packet(void *handle, int direction, int type, +void log_packet(LogContext *ctx, int direction, int type, const char *texttype, const void *data, int len, int n_blanks, const struct logblank_t *blanks, const unsigned long *seq, unsigned downstream_id, const char *additional_log_text) { - struct LogContext *ctx = (struct LogContext *)handle; char dumpdata[80], smalldata[5]; int p = 0, b = 0, omitted = 0; int output_pos = 0; /* NZ if pending output in dumpdata */ @@ -372,9 +367,9 @@ void log_packet(void *handle, int direction, int type, logflush(ctx); } -void *log_init(void *frontend, Conf *conf) +LogContext *log_init(void *frontend, Conf *conf) { - struct LogContext *ctx = snew(struct LogContext); + LogContext *ctx = snew(LogContext); ctx->lgfp = NULL; ctx->state = L_CLOSED; ctx->frontend = frontend; @@ -385,10 +380,8 @@ void *log_init(void *frontend, Conf *conf) return ctx; } -void log_free(void *handle) +void log_free(LogContext *ctx) { - struct LogContext *ctx = (struct LogContext *)handle; - logfclose(ctx); bufchain_clear(&ctx->queue); if (ctx->currlogfilename) @@ -397,9 +390,8 @@ void log_free(void *handle) sfree(ctx); } -void log_reconfig(void *handle, Conf *conf) +void log_reconfig(LogContext *ctx, Conf *conf) { - struct LogContext *ctx = (struct LogContext *)handle; int reset_logging; if (!filename_equal(conf_get_filename(ctx->conf, CONF_logfilename), diff --git a/pscp.c b/pscp.c index 964e2443..bc2140f5 100644 --- a/pscp.c +++ b/pscp.c @@ -340,7 +340,7 @@ static void do_cmd(char *host, char *user, char *cmd) { const char *err; char *realhost; - void *logctx; + LogContext *logctx; if (host == NULL || host[0] == '\0') bump("Empty host name"); diff --git a/psftp.c b/psftp.c index b28c0976..cd419ebe 100644 --- a/psftp.c +++ b/psftp.c @@ -2669,7 +2669,7 @@ static int psftp_connect(char *userhost, char *user, int portnumber) { char *host, *realhost; const char *err; - void *logctx; + LogContext *logctx; /* Separate host and username */ host = userhost; diff --git a/putty.h b/putty.h index 042f66c5..14451756 100644 --- a/putty.h +++ b/putty.h @@ -462,7 +462,7 @@ struct backend_tag { int (*sendok) (void *handle); int (*ldisc) (void *handle, int); void (*provide_ldisc) (void *handle, Ldisc *ldisc); - void (*provide_logctx) (void *handle, void *logctx); + void (*provide_logctx) (void *handle, LogContext *logctx); /* * back->unthrottle() tells the back end that the front end * buffer is clearing. @@ -1110,7 +1110,7 @@ int term_data_untrusted(Terminal *, const void *data, int len); void term_provide_resize_fn(Terminal *term, void (*resize_fn)(void *, int, int), void *resize_ctx); -void term_provide_logctx(Terminal *term, void *logctx); +void term_provide_logctx(Terminal *term, LogContext *logctx); void term_set_focus(Terminal *term, int has_focus); char *term_get_ttymode(Terminal *term, const char *mode); int term_get_userpass_input(Terminal *term, prompts_t *p, bufchain *input); @@ -1120,14 +1120,14 @@ int format_arrow_key(char *buf, Terminal *term, int xkey, int ctrl); /* * Exports from logging.c. */ -void *log_init(void *frontend, Conf *conf); -void log_free(void *logctx); -void log_reconfig(void *logctx, Conf *conf); -void logfopen(void *logctx); -void logfclose(void *logctx); -void logtraffic(void *logctx, unsigned char c, int logmode); -void logflush(void *logctx); -void log_eventlog(void *logctx, const char *string); +LogContext *log_init(void *frontend, Conf *conf); +void log_free(LogContext *logctx); +void log_reconfig(LogContext *logctx, Conf *conf); +void logfopen(LogContext *logctx); +void logfclose(LogContext *logctx); +void logtraffic(LogContext *logctx, unsigned char c, int logmode); +void logflush(LogContext *logctx); +void log_eventlog(LogContext *logctx, const char *string); enum { PKT_INCOMING, PKT_OUTGOING }; enum { PKTLOG_EMIT, PKTLOG_BLANK, PKTLOG_OMIT }; struct logblank_t { @@ -1135,7 +1135,7 @@ struct logblank_t { int len; int type; }; -void log_packet(void *logctx, int direction, int type, +void log_packet(LogContext *logctx, int direction, int type, const char *texttype, const void *data, int len, int n_blanks, const struct logblank_t *blanks, const unsigned long *sequence, @@ -1353,7 +1353,7 @@ int askappend(void *frontend, Filename *filename, */ extern int console_batch_mode; int console_get_userpass_input(prompts_t *p); -void console_provide_logctx(void *logctx); +void console_provide_logctx(LogContext *logctx); int is_interactive(void); /* diff --git a/raw.c b/raw.c index 58a500c7..658bd030 100644 --- a/raw.c +++ b/raw.c @@ -279,7 +279,7 @@ static void raw_provide_ldisc(void *handle, Ldisc *ldisc) /* This is a stub. */ } -static void raw_provide_logctx(void *handle, void *logctx) +static void raw_provide_logctx(void *handle, LogContext *logctx) { /* This is a stub. */ } diff --git a/rlogin.c b/rlogin.c index 7f9093e4..dcba9c0c 100644 --- a/rlogin.c +++ b/rlogin.c @@ -371,7 +371,7 @@ static void rlogin_provide_ldisc(void *handle, Ldisc *ldisc) /* This is a stub. */ } -static void rlogin_provide_logctx(void *handle, void *logctx) +static void rlogin_provide_logctx(void *handle, LogContext *logctx) { /* This is a stub. */ } diff --git a/ssh.c b/ssh.c index d02b7321..609e1155 100644 --- a/ssh.c +++ b/ssh.c @@ -701,7 +701,7 @@ struct ssh_tag { const Plug_vtable *plugvt; Ldisc *ldisc; - void *logctx; + LogContext *logctx; unsigned char session_key[32]; int v1_remote_protoflags; @@ -11434,7 +11434,7 @@ static void ssh_provide_ldisc(void *handle, Ldisc *ldisc) ssh->ldisc = ldisc; } -static void ssh_provide_logctx(void *handle, void *logctx) +static void ssh_provide_logctx(void *handle, LogContext *logctx) { Ssh ssh = (Ssh) handle; ssh->logctx = logctx; diff --git a/sshbpp.h b/sshbpp.h index 5ec3c6ce..c1ac7a13 100644 --- a/sshbpp.h +++ b/sshbpp.h @@ -19,7 +19,7 @@ struct BinaryPacketProtocol { bufchain *in_raw, *out_raw; PacketQueue *in_pq; PacketLogSettings *pls; - void *logctx; + LogContext *logctx; int seen_disconnect; char *error; diff --git a/telnet.c b/telnet.c index 0f958b50..ed585276 100644 --- a/telnet.c +++ b/telnet.c @@ -1065,7 +1065,7 @@ static void telnet_provide_ldisc(void *handle, Ldisc *ldisc) telnet->ldisc = ldisc; } -static void telnet_provide_logctx(void *handle, void *logctx) +static void telnet_provide_logctx(void *handle, LogContext *logctx) { /* This is a stub. */ } diff --git a/terminal.c b/terminal.c index a368b23f..04e222d0 100644 --- a/terminal.c +++ b/terminal.c @@ -6687,7 +6687,7 @@ int term_data_untrusted(Terminal *term, const void *vdata, int len) return 0; /* assumes that term_data() always returns 0 */ } -void term_provide_logctx(Terminal *term, void *logctx) +void term_provide_logctx(Terminal *term, LogContext *logctx) { term->logctx = logctx; } diff --git a/terminal.h b/terminal.h index 3eb60939..244ff3bc 100644 --- a/terminal.h +++ b/terminal.h @@ -234,7 +234,7 @@ struct terminal_tag { void *frontend; - void *logctx; + LogContext *logctx; struct unicode_data *ucsdata; diff --git a/testback.c b/testback.c index d84c77db..78b89333 100644 --- a/testback.c +++ b/testback.c @@ -50,7 +50,7 @@ static int null_exitcode(void *); static int null_sendok(void *); static int null_ldisc(void *, int); static void null_provide_ldisc(void *, Ldisc *); -static void null_provide_logctx(void *, void *); +static void null_provide_logctx(void *, LogContext *); static void null_unthrottle(void *, int); static int null_cfg_info(void *); @@ -161,7 +161,7 @@ static void null_provide_ldisc (void *handle, Ldisc *ldisc) { } -static void null_provide_logctx(void *handle, void *logctx) { +static void null_provide_logctx(void *handle, LogContext *logctx) { } diff --git a/unix/gtkwin.c b/unix/gtkwin.c index e28146b4..18bea32f 100644 --- a/unix/gtkwin.c +++ b/unix/gtkwin.c @@ -162,7 +162,7 @@ struct gui_data { Backend *back; void *backhandle; Terminal *term; - void *logctx; + LogContext *logctx; int exited; struct unicode_data ucsdata; Conf *conf; diff --git a/unix/uxcons.c b/unix/uxcons.c index d0fe986b..e7f531dc 100644 --- a/unix/uxcons.c +++ b/unix/uxcons.c @@ -405,7 +405,7 @@ void old_keyfile_warning(void) postmsg(&cf); } -void console_provide_logctx(void *logctx) +void console_provide_logctx(LogContext *logctx) { console_logctx = logctx; } diff --git a/unix/uxpgnt.c b/unix/uxpgnt.c index 0e37c1a0..07248d39 100644 --- a/unix/uxpgnt.c +++ b/unix/uxpgnt.c @@ -92,7 +92,7 @@ int platform_default_i(const char *name, int def) { return def; } FontSpec *platform_default_fontspec(const char *name) { return fontspec_new(""); } Filename *platform_default_filename(const char *name) { return filename_from_str(""); } char *x_get_default(const char *key) { return NULL; } -void log_eventlog(void *handle, const char *event) {} +void log_eventlog(LogContext *logctx, const char *event) {} int from_backend(void *frontend, int is_stderr, const void *data, int datalen) { assert(!"only here to satisfy notional call from backend_socket_log"); } diff --git a/unix/uxplink.c b/unix/uxplink.c index a8d35b7a..64e29c31 100644 --- a/unix/uxplink.c +++ b/unix/uxplink.c @@ -25,7 +25,7 @@ #define MAX_STDIN_BACKLOG 4096 -static void *logctx; +static LogContext *logctx; static struct termios orig_termios; diff --git a/unix/uxpty.c b/unix/uxpty.c index 9df61532..b1204a10 100644 --- a/unix/uxpty.c +++ b/unix/uxpty.c @@ -1212,7 +1212,7 @@ static void pty_provide_ldisc(void *handle, Ldisc *ldisc) /* This is a stub. */ } -static void pty_provide_logctx(void *handle, void *logctx) +static void pty_provide_logctx(void *handle, LogContext *logctx) { /* Pty pty = (Pty)handle; */ /* This is a stub. */ diff --git a/unix/uxser.c b/unix/uxser.c index 558cf015..50eb83e6 100644 --- a/unix/uxser.c +++ b/unix/uxser.c @@ -549,7 +549,7 @@ static void serial_provide_ldisc(void *handle, Ldisc *ldisc) /* This is a stub. */ } -static void serial_provide_logctx(void *handle, void *logctx) +static void serial_provide_logctx(void *handle, LogContext *logctx) { /* This is a stub. */ } diff --git a/windows/wincons.c b/windows/wincons.c index 4827ddbd..a7cbeeac 100644 --- a/windows/wincons.c +++ b/windows/wincons.c @@ -335,7 +335,7 @@ void pgp_fingerprints(void) " " PGP_PREV_MASTER_KEY_FP "\n", stdout); } -void console_provide_logctx(void *logctx) +void console_provide_logctx(LogContext *logctx) { console_logctx = logctx; } diff --git a/windows/winser.c b/windows/winser.c index 2dd45fac..f0ea94bd 100644 --- a/windows/winser.c +++ b/windows/winser.c @@ -414,7 +414,7 @@ static void serial_provide_ldisc(void *handle, Ldisc *ldisc) /* This is a stub. */ } -static void serial_provide_logctx(void *handle, void *logctx) +static void serial_provide_logctx(void *handle, LogContext *logctx) { /* This is a stub. */ } diff --git a/windows/winstuff.h b/windows/winstuff.h index 5dc18fb1..727c4b06 100644 --- a/windows/winstuff.h +++ b/windows/winstuff.h @@ -240,7 +240,7 @@ void quit_help(HWND hwnd); * windlg.c. Likewise the saved-sessions list. */ GLOBAL Terminal *term; -GLOBAL void *logctx; +GLOBAL LogContext *logctx; /* * Windows-specific clipboard helper function shared with windlg.c, From c51fe7c2171a8aa38e2246af22862f6f02d2b3d8 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Tue, 11 Sep 2018 15:33:10 +0100 Subject: [PATCH 391/607] Pass the Ssh structure to portfwd.c with a tag. Again, safer than using a 'void *'. --- defs.h | 1 + portfwd.c | 18 +++++++++--------- ssh.c | 3 +-- ssh.h | 5 ++--- 4 files changed, 13 insertions(+), 14 deletions(-) diff --git a/defs.h b/defs.h index 45b56d60..58a4edff 100644 --- a/defs.h +++ b/defs.h @@ -47,6 +47,7 @@ typedef struct Plug_vtable Plug_vtable; typedef struct Ldisc_tag Ldisc; typedef struct LogContext_tag LogContext; +typedef struct ssh_tag *Ssh; /* Note indirection: for historical reasons (it used to be closer to * the OS socket type), the type that most code uses for a socket is * 'Socket', not 'Socket *'. So an implementation of Socket or Plug diff --git a/portfwd.c b/portfwd.c index 069bc3bf..e6b06e14 100644 --- a/portfwd.c +++ b/portfwd.c @@ -23,8 +23,8 @@ typedef enum { struct PortForwarding { struct ssh_channel *c; /* channel structure held by ssh.c */ - void *backhandle; /* instance of SSH backend itself */ - /* Note that backhandle need not be filled in if c is non-NULL */ + Ssh ssh; /* instance of SSH backend itself */ + /* Note that ssh need not be filled in if c is non-NULL */ Socket s; int throttled, throttle_override; int ready; @@ -47,7 +47,7 @@ struct PortForwarding { }; struct PortListener { - void *backhandle; /* instance of SSH backend itself */ + Ssh ssh; /* instance of SSH backend itself */ Socket s; int is_dynamic; /* @@ -396,7 +396,7 @@ static void pfd_receive(Plug plug, int urgent, char *data, int len) */ sk_set_frozen(pf->s, 1); - pf->c = new_sock_channel(pf->backhandle, pf); + pf->c = new_sock_channel(pf->ssh, pf); if (pf->c == NULL) { pfd_close(pf); return; @@ -464,7 +464,7 @@ char *pfd_connect(struct PortForwarding **pf_ret, char *hostname,int port, pf->throttled = pf->throttle_override = 0; pf->ready = 1; pf->c = c; - pf->backhandle = NULL; /* we shouldn't need this */ + pf->ssh = NULL; /* we shouldn't need this */ pf->socks_state = SOCKS_NONE; pf->s = new_connection(addr, dummy_realhost, port, @@ -497,7 +497,7 @@ static int pfl_accepting(Plug p, accept_fn_t constructor, accept_ctx_t ctx) pf->plugvt = &PortForwarding_plugvt; pf->c = NULL; - pf->backhandle = pl->backhandle; + pf->ssh = pl->ssh; pf->s = s = constructor(ctx, &pf->plugvt); if ((err = sk_socket_error(s)) != NULL) { @@ -518,7 +518,7 @@ static int pfl_accepting(Plug p, accept_fn_t constructor, accept_ctx_t ctx) pf->socks_state = SOCKS_NONE; pf->hostname = dupstr(pl->hostname); pf->port = pl->port; - pf->c = new_sock_channel(pl->backhandle, pf); + pf->c = new_sock_channel(pl->ssh, pf); if (pf->c == NULL) { free_portfwd_state(pf); @@ -547,7 +547,7 @@ static const Plug_vtable PortListener_plugvt = { * dynamically allocated error message string. */ char *pfl_listen(char *desthost, int destport, char *srcaddr, - int port, void *backhandle, Conf *conf, + int port, Ssh ssh, Conf *conf, struct PortListener **pl_ret, int address_family) { const char *err; @@ -564,7 +564,7 @@ char *pfl_listen(char *desthost, int destport, char *srcaddr, pl->is_dynamic = FALSE; } else pl->is_dynamic = TRUE; - pl->backhandle = backhandle; + pl->ssh = ssh; pl->s = new_listener(srcaddr, port, &pl->plugvt, !conf_get_int(conf, CONF_lport_acceptall), diff --git a/ssh.c b/ssh.c index 609e1155..1b75fb84 100644 --- a/ssh.c +++ b/ssh.c @@ -11293,9 +11293,8 @@ static void ssh_special(void *handle, Telnet_Special code) } } -void *new_sock_channel(void *handle, struct PortForwarding *pf) +void *new_sock_channel(Ssh ssh, struct PortForwarding *pf) { - Ssh ssh = (Ssh) handle; struct ssh_channel *c; c = snew(struct ssh_channel); diff --git a/ssh.h b/ssh.h index 99ff5b73..6c606abb 100644 --- a/ssh.h +++ b/ssh.h @@ -8,7 +8,6 @@ #include "misc.h" struct ssh_channel; -typedef struct ssh_tag *Ssh; extern int sshfwd_write(struct ssh_channel *c, const void *, int); extern void sshfwd_write_eof(struct ssh_channel *c); @@ -666,7 +665,7 @@ void logevent(void *, const char *); struct PortForwarding; /* Allocate and register a new channel for port forwarding */ -void *new_sock_channel(void *handle, struct PortForwarding *pf); +void *new_sock_channel(Ssh ssh, struct PortForwarding *pf); void ssh_send_port_open(void *channel, const char *hostname, int port, const char *org); @@ -682,7 +681,7 @@ extern void pfd_override_throttle(struct PortForwarding *, int enable); struct PortListener; /* desthost == NULL indicates dynamic (SOCKS) port forwarding */ extern char *pfl_listen(char *desthost, int destport, char *srcaddr, - int port, void *backhandle, Conf *conf, + int port, Ssh ssh, Conf *conf, struct PortListener **pl, int address_family); extern void pfl_terminate(struct PortListener *); From eefebaaa9ebce7000e32f1d5ecda13a38ba6bd70 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Tue, 11 Sep 2018 16:23:38 +0100 Subject: [PATCH 392/607] Turn Backend into a sensible classoid. Nearly every part of the code that ever handles a full backend structure has historically done it using a pair of pointer variables, one pointing at a constant struct full of function pointers, and the other pointing to a 'void *' state object that's passed to each of those. While I'm modernising the rest of the code, this seems like a good time to turn that into the same more or less type-safe and less cumbersome system as I'm using for other parts of the code, such as Socket, Plug, BinaryPacketProtocol and so forth: the Backend structure contains a vtable pointer, and a system of macro wrappers handles dispatching through that vtable. --- be_all.c | 2 +- be_all_s.c | 2 +- be_none.c | 2 +- be_nos_s.c | 2 +- be_nossh.c | 2 +- be_ssh.c | 2 +- cmdline.c | 9 ++-- config.c | 23 +++++----- defs.h | 5 ++- ldisc.c | 55 ++++++++++++------------ ldisc.h | 3 +- pinger.c | 10 ++--- pscp.c | 80 +++++++++++++++++------------------ psftp.c | 74 ++++++++++++++++---------------- putty.h | 102 +++++++++++++++++++++++++++------------------ raw.c | 54 ++++++++++++------------ rlogin.c | 61 ++++++++++++++------------- settings.c | 21 +++++----- ssh.c | 92 ++++++++++++++++++++-------------------- ssh.h | 2 +- telnet.c | 69 +++++++++++++++--------------- terminal.c | 21 ++++------ terminal.h | 3 +- testback.c | 92 ++++++++++++++++++++-------------------- unix/gtkwin.c | 60 +++++++++++++------------- unix/unix.h | 8 ++-- unix/uxplink.c | 70 +++++++++++++++---------------- unix/uxpterm.c | 2 +- unix/uxpty.c | 74 ++++++++++++++++---------------- unix/uxputty.c | 16 +++---- unix/uxser.c | 52 ++++++++++++----------- windows/wincfg.c | 2 +- windows/window.c | 64 ++++++++++++++-------------- windows/winplink.c | 56 ++++++++++++------------- windows/winser.c | 52 ++++++++++++----------- windows/winstuff.h | 2 +- 36 files changed, 634 insertions(+), 612 deletions(-) diff --git a/be_all.c b/be_all.c index c58903cc..6a09f748 100644 --- a/be_all.c +++ b/be_all.c @@ -22,7 +22,7 @@ const int be_default_protocol = PROT_TELNET; const int be_default_protocol = PROT_SSH; #endif -Backend *backends[] = { +const struct Backend_vtable *const backends[] = { &ssh_backend, &telnet_backend, &rlogin_backend, diff --git a/be_all_s.c b/be_all_s.c index 0ffd0737..d40d7639 100644 --- a/be_all_s.c +++ b/be_all_s.c @@ -22,7 +22,7 @@ const int be_default_protocol = PROT_TELNET; const int be_default_protocol = PROT_SSH; #endif -Backend *backends[] = { +const struct Backend_vtable *const backends[] = { &ssh_backend, &telnet_backend, &rlogin_backend, diff --git a/be_none.c b/be_none.c index 688b8daf..7cf52fa1 100644 --- a/be_none.c +++ b/be_none.c @@ -6,6 +6,6 @@ #include #include "putty.h" -Backend *backends[] = { +const struct Backend_vtable *const backends[] = { NULL }; diff --git a/be_nos_s.c b/be_nos_s.c index a574ead9..a12125ab 100644 --- a/be_nos_s.c +++ b/be_nos_s.c @@ -10,7 +10,7 @@ const int be_default_protocol = PROT_TELNET; const char *const appname = "PuTTYtel"; -Backend *backends[] = { +const struct Backend_vtable *const backends[] = { &telnet_backend, &rlogin_backend, &raw_backend, diff --git a/be_nossh.c b/be_nossh.c index 33d783a8..463497a2 100644 --- a/be_nossh.c +++ b/be_nossh.c @@ -10,7 +10,7 @@ const int be_default_protocol = PROT_TELNET; const char *const appname = "PuTTYtel"; -Backend *backends[] = { +const struct Backend_vtable *const backends[] = { &telnet_backend, &rlogin_backend, &raw_backend, diff --git a/be_ssh.c b/be_ssh.c index 57d241c2..ec1da386 100644 --- a/be_ssh.c +++ b/be_ssh.c @@ -10,7 +10,7 @@ const int be_default_protocol = PROT_SSH; -Backend *backends[] = { +const struct Backend_vtable *const backends[] = { &ssh_backend, NULL }; diff --git a/cmdline.c b/cmdline.c index 0fefb428..0ce3f8a1 100644 --- a/cmdline.c +++ b/cmdline.c @@ -275,13 +275,14 @@ int cmdline_process_param(const char *p, char *value, const char *comma = strchr(p, ','); if (comma) { char *prefix = dupprintf("%.*s", (int)(comma - p), p); - const Backend *b = backend_from_name(prefix); + const struct Backend_vtable *vt = + backend_vt_from_name(prefix); - if (b) { - default_protocol = b->protocol; + if (vt) { + default_protocol = vt->protocol; conf_set_int(conf, CONF_protocol, default_protocol); - port_override = b->default_port; + port_override = vt->default_port; } else { cmdline_error("unrecognised protocol prefix '%s'", prefix); diff --git a/config.c b/config.c index 16d3f7d5..fac7dc3d 100644 --- a/config.c +++ b/config.c @@ -267,10 +267,10 @@ void config_protocolbuttons_handler(union control *ctrl, void *dlg, conf_set_int(conf, CONF_protocol, newproto); if (oldproto != newproto) { - Backend *ob = backend_from_proto(oldproto); - Backend *nb = backend_from_proto(newproto); - assert(ob); - assert(nb); + const struct Backend_vtable *ovt = backend_vt_from_proto(oldproto); + const struct Backend_vtable *nvt = backend_vt_from_proto(newproto); + assert(ovt); + assert(nvt); /* Iff the user hasn't changed the port from the old protocol's * default, update it with the new protocol's default. * (This includes a "default" of 0, implying that there is no @@ -281,8 +281,8 @@ void config_protocolbuttons_handler(union control *ctrl, void *dlg, * getting to the protocol; we want that non-default port * to be preserved. */ port = conf_get_int(conf, CONF_port); - if (port == ob->default_port) - conf_set_int(conf, CONF_port, nb->default_port); + if (port == ovt->default_port) + conf_set_int(conf, CONF_port, nvt->default_port); } dlg_refresh(hp->host, dlg); dlg_refresh(hp->port, dlg); @@ -1503,7 +1503,7 @@ void setup_config_box(struct controlbox *b, int midsession, hp->port = c; ctrl_columns(s, 1, 100); - if (!backend_from_proto(PROT_SSH)) { + if (!backend_vt_from_proto(PROT_SSH)) { ctrl_radiobuttons(s, "Connection type:", NO_SHORTCUT, 3, HELPCTX(session_hostname), config_protocolbuttons_handler, P(hp), @@ -1594,7 +1594,7 @@ void setup_config_box(struct controlbox *b, int midsession, { const char *sshlogname, *sshrawlogname; if ((midsession && protocol == PROT_SSH) || - (!midsession && backend_from_proto(PROT_SSH))) { + (!midsession && backend_vt_from_proto(PROT_SSH))) { sshlogname = "SSH packets"; sshrawlogname = "SSH packets and raw data"; } else { @@ -1630,7 +1630,7 @@ void setup_config_box(struct controlbox *b, int midsession, conf_checkbox_handler, I(CONF_logflush)); if ((midsession && protocol == PROT_SSH) || - (!midsession && backend_from_proto(PROT_SSH))) { + (!midsession && backend_vt_from_proto(PROT_SSH))) { s = ctrl_getset(b, "Session/Logging", "ssh", "Options specific to SSH packet logging"); ctrl_checkbox(s, "Omit known password fields", 'k', @@ -2107,7 +2107,7 @@ void setup_config_box(struct controlbox *b, int midsession, #endif { - const char *label = backend_from_proto(PROT_SSH) ? + const char *label = backend_vt_from_proto(PROT_SSH) ? "Logical name of remote host (e.g. for SSH key lookup):" : "Logical name of remote host:"; s = ctrl_getset(b, "Connection", "identity", @@ -2319,7 +2319,8 @@ void setup_config_box(struct controlbox *b, int midsession, * when we're not doing SSH. */ - if (backend_from_proto(PROT_SSH) && (!midsession || protocol == PROT_SSH)) { + if (backend_vt_from_proto(PROT_SSH) && + (!midsession || protocol == PROT_SSH)) { /* * The Connection/SSH panel. diff --git a/defs.h b/defs.h index 58a4edff..43f56dfe 100644 --- a/defs.h +++ b/defs.h @@ -21,7 +21,6 @@ #endif typedef struct conf_tag Conf; -typedef struct backend_tag Backend; typedef struct terminal_tag Terminal; typedef struct Filename Filename; @@ -44,10 +43,14 @@ typedef struct SockAddr_tag *SockAddr; typedef struct Socket_vtable Socket_vtable; typedef struct Plug_vtable Plug_vtable; +typedef struct Backend Backend; +typedef struct Backend_vtable Backend_vtable; + typedef struct Ldisc_tag Ldisc; typedef struct LogContext_tag LogContext; typedef struct ssh_tag *Ssh; + /* Note indirection: for historical reasons (it used to be closer to * the OS socket type), the type that most code uses for a socket is * 'Socket', not 'Socket *'. So an implementation of Socket or Plug diff --git a/ldisc.c b/ldisc.c index ba90e1d0..3596ea63 100644 --- a/ldisc.c +++ b/ldisc.c @@ -15,11 +15,11 @@ #define ECHOING (ldisc->localecho == FORCE_ON || \ (ldisc->localecho == AUTO && \ - (ldisc->back->ldisc(ldisc->backhandle, LD_ECHO) || \ + (backend_ldisc_option_state(ldisc->backend, LD_ECHO) || \ term_ldisc(ldisc->term, LD_ECHO)))) #define EDITING (ldisc->localedit == FORCE_ON || \ (ldisc->localedit == AUTO && \ - (ldisc->back->ldisc(ldisc->backhandle, LD_EDIT) || \ + (backend_ldisc_option_state(ldisc->backend, LD_EDIT) || \ term_ldisc(ldisc->term, LD_EDIT)))) static void c_write(Ldisc *ldisc, const void *buf, int len) @@ -78,8 +78,7 @@ static void bsb(Ldisc *ldisc, int n) #define KCTRL(x) ((x^'@') | 0x100) Ldisc *ldisc_create(Conf *conf, Terminal *term, - Backend *back, void *backhandle, - void *frontend) + Backend *backend, void *frontend) { Ldisc *ldisc = snew(Ldisc); @@ -88,8 +87,7 @@ Ldisc *ldisc_create(Conf *conf, Terminal *term, ldisc->bufsiz = 0; ldisc->quotenext = 0; - ldisc->back = back; - ldisc->backhandle = backhandle; + ldisc->backend = backend; ldisc->term = term; ldisc->frontend = frontend; @@ -98,8 +96,8 @@ Ldisc *ldisc_create(Conf *conf, Terminal *term, /* Link ourselves into the backend and the terminal */ if (term) term->ldisc = ldisc; - if (back) - back->provide_ldisc(backhandle, ldisc); + if (backend) + backend_provide_ldisc(backend, ldisc); return ldisc; } @@ -117,8 +115,8 @@ void ldisc_free(Ldisc *ldisc) { if (ldisc->term) ldisc->term->ldisc = NULL; - if (ldisc->back) - ldisc->back->provide_ldisc(ldisc->backhandle, NULL); + if (ldisc->backend) + backend_provide_ldisc(ldisc->backend, NULL); if (ldisc->buf) sfree(ldisc->buf); sfree(ldisc); @@ -219,7 +217,7 @@ void ldisc_send(Ldisc *ldisc, const void *vbuf, int len, int interactive) bsb(ldisc, plen(ldisc, ldisc->buf[ldisc->buflen - 1])); ldisc->buflen--; } - ldisc->back->special(ldisc->backhandle, TS_EL); + backend_special(ldisc->backend, TS_EL); /* * We don't send IP, SUSP or ABORT if the user has * configured telnet specials off! This breaks @@ -228,11 +226,11 @@ void ldisc_send(Ldisc *ldisc, const void *vbuf, int len, int interactive) if (!ldisc->telnet_keyboard) goto default_case; if (c == CTRL('C')) - ldisc->back->special(ldisc->backhandle, TS_IP); + backend_special(ldisc->backend, TS_IP); if (c == CTRL('Z')) - ldisc->back->special(ldisc->backhandle, TS_SUSP); + backend_special(ldisc->backend, TS_SUSP); if (c == CTRL('\\')) - ldisc->back->special(ldisc->backhandle, TS_ABORT); + backend_special(ldisc->backend, TS_ABORT); break; case CTRL('R'): /* redraw line */ if (ECHOING) { @@ -247,9 +245,9 @@ void ldisc_send(Ldisc *ldisc, const void *vbuf, int len, int interactive) break; case CTRL('D'): /* logout or send */ if (ldisc->buflen == 0) { - ldisc->back->special(ldisc->backhandle, TS_EOF); + backend_special(ldisc->backend, TS_EOF); } else { - ldisc->back->send(ldisc->backhandle, ldisc->buf, ldisc->buflen); + backend_send(ldisc->backend, ldisc->buf, ldisc->buflen); ldisc->buflen = 0; } break; @@ -285,13 +283,14 @@ void ldisc_send(Ldisc *ldisc, const void *vbuf, int len, int interactive) /* FALLTHROUGH */ case KCTRL('M'): /* send with newline */ if (ldisc->buflen > 0) - ldisc->back->send(ldisc->backhandle, ldisc->buf, ldisc->buflen); + backend_send(ldisc->backend, + ldisc->buf, ldisc->buflen); if (ldisc->protocol == PROT_RAW) - ldisc->back->send(ldisc->backhandle, "\r\n", 2); + backend_send(ldisc->backend, "\r\n", 2); else if (ldisc->protocol == PROT_TELNET && ldisc->telnet_newline) - ldisc->back->special(ldisc->backhandle, TS_EOL); + backend_special(ldisc->backend, TS_EOL); else - ldisc->back->send(ldisc->backhandle, "\r", 1); + backend_send(ldisc->backend, "\r", 1); if (ECHOING) c_write(ldisc, "\r\n", 2); ldisc->buflen = 0; @@ -313,7 +312,7 @@ void ldisc_send(Ldisc *ldisc, const void *vbuf, int len, int interactive) } } else { if (ldisc->buflen != 0) { - ldisc->back->send(ldisc->backhandle, ldisc->buf, ldisc->buflen); + backend_send(ldisc->backend, ldisc->buf, ldisc->buflen); while (ldisc->buflen > 0) { bsb(ldisc, plen(ldisc, ldisc->buf[ldisc->buflen - 1])); ldisc->buflen--; @@ -326,33 +325,33 @@ void ldisc_send(Ldisc *ldisc, const void *vbuf, int len, int interactive) switch (buf[0]) { case CTRL('M'): if (ldisc->protocol == PROT_TELNET && ldisc->telnet_newline) - ldisc->back->special(ldisc->backhandle, TS_EOL); + backend_special(ldisc->backend, TS_EOL); else - ldisc->back->send(ldisc->backhandle, "\r", 1); + backend_send(ldisc->backend, "\r", 1); break; case CTRL('?'): case CTRL('H'): if (ldisc->telnet_keyboard) { - ldisc->back->special(ldisc->backhandle, TS_EC); + backend_special(ldisc->backend, TS_EC); break; } case CTRL('C'): if (ldisc->telnet_keyboard) { - ldisc->back->special(ldisc->backhandle, TS_IP); + backend_special(ldisc->backend, TS_IP); break; } case CTRL('Z'): if (ldisc->telnet_keyboard) { - ldisc->back->special(ldisc->backhandle, TS_SUSP); + backend_special(ldisc->backend, TS_SUSP); break; } default: - ldisc->back->send(ldisc->backhandle, buf, len); + backend_send(ldisc->backend, buf, len); break; } } else - ldisc->back->send(ldisc->backhandle, buf, len); + backend_send(ldisc->backend, buf, len); } } } diff --git a/ldisc.h b/ldisc.h index 44f5772f..af7afde3 100644 --- a/ldisc.h +++ b/ldisc.h @@ -10,8 +10,7 @@ struct Ldisc_tag { Terminal *term; - Backend *back; - void *backhandle; + Backend *backend; void *frontend; /* diff --git a/pinger.c b/pinger.c index d8f110ac..c83b71d2 100644 --- a/pinger.c +++ b/pinger.c @@ -9,8 +9,7 @@ struct pinger_tag { int interval; int pending; unsigned long when_set, next; - Backend *back; - void *backhandle; + Backend *backend; }; static void pinger_schedule(Pinger pinger); @@ -20,7 +19,7 @@ static void pinger_timer(void *ctx, unsigned long now) Pinger pinger = (Pinger)ctx; if (pinger->pending && now == pinger->next) { - pinger->back->special(pinger->backhandle, TS_PING); + backend_special(pinger->backend, TS_PING); pinger->pending = FALSE; pinger_schedule(pinger); } @@ -45,14 +44,13 @@ static void pinger_schedule(Pinger pinger) } } -Pinger pinger_new(Conf *conf, Backend *back, void *backhandle) +Pinger pinger_new(Conf *conf, Backend *backend) { Pinger pinger = snew(struct pinger_tag); pinger->interval = conf_get_int(conf, CONF_ping_interval); pinger->pending = FALSE; - pinger->back = back; - pinger->backhandle = backhandle; + pinger->backend = backend; pinger_schedule(pinger); return pinger; diff --git a/pscp.c b/pscp.c index bc2140f5..854e6815 100644 --- a/pscp.c +++ b/pscp.c @@ -43,8 +43,7 @@ static int fallback_cmd_is_sftp = 0; static int using_sftp = 0; static int uploading = 0; -static Backend *back; -static void *backhandle; +static Backend *backend; static Conf *conf; int sent_eof = FALSE; @@ -247,7 +246,7 @@ static int ssh_scp_recv(void *buf, int len) } while (outlen > 0) { - if (back->exitcode(backhandle) >= 0 || ssh_sftp_loop_iteration() < 0) + if (backend_exitcode(backend) >= 0 || ssh_sftp_loop_iteration() < 0) return 0; /* doom */ } @@ -259,8 +258,8 @@ static int ssh_scp_recv(void *buf, int len) */ static void ssh_scp_init(void) { - while (!back->sendok(backhandle)) { - if (back->exitcode(backhandle) >= 0) { + while (!backend_sendok(backend)) { + if (backend_exitcode(backend) >= 0) { errs++; return; } @@ -271,7 +270,7 @@ static void ssh_scp_init(void) } /* Work out which backend we ended up using. */ - if (!ssh_fallback_cmd(backhandle)) + if (!ssh_fallback_cmd(backend)) using_sftp = main_cmd_is_sftp; else using_sftp = fallback_cmd_is_sftp; @@ -300,9 +299,9 @@ static void bump(const char *fmt, ...) sfree(str2); errs++; - if (back != NULL && back->connected(backhandle)) { + if (backend && backend_connected(backend)) { char ch; - back->special(backhandle, TS_EOF); + backend_special(backend, TS_EOF); sent_eof = TRUE; ssh_scp_recv(&ch, 1); } @@ -498,21 +497,19 @@ static void do_cmd(char *host, char *user, char *cmd) } conf_set_int(conf, CONF_nopty, TRUE); - back = &ssh_backend; - logctx = log_init(NULL, conf); console_provide_logctx(logctx); platform_psftp_pre_conn_setup(); - err = back->init(NULL, &backhandle, conf, - conf_get_str(conf, CONF_host), - conf_get_int(conf, CONF_port), - &realhost, 0, - conf_get_int(conf, CONF_tcp_keepalives)); + err = backend_init(&ssh_backend, NULL, &backend, conf, + conf_get_str(conf, CONF_host), + conf_get_int(conf, CONF_port), + &realhost, 0, + conf_get_int(conf, CONF_tcp_keepalives)); if (err != NULL) bump("ssh_init: %s", err); - back->provide_logctx(backhandle, logctx); + backend_provide_logctx(backend, logctx); ssh_scp_init(); if (verbose && realhost != NULL && errs == 0) tell_user(stderr, "Connected to %s", realhost); @@ -644,12 +641,12 @@ int sftp_recvdata(char *buf, int len) } int sftp_senddata(char *buf, int len) { - back->send(backhandle, buf, len); + backend_send(backend, buf, len); return 1; } int sftp_sendbuffer(void) { - return back->sendbuffer(backhandle); + return backend_sendbuffer(backend); } /* ---------------------------------------------------------------------- @@ -806,8 +803,8 @@ int scp_send_errmsg(char *str) if (using_sftp) { /* do nothing; we never need to send our errors to the server */ } else { - back->send(backhandle, "\001", 1);/* scp protocol error prefix */ - back->send(backhandle, str, strlen(str)); + backend_send(backend, "\001", 1);/* scp protocol error prefix */ + backend_send(backend, str, strlen(str)); } return 0; /* can't fail */ } @@ -822,7 +819,7 @@ int scp_send_filetimes(unsigned long mtime, unsigned long atime) } else { char buf[80]; sprintf(buf, "T%lu 0 %lu 0\n", mtime, atime); - back->send(backhandle, buf, strlen(buf)); + backend_send(backend, buf, strlen(buf)); return response(); } } @@ -869,9 +866,9 @@ int scp_send_filename(const char *name, uint64 size, int permissions) if (permissions < 0) permissions = 0644; sprintf(buf, "C%04o %s ", (int)(permissions & 07777), sizestr); - back->send(backhandle, buf, strlen(buf)); - back->send(backhandle, name, strlen(name)); - back->send(backhandle, "\n", 1); + backend_send(backend, buf, strlen(buf)); + backend_send(backend, name, strlen(name)); + backend_send(backend, "\n", 1); return response(); } } @@ -903,7 +900,7 @@ int scp_send_filedata(char *data, int len) scp_sftp_fileoffset = uint64_add32(scp_sftp_fileoffset, len); return 0; } else { - int bufsize = back->send(backhandle, data, len); + int bufsize = backend_send(backend, data, len); /* * If the network transfer is backing up - that is, the @@ -914,7 +911,7 @@ int scp_send_filedata(char *data, int len) while (bufsize > MAX_SCP_BUFSIZE) { if (ssh_sftp_loop_iteration() < 0) return 1; - bufsize = back->sendbuffer(backhandle); + bufsize = backend_sendbuffer(backend); } return 0; @@ -963,7 +960,7 @@ int scp_send_finish(void) scp_has_times = 0; return 0; } else { - back->send(backhandle, "", 1); + backend_send(backend, "", 1); return response(); } } @@ -1033,9 +1030,9 @@ int scp_send_dirname(const char *name, int modes) } else { char buf[40]; sprintf(buf, "D%04o 0 ", modes); - back->send(backhandle, buf, strlen(buf)); - back->send(backhandle, name, strlen(name)); - back->send(backhandle, "\n", 1); + backend_send(backend, buf, strlen(buf)); + backend_send(backend, name, strlen(name)); + backend_send(backend, "\n", 1); return response(); } } @@ -1046,7 +1043,7 @@ int scp_send_enddir(void) sfree(scp_sftp_remotepath); return 0; } else { - back->send(backhandle, "E\n", 2); + backend_send(backend, "E\n", 2); return response(); } } @@ -1144,7 +1141,7 @@ int scp_sink_setup(const char *source, int preserve, int recursive) int scp_sink_init(void) { if (!using_sftp) { - back->send(backhandle, "", 1); + backend_send(backend, "", 1); } return 0; } @@ -1457,14 +1454,14 @@ int scp_get_sink_action(struct scp_sink_action *act) case '\02': /* fatal error */ bump("%s", act->buf); case 'E': - back->send(backhandle, "", 1); + backend_send(backend, "", 1); act->action = SCP_SINK_ENDDIR; return 0; case 'T': if (sscanf(act->buf, "%lu %*d %lu %*d", &act->mtime, &act->atime) == 2) { act->settime = 1; - back->send(backhandle, "", 1); + backend_send(backend, "", 1); continue; /* go round again */ } bump("Protocol error: Illegal time format"); @@ -1521,7 +1518,7 @@ int scp_accept_filexfer(void) sfree(scp_sftp_currentname); return 0; } else { - back->send(backhandle, "", 1); + backend_send(backend, "", 1); return 0; /* can't fail */ } } @@ -1606,7 +1603,7 @@ int scp_finish_filerecv(void) fxp_close_recv(pktin, req); return 0; } else { - back->send(backhandle, "", 1); + backend_send(backend, "", 1); return response(); } } @@ -2355,7 +2352,7 @@ int psftp_main(int argc, char *argv[]) } argc -= i; argv += i; - back = NULL; + backend = NULL; if (list) { if (argc != 1) @@ -2375,9 +2372,9 @@ int psftp_main(int argc, char *argv[]) tolocal(argc, argv); } - if (back != NULL && back->connected(backhandle)) { + if (backend && backend_connected(backend)) { char ch; - back->special(backhandle, TS_EOF); + backend_special(backend, TS_EOF); sent_eof = TRUE; ssh_scp_recv(&ch, 1); } @@ -2385,9 +2382,8 @@ int psftp_main(int argc, char *argv[]) cmdline_cleanup(); console_provide_logctx(NULL); - back->free(backhandle); - backhandle = NULL; - back = NULL; + backend_free(backend); + backend = NULL; sk_cleanup(); return (errs == 0 ? 0 : 1); } diff --git a/psftp.c b/psftp.c index cd419ebe..c2d23832 100644 --- a/psftp.c +++ b/psftp.c @@ -34,8 +34,7 @@ void do_sftp_cleanup(); */ char *pwd, *homedir; -static Backend *back; -static void *backhandle; +static Backend *backend; static Conf *conf; int sent_eof = FALSE; @@ -967,14 +966,14 @@ int sftp_cmd_quit(struct sftp_command *cmd) int sftp_cmd_close(struct sftp_command *cmd) { - if (back == NULL) { + if (!backend) { not_connected(); return 0; } - if (back != NULL && back->connected(backhandle)) { + if (backend_connected(backend)) { char ch; - back->special(backhandle, TS_EOF); + backend_special(backend, TS_EOF); sent_eof = TRUE; sftp_recvdata(&ch, 1); } @@ -999,7 +998,7 @@ int sftp_cmd_ls(struct sftp_command *cmd) struct sftp_request *req; int i; - if (back == NULL) { + if (!backend) { not_connected(); return 0; } @@ -1123,7 +1122,7 @@ int sftp_cmd_cd(struct sftp_command *cmd) struct sftp_request *req; char *dir; - if (back == NULL) { + if (!backend) { not_connected(); return 0; } @@ -1164,7 +1163,7 @@ int sftp_cmd_cd(struct sftp_command *cmd) */ int sftp_cmd_pwd(struct sftp_command *cmd) { - if (back == NULL) { + if (!backend) { not_connected(); return 0; } @@ -1188,7 +1187,7 @@ int sftp_general_get(struct sftp_command *cmd, int restart, int multiple) int i, ret; int recurse = FALSE; - if (back == NULL) { + if (!backend) { not_connected(); return 0; } @@ -1304,7 +1303,7 @@ int sftp_general_put(struct sftp_command *cmd, int restart, int multiple) int i, ret; int recurse = FALSE; - if (back == NULL) { + if (!backend) { not_connected(); return 0; } @@ -1405,7 +1404,7 @@ int sftp_cmd_mkdir(struct sftp_command *cmd) int result; int i, ret; - if (back == NULL) { + if (!backend) { not_connected(); return 0; } @@ -1463,7 +1462,7 @@ int sftp_cmd_rmdir(struct sftp_command *cmd) { int i, ret; - if (back == NULL) { + if (!backend) { not_connected(); return 0; } @@ -1504,7 +1503,7 @@ int sftp_cmd_rm(struct sftp_command *cmd) { int i, ret; - if (back == NULL) { + if (!backend) { not_connected(); return 0; } @@ -1597,7 +1596,7 @@ int sftp_cmd_mv(struct sftp_command *cmd) struct sftp_context_mv actx, *ctx = &actx; int i, ret; - if (back == NULL) { + if (!backend) { not_connected(); return 0; } @@ -1689,7 +1688,7 @@ int sftp_cmd_chmod(struct sftp_command *cmd) int i, ret; struct sftp_context_chmod actx, *ctx = &actx; - if (back == NULL) { + if (!backend) { not_connected(); return 0; } @@ -1815,7 +1814,7 @@ static int sftp_cmd_open(struct sftp_command *cmd) { int portnumber; - if (back != NULL) { + if (backend) { printf("psftp: already connected\n"); return 0; } @@ -1835,7 +1834,7 @@ static int sftp_cmd_open(struct sftp_command *cmd) portnumber = 0; if (psftp_connect(cmd->words[1], NULL, portnumber)) { - back = NULL; /* connection is already closed */ + backend = NULL; /* connection is already closed */ return -1; /* this is fatal */ } do_sftp_init(); @@ -2214,7 +2213,7 @@ struct sftp_command *sftp_getcmd(FILE *fp, int mode, int modeflags) printf("psftp> "); line = fgetline(fp); } else { - line = ssh_sftp_get_cmdline("psftp> ", back == NULL); + line = ssh_sftp_get_cmdline("psftp> ", !backend); } if (!line || !*line) { @@ -2355,14 +2354,13 @@ static int do_sftp_init(void) void do_sftp_cleanup() { char ch; - if (back) { - back->special(backhandle, TS_EOF); + if (backend) { + backend_special(backend, TS_EOF); sent_eof = TRUE; sftp_recvdata(&ch, 1); - back->free(backhandle); + backend_free(backend); sftp_cleanup_request(); - back = NULL; - backhandle = NULL; + backend = NULL; } if (pwd) { sfree(pwd); @@ -2602,7 +2600,7 @@ int sftp_recvdata(char *buf, int len) } while (outlen > 0) { - if (back->exitcode(backhandle) >= 0 || ssh_sftp_loop_iteration() < 0) + if (backend_exitcode(backend) >= 0 || ssh_sftp_loop_iteration() < 0) return 0; /* doom */ } @@ -2610,12 +2608,12 @@ int sftp_recvdata(char *buf, int len) } int sftp_senddata(char *buf, int len) { - back->send(backhandle, buf, len); + backend_send(backend, buf, len); return 1; } int sftp_sendbuffer(void) { - return back->sendbuffer(backhandle); + return backend_sendbuffer(backend); } /* @@ -2826,25 +2824,23 @@ static int psftp_connect(char *userhost, char *user, int portnumber) "exec sftp-server"); conf_set_int(conf, CONF_ssh_subsys2, FALSE); - back = &ssh_backend; - logctx = log_init(NULL, conf); console_provide_logctx(logctx); platform_psftp_pre_conn_setup(); - err = back->init(NULL, &backhandle, conf, - conf_get_str(conf, CONF_host), - conf_get_int(conf, CONF_port), - &realhost, 0, - conf_get_int(conf, CONF_tcp_keepalives)); + err = backend_init(&ssh_backend, NULL, &backend, conf, + conf_get_str(conf, CONF_host), + conf_get_int(conf, CONF_port), + &realhost, 0, + conf_get_int(conf, CONF_tcp_keepalives)); if (err != NULL) { fprintf(stderr, "ssh_init: %s\n", err); return 1; } - back->provide_logctx(backhandle, logctx); - while (!back->sendok(backhandle)) { - if (back->exitcode(backhandle) >= 0) + backend_provide_logctx(backend, logctx); + while (!backend_sendok(backend)) { + if (backend_exitcode(backend) >= 0) return 1; if (ssh_sftp_loop_iteration() < 0) { fprintf(stderr, "ssh_init: error during SSH connection setup\n"); @@ -2945,7 +2941,7 @@ int psftp_main(int argc, char *argv[]) } argc -= i; argv += i; - back = NULL; + backend = NULL; /* * If the loaded session provides a hostname, and a hostname has not @@ -2975,9 +2971,9 @@ int psftp_main(int argc, char *argv[]) ret = do_sftp(mode, modeflags, batchfile); - if (back != NULL && back->connected(backhandle)) { + if (backend && backend_connected(backend)) { char ch; - back->special(backhandle, TS_EOF); + backend_special(backend, TS_EOF); sent_eof = TRUE; sftp_recvdata(&ch, 1); } diff --git a/putty.h b/putty.h index 14451756..2f53d645 100644 --- a/putty.h +++ b/putty.h @@ -441,43 +441,67 @@ enum { ADDRTYPE_UNSPEC, ADDRTYPE_IPV4, ADDRTYPE_IPV6, ADDRTYPE_NAME }; -struct backend_tag { - const char *(*init) (void *frontend_handle, void **backend_handle, +struct Backend { + const Backend_vtable *vt; +}; +struct Backend_vtable { + const char *(*init) (void *frontend_handle, Backend **backend_out, Conf *conf, const char *host, int port, char **realhost, int nodelay, int keepalive); - void (*free) (void *handle); - /* back->reconfig() passes in a replacement configuration. */ - void (*reconfig) (void *handle, Conf *conf); - /* back->send() returns the current amount of buffered data. */ - int (*send) (void *handle, const char *buf, int len); - /* back->sendbuffer() does the same thing but without attempting a send */ - int (*sendbuffer) (void *handle); - void (*size) (void *handle, int width, int height); - void (*special) (void *handle, Telnet_Special code); - const struct telnet_special *(*get_specials) (void *handle); - int (*connected) (void *handle); - int (*exitcode) (void *handle); - /* If back->sendok() returns FALSE, data sent to it from the frontend - * may be lost. */ - int (*sendok) (void *handle); - int (*ldisc) (void *handle, int); - void (*provide_ldisc) (void *handle, Ldisc *ldisc); - void (*provide_logctx) (void *handle, LogContext *logctx); - /* - * back->unthrottle() tells the back end that the front end - * buffer is clearing. - */ - void (*unthrottle) (void *handle, int); - int (*cfg_info) (void *handle); + + void (*free) (Backend *be); + /* Pass in a replacement configuration. */ + void (*reconfig) (Backend *be, Conf *conf); + /* send() returns the current amount of buffered data. */ + int (*send) (Backend *be, const char *buf, int len); + /* sendbuffer() does the same thing but without attempting a send */ + int (*sendbuffer) (Backend *be); + void (*size) (Backend *be, int width, int height); + void (*special) (Backend *be, Telnet_Special code); + const struct telnet_special *(*get_specials) (Backend *be); + int (*connected) (Backend *be); + int (*exitcode) (Backend *be); + /* If back->sendok() returns FALSE, the backend doesn't currently + * want input data, so the frontend should avoid acquiring any if + * possible (passing back-pressure on to its sender). */ + int (*sendok) (Backend *be); + int (*ldisc_option_state) (Backend *be, int); + void (*provide_ldisc) (Backend *be, Ldisc *ldisc); + void (*provide_logctx) (Backend *be, LogContext *logctx); + /* Tells the back end that the front end buffer is clearing. */ + void (*unthrottle) (Backend *be, int bufsize); + int (*cfg_info) (Backend *be); + /* Only implemented in the SSH protocol: check whether a * connection-sharing upstream exists for a given configuration. */ int (*test_for_upstream)(const char *host, int port, Conf *conf); + const char *name; int protocol; int default_port; }; -extern Backend *backends[]; +#define backend_init(vt, fe, out, conf, host, port, rhost, nd, ka) \ + ((vt)->init(fe, out, conf, host, port, rhost, nd, ka)) +#define backend_free(be) ((be)->vt->free(be)) +#define backend_reconfig(be, conf) ((be)->vt->reconfig(be, conf)) +#define backend_send(be, buf, len) ((be)->vt->send(be, buf, len)) +#define backend_sendbuffer(be) ((be)->vt->sendbuffer(be)) +#define backend_size(be, w, h) ((be)->vt->size(be, w, h)) +#define backend_special(be, code) ((be)->vt->special(be, code)) +#define backend_get_specials(be) ((be)->vt->get_specials(be)) +#define backend_connected(be) ((be)->vt->connected(be)) +#define backend_exitcode(be) ((be)->vt->exitcode(be)) +#define backend_sendok(be) ((be)->vt->sendok(be)) +#define backend_ldisc_option_state(be, opt) \ + ((be)->vt->ldisc_option_state(be, opt)) +#define backend_provide_ldisc(be, ldisc) ((be)->vt->provide_ldisc(be, ldisc)) +#define backend_provide_logctx(be, logctx) \ + ((be)->vt->provide_logctx(be, logctx)) +#define backend_unthrottle(be, bufsize) ((be)->vt->unthrottle(be, bufsize)) +#define backend_cfg_info(be) ((be)->vt->cfg_info(be)) + +extern const struct Backend_vtable *const backends[]; /* * Suggested default protocol provided by the backend link module. @@ -1046,8 +1070,8 @@ void random_destroy_seed(void); /* * Exports from settings.c. */ -Backend *backend_from_name(const char *name); -Backend *backend_from_proto(int proto); +const struct Backend_vtable *backend_vt_from_name(const char *name); +const struct Backend_vtable *backend_vt_from_proto(int proto); char *get_remote_username(Conf *conf); /* dynamically allocated */ char *save_settings(const char *section, Conf *conf); void save_open_settings(void *sesskey, Conf *conf); @@ -1107,9 +1131,7 @@ void term_request_paste(Terminal *, int clipboard); void term_seen_key_event(Terminal *); int term_data(Terminal *, int is_stderr, const void *data, int len); int term_data_untrusted(Terminal *, const void *data, int len); -void term_provide_resize_fn(Terminal *term, - void (*resize_fn)(void *, int, int), - void *resize_ctx); +void term_provide_backend(Terminal *term, Backend *backend); void term_provide_logctx(Terminal *term, LogContext *logctx); void term_set_focus(Terminal *term, int has_focus); char *term_get_ttymode(Terminal *term, const char *mode); @@ -1145,36 +1167,36 @@ void log_packet(LogContext *logctx, int direction, int type, * Exports from testback.c */ -extern Backend null_backend; -extern Backend loop_backend; +extern const struct Backend_vtable null_backend; +extern const struct Backend_vtable loop_backend; /* * Exports from raw.c. */ -extern Backend raw_backend; +extern const struct Backend_vtable raw_backend; /* * Exports from rlogin.c. */ -extern Backend rlogin_backend; +extern const struct Backend_vtable rlogin_backend; /* * Exports from telnet.c. */ -extern Backend telnet_backend; +extern const struct Backend_vtable telnet_backend; /* * Exports from ssh.c. */ -extern Backend ssh_backend; +extern const struct Backend_vtable ssh_backend; /* * Exports from ldisc.c. */ -Ldisc *ldisc_create(Conf *, Terminal *, Backend *, void *, void *); +Ldisc *ldisc_create(Conf *, Terminal *, Backend *, void *); void ldisc_configure(Ldisc *, Conf *); void ldisc_free(Ldisc *); void ldisc_send(Ldisc *, const void *buf, int len, int interactive); @@ -1205,7 +1227,7 @@ void random_unref(void); * Exports from pinger.c. */ typedef struct pinger_tag *Pinger; -Pinger pinger_new(Conf *conf, Backend *back, void *backhandle); +Pinger pinger_new(Conf *conf, Backend *backend); void pinger_reconfig(Pinger, Conf *oldconf, Conf *newconf); void pinger_free(Pinger); diff --git a/raw.c b/raw.c index 658bd030..56eb0385 100644 --- a/raw.c +++ b/raw.c @@ -20,9 +20,10 @@ typedef struct raw_backend_data { Conf *conf; const Plug_vtable *plugvt; + Backend backend; } *Raw; -static void raw_size(void *handle, int width, int height); +static void raw_size(Backend *be, int width, int height); static void c_write(Raw raw, const void *buf, int len) { @@ -116,7 +117,7 @@ static const Plug_vtable Raw_plugvt = { * Also places the canonical host name into `realhost'. It must be * freed by the caller. */ -static const char *raw_init(void *frontend_handle, void **backend_handle, +static const char *raw_init(void *frontend_handle, Backend **backend_handle, Conf *conf, const char *host, int port, char **realhost, int nodelay, int keepalive) @@ -129,9 +130,10 @@ static const char *raw_init(void *frontend_handle, void **backend_handle, raw = snew(struct raw_backend_data); raw->plugvt = &Raw_plugvt; + raw->backend.vt = &raw_backend; raw->s = NULL; raw->closed_on_socket_error = FALSE; - *backend_handle = raw; + *backend_handle = &raw->backend; raw->sent_console_eof = raw->sent_socket_eof = FALSE; raw->bufsize = 0; raw->session_started = FALSE; @@ -176,9 +178,9 @@ static const char *raw_init(void *frontend_handle, void **backend_handle, return NULL; } -static void raw_free(void *handle) +static void raw_free(Backend *be) { - Raw raw = (Raw) handle; + Raw raw = FROMFIELD(be, struct raw_backend_data, backend); if (raw->s) sk_close(raw->s); @@ -189,16 +191,16 @@ static void raw_free(void *handle) /* * Stub routine (we don't have any need to reconfigure this backend). */ -static void raw_reconfig(void *handle, Conf *conf) +static void raw_reconfig(Backend *be, Conf *conf) { } /* * Called to send data down the raw connection. */ -static int raw_send(void *handle, const char *buf, int len) +static int raw_send(Backend *be, const char *buf, int len) { - Raw raw = (Raw) handle; + Raw raw = FROMFIELD(be, struct raw_backend_data, backend); if (raw->s == NULL) return 0; @@ -211,16 +213,16 @@ static int raw_send(void *handle, const char *buf, int len) /* * Called to query the current socket sendability status. */ -static int raw_sendbuffer(void *handle) +static int raw_sendbuffer(Backend *be) { - Raw raw = (Raw) handle; + Raw raw = FROMFIELD(be, struct raw_backend_data, backend); return raw->bufsize; } /* * Called to set the size of the window */ -static void raw_size(void *handle, int width, int height) +static void raw_size(Backend *be, int width, int height) { /* Do nothing! */ return; @@ -229,9 +231,9 @@ static void raw_size(void *handle, int width, int height) /* * Send raw special codes. We only handle outgoing EOF here. */ -static void raw_special(void *handle, Telnet_Special code) +static void raw_special(Backend *be, Telnet_Special code) { - Raw raw = (Raw) handle; + Raw raw = FROMFIELD(be, struct raw_backend_data, backend); if (code == TS_EOF && raw->s) { sk_write_eof(raw->s); raw->sent_socket_eof= TRUE; @@ -245,48 +247,48 @@ static void raw_special(void *handle, Telnet_Special code) * Return a list of the special codes that make sense in this * protocol. */ -static const struct telnet_special *raw_get_specials(void *handle) +static const struct telnet_special *raw_get_specials(Backend *be) { return NULL; } -static int raw_connected(void *handle) +static int raw_connected(Backend *be) { - Raw raw = (Raw) handle; + Raw raw = FROMFIELD(be, struct raw_backend_data, backend); return raw->s != NULL; } -static int raw_sendok(void *handle) +static int raw_sendok(Backend *be) { return 1; } -static void raw_unthrottle(void *handle, int backlog) +static void raw_unthrottle(Backend *be, int backlog) { - Raw raw = (Raw) handle; + Raw raw = FROMFIELD(be, struct raw_backend_data, backend); sk_set_frozen(raw->s, backlog > RAW_MAX_BACKLOG); } -static int raw_ldisc(void *handle, int option) +static int raw_ldisc(Backend *be, int option) { if (option == LD_EDIT || option == LD_ECHO) return 1; return 0; } -static void raw_provide_ldisc(void *handle, Ldisc *ldisc) +static void raw_provide_ldisc(Backend *be, Ldisc *ldisc) { /* This is a stub. */ } -static void raw_provide_logctx(void *handle, LogContext *logctx) +static void raw_provide_logctx(Backend *be, LogContext *logctx) { /* This is a stub. */ } -static int raw_exitcode(void *handle) +static int raw_exitcode(Backend *be) { - Raw raw = (Raw) handle; + Raw raw = FROMFIELD(be, struct raw_backend_data, backend); if (raw->s != NULL) return -1; /* still connected */ else if (raw->closed_on_socket_error) @@ -299,12 +301,12 @@ static int raw_exitcode(void *handle) /* * cfg_info for Raw does nothing at all. */ -static int raw_cfg_info(void *handle) +static int raw_cfg_info(Backend *be) { return 0; } -Backend raw_backend = { +const struct Backend_vtable raw_backend = { raw_init, raw_free, raw_reconfig, diff --git a/rlogin.c b/rlogin.c index dcba9c0c..978e3084 100644 --- a/rlogin.c +++ b/rlogin.c @@ -26,10 +26,9 @@ typedef struct rlogin_tag { prompts_t *prompt; const Plug_vtable *plugvt; + Backend backend; } *Rlogin; -static void rlogin_size(void *handle, int width, int height); - static void c_write(Rlogin rlogin, const void *buf, int len) { int backlog = from_backend(rlogin->frontend, 0, buf, len); @@ -80,7 +79,8 @@ static void rlogin_receive(Plug plug, int urgent, char *data, int len) len--; if (c == '\x80') { rlogin->cansize = 1; - rlogin_size(rlogin, rlogin->term_width, rlogin->term_height); + backend_size(&rlogin->backend, + rlogin->term_width, rlogin->term_height); } /* * We should flush everything (aka Telnet SYNCH) if we see @@ -148,7 +148,7 @@ static const Plug_vtable Rlogin_plugvt = { * Also places the canonical host name into `realhost'. It must be * freed by the caller. */ -static const char *rlogin_init(void *frontend_handle, void **backend_handle, +static const char *rlogin_init(void *frontend_handle, Backend **backend_handle, Conf *conf, const char *host, int port, char **realhost, int nodelay, int keepalive) @@ -162,6 +162,7 @@ static const char *rlogin_init(void *frontend_handle, void **backend_handle, rlogin = snew(struct rlogin_tag); rlogin->plugvt = &Rlogin_plugvt; + rlogin->backend.vt = &rlogin_backend; rlogin->s = NULL; rlogin->closed_on_socket_error = FALSE; rlogin->frontend = frontend_handle; @@ -171,7 +172,7 @@ static const char *rlogin_init(void *frontend_handle, void **backend_handle, rlogin->cansize = 0; rlogin->prompt = NULL; rlogin->conf = conf_copy(conf); - *backend_handle = rlogin; + *backend_handle = &rlogin->backend; addressfamily = conf_get_int(conf, CONF_addressfamily); /* @@ -232,9 +233,9 @@ static const char *rlogin_init(void *frontend_handle, void **backend_handle, return NULL; } -static void rlogin_free(void *handle) +static void rlogin_free(Backend *be) { - Rlogin rlogin = (Rlogin) handle; + Rlogin rlogin = FROMFIELD(be, struct rlogin_tag, backend); if (rlogin->prompt) free_prompts(rlogin->prompt); @@ -247,16 +248,16 @@ static void rlogin_free(void *handle) /* * Stub routine (we don't have any need to reconfigure this backend). */ -static void rlogin_reconfig(void *handle, Conf *conf) +static void rlogin_reconfig(Backend *be, Conf *conf) { } /* * Called to send data down the rlogin connection. */ -static int rlogin_send(void *handle, const char *buf, int len) +static int rlogin_send(Backend *be, const char *buf, int len) { - Rlogin rlogin = (Rlogin) handle; + Rlogin rlogin = FROMFIELD(be, struct rlogin_tag, backend); bufchain bc; if (rlogin->s == NULL) @@ -296,18 +297,18 @@ static int rlogin_send(void *handle, const char *buf, int len) /* * Called to query the current socket sendability status. */ -static int rlogin_sendbuffer(void *handle) +static int rlogin_sendbuffer(Backend *be) { - Rlogin rlogin = (Rlogin) handle; + Rlogin rlogin = FROMFIELD(be, struct rlogin_tag, backend); return rlogin->bufsize; } /* * Called to set the size of the window */ -static void rlogin_size(void *handle, int width, int height) +static void rlogin_size(Backend *be, int width, int height) { - Rlogin rlogin = (Rlogin) handle; + Rlogin rlogin = FROMFIELD(be, struct rlogin_tag, backend); char b[12] = { '\xFF', '\xFF', 0x73, 0x73, 0, 0, 0, 0, 0, 0, 0, 0 }; rlogin->term_width = width; @@ -327,7 +328,7 @@ static void rlogin_size(void *handle, int width, int height) /* * Send rlogin special codes. */ -static void rlogin_special(void *handle, Telnet_Special code) +static void rlogin_special(Backend *be, Telnet_Special code) { /* Do nothing! */ return; @@ -337,48 +338,48 @@ static void rlogin_special(void *handle, Telnet_Special code) * Return a list of the special codes that make sense in this * protocol. */ -static const struct telnet_special *rlogin_get_specials(void *handle) +static const struct telnet_special *rlogin_get_specials(Backend *be) { return NULL; } -static int rlogin_connected(void *handle) +static int rlogin_connected(Backend *be) { - Rlogin rlogin = (Rlogin) handle; + Rlogin rlogin = FROMFIELD(be, struct rlogin_tag, backend); return rlogin->s != NULL; } -static int rlogin_sendok(void *handle) +static int rlogin_sendok(Backend *be) { - /* Rlogin rlogin = (Rlogin) handle; */ + /* Rlogin rlogin = FROMFIELD(be, struct rlogin_tag, backend); */ return 1; } -static void rlogin_unthrottle(void *handle, int backlog) +static void rlogin_unthrottle(Backend *be, int backlog) { - Rlogin rlogin = (Rlogin) handle; + Rlogin rlogin = FROMFIELD(be, struct rlogin_tag, backend); sk_set_frozen(rlogin->s, backlog > RLOGIN_MAX_BACKLOG); } -static int rlogin_ldisc(void *handle, int option) +static int rlogin_ldisc(Backend *be, int option) { - /* Rlogin rlogin = (Rlogin) handle; */ + /* Rlogin rlogin = FROMFIELD(be, struct rlogin_tag, backend); */ return 0; } -static void rlogin_provide_ldisc(void *handle, Ldisc *ldisc) +static void rlogin_provide_ldisc(Backend *be, Ldisc *ldisc) { /* This is a stub. */ } -static void rlogin_provide_logctx(void *handle, LogContext *logctx) +static void rlogin_provide_logctx(Backend *be, LogContext *logctx) { /* This is a stub. */ } -static int rlogin_exitcode(void *handle) +static int rlogin_exitcode(Backend *be) { - Rlogin rlogin = (Rlogin) handle; + Rlogin rlogin = FROMFIELD(be, struct rlogin_tag, backend); if (rlogin->s != NULL) return -1; /* still connected */ else if (rlogin->closed_on_socket_error) @@ -391,12 +392,12 @@ static int rlogin_exitcode(void *handle) /* * cfg_info for rlogin does nothing at all. */ -static int rlogin_cfg_info(void *handle) +static int rlogin_cfg_info(Backend *be) { return 0; } -Backend rlogin_backend = { +const struct Backend_vtable rlogin_backend = { rlogin_init, rlogin_free, rlogin_reconfig, diff --git a/settings.c b/settings.c index d7e65e2d..ecdb3a4b 100644 --- a/settings.c +++ b/settings.c @@ -74,18 +74,18 @@ const char *const ttymodes[] = { * (which is only present in tools that manage settings). */ -Backend *backend_from_name(const char *name) +const struct Backend_vtable *backend_vt_from_name(const char *name) { - Backend **p; + const struct Backend_vtable *const *p; for (p = backends; *p != NULL; p++) if (!strcmp((*p)->name, name)) return *p; return NULL; } -Backend *backend_from_proto(int proto) +const struct Backend_vtable *backend_vt_from_proto(int proto) { - Backend **p; + const struct Backend_vtable *const *p; for (p = backends; *p != NULL; p++) if ((*p)->protocol == proto) return *p; @@ -528,9 +528,10 @@ void save_open_settings(void *sesskey, Conf *conf) write_setting_i(sesskey, "SSHLogOmitData", conf_get_int(conf, CONF_logomitdata)); p = "raw"; { - const Backend *b = backend_from_proto(conf_get_int(conf, CONF_protocol)); - if (b) - p = b->name; + const struct Backend_vtable *vt = + backend_vt_from_proto(conf_get_int(conf, CONF_protocol)); + if (vt) + p = vt->name; } write_setting_s(sesskey, "Protocol", p); write_setting_i(sesskey, "PortNumber", conf_get_int(conf, CONF_port)); @@ -791,9 +792,9 @@ void load_open_settings(void *sesskey, Conf *conf) conf_set_int(conf, CONF_protocol, default_protocol); conf_set_int(conf, CONF_port, default_port); { - const Backend *b = backend_from_name(prot); - if (b) { - conf_set_int(conf, CONF_protocol, b->protocol); + const struct Backend_vtable *vt = backend_vt_from_name(prot); + if (vt) { + conf_set_int(conf, CONF_protocol, vt->protocol); gppi(sesskey, "PortNumber", default_port, conf, CONF_port); } } diff --git a/ssh.c b/ssh.c index 1b75fb84..952b901f 100644 --- a/ssh.c +++ b/ssh.c @@ -561,14 +561,14 @@ struct ssh_portfwd { static void ssh1_protocol_setup(Ssh ssh); static void ssh2_protocol_setup(Ssh ssh); static void ssh2_bare_connection_protocol_setup(Ssh ssh); -static void ssh_size(void *handle, int width, int height); -static void ssh_special(void *handle, Telnet_Special); +static void ssh_size(Backend *be, int width, int height); +static void ssh_special(Backend *be, Telnet_Special); static int ssh2_try_send(struct ssh_channel *c); static int ssh_send_channel_data(struct ssh_channel *c, const char *buf, int len); static void ssh_throttle_all(Ssh ssh, int enable, int bufsize); static void ssh2_set_window(struct ssh_channel *c, int newwin); -static int ssh_sendbuffer(void *handle); +static int ssh_sendbuffer(Backend *be); static int ssh_do_close(Ssh ssh, int notify_exit); static void ssh2_timer(void *ctx, unsigned long now); static int ssh2_timer_update(Ssh ssh, unsigned long rekey_time); @@ -699,6 +699,7 @@ struct ssh_tag { Socket s; const Plug_vtable *plugvt; + Backend backend; Ldisc *ldisc; LogContext *logctx; @@ -1877,7 +1878,7 @@ static void do_ssh_init(Ssh ssh) update_specials_menu(ssh->frontend); ssh->state = SSH_STATE_BEFORE_SIZE; - ssh->pinger = pinger_new(ssh->conf, &ssh_backend, ssh); + ssh->pinger = pinger_new(ssh->conf, &ssh->backend); sfree(s->vstring); @@ -2029,7 +2030,7 @@ static void do_ssh_connection_init(Ssh ssh) update_specials_menu(ssh->frontend); ssh->state = SSH_STATE_BEFORE_SIZE; - ssh->pinger = pinger_new(ssh->conf, &ssh_backend, ssh); + ssh->pinger = pinger_new(ssh->conf, &ssh->backend); /* * Get connection protocol under way. @@ -4726,9 +4727,9 @@ static void do_ssh1_connection(void *vctx) ssh->state = SSH_STATE_SESSION; if (ssh->size_needed) - ssh_size(ssh, ssh->term_width, ssh->term_height); + backend_size(&ssh->backend, ssh->term_width, ssh->term_height); if (ssh->eof_needed) - ssh_special(ssh, TS_EOF); + backend_special(&ssh->backend, TS_EOF); if (ssh->ldisc) ldisc_echoedit_update(ssh->ldisc); /* cause ldisc to notice changes */ @@ -10110,9 +10111,9 @@ static void do_ssh2_connection(void *vctx) ssh->state = SSH_STATE_SESSION; if (ssh->size_needed) - ssh_size(ssh, ssh->term_width, ssh->term_height); + backend_size(&ssh->backend, ssh->term_width, ssh->term_height); if (ssh->eof_needed) - ssh_special(ssh, TS_EOF); + backend_special(&ssh->backend, TS_EOF); /* * Transfer data! @@ -10664,7 +10665,7 @@ static void ssh_cache_conf_values(Ssh ssh) * * Returns an error message, or NULL on success. */ -static const char *ssh_init(void *frontend_handle, void **backend_handle, +static const char *ssh_init(void *frontend_handle, Backend **backend_handle, Conf *conf, const char *host, int port, char **realhost, int nodelay, int keepalive) @@ -10777,7 +10778,8 @@ static const char *ssh_init(void *frontend_handle, void **backend_handle, #endif ssh->gss_kex_used = FALSE; - *backend_handle = ssh; + ssh->backend.vt = &ssh_backend; + *backend_handle = &ssh->backend; ssh->frontend = frontend_handle; ssh->term_width = conf_get_int(ssh->conf, CONF_width); @@ -10826,9 +10828,9 @@ static const char *ssh_init(void *frontend_handle, void **backend_handle, return NULL; } -static void ssh_free(void *handle) +static void ssh_free(Backend *be) { - Ssh ssh = (Ssh) handle; + Ssh ssh = FROMFIELD(be, struct ssh_tag, backend); struct ssh_channel *c; struct ssh_rportfwd *pf; struct X11FakeAuth *auth; @@ -10937,9 +10939,9 @@ static void ssh_free(void *handle) /* * Reconfigure the SSH backend. */ -static void ssh_reconfig(void *handle, Conf *conf) +static void ssh_reconfig(Backend *be, Conf *conf) { - Ssh ssh = (Ssh) handle; + Ssh ssh = FROMFIELD(be, struct ssh_tag, backend); const char *rekeying = NULL; int rekey_mandatory = FALSE; unsigned long old_max_data_size; @@ -10999,9 +11001,9 @@ static void ssh_reconfig(void *handle, Conf *conf) /* * Called to send data down the SSH connection. */ -static int ssh_send(void *handle, const char *buf, int len) +static int ssh_send(Backend *be, const char *buf, int len) { - Ssh ssh = (Ssh) handle; + Ssh ssh = FROMFIELD(be, struct ssh_tag, backend); if (ssh == NULL || ssh->s == NULL) return 0; @@ -11009,15 +11011,15 @@ static int ssh_send(void *handle, const char *buf, int len) bufchain_add(&ssh->user_input, buf, len); queue_idempotent_callback(&ssh->user_input_consumer); - return ssh_sendbuffer(ssh); + return backend_sendbuffer(&ssh->backend); } /* * Called to query the current amount of buffered stdin data. */ -static int ssh_sendbuffer(void *handle) +static int ssh_sendbuffer(Backend *be) { - Ssh ssh = (Ssh) handle; + Ssh ssh = FROMFIELD(be, struct ssh_tag, backend); int override_value; if (ssh == NULL || ssh->s == NULL) @@ -11047,9 +11049,9 @@ static int ssh_sendbuffer(void *handle) /* * Called to set the size of the window from SSH's POV. */ -static void ssh_size(void *handle, int width, int height) +static void ssh_size(Backend *be, int width, int height) { - Ssh ssh = (Ssh) handle; + Ssh ssh = FROMFIELD(be, struct ssh_tag, backend); PktOut *pktout; ssh->term_width = width; @@ -11090,7 +11092,7 @@ static void ssh_size(void *handle, int width, int height) * Return a list of the special codes that make sense in this * protocol. */ -static const struct telnet_special *ssh_get_specials(void *handle) +static const struct telnet_special *ssh_get_specials(Backend *be) { static const struct telnet_special ssh1_ignore_special[] = { {"IGNORE message", TS_NOP} @@ -11126,7 +11128,7 @@ static const struct telnet_special *ssh_get_specials(void *handle) struct telnet_special *specials = NULL; int nspecials = 0, specialsize = 0; - Ssh ssh = (Ssh) handle; + Ssh ssh = FROMFIELD(be, struct ssh_tag, backend); sfree(ssh->specials); @@ -11196,9 +11198,9 @@ static const struct telnet_special *ssh_get_specials(void *handle) * can send an EOF and collect resulting output (e.g. `plink * hostname sort'). */ -static void ssh_special(void *handle, Telnet_Special code) +static void ssh_special(Backend *be, Telnet_Special code) { - Ssh ssh = (Ssh) handle; + Ssh ssh = FROMFIELD(be, struct ssh_tag, backend); PktOut *pktout; if (code == TS_EOF) { @@ -11344,9 +11346,9 @@ void ssh_send_packet_from_downstream(Ssh ssh, unsigned id, int type, * This is called when stdout/stderr (the entity to which * from_backend sends data) manages to clear some backlog. */ -static void ssh_unthrottle(void *handle, int bufsize) +static void ssh_unthrottle(Backend *be, int bufsize) { - Ssh ssh = (Ssh) handle; + Ssh ssh = FROMFIELD(be, struct ssh_tag, backend); if (ssh->version == 1) { if (ssh->v1_stdout_throttling && bufsize < SSH1_BUFFER_LIMIT) { @@ -11405,21 +11407,21 @@ void ssh_send_port_open(void *channel, const char *hostname, int port, } } -static int ssh_connected(void *handle) +static int ssh_connected(Backend *be) { - Ssh ssh = (Ssh) handle; + Ssh ssh = FROMFIELD(be, struct ssh_tag, backend); return ssh->s != NULL; } -static int ssh_sendok(void *handle) +static int ssh_sendok(Backend *be) { - Ssh ssh = (Ssh) handle; + Ssh ssh = FROMFIELD(be, struct ssh_tag, backend); return ssh->send_ok; } -static int ssh_ldisc(void *handle, int option) +static int ssh_ldisc(Backend *be, int option) { - Ssh ssh = (Ssh) handle; + Ssh ssh = FROMFIELD(be, struct ssh_tag, backend); if (option == LD_ECHO) return ssh->echoing; if (option == LD_EDIT) @@ -11427,21 +11429,21 @@ static int ssh_ldisc(void *handle, int option) return FALSE; } -static void ssh_provide_ldisc(void *handle, Ldisc *ldisc) +static void ssh_provide_ldisc(Backend *be, Ldisc *ldisc) { - Ssh ssh = (Ssh) handle; + Ssh ssh = FROMFIELD(be, struct ssh_tag, backend); ssh->ldisc = ldisc; } -static void ssh_provide_logctx(void *handle, LogContext *logctx) +static void ssh_provide_logctx(Backend *be, LogContext *logctx) { - Ssh ssh = (Ssh) handle; + Ssh ssh = FROMFIELD(be, struct ssh_tag, backend); ssh->logctx = logctx; } -static int ssh_return_exitcode(void *handle) +static int ssh_return_exitcode(Backend *be) { - Ssh ssh = (Ssh) handle; + Ssh ssh = FROMFIELD(be, struct ssh_tag, backend); if (ssh->s != NULL) return -1; else @@ -11453,9 +11455,9 @@ static int ssh_return_exitcode(void *handle) * (1 or 2 for the full SSH-1 or SSH-2 protocol; -1 for the bare * SSH-2 connection protocol, i.e. a downstream; 0 for not-decided-yet.) */ -static int ssh_cfg_info(void *handle) +static int ssh_cfg_info(Backend *be) { - Ssh ssh = (Ssh) handle; + Ssh ssh = FROMFIELD(be, struct ssh_tag, backend); if (ssh->version == 0) return 0; /* don't know yet */ else if (ssh->bare_connection) @@ -11469,13 +11471,13 @@ static int ssh_cfg_info(void *handle) * that fails. This variable is the means by which scp.c can reach * into the SSH code and find out which one it got. */ -extern int ssh_fallback_cmd(void *handle) +extern int ssh_fallback_cmd(Backend *be) { - Ssh ssh = (Ssh) handle; + Ssh ssh = FROMFIELD(be, struct ssh_tag, backend); return ssh->fallback_cmd; } -Backend ssh_backend = { +const struct Backend_vtable ssh_backend = { ssh_init, ssh_free, ssh_reconfig, diff --git a/ssh.h b/ssh.h index 6c606abb..4529bbcc 100644 --- a/ssh.h +++ b/ssh.h @@ -629,7 +629,7 @@ extern const char sshver[]; * that fails. This variable is the means by which scp.c can reach * into the SSH code and find out which one it got. */ -extern int ssh_fallback_cmd(void *handle); +extern int ssh_fallback_cmd(Backend *backend); void SHATransform(word32 * digest, word32 * data); diff --git a/telnet.c b/telnet.c index ed585276..673c152f 100644 --- a/telnet.c +++ b/telnet.c @@ -117,8 +117,6 @@ static const char *telopt(int opt) #undef telnet_str } -static void telnet_size(void *handle, int width, int height); - struct Opt { int send; /* what we initially send */ int nsend; /* -ve send if requested to stop it */ @@ -199,6 +197,7 @@ typedef struct telnet_tag { Pinger pinger; const Plug_vtable *plugvt; + Backend backend; } *Telnet; #define TELNET_MAX_BACKLOG 4096 @@ -280,7 +279,8 @@ static void option_side_effects(Telnet telnet, const struct Opt *o, int enabled) static void activate_option(Telnet telnet, const struct Opt *o) { if (o->send == WILL && o->option == TELOPT_NAWS) - telnet_size(telnet, telnet->term_width, telnet->term_height); + backend_size(&telnet->backend, + telnet->term_width, telnet->term_height); if (o->send == WILL && (o->option == TELOPT_NEW_ENVIRON || o->option == TELOPT_OLD_ENVIRON)) { @@ -705,7 +705,7 @@ static const Plug_vtable Telnet_plugvt = { * Also places the canonical host name into `realhost'. It must be * freed by the caller. */ -static const char *telnet_init(void *frontend_handle, void **backend_handle, +static const char *telnet_init(void *frontend_handle, Backend **backend_handle, Conf *conf, const char *host, int port, char **realhost, int nodelay, int keepalive) { @@ -717,6 +717,7 @@ static const char *telnet_init(void *frontend_handle, void **backend_handle, telnet = snew(struct telnet_tag); telnet->plugvt = &Telnet_plugvt; + telnet->backend.vt = &telnet_backend; telnet->conf = conf_copy(conf); telnet->s = NULL; telnet->closed_on_socket_error = FALSE; @@ -732,7 +733,7 @@ static const char *telnet_init(void *frontend_handle, void **backend_handle, telnet->ldisc = NULL; telnet->pinger = NULL; telnet->session_started = TRUE; - *backend_handle = telnet; + *backend_handle = &telnet->backend; /* * Try to find host. @@ -756,7 +757,7 @@ static const char *telnet_init(void *frontend_handle, void **backend_handle, if ((err = sk_socket_error(telnet->s)) != NULL) return err; - telnet->pinger = pinger_new(telnet->conf, &telnet_backend, telnet); + telnet->pinger = pinger_new(telnet->conf, &telnet->backend); /* * Initialise option states. @@ -805,9 +806,9 @@ static const char *telnet_init(void *frontend_handle, void **backend_handle, return NULL; } -static void telnet_free(void *handle) +static void telnet_free(Backend *be) { - Telnet telnet = (Telnet) handle; + Telnet telnet = FROMFIELD(be, struct telnet_tag, backend); sfree(telnet->sb_buf); if (telnet->s) @@ -822,9 +823,9 @@ static void telnet_free(void *handle) * necessary, in this backend: we just save the fresh config for * any subsequent negotiations. */ -static void telnet_reconfig(void *handle, Conf *conf) +static void telnet_reconfig(Backend *be, Conf *conf) { - Telnet telnet = (Telnet) handle; + Telnet telnet = FROMFIELD(be, struct telnet_tag, backend); pinger_reconfig(telnet->pinger, telnet->conf, conf); conf_free(telnet->conf); telnet->conf = conf_copy(conf); @@ -833,9 +834,9 @@ static void telnet_reconfig(void *handle, Conf *conf) /* * Called to send data down the Telnet connection. */ -static int telnet_send(void *handle, const char *buf, int len) +static int telnet_send(Backend *be, const char *buf, int len) { - Telnet telnet = (Telnet) handle; + Telnet telnet = FROMFIELD(be, struct telnet_tag, backend); unsigned char *p, *end; static const unsigned char iac[2] = { IAC, IAC }; static const unsigned char cr[2] = { CR, NUL }; @@ -868,18 +869,18 @@ static int telnet_send(void *handle, const char *buf, int len) /* * Called to query the current socket sendability status. */ -static int telnet_sendbuffer(void *handle) +static int telnet_sendbuffer(Backend *be) { - Telnet telnet = (Telnet) handle; + Telnet telnet = FROMFIELD(be, struct telnet_tag, backend); return telnet->bufsize; } /* * Called to set the size of the window from Telnet's POV. */ -static void telnet_size(void *handle, int width, int height) +static void telnet_size(Backend *be, int width, int height) { - Telnet telnet = (Telnet) handle; + Telnet telnet = FROMFIELD(be, struct telnet_tag, backend); unsigned char b[24]; int n; char *logbuf; @@ -913,9 +914,9 @@ static void telnet_size(void *handle, int width, int height) /* * Send Telnet special codes. */ -static void telnet_special(void *handle, Telnet_Special code) +static void telnet_special(Backend *be, Telnet_Special code) { - Telnet telnet = (Telnet) handle; + Telnet telnet = FROMFIELD(be, struct telnet_tag, backend); unsigned char b[2]; if (telnet->s == NULL) @@ -1008,7 +1009,7 @@ static void telnet_special(void *handle, Telnet_Special code) } } -static const struct telnet_special *telnet_get_specials(void *handle) +static const struct telnet_special *telnet_get_specials(Backend *be) { static const struct telnet_special specials[] = { {"Are You There", TS_AYT}, @@ -1031,27 +1032,27 @@ static const struct telnet_special *telnet_get_specials(void *handle) return specials; } -static int telnet_connected(void *handle) +static int telnet_connected(Backend *be) { - Telnet telnet = (Telnet) handle; + Telnet telnet = FROMFIELD(be, struct telnet_tag, backend); return telnet->s != NULL; } -static int telnet_sendok(void *handle) +static int telnet_sendok(Backend *be) { - /* Telnet telnet = (Telnet) handle; */ + /* Telnet telnet = FROMFIELD(be, struct telnet_tag, backend); */ return 1; } -static void telnet_unthrottle(void *handle, int backlog) +static void telnet_unthrottle(Backend *be, int backlog) { - Telnet telnet = (Telnet) handle; + Telnet telnet = FROMFIELD(be, struct telnet_tag, backend); sk_set_frozen(telnet->s, backlog > TELNET_MAX_BACKLOG); } -static int telnet_ldisc(void *handle, int option) +static int telnet_ldisc(Backend *be, int option) { - Telnet telnet = (Telnet) handle; + Telnet telnet = FROMFIELD(be, struct telnet_tag, backend); if (option == LD_ECHO) return telnet->echoing; if (option == LD_EDIT) @@ -1059,20 +1060,20 @@ static int telnet_ldisc(void *handle, int option) return FALSE; } -static void telnet_provide_ldisc(void *handle, Ldisc *ldisc) +static void telnet_provide_ldisc(Backend *be, Ldisc *ldisc) { - Telnet telnet = (Telnet) handle; + Telnet telnet = FROMFIELD(be, struct telnet_tag, backend); telnet->ldisc = ldisc; } -static void telnet_provide_logctx(void *handle, LogContext *logctx) +static void telnet_provide_logctx(Backend *be, LogContext *logctx) { /* This is a stub. */ } -static int telnet_exitcode(void *handle) +static int telnet_exitcode(Backend *be) { - Telnet telnet = (Telnet) handle; + Telnet telnet = FROMFIELD(be, struct telnet_tag, backend); if (telnet->s != NULL) return -1; /* still connected */ else if (telnet->closed_on_socket_error) @@ -1085,12 +1086,12 @@ static int telnet_exitcode(void *handle) /* * cfg_info for Telnet does nothing at all. */ -static int telnet_cfg_info(void *handle) +static int telnet_cfg_info(Backend *be) { return 0; } -Backend telnet_backend = { +const struct Backend_vtable telnet_backend = { telnet_init, telnet_free, telnet_reconfig, diff --git a/terminal.c b/terminal.c index 04e222d0..1dc83dc1 100644 --- a/terminal.c +++ b/terminal.c @@ -1693,8 +1693,7 @@ Terminal *term_init(Conf *myconf, struct unicode_data *ucsdata, term->lastbeep = FALSE; term->beep_overloaded = FALSE; term->attr_mask = 0xffffffff; - term->resize_fn = NULL; - term->resize_ctx = NULL; + term->backend = NULL; term->in_term_out = FALSE; term->ltemp = NULL; term->ltemp_size = 0; @@ -1964,22 +1963,18 @@ void term_size(Terminal *term, int newrows, int newcols, int newsavelines) update_sbar(term); term_update(term); - if (term->resize_fn) - term->resize_fn(term->resize_ctx, term->cols, term->rows); + if (term->backend) + backend_size(term->backend, term->cols, term->rows); } /* - * Hand a function and context pointer to the terminal which it can - * use to notify a back end of resizes. + * Hand a backend to the terminal, so it can be notified of resizes. */ -void term_provide_resize_fn(Terminal *term, - void (*resize_fn)(void *, int, int), - void *resize_ctx) +void term_provide_backend(Terminal *term, Backend *backend) { - term->resize_fn = resize_fn; - term->resize_ctx = resize_ctx; - if (resize_fn && term->cols > 0 && term->rows > 0) - resize_fn(resize_ctx, term->cols, term->rows); + term->backend = backend; + if (term->backend && term->cols > 0 && term->rows > 0) + backend_size(term->backend, term->cols, term->rows); } /* Find the bottom line on the screen that has any content. diff --git a/terminal.h b/terminal.h index 244ff3bc..8ec256d4 100644 --- a/terminal.h +++ b/terminal.h @@ -227,8 +227,7 @@ struct terminal_tag { wchar_t *paste_buffer; int paste_len, paste_pos; - void (*resize_fn)(void *, int, int); - void *resize_ctx; + Backend *backend; Ldisc *ldisc; diff --git a/testback.c b/testback.c index 78b89333..f3e9e35f 100644 --- a/testback.c +++ b/testback.c @@ -32,36 +32,36 @@ #include "putty.h" -static const char *null_init(void *, void **, Conf *, const char *, int, +static const char *null_init(void *, Backend **, Conf *, const char *, int, char **, int, int); -static const char *loop_init(void *, void **, Conf *, const char *, int, +static const char *loop_init(void *, Backend **, Conf *, const char *, int, char **, int, int); -static void null_free(void *); -static void loop_free(void *); -static void null_reconfig(void *, Conf *); -static int null_send(void *, const char *, int); -static int loop_send(void *, const char *, int); -static int null_sendbuffer(void *); -static void null_size(void *, int, int); -static void null_special(void *, Telnet_Special); -static const struct telnet_special *null_get_specials(void *handle); -static int null_connected(void *); -static int null_exitcode(void *); -static int null_sendok(void *); -static int null_ldisc(void *, int); -static void null_provide_ldisc(void *, Ldisc *); -static void null_provide_logctx(void *, LogContext *); -static void null_unthrottle(void *, int); -static int null_cfg_info(void *); - -Backend null_backend = { +static void null_free(Backend *); +static void loop_free(Backend *); +static void null_reconfig(Backend *, Conf *); +static int null_send(Backend *, const char *, int); +static int loop_send(Backend *, const char *, int); +static int null_sendbuffer(Backend *); +static void null_size(Backend *, int, int); +static void null_special(Backend *, Telnet_Special); +static const struct telnet_special *null_get_specials(Backend *); +static int null_connected(Backend *); +static int null_exitcode(Backend *); +static int null_sendok(Backend *); +static int null_ldisc(Backend *, int); +static void null_provide_ldisc(Backend *, Ldisc *); +static void null_provide_logctx(Backend *, LogContext *); +static void null_unthrottle(Backend *, int); +static int null_cfg_info(Backend *); + +const struct Backend_vtable null_backend = { null_init, null_free, null_reconfig, null_send, null_sendbuffer, null_size, null_special, null_get_specials, null_connected, null_exitcode, null_sendok, null_ldisc, null_provide_ldisc, null_provide_logctx, null_unthrottle, null_cfg_info, NULL /* test_for_upstream */, "null", -1, 0 }; -Backend loop_backend = { +const struct Backend_vtable loop_backend = { loop_init, loop_free, null_reconfig, loop_send, null_sendbuffer, null_size, null_special, null_get_specials, null_connected, null_exitcode, null_sendok, null_ldisc, null_provide_ldisc, null_provide_logctx, null_unthrottle, @@ -70,102 +70,104 @@ Backend loop_backend = { struct loop_state { Terminal *term; + Backend backend; }; -static const char *null_init(void *frontend_handle, void **backend_handle, +static const char *null_init(void *frontend_handle, Backend **backend_handle, Conf *conf, const char *host, int port, char **realhost, int nodelay, int keepalive) { - + *backend_handle = NULL; return NULL; } -static const char *loop_init(void *frontend_handle, void **backend_handle, +static const char *loop_init(void *frontend_handle, Backend **backend_handle, Conf *conf, const char *host, int port, char **realhost, int nodelay, int keepalive) { struct loop_state *st = snew(struct loop_state); st->term = frontend_handle; - *backend_handle = st; + *backend_handle = &st->backend; return NULL; } -static void null_free(void *handle) +static void null_free(Backend *be) { } -static void loop_free(void *handle) +static void loop_free(Backend *be) { + struct loop_state *st = FROMFIELD(be, struct loop_state, backend); - sfree(handle); + sfree(st); } -static void null_reconfig(void *handle, Conf *conf) { +static void null_reconfig(Backend *be, Conf *conf) { } -static int null_send(void *handle, const char *buf, int len) { +static int null_send(Backend *be, const char *buf, int len) { return 0; } -static int loop_send(void *handle, const char *buf, int len) { - struct loop_state *st = handle; +static int loop_send(Backend *be, const char *buf, int len) { + struct loop_state *st = FROMFIELD(be, struct loop_state, backend); return from_backend(st->term, 0, buf, len); } -static int null_sendbuffer(void *handle) { +static int null_sendbuffer(Backend *be) { return 0; } -static void null_size(void *handle, int width, int height) { +static void null_size(Backend *be, int width, int height) { } -static void null_special(void *handle, Telnet_Special code) { +static void null_special(Backend *be, Telnet_Special code) { } -static const struct telnet_special *null_get_specials (void *handle) { +static const struct telnet_special *null_get_specials (Backend *be) { return NULL; } -static int null_connected(void *handle) { +static int null_connected(Backend *be) { return 0; } -static int null_exitcode(void *handle) { +static int null_exitcode(Backend *be) { return 0; } -static int null_sendok(void *handle) { +static int null_sendok(Backend *be) { return 1; } -static void null_unthrottle(void *handle, int backlog) { +static void null_unthrottle(Backend *be, int backlog) { } -static int null_ldisc(void *handle, int option) { +static int null_ldisc(Backend *be, int option) { return 0; } -static void null_provide_ldisc (void *handle, Ldisc *ldisc) { +static void null_provide_ldisc (Backend *be, Ldisc *ldisc) { } -static void null_provide_logctx(void *handle, LogContext *logctx) { +static void null_provide_logctx(Backend *be, LogContext *logctx) { } -static int null_cfg_info(void *handle) +static int null_cfg_info(Backend *be) { return 0; } diff --git a/unix/gtkwin.c b/unix/gtkwin.c index 18bea32f..6867ac07 100644 --- a/unix/gtkwin.c +++ b/unix/gtkwin.c @@ -159,8 +159,7 @@ struct gui_data { char *icontitle; int master_fd, master_func_id; Ldisc *ldisc; - Backend *back; - void *backhandle; + Backend *backend; Terminal *term; LogContext *logctx; int exited; @@ -1609,8 +1608,8 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) #ifdef KEY_EVENT_DIAGNOSTICS debug((" - Ctrl-Break special case, sending TS_BRK\n")); #endif - if (inst->back) - inst->back->special(inst->backhandle, TS_BRK); + if (inst->backend) + backend_special(inst->backend, TS_BRK); return TRUE; } @@ -2399,7 +2398,7 @@ static void exit_callback(void *vinst) int exitcode, close_on_exit; if (!inst->exited && - (exitcode = inst->back->exitcode(inst->backhandle)) >= 0) { + (exitcode = backend_exitcode(inst->backend)) >= 0) { destroy_inst_connection(inst); close_on_exit = conf_get_int(inst->conf, CONF_close_on_exit); @@ -2424,13 +2423,12 @@ static void destroy_inst_connection(struct gui_data *inst) ldisc_free(inst->ldisc); inst->ldisc = NULL; } - if (inst->backhandle) { - inst->back->free(inst->backhandle); - inst->backhandle = NULL; - inst->back = NULL; + if (inst->backend) { + backend_free(inst->backend); + inst->backend = NULL; } if (inst->term) - term_provide_resize_fn(inst->term, NULL, NULL); + term_provide_backend(inst->term, NULL); if (inst->menu) { update_specials_menu(inst); gtk_widget_set_sensitive(inst->restartitem, TRUE); @@ -4480,8 +4478,8 @@ void special_menuitem(GtkMenuItem *item, gpointer data) int code = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(item), "user-data")); - if (inst->back) - inst->back->special(inst->backhandle, code); + if (inst->backend) + backend_special(inst->backend, code); } void about_menuitem(GtkMenuItem *item, gpointer data) @@ -4582,7 +4580,7 @@ void change_settings_menuitem(GtkMenuItem *item, gpointer data) dialog = create_config_box( title, ctx->newconf, 1, - inst->back ? inst->back->cfg_info(inst->backhandle) : 0, + inst->backend ? backend_cfg_info(inst->backend) : 0, after_change_settings_dialog, ctx); register_dialog(inst, DIALOG_SLOT_RECONFIGURE, dialog); @@ -4633,8 +4631,8 @@ static void after_change_settings_dialog(void *vctx, int retval) term_reconfig(inst->term, inst->conf); setup_clipboards(inst, inst->term, inst->conf); /* Pass new config data to the back end */ - if (inst->back) - inst->back->reconfig(inst->backhandle, inst->conf); + if (inst->backend) + backend_reconfig(inst->backend, inst->conf); cache_conf_values(inst); @@ -4851,7 +4849,7 @@ void restart_session_menuitem(GtkMenuItem *item, gpointer data) { struct gui_data *inst = (struct gui_data *)data; - if (!inst->back) { + if (!inst->backend) { logevent(inst, "----- Session restarted -----"); term_pwron(inst->term, FALSE); start_backend(inst); @@ -4984,8 +4982,8 @@ void update_specials_menu(void *frontend) const struct telnet_special *specials; - if (inst->back) - specials = inst->back->get_specials(inst->backhandle); + if (inst->backend) + specials = backend_get_specials(inst->backend); else specials = NULL; @@ -5045,20 +5043,20 @@ void update_specials_menu(void *frontend) static void start_backend(struct gui_data *inst) { - extern Backend *select_backend(Conf *conf); + const struct Backend_vtable *vt; char *realhost; const char *error; char *s; - inst->back = select_backend(inst->conf); + vt = select_backend(inst->conf); - error = inst->back->init((void *)inst, &inst->backhandle, - inst->conf, - conf_get_str(inst->conf, CONF_host), - conf_get_int(inst->conf, CONF_port), - &realhost, - conf_get_int(inst->conf, CONF_tcp_nodelay), - conf_get_int(inst->conf, CONF_tcp_keepalives)); + error = backend_init(vt, (void *)inst, &inst->backend, + inst->conf, + conf_get_str(inst->conf, CONF_host), + conf_get_int(inst->conf, CONF_port), + &realhost, + conf_get_int(inst->conf, CONF_tcp_nodelay), + conf_get_int(inst->conf, CONF_tcp_keepalives)); if (error) { char *msg = dupprintf("Unable to open connection to %s:\n%s", @@ -5079,13 +5077,11 @@ static void start_backend(struct gui_data *inst) } sfree(realhost); - inst->back->provide_logctx(inst->backhandle, inst->logctx); + backend_provide_logctx(inst->backend, inst->logctx); - term_provide_resize_fn(inst->term, inst->back->size, inst->backhandle); + term_provide_backend(inst->term, inst->backend); - inst->ldisc = - ldisc_create(inst->conf, inst->term, inst->back, inst->backhandle, - inst); + inst->ldisc = ldisc_create(inst->conf, inst->term, inst->backend, inst); gtk_widget_set_sensitive(inst->restartitem, FALSE); } diff --git a/unix/unix.h b/unix/unix.h index 14ce470a..f9ff3c68 100644 --- a/unix/unix.h +++ b/unix/unix.h @@ -67,7 +67,7 @@ struct FontSpec *fontspec_new(const char *name); typedef void *Context; /* FIXME: probably needs changing */ -extern Backend pty_backend; +extern const struct Backend_vtable pty_backend; #define BROKEN_PIPE_ERROR_CODE EPIPE /* used in sshshare.c */ @@ -178,6 +178,8 @@ void window_setup_error(const char *errmsg); GtkWidget *make_gtk_toplevel_window(void *frontend); #endif +const struct Backend_vtable *select_backend(Conf *conf); + /* Defined in gtkcomm.c */ void gtkcomm_setup(void); @@ -324,9 +326,9 @@ void *sk_getxdmdata(Socket sock, int *lenp); } while (0) /* - * Exports from winser.c. + * Exports from uxser.c. */ -extern Backend serial_backend; +extern const struct Backend_vtable serial_backend; /* * uxpeer.c, wrapping getsockopt(SO_PEERCRED). diff --git a/unix/uxplink.c b/unix/uxplink.c index 64e29c31..7bcac362 100644 --- a/unix/uxplink.c +++ b/unix/uxplink.c @@ -91,8 +91,7 @@ void cmdline_error(const char *p, ...) static int local_tty = FALSE; /* do we have a local tty? */ -static Backend *back; -static void *backhandle; +static Backend *backend; static Conf *conf; /* @@ -459,13 +458,13 @@ static void from_tty(void *vbuf, unsigned len) } else { q = memchr(p, '\xff', end - p); if (q == NULL) q = end; - back->send(backhandle, p, q - p); + backend_send(backend, p, q - p); p = q; } break; case FF: if (*p == '\xff') { - back->send(backhandle, p, 1); + backend_send(backend, p, 1); p++; state = NORMAL; } else if (*p == '\0') { @@ -475,7 +474,7 @@ static void from_tty(void *vbuf, unsigned len) break; case FF00: if (*p == '\0') { - back->special(backhandle, TS_BRK); + backend_special(backend, TS_BRK); } else { /* * Pretend that PARMRK wasn't set. This involves @@ -494,11 +493,11 @@ static void from_tty(void *vbuf, unsigned len) if (!(orig_termios.c_iflag & IGNPAR)) { /* PE/FE get passed on as NUL. */ *p = 0; - back->send(backhandle, p, 1); + backend_send(backend, p, 1); } } else { /* INPCK not set. Assume we got a parity error. */ - back->send(backhandle, p, 1); + backend_send(backend, p, 1); } } p++; @@ -606,6 +605,7 @@ int main(int argc, char **argv) int just_test_share_exists = FALSE; unsigned long now; struct winsize size; + const struct Backend_vtable *backvt; fdlist = NULL; fdcount = fdsize = 0; @@ -643,10 +643,10 @@ int main(int argc, char **argv) */ char *p = getenv("PLINK_PROTOCOL"); if (p) { - const Backend *b = backend_from_name(p); - if (b) { - default_protocol = b->protocol; - default_port = b->default_port; + const struct Backend_vtable *vt = backend_vt_from_name(p); + if (vt) { + default_protocol = vt->protocol; + default_port = vt->default_port; conf_set_int(conf, CONF_protocol, default_protocol); conf_set_int(conf, CONF_port, default_port); } @@ -766,8 +766,8 @@ int main(int argc, char **argv) * Select protocol. This is farmed out into a table in a * separate file to enable an ssh-free variant. */ - back = backend_from_proto(conf_get_int(conf, CONF_protocol)); - if (back == NULL) { + backvt = backend_vt_from_proto(conf_get_int(conf, CONF_protocol)); + if (!backvt) { fprintf(stderr, "Internal fault: Unsupported protocol found\n"); return 1; @@ -817,13 +817,13 @@ int main(int argc, char **argv) conf_set_int(conf, CONF_ssh_simple, TRUE); if (just_test_share_exists) { - if (!back->test_for_upstream) { + if (!backvt->test_for_upstream) { fprintf(stderr, "Connection sharing not supported for connection " - "type '%s'\n", back->name); + "type '%s'\n", backvt->name); return 1; } - if (back->test_for_upstream(conf_get_str(conf, CONF_host), - conf_get_int(conf, CONF_port), conf)) + if (backvt->test_for_upstream(conf_get_str(conf, CONF_host), + conf_get_int(conf, CONF_port), conf)) return 0; else return 1; @@ -845,17 +845,17 @@ int main(int argc, char **argv) __AFL_INIT(); #endif - error = back->init(NULL, &backhandle, conf, - conf_get_str(conf, CONF_host), - conf_get_int(conf, CONF_port), - &realhost, nodelay, - conf_get_int(conf, CONF_tcp_keepalives)); + error = backend_init(backvt, NULL, &backend, conf, + conf_get_str(conf, CONF_host), + conf_get_int(conf, CONF_port), + &realhost, nodelay, + conf_get_int(conf, CONF_tcp_keepalives)); if (error) { fprintf(stderr, "Unable to open connection:\n%s\n", error); return 1; } - back->provide_logctx(backhandle, logctx); - ldisc_create(conf, NULL, back, backhandle, NULL); + backend_provide_logctx(backend, logctx); + ldisc_create(conf, NULL, backend, NULL); sfree(realhost); } @@ -885,9 +885,9 @@ int main(int argc, char **argv) FD_SET_MAX(signalpipe[0], maxfd, rset); if (!sending && - back->connected(backhandle) && - back->sendok(backhandle) && - back->sendbuffer(backhandle) < MAX_STDIN_BACKLOG) { + backend_connected(backend) && + backend_sendok(backend) && + backend_sendbuffer(backend) < MAX_STDIN_BACKLOG) { /* If we're OK to send, then try to read from stdin. */ FD_SET_MAX(STDIN_FILENO, maxfd, rset); } @@ -988,46 +988,46 @@ int main(int argc, char **argv) /* ignore error */; /* ignore its value; it'll be `x' */ if (ioctl(STDIN_FILENO, TIOCGWINSZ, (void *)&size) >= 0) - back->size(backhandle, size.ws_col, size.ws_row); + backend_size(backend, size.ws_col, size.ws_row); } if (FD_ISSET(STDIN_FILENO, &rset)) { char buf[4096]; int ret; - if (back->connected(backhandle)) { + if (backend_connected(backend)) { ret = read(STDIN_FILENO, buf, sizeof(buf)); if (ret < 0) { perror("stdin: read"); exit(1); } else if (ret == 0) { - back->special(backhandle, TS_EOF); + backend_special(backend, TS_EOF); sending = FALSE; /* send nothing further after this */ } else { if (local_tty) from_tty(buf, ret); else - back->send(backhandle, buf, ret); + backend_send(backend, buf, ret); } } } if (FD_ISSET(STDOUT_FILENO, &wset)) { - back->unthrottle(backhandle, try_output(FALSE)); + backend_unthrottle(backend, try_output(FALSE)); } if (FD_ISSET(STDERR_FILENO, &wset)) { - back->unthrottle(backhandle, try_output(TRUE)); + backend_unthrottle(backend, try_output(TRUE)); } run_toplevel_callbacks(); - if (!back->connected(backhandle) && + if (!backend_connected(backend) && bufchain_size(&stdout_data) == 0 && bufchain_size(&stderr_data) == 0) break; /* we closed the connection */ } - exitcode = back->exitcode(backhandle); + exitcode = backend_exitcode(backend); if (exitcode < 0) { fprintf(stderr, "Remote process exit code unavailable\n"); exitcode = 1; /* this is an error condition */ diff --git a/unix/uxpterm.c b/unix/uxpterm.c index d80c3780..4df8b164 100644 --- a/unix/uxpterm.c +++ b/unix/uxpterm.c @@ -13,7 +13,7 @@ const int new_session = 0, saved_sessions = 0; /* or these */ const int dup_check_launchable = 0; /* no need to check host name in conf */ const int use_pty_argv = TRUE; -Backend *select_backend(Conf *conf) +const struct Backend_vtable *select_backend(Conf *conf) { return &pty_backend; } diff --git a/unix/uxpty.c b/unix/uxpty.c index b1204a10..870e5156 100644 --- a/unix/uxpty.c +++ b/unix/uxpty.c @@ -78,6 +78,7 @@ struct pty_tag { int child_dead, finished; int exit_code; bufchain output_data; + Backend backend; }; /* @@ -728,9 +729,9 @@ static void pty_uxsel_setup(Pty pty) * Also places the canonical host name into `realhost'. It must be * freed by the caller. */ -static const char *pty_init(void *frontend, void **backend_handle, Conf *conf, - const char *host, int port, char **realhost, - int nodelay, int keepalive) +static const char *pty_init(void *frontend, Backend **backend_handle, + Conf *conf, const char *host, int port, + char **realhost, int nodelay, int keepalive) { int slavefd; pid_t pid, pgrp; @@ -752,7 +753,8 @@ static const char *pty_init(void *frontend, void **backend_handle, Conf *conf, } pty->frontend = frontend; - *backend_handle = NULL; /* we can't sensibly use this, sadly */ + pty->backend.vt = &pty_backend; + *backend_handle = &pty->backend; pty->conf = conf_copy(conf); pty->term_width = conf_get_int(conf, CONF_width); @@ -1025,16 +1027,14 @@ static const char *pty_init(void *frontend, void **backend_handle, Conf *conf, } pty_uxsel_setup(pty); - *backend_handle = pty; - *realhost = dupstr(""); return NULL; } -static void pty_reconfig(void *handle, Conf *conf) +static void pty_reconfig(Backend *be, Conf *conf) { - Pty pty = (Pty)handle; + Pty pty = FROMFIELD(be, struct pty_tag, backend); /* * We don't have much need to reconfigure this backend, but * unfortunately we do need to pick up the setting of Close On @@ -1046,9 +1046,9 @@ static void pty_reconfig(void *handle, Conf *conf) /* * Stub routine (never called in pterm). */ -static void pty_free(void *handle) +static void pty_free(Backend *be) { - Pty pty = (Pty)handle; + Pty pty = FROMFIELD(be, struct pty_tag, backend); /* Either of these may fail `not found'. That's fine with us. */ del234(ptys_by_pid, pty); @@ -1099,9 +1099,9 @@ static void pty_try_write(Pty pty) /* * Called to send data down the pty. */ -static int pty_send(void *handle, const char *buf, int len) +static int pty_send(Backend *be, const char *buf, int len) { - Pty pty = (Pty)handle; + Pty pty = FROMFIELD(be, struct pty_tag, backend); if (pty->master_fd < 0) return 0; /* ignore all writes if fd closed */ @@ -1129,18 +1129,18 @@ static void pty_close(Pty pty) /* * Called to query the current socket sendability status. */ -static int pty_sendbuffer(void *handle) +static int pty_sendbuffer(Backend *be) { - /* Pty pty = (Pty)handle; */ + /* Pty pty = FROMFIELD(be, struct pty_tag, backend); */ return 0; } /* * Called to set the size of the window */ -static void pty_size(void *handle, int width, int height) +static void pty_size(Backend *be, int width, int height) { - Pty pty = (Pty)handle; + Pty pty = FROMFIELD(be, struct pty_tag, backend); struct winsize size; pty->term_width = width; @@ -1159,9 +1159,9 @@ static void pty_size(void *handle, int width, int height) /* * Send special codes. */ -static void pty_special(void *handle, Telnet_Special code) +static void pty_special(Backend *be, Telnet_Special code) { - /* Pty pty = (Pty)handle; */ + /* Pty pty = FROMFIELD(be, struct pty_tag, backend); */ /* Do nothing! */ return; } @@ -1170,9 +1170,9 @@ static void pty_special(void *handle, Telnet_Special code) * Return a list of the special codes that make sense in this * protocol. */ -static const struct telnet_special *pty_get_specials(void *handle) +static const struct telnet_special *pty_get_specials(Backend *be) { - /* Pty pty = (Pty)handle; */ + /* Pty pty = FROMFIELD(be, struct pty_tag, backend); */ /* * Hmm. When I get round to having this actually usable, it * might be quite nice to have the ability to deliver a few @@ -1182,58 +1182,58 @@ static const struct telnet_special *pty_get_specials(void *handle) return NULL; } -static int pty_connected(void *handle) +static int pty_connected(Backend *be) { - /* Pty pty = (Pty)handle; */ + /* Pty pty = FROMFIELD(be, struct pty_tag, backend); */ return TRUE; } -static int pty_sendok(void *handle) +static int pty_sendok(Backend *be) { - /* Pty pty = (Pty)handle; */ + /* Pty pty = FROMFIELD(be, struct pty_tag, backend); */ return 1; } -static void pty_unthrottle(void *handle, int backlog) +static void pty_unthrottle(Backend *be, int backlog) { - /* Pty pty = (Pty)handle; */ + /* Pty pty = FROMFIELD(be, struct pty_tag, backend); */ /* do nothing */ } -static int pty_ldisc(void *handle, int option) +static int pty_ldisc(Backend *be, int option) { - /* Pty pty = (Pty)handle; */ + /* Pty pty = FROMFIELD(be, struct pty_tag, backend); */ return 0; /* neither editing nor echoing */ } -static void pty_provide_ldisc(void *handle, Ldisc *ldisc) +static void pty_provide_ldisc(Backend *be, Ldisc *ldisc) { - /* Pty pty = (Pty)handle; */ + /* Pty pty = FROMFIELD(be, struct pty_tag, backend); */ /* This is a stub. */ } -static void pty_provide_logctx(void *handle, LogContext *logctx) +static void pty_provide_logctx(Backend *be, LogContext *logctx) { - /* Pty pty = (Pty)handle; */ + /* Pty pty = FROMFIELD(be, struct pty_tag, backend); */ /* This is a stub. */ } -static int pty_exitcode(void *handle) +static int pty_exitcode(Backend *be) { - Pty pty = (Pty)handle; + Pty pty = FROMFIELD(be, struct pty_tag, backend); if (!pty->finished) return -1; /* not dead yet */ else return pty->exit_code; } -static int pty_cfg_info(void *handle) +static int pty_cfg_info(Backend *be) { - /* Pty pty = (Pty)handle; */ + /* Pty pty = FROMFIELD(be, struct pty_tag, backend); */ return 0; } -Backend pty_backend = { +const struct Backend_vtable pty_backend = { pty_init, pty_free, pty_reconfig, diff --git a/unix/uxputty.c b/unix/uxputty.c index fb280187..52e4cef1 100644 --- a/unix/uxputty.c +++ b/unix/uxputty.c @@ -37,11 +37,12 @@ void cleanup_exit(int code) exit(code); } -Backend *select_backend(Conf *conf) +const struct Backend_vtable *select_backend(Conf *conf) { - Backend *back = backend_from_proto(conf_get_int(conf, CONF_protocol)); - assert(back != NULL); - return back; + const struct Backend_vtable *vt = + backend_vt_from_proto(conf_get_int(conf, CONF_protocol)); + assert(vt != NULL); + return vt; } void initial_config_box(Conf *conf, post_dialog_fn_t after, void *afterctx) @@ -83,9 +84,10 @@ void setup(int single) default_protocol = be_default_protocol; /* Find the appropriate default port. */ { - Backend *b = backend_from_proto(default_protocol); + const struct Backend_vtable *vt = + backend_vt_from_proto(default_protocol); default_port = 0; /* illegal */ - if (b) - default_port = b->default_port; + if (vt) + default_port = vt->default_port; } } diff --git a/unix/uxser.c b/unix/uxser.c index 50eb83e6..e352f049 100644 --- a/unix/uxser.c +++ b/unix/uxser.c @@ -23,6 +23,7 @@ typedef struct serial_backend_data { int finished; int inbufsize; bufchain output_data; + Backend backend; } *Serial; /* @@ -287,7 +288,7 @@ static const char *serial_configure(Serial serial, Conf *conf) * Also places the canonical host name into `realhost'. It must be * freed by the caller. */ -static const char *serial_init(void *frontend_handle, void **backend_handle, +static const char *serial_init(void *frontend_handle, Backend **backend_handle, Conf *conf, const char *host, int port, char **realhost, int nodelay, int keepalive) @@ -297,7 +298,8 @@ static const char *serial_init(void *frontend_handle, void **backend_handle, char *line; serial = snew(struct serial_backend_data); - *backend_handle = serial; + serial->backend.vt = &serial_backend; + *backend_handle = &serial->backend; serial->frontend = frontend_handle; serial->finished = FALSE; @@ -345,9 +347,9 @@ static void serial_close(Serial serial) } } -static void serial_free(void *handle) +static void serial_free(Backend *be) { - Serial serial = (Serial) handle; + Serial serial = FROMFIELD(be, struct serial_backend_data, backend); serial_close(serial); @@ -356,9 +358,9 @@ static void serial_free(void *handle) sfree(serial); } -static void serial_reconfig(void *handle, Conf *conf) +static void serial_reconfig(Backend *be, Conf *conf) { - Serial serial = (Serial) handle; + Serial serial = FROMFIELD(be, struct serial_backend_data, backend); /* * FIXME: what should we do if this returns an error? @@ -460,9 +462,9 @@ static void serial_try_write(Serial serial) /* * Called to send data down the serial connection. */ -static int serial_send(void *handle, const char *buf, int len) +static int serial_send(Backend *be, const char *buf, int len) { - Serial serial = (Serial) handle; + Serial serial = FROMFIELD(be, struct serial_backend_data, backend); if (serial->fd < 0) return 0; @@ -476,16 +478,16 @@ static int serial_send(void *handle, const char *buf, int len) /* * Called to query the current sendability status. */ -static int serial_sendbuffer(void *handle) +static int serial_sendbuffer(Backend *be) { - Serial serial = (Serial) handle; + Serial serial = FROMFIELD(be, struct serial_backend_data, backend); return bufchain_size(&serial->output_data); } /* * Called to set the size of the window */ -static void serial_size(void *handle, int width, int height) +static void serial_size(Backend *be, int width, int height) { /* Do nothing! */ return; @@ -494,9 +496,9 @@ static void serial_size(void *handle, int width, int height) /* * Send serial special codes. */ -static void serial_special(void *handle, Telnet_Special code) +static void serial_special(Backend *be, Telnet_Special code) { - Serial serial = (Serial) handle; + Serial serial = FROMFIELD(be, struct serial_backend_data, backend); if (serial->fd >= 0 && code == TS_BRK) { tcsendbreak(serial->fd, 0); @@ -510,7 +512,7 @@ static void serial_special(void *handle, Telnet_Special code) * Return a list of the special codes that make sense in this * protocol. */ -static const struct telnet_special *serial_get_specials(void *handle) +static const struct telnet_special *serial_get_specials(Backend *be) { static const struct telnet_special specials[] = { {"Break", TS_BRK}, @@ -519,24 +521,24 @@ static const struct telnet_special *serial_get_specials(void *handle) return specials; } -static int serial_connected(void *handle) +static int serial_connected(Backend *be) { return 1; /* always connected */ } -static int serial_sendok(void *handle) +static int serial_sendok(Backend *be) { return 1; } -static void serial_unthrottle(void *handle, int backlog) +static void serial_unthrottle(Backend *be, int backlog) { - Serial serial = (Serial) handle; + Serial serial = FROMFIELD(be, struct serial_backend_data, backend); serial->inbufsize = backlog; serial_uxsel_setup(serial); } -static int serial_ldisc(void *handle, int option) +static int serial_ldisc(Backend *be, int option) { /* * Local editing and local echo are off by default. @@ -544,19 +546,19 @@ static int serial_ldisc(void *handle, int option) return 0; } -static void serial_provide_ldisc(void *handle, Ldisc *ldisc) +static void serial_provide_ldisc(Backend *be, Ldisc *ldisc) { /* This is a stub. */ } -static void serial_provide_logctx(void *handle, LogContext *logctx) +static void serial_provide_logctx(Backend *be, LogContext *logctx) { /* This is a stub. */ } -static int serial_exitcode(void *handle) +static int serial_exitcode(Backend *be) { - Serial serial = (Serial) handle; + Serial serial = FROMFIELD(be, struct serial_backend_data, backend); if (serial->fd >= 0) return -1; /* still connected */ else @@ -567,12 +569,12 @@ static int serial_exitcode(void *handle) /* * cfg_info for Serial does nothing at all. */ -static int serial_cfg_info(void *handle) +static int serial_cfg_info(Backend *be) { return 0; } -Backend serial_backend = { +const struct Backend_vtable serial_backend = { serial_init, serial_free, serial_reconfig, diff --git a/windows/wincfg.c b/windows/wincfg.c index 950cef11..9e242875 100644 --- a/windows/wincfg.c +++ b/windows/wincfg.c @@ -393,7 +393,7 @@ void win_setup_config_box(struct controlbox *b, HWND *hwndp, int has_help, * $XAUTHORITY is not reliable on Windows, so we provide a * means to override it. */ - if (!midsession && backend_from_proto(PROT_SSH)) { + if (!midsession && backend_vt_from_proto(PROT_SSH)) { s = ctrl_getset(b, "Connection/SSH/X11", "x11", "X11 forwarding"); ctrl_filesel(s, "X authority file for local display", 't', NULL, FALSE, "Select X authority file", diff --git a/windows/window.c b/windows/window.c index 80b94201..0d29b136 100644 --- a/windows/window.c +++ b/windows/window.c @@ -126,8 +126,7 @@ static int caret_x = -1, caret_y = -1; static int kbd_codepage; static Ldisc *ldisc; -static Backend *back; -static void *backhandle; +static Backend *backend; static struct unicode_data ucsdata; static int session_closed; @@ -248,6 +247,7 @@ char *get_ttymode(void *frontend, const char *mode) static void start_backend(void) { + const struct Backend_vtable *vt; const char *error; char msg[1024], *title; char *realhost; @@ -257,8 +257,8 @@ static void start_backend(void) * Select protocol. This is farmed out into a table in a * separate file to enable an ssh-free variant. */ - back = backend_from_proto(conf_get_int(conf, CONF_protocol)); - if (back == NULL) { + vt = backend_vt_from_proto(conf_get_int(conf, CONF_protocol)); + if (!vt) { char *str = dupprintf("%s Internal Error", appname); MessageBox(NULL, "Unsupported protocol number found", str, MB_OK | MB_ICONEXCLAMATION); @@ -266,13 +266,13 @@ static void start_backend(void) cleanup_exit(1); } - error = back->init(NULL, &backhandle, conf, - conf_get_str(conf, CONF_host), - conf_get_int(conf, CONF_port), - &realhost, - conf_get_int(conf, CONF_tcp_nodelay), - conf_get_int(conf, CONF_tcp_keepalives)); - back->provide_logctx(backhandle, logctx); + error = backend_init(vt, NULL, &backend, conf, + conf_get_str(conf, CONF_host), + conf_get_int(conf, CONF_port), + &realhost, + conf_get_int(conf, CONF_tcp_nodelay), + conf_get_int(conf, CONF_tcp_keepalives)); + backend_provide_logctx(backend, logctx); if (error) { char *str = dupprintf("%s Error", appname); sprintf(msg, "Unable to open connection to\n" @@ -294,12 +294,12 @@ static void start_backend(void) /* * Connect the terminal to the backend for resize purposes. */ - term_provide_resize_fn(term, back->size, backhandle); + term_provide_backend(term, backend); /* * Set up a line discipline. */ - ldisc = ldisc_create(conf, term, back, backhandle, NULL); + ldisc = ldisc_create(conf, term, backend, NULL); /* * Destroy the Restart Session menu item. (This will return @@ -329,11 +329,10 @@ static void close_session(void *ignored_context) ldisc_free(ldisc); ldisc = NULL; } - if (back) { - back->free(backhandle); - backhandle = NULL; - back = NULL; - term_provide_resize_fn(term, NULL, NULL); + if (backend) { + backend_free(backend); + backend = NULL; + term_provide_backend(term, NULL); update_specials_menu(NULL); } @@ -413,10 +412,11 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) default_protocol = be_default_protocol; /* Find the appropriate default port. */ { - Backend *b = backend_from_proto(default_protocol); + const struct Backend_vtable *vt = + backend_vt_from_proto(default_protocol); default_port = 0; /* illegal */ - if (b) - default_port = b->default_port; + if (vt) + default_port = vt->default_port; } conf_set_int(conf, CONF_logtype, LGTYP_NONE); @@ -951,8 +951,8 @@ void update_specials_menu(void *frontend) HMENU new_menu; int i, j; - if (back) - specials = back->get_specials(backhandle); + if (backend) + specials = backend_get_specials(backend); else specials = NULL; @@ -1975,7 +1975,7 @@ void notify_remote_exit(void *fe) int exitcode, close_on_exit; if (!session_closed && - (exitcode = back->exitcode(backhandle)) >= 0) { + (exitcode = backend_exitcode(backend)) >= 0) { close_on_exit = conf_get_int(conf, CONF_close_on_exit); /* Abnormal exits will already have set session_closed and taken * appropriate action. */ @@ -2161,7 +2161,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, } break; case IDM_RESTART: - if (!back) { + if (!backend) { logevent(NULL, "----- Session restarted -----"); term_pwron(term, FALSE); start_backend(); @@ -2190,7 +2190,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, prev_conf = conf_copy(conf); reconfig_result = - do_reconfig(hwnd, back ? back->cfg_info(backhandle) : 0); + do_reconfig(hwnd, backend ? backend_cfg_info(backend) : 0); reconfiguring = FALSE; if (!reconfig_result) { conf_free(prev_conf); @@ -2237,8 +2237,8 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, setup_clipboards(term, conf); /* Pass new config data to the back end */ - if (back) - back->reconfig(backhandle, conf); + if (backend) + backend_reconfig(backend, conf); /* Screen size changed ? */ if (conf_get_int(conf, CONF_height) != @@ -2414,8 +2414,8 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, */ if (i >= n_specials) break; - if (back) - back->special(backhandle, specials[i].code); + if (backend) + backend_special(backend, specials[i].code); } } break; @@ -4405,8 +4405,8 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, return p - output; } if (wParam == VK_CANCEL && shift_state == 2) { /* Ctrl-Break */ - if (back) - back->special(backhandle, TS_BRK); + if (backend) + backend_special(backend, TS_BRK); return 0; } if (wParam == VK_PAUSE) { /* Break/Pause */ diff --git a/windows/winplink.c b/windows/winplink.c index a940677f..455b18a7 100644 --- a/windows/winplink.c +++ b/windows/winplink.c @@ -76,8 +76,7 @@ DWORD orig_console_mode; WSAEVENT netevent; -static Backend *back; -static void *backhandle; +static Backend *backend; static Conf *conf; int term_ldisc(Terminal *term, int mode) @@ -254,11 +253,11 @@ int stdin_gotdata(struct handle *h, void *data, int len) cleanup_exit(0); } noise_ultralight(len); - if (back->connected(backhandle)) { + if (backend_connected(backend)) { if (len > 0) { - return back->send(backhandle, data, len); + return backend_send(backend, data, len); } else { - back->special(backhandle, TS_EOF); + backend_special(backend, TS_EOF); return 0; } } else @@ -281,9 +280,9 @@ void stdouterr_sent(struct handle *h, int new_backlog) (h == stdout_handle ? "output" : "error"), buf); cleanup_exit(0); } - if (back->connected(backhandle)) { - back->unthrottle(backhandle, (handle_backlog(stdout_handle) + - handle_backlog(stderr_handle))); + if (backend_connected(backend)) { + backend_unthrottle(backend, (handle_backlog(stdout_handle) + + handle_backlog(stderr_handle))); } } @@ -300,6 +299,7 @@ int main(int argc, char **argv) int use_subsystem = 0; int just_test_share_exists = FALSE; unsigned long now, next, then; + const struct Backend_vtable *vt; dll_hijacking_protection(); @@ -334,10 +334,10 @@ int main(int argc, char **argv) */ char *p = getenv("PLINK_PROTOCOL"); if (p) { - const Backend *b = backend_from_name(p); - if (b) { - default_protocol = b->protocol; - default_port = b->default_port; + const struct Backend_vtable *vt = backend_vt_from_name(p); + if (vt) { + default_protocol = vt->protocol; + default_port = vt->default_port; conf_set_int(conf, CONF_protocol, default_protocol); conf_set_int(conf, CONF_port, default_port); } @@ -432,8 +432,8 @@ int main(int argc, char **argv) * Select protocol. This is farmed out into a table in a * separate file to enable an ssh-free variant. */ - back = backend_from_proto(conf_get_int(conf, CONF_protocol)); - if (back == NULL) { + vt = backend_vt_from_proto(conf_get_int(conf, CONF_protocol)); + if (vt == NULL) { fprintf(stderr, "Internal fault: Unsupported protocol found\n"); return 1; @@ -460,13 +460,13 @@ int main(int argc, char **argv) console_provide_logctx(logctx); if (just_test_share_exists) { - if (!back->test_for_upstream) { + if (!vt->test_for_upstream) { fprintf(stderr, "Connection sharing not supported for connection " - "type '%s'\n", back->name); + "type '%s'\n", vt->name); return 1; } - if (back->test_for_upstream(conf_get_str(conf, CONF_host), - conf_get_int(conf, CONF_port), conf)) + if (vt->test_for_upstream(conf_get_str(conf, CONF_host), + conf_get_int(conf, CONF_port), conf)) return 0; else return 1; @@ -487,16 +487,16 @@ int main(int argc, char **argv) int nodelay = conf_get_int(conf, CONF_tcp_nodelay) && (GetFileType(GetStdHandle(STD_INPUT_HANDLE)) == FILE_TYPE_CHAR); - error = back->init(NULL, &backhandle, conf, - conf_get_str(conf, CONF_host), - conf_get_int(conf, CONF_port), - &realhost, nodelay, - conf_get_int(conf, CONF_tcp_keepalives)); + error = backend_init(vt, NULL, &backend, conf, + conf_get_str(conf, CONF_host), + conf_get_int(conf, CONF_port), + &realhost, nodelay, + conf_get_int(conf, CONF_tcp_keepalives)); if (error) { fprintf(stderr, "Unable to open connection:\n%s", error); return 1; } - back->provide_logctx(backhandle, logctx); + backend_provide_logctx(backend, logctx); sfree(realhost); } @@ -532,7 +532,7 @@ int main(int argc, char **argv) int n; DWORD ticks; - if (!sending && back->sendok(backhandle)) { + if (!sending && backend_sendok(backend)) { stdin_handle = handle_input_new(inhandle, stdin_gotdata, NULL, 0); sending = TRUE; @@ -643,13 +643,13 @@ int main(int argc, char **argv) sfree(handles); if (sending) - handle_unthrottle(stdin_handle, back->sendbuffer(backhandle)); + handle_unthrottle(stdin_handle, backend_sendbuffer(backend)); - if (!back->connected(backhandle) && + if (!backend_connected(backend) && handle_backlog(stdout_handle) + handle_backlog(stderr_handle) == 0) break; /* we closed the connection */ } - exitcode = back->exitcode(backhandle); + exitcode = backend_exitcode(backend); if (exitcode < 0) { fprintf(stderr, "Remote process exit code unavailable\n"); exitcode = 1; /* this is an error condition */ diff --git a/windows/winser.c b/windows/winser.c index f0ea94bd..1efac931 100644 --- a/windows/winser.c +++ b/windows/winser.c @@ -17,6 +17,7 @@ typedef struct serial_backend_data { int bufsize; long clearbreak_time; int break_in_progress; + Backend backend; } *Serial; static void serial_terminate(Serial serial) @@ -198,7 +199,7 @@ static const char *serial_configure(Serial serial, HANDLE serport, Conf *conf) * Also places the canonical host name into `realhost'. It must be * freed by the caller. */ -static const char *serial_init(void *frontend_handle, void **backend_handle, +static const char *serial_init(void *frontend_handle, Backend **backend_handle, Conf *conf, const char *host, int port, char **realhost, int nodelay, int keepalive) { @@ -212,7 +213,8 @@ static const char *serial_init(void *frontend_handle, void **backend_handle, serial->out = serial->in = NULL; serial->bufsize = 0; serial->break_in_progress = FALSE; - *backend_handle = serial; + serial->backend.vt = &serial_backend; + *backend_handle = &serial->backend; serial->frontend = frontend_handle; @@ -279,18 +281,18 @@ static const char *serial_init(void *frontend_handle, void **backend_handle, return NULL; } -static void serial_free(void *handle) +static void serial_free(Backend *be) { - Serial serial = (Serial) handle; + Serial serial = FROMFIELD(be, struct serial_backend_data, backend); serial_terminate(serial); expire_timer_context(serial); sfree(serial); } -static void serial_reconfig(void *handle, Conf *conf) +static void serial_reconfig(Backend *be, Conf *conf) { - Serial serial = (Serial) handle; + Serial serial = FROMFIELD(be, struct serial_backend_data, backend); serial_configure(serial, serial->port, conf); @@ -303,9 +305,9 @@ static void serial_reconfig(void *handle, Conf *conf) /* * Called to send data down the serial connection. */ -static int serial_send(void *handle, const char *buf, int len) +static int serial_send(Backend *be, const char *buf, int len) { - Serial serial = (Serial) handle; + Serial serial = FROMFIELD(be, struct serial_backend_data, backend); if (serial->out == NULL) return 0; @@ -317,16 +319,16 @@ static int serial_send(void *handle, const char *buf, int len) /* * Called to query the current sendability status. */ -static int serial_sendbuffer(void *handle) +static int serial_sendbuffer(Backend *be) { - Serial serial = (Serial) handle; + Serial serial = FROMFIELD(be, struct serial_backend_data, backend); return serial->bufsize; } /* * Called to set the size of the window */ -static void serial_size(void *handle, int width, int height) +static void serial_size(Backend *be, int width, int height) { /* Do nothing! */ return; @@ -346,9 +348,9 @@ static void serbreak_timer(void *ctx, unsigned long now) /* * Send serial special codes. */ -static void serial_special(void *handle, Telnet_Special code) +static void serial_special(Backend *be, Telnet_Special code) { - Serial serial = (Serial) handle; + Serial serial = FROMFIELD(be, struct serial_backend_data, backend); if (serial->port && code == TS_BRK) { logevent(serial->frontend, "Starting serial break at user request"); @@ -375,7 +377,7 @@ static void serial_special(void *handle, Telnet_Special code) * Return a list of the special codes that make sense in this * protocol. */ -static const struct telnet_special *serial_get_specials(void *handle) +static const struct telnet_special *serial_get_specials(Backend *be) { static const struct telnet_special specials[] = { {"Break", TS_BRK}, @@ -384,24 +386,24 @@ static const struct telnet_special *serial_get_specials(void *handle) return specials; } -static int serial_connected(void *handle) +static int serial_connected(Backend *be) { return 1; /* always connected */ } -static int serial_sendok(void *handle) +static int serial_sendok(Backend *be) { return 1; } -static void serial_unthrottle(void *handle, int backlog) +static void serial_unthrottle(Backend *be, int backlog) { - Serial serial = (Serial) handle; + Serial serial = FROMFIELD(be, struct serial_backend_data, backend); if (serial->in) handle_unthrottle(serial->in, backlog); } -static int serial_ldisc(void *handle, int option) +static int serial_ldisc(Backend *be, int option) { /* * Local editing and local echo are off by default. @@ -409,19 +411,19 @@ static int serial_ldisc(void *handle, int option) return 0; } -static void serial_provide_ldisc(void *handle, Ldisc *ldisc) +static void serial_provide_ldisc(Backend *be, Ldisc *ldisc) { /* This is a stub. */ } -static void serial_provide_logctx(void *handle, LogContext *logctx) +static void serial_provide_logctx(Backend *be, LogContext *logctx) { /* This is a stub. */ } -static int serial_exitcode(void *handle) +static int serial_exitcode(Backend *be) { - Serial serial = (Serial) handle; + Serial serial = FROMFIELD(be, struct serial_backend_data, backend); if (serial->port != INVALID_HANDLE_VALUE) return -1; /* still connected */ else @@ -432,12 +434,12 @@ static int serial_exitcode(void *handle) /* * cfg_info for Serial does nothing at all. */ -static int serial_cfg_info(void *handle) +static int serial_cfg_info(Backend *be) { return 0; } -Backend serial_backend = { +const struct Backend_vtable serial_backend = { serial_init, serial_free, serial_reconfig, diff --git a/windows/winstuff.h b/windows/winstuff.h index 727c4b06..87dc48b6 100644 --- a/windows/winstuff.h +++ b/windows/winstuff.h @@ -596,7 +596,7 @@ void agent_schedule_callback(void (*callback)(void *, void *, int), /* * Exports from winser.c. */ -extern Backend serial_backend; +extern const struct Backend_vtable serial_backend; /* * Exports from winjump.c. From 8dfb2a118618618fe38d129aa42ece6803ea1ac6 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Wed, 12 Sep 2018 09:10:51 +0100 Subject: [PATCH 393/607] Introduce a typedef for frontend handles. This is another major source of unexplained 'void *' parameters throughout the code. In particular, the currently unused testback.c actually gave the wrong pointer type to its internal store of the frontend handle - it cast the input void * to a Terminal *, from which it got implicitly cast back again when calling from_backend, and nobody noticed. Now it uses the right type internally as well as externally. --- be_misc.c | 2 +- callback.c | 8 +- defs.h | 2 + fuzzterm.c | 52 ++++---- ldisc.c | 2 +- ldisc.h | 2 +- logging.c | 4 +- misc.c | 2 +- network.h | 5 +- proxy.c | 2 +- pscp.c | 9 +- psftp.c | 9 +- putty.h | 96 +++++++------- raw.c | 6 +- rlogin.c | 6 +- ssh.c | 6 +- ssh.h | 2 +- telnet.c | 6 +- terminal.c | 2 +- terminal.h | 2 +- testback.c | 14 +- unix/gtkapp.c | 4 +- unix/gtkcomm.c | 2 +- unix/gtkdlg.c | 12 +- unix/gtkmain.c | 2 +- unix/gtkwin.c | 322 +++++++++++++++++++-------------------------- unix/unix.h | 16 +-- unix/uxcons.c | 18 +-- unix/uxpgnt.c | 4 +- unix/uxplink.c | 12 +- unix/uxpty.c | 4 +- unix/uxser.c | 6 +- unix/uxsftp.c | 2 +- windows/wincons.c | 18 +-- windows/windlg.c | 10 +- windows/window.c | 70 +++++----- windows/winplink.c | 12 +- windows/winser.c | 6 +- windows/winsftp.c | 2 +- windows/winstuff.h | 2 +- 40 files changed, 357 insertions(+), 406 deletions(-) diff --git a/be_misc.c b/be_misc.c index 9fcfec55..4774bd70 100644 --- a/be_misc.c +++ b/be_misc.c @@ -9,7 +9,7 @@ #include "putty.h" #include "network.h" -void backend_socket_log(void *frontend, int type, SockAddr addr, int port, +void backend_socket_log(Frontend *frontend, int type, SockAddr addr, int port, const char *error_msg, int error_code, Conf *conf, int session_started) { diff --git a/callback.c b/callback.c index 10f923d0..0a05f624 100644 --- a/callback.c +++ b/callback.c @@ -17,13 +17,13 @@ struct callback { struct callback *cbcurr = NULL, *cbhead = NULL, *cbtail = NULL; toplevel_callback_notify_fn_t notify_frontend = NULL; -void *frontend = NULL; +void *notify_ctx = NULL; void request_callback_notifications(toplevel_callback_notify_fn_t fn, - void *fr) + void *ctx) { notify_frontend = fn; - frontend = fr; + notify_ctx = ctx; } static void run_idempotent_callback(void *ctx) @@ -87,7 +87,7 @@ void queue_toplevel_callback(toplevel_callback_fn_t fn, void *ctx) * callback keeps re-scheduling itself. */ if (notify_frontend && !cbhead && !cbcurr) - notify_frontend(frontend); + notify_frontend(notify_ctx); if (cbtail) cbtail->next = cb; diff --git a/defs.h b/defs.h index 43f56dfe..53ded962 100644 --- a/defs.h +++ b/defs.h @@ -49,6 +49,8 @@ typedef struct Backend_vtable Backend_vtable; typedef struct Ldisc_tag Ldisc; typedef struct LogContext_tag LogContext; +typedef struct Frontend Frontend; + typedef struct ssh_tag *Ssh; /* Note indirection: for historical reasons (it used to be closer to diff --git a/fuzzterm.c b/fuzzterm.c index cdefb0d9..fda9f6c8 100644 --- a/fuzzterm.c +++ b/fuzzterm.c @@ -38,12 +38,12 @@ int main(int argc, char **argv) return 0; } -int from_backend(void *frontend, int is_stderr, const void *data, int len) +int from_backend(Frontend *frontend, int is_stderr, const void *data, int len) { return 0; } /* functions required by terminal.c */ -void request_resize(void *frontend, int x, int y) { } +void request_resize(Frontend *frontend, int x, int y) { } void do_text(Context ctx, int x, int y, wchar_t * text, int len, unsigned long attr, int lattr, truecolour tc) { @@ -67,40 +67,40 @@ void do_cursor(Context ctx, int x, int y, wchar_t * text, int len, printf("\n"); } int char_width(Context ctx, int uc) { return 1; } -void set_title(void *frontend, char *t) { } -void set_icon(void *frontend, char *t) { } -void set_sbar(void *frontend, int a, int b, int c) { } +void set_title(Frontend *frontend, char *t) { } +void set_icon(Frontend *frontend, char *t) { } +void set_sbar(Frontend *frontend, int a, int b, int c) { } void ldisc_send(Ldisc *ldisc, const void *buf, int len, int interactive) {} void ldisc_echoedit_update(Ldisc *ldisc) {} -Context get_ctx(void *frontend) { +Context get_ctx(Frontend *frontend) { static char x; return &x; } void free_ctx(Context ctx) { } -void palette_set(void *frontend, int a, int b, int c, int d) { } -void palette_reset(void *frontend) { } -int palette_get(void *frontend, int n, int *r, int *g, int *b) {return FALSE;} -void write_clip(void *frontend, int clipboard, +void palette_set(Frontend *frontend, int a, int b, int c, int d) { } +void palette_reset(Frontend *frontend) { } +int palette_get(Frontend *frontend, int n, int *r, int *g, int *b) {return FALSE;} +void write_clip(Frontend *frontend, int clipboard, wchar_t *a, int *b, truecolour *c, int d, int e) { } -void set_raw_mouse_mode(void *frontend, int m) { } -void frontend_request_paste(void *frontend, int clipboard) { } -void do_beep(void *frontend, int a) { } -void sys_cursor(void *frontend, int x, int y) { } +void set_raw_mouse_mode(Frontend *frontend, int m) { } +void frontend_request_paste(Frontend *frontend, int clipboard) { } +void do_beep(Frontend *frontend, int a) { } +void sys_cursor(Frontend *frontend, int x, int y) { } void modalfatalbox(const char *fmt, ...) { exit(0); } void nonfatal(const char *fmt, ...) { } -void set_iconic(void *frontend, int iconic) { } -void move_window(void *frontend, int x, int y) { } -void set_zorder(void *frontend, int top) { } -void refresh_window(void *frontend) { } -void set_zoomed(void *frontend, int zoomed) { } -int is_iconic(void *frontend) { return 0; } -void get_window_pos(void *frontend, int *x, int *y) { *x = 0; *y = 0; } -void get_window_pixels(void *frontend, int *x, int *y) { *x = 0; *y = 0; } -char *get_window_title(void *frontend, int icon) { return "moo"; } -int frontend_is_utf8(void *frontend) { return TRUE; } +void set_iconic(Frontend *frontend, int iconic) { } +void move_window(Frontend *frontend, int x, int y) { } +void set_zorder(Frontend *frontend, int top) { } +void refresh_window(Frontend *frontend) { } +void set_zoomed(Frontend *frontend, int zoomed) { } +int is_iconic(Frontend *frontend) { return 0; } +void get_window_pos(Frontend *frontend, int *x, int *y) { *x = 0; *y = 0; } +void get_window_pixels(Frontend *frontend, int *x, int *y) { *x = 0; *y = 0; } +char *get_window_title(Frontend *frontend, int icon) { return "moo"; } +int frontend_is_utf8(Frontend *frontend) { return TRUE; } /* needed by timing.c */ void timer_change_notify(unsigned long next) { } @@ -142,8 +142,8 @@ int dlg_coloursel_results(union control *ctrl, void *dlg, void dlg_refresh(union control *ctrl, void *dlg) { } /* miscellany */ -void logevent(void *frontend, const char *msg) { } -int askappend(void *frontend, Filename *filename, +void logevent(Frontend *frontend, const char *msg) { } +int askappend(Frontend *frontend, Filename *filename, void (*callback)(void *ctx, int result), void *ctx) { return 0; } const char *const appname = "FuZZterm"; diff --git a/ldisc.c b/ldisc.c index 3596ea63..e17b13c7 100644 --- a/ldisc.c +++ b/ldisc.c @@ -78,7 +78,7 @@ static void bsb(Ldisc *ldisc, int n) #define KCTRL(x) ((x^'@') | 0x100) Ldisc *ldisc_create(Conf *conf, Terminal *term, - Backend *backend, void *frontend) + Backend *backend, Frontend *frontend) { Ldisc *ldisc = snew(Ldisc); diff --git a/ldisc.h b/ldisc.h index af7afde3..e3d043b5 100644 --- a/ldisc.h +++ b/ldisc.h @@ -11,7 +11,7 @@ struct Ldisc_tag { Terminal *term; Backend *backend; - void *frontend; + Frontend *frontend; /* * Values cached out of conf. diff --git a/logging.c b/logging.c index 75c457e3..b1fb638b 100644 --- a/logging.c +++ b/logging.c @@ -17,7 +17,7 @@ struct LogContext_tag { enum { L_CLOSED, L_OPENING, L_OPEN, L_ERROR } state; bufchain queue; Filename *currlogfilename; - void *frontend; + Frontend *frontend; Conf *conf; int logtype; /* cached out of conf */ }; @@ -367,7 +367,7 @@ void log_packet(LogContext *ctx, int direction, int type, logflush(ctx); } -LogContext *log_init(void *frontend, Conf *conf) +LogContext *log_init(Frontend *frontend, Conf *conf) { LogContext *ctx = snew(LogContext); ctx->lgfp = NULL; diff --git a/misc.c b/misc.c index 92890322..fdd5635c 100644 --- a/misc.c +++ b/misc.c @@ -216,7 +216,7 @@ char *host_strduptrim(const char *s) return dupstr(s); } -prompts_t *new_prompts(void *frontend) +prompts_t *new_prompts(Frontend *frontend) { prompts_t *p = snew(prompts_t); p->prompts = NULL; diff --git a/network.h b/network.h index 9914ce34..79f44f5e 100644 --- a/network.h +++ b/network.h @@ -95,7 +95,8 @@ Socket new_connection(SockAddr addr, const char *hostname, Socket new_listener(const char *srcaddr, int port, Plug plug, int local_host_only, Conf *conf, int addressfamily); SockAddr name_lookup(const char *host, int port, char **canonicalname, - Conf *conf, int addressfamily, void *frontend_for_logging, + Conf *conf, int addressfamily, + Frontend *frontend_for_logging, const char *lookup_reason_for_logging); int proxy_for_destination (SockAddr addr, const char *hostname, int port, Conf *conf); @@ -221,7 +222,7 @@ extern Plug nullplug; /* * Exports from be_misc.c. */ -void backend_socket_log(void *frontend, int type, SockAddr addr, int port, +void backend_socket_log(Frontend *frontend, int type, SockAddr addr, int port, const char *error_msg, int error_code, Conf *conf, int session_started); void log_proxy_stderr(Plug plug, bufchain *buf, const void *vdata, int len); diff --git a/proxy.c b/proxy.c index 6ccd4025..f55973fc 100644 --- a/proxy.c +++ b/proxy.c @@ -368,7 +368,7 @@ static char *dns_log_msg(const char *host, int addressfamily, } SockAddr name_lookup(const char *host, int port, char **canonicalname, - Conf *conf, int addressfamily, void *frontend, + Conf *conf, int addressfamily, Frontend *frontend, const char *reason) { char *logmsg; diff --git a/pscp.c b/pscp.c index 854e6815..594f119f 100644 --- a/pscp.c +++ b/pscp.c @@ -118,7 +118,7 @@ void nonfatal(const char *fmt, ...) sfree(str2); errs++; } -void connection_fatal(void *frontend, const char *fmt, ...) +void connection_fatal(Frontend *frontend, const char *fmt, ...) { char *str, *str2; va_list ap; @@ -157,7 +157,8 @@ static unsigned char *outptr; /* where to put the data */ static unsigned outlen; /* how much data required */ static unsigned char *pending = NULL; /* any spare data */ static unsigned pendlen = 0, pendsize = 0; /* length and phys. size of buffer */ -int from_backend(void *frontend, int is_stderr, const void *data, int datalen) +int from_backend(Frontend *frontend, int is_stderr, + const void *data, int datalen) { unsigned char *p = (unsigned char *) data; unsigned len = (unsigned) datalen; @@ -195,7 +196,7 @@ int from_backend(void *frontend, int is_stderr, const void *data, int datalen) return 0; } -int from_backend_untrusted(void *frontend_handle, const void *data, int len) +int from_backend_untrusted(Frontend *frontend, const void *data, int len) { /* * No "untrusted" output should get here (the way the code is @@ -204,7 +205,7 @@ int from_backend_untrusted(void *frontend_handle, const void *data, int len) assert(!"Unexpected call to from_backend_untrusted()"); return 0; /* not reached */ } -int from_backend_eof(void *frontend) +int from_backend_eof(Frontend *frontend) { /* * We usually expect to be the party deciding when to close the diff --git a/psftp.c b/psftp.c index c2d23832..d57b118e 100644 --- a/psftp.c +++ b/psftp.c @@ -2466,7 +2466,7 @@ void nonfatal(const char *fmt, ...) fputs(str2, stderr); sfree(str2); } -void connection_fatal(void *frontend, const char *fmt, ...) +void connection_fatal(Frontend *frontend, const char *fmt, ...) { char *str, *str2; va_list ap; @@ -2506,7 +2506,8 @@ static unsigned char *outptr; /* where to put the data */ static unsigned outlen; /* how much data required */ static unsigned char *pending = NULL; /* any spare data */ static unsigned pendlen = 0, pendsize = 0; /* length and phys. size of buffer */ -int from_backend(void *frontend, int is_stderr, const void *data, int datalen) +int from_backend(Frontend *frontend, int is_stderr, + const void *data, int datalen) { unsigned char *p = (unsigned char *) data; unsigned len = (unsigned) datalen; @@ -2550,7 +2551,7 @@ int from_backend(void *frontend, int is_stderr, const void *data, int datalen) return 0; } -int from_backend_untrusted(void *frontend_handle, const void *data, int len) +int from_backend_untrusted(Frontend *frontend, const void *data, int len) { /* * No "untrusted" output should get here (the way the code is @@ -2559,7 +2560,7 @@ int from_backend_untrusted(void *frontend_handle, const void *data, int len) assert(!"Unexpected call to from_backend_untrusted()"); return 0; /* not reached */ } -int from_backend_eof(void *frontend) +int from_backend_eof(Frontend *frontend) { /* * We expect to be the party deciding when to close the diff --git a/putty.h b/putty.h index 2f53d645..1a8c30ce 100644 --- a/putty.h +++ b/putty.h @@ -445,7 +445,7 @@ struct Backend { const Backend_vtable *vt; }; struct Backend_vtable { - const char *(*init) (void *frontend_handle, Backend **backend_out, + const char *(*init) (Frontend *frontend, Backend **backend_out, Conf *conf, const char *host, int port, char **realhost, int nodelay, int keepalive); @@ -608,11 +608,11 @@ typedef struct { size_t n_prompts; /* May be zero (in which case display the foregoing, * if any, and return success) */ prompt_t **prompts; - void *frontend; + Frontend *frontend; void *data; /* slot for housekeeping data, managed by * get_userpass_input(); initially NULL */ } prompts_t; -prompts_t *new_prompts(void *frontend); +prompts_t *new_prompts(Frontend *frontend); void add_prompt(prompts_t *p, char *promptstr, int echo); void prompt_set_result(prompt_t *pr, const char *newstr); void prompt_ensure_result_size(prompt_t *pr, int len); @@ -673,7 +673,7 @@ enum { ALL_CLIPBOARDS(CLIP_ID) N_CLIPBOARDS }; /* * Exports from the front end. */ -void request_resize(void *frontend, int, int); +void request_resize(Frontend *frontend, int, int); void do_text(Context, int, int, wchar_t *, int, unsigned long, int, truecolour); void do_cursor(Context, int, int, wchar_t *, int, unsigned long, int, @@ -682,46 +682,46 @@ int char_width(Context ctx, int uc); #ifdef OPTIMISE_SCROLL void do_scroll(Context, int, int, int); #endif -void set_title(void *frontend, char *); -void set_icon(void *frontend, char *); -void set_sbar(void *frontend, int, int, int); -Context get_ctx(void *frontend); +void set_title(Frontend *frontend, char *); +void set_icon(Frontend *frontend, char *); +void set_sbar(Frontend *frontend, int, int, int); +Context get_ctx(Frontend *frontend); void free_ctx(Context); -void palette_set(void *frontend, int, int, int, int); -void palette_reset(void *frontend); -int palette_get(void *frontend, int n, int *r, int *g, int *b); -void write_clip(void *frontend, int clipboard, wchar_t *, int *, +void palette_set(Frontend *frontend, int, int, int, int); +void palette_reset(Frontend *frontend); +int palette_get(Frontend *frontend, int n, int *r, int *g, int *b); +void write_clip(Frontend *frontend, int clipboard, wchar_t *, int *, truecolour *, int, int); -void optimised_move(void *frontend, int, int, int); -void set_raw_mouse_mode(void *frontend, int); -void connection_fatal(void *frontend, const char *, ...); +void optimised_move(Frontend *frontend, int, int, int); +void set_raw_mouse_mode(Frontend *frontend, int); +void connection_fatal(Frontend *frontend, const char *, ...); void nonfatal(const char *, ...); void modalfatalbox(const char *, ...); #ifdef macintosh #pragma noreturn(modalfatalbox) #endif -void do_beep(void *frontend, int); -void begin_session(void *frontend); -void sys_cursor(void *frontend, int x, int y); -void frontend_request_paste(void *frontend, int clipboard); -void frontend_keypress(void *frontend); -void frontend_echoedit_update(void *frontend, int echo, int edit); +void do_beep(Frontend *frontend, int); +void begin_session(Frontend *frontend); +void sys_cursor(Frontend *frontend, int x, int y); +void frontend_request_paste(Frontend *frontend, int clipboard); +void frontend_keypress(Frontend *frontend); +void frontend_echoedit_update(Frontend *frontend, int echo, int edit); /* It's the backend's responsibility to invoke this at the start of a * connection, if necessary; it can also invoke it later if the set of * special commands changes. It does not need to invoke it at session * shutdown. */ -void update_specials_menu(void *frontend); -int from_backend(void *frontend, int is_stderr, const void *data, int len); -int from_backend_untrusted(void *frontend, const void *data, int len); +void update_specials_menu(Frontend *frontend); +int from_backend(Frontend *frontend, int is_stderr, const void *data, int len); +int from_backend_untrusted(Frontend *frontend, const void *data, int len); /* Called when the back end wants to indicate that EOF has arrived on * the server-to-client stream. Returns FALSE to indicate that we * intend to keep the session open in the other direction, or TRUE to * indicate that if they're closing so are we. */ -int from_backend_eof(void *frontend); -void notify_remote_exit(void *frontend); +int from_backend_eof(Frontend *frontend); +void notify_remote_exit(Frontend *frontend); /* Get a sensible value for a tty mode. NULL return = don't set. * Otherwise, returned value should be freed by caller. */ -char *get_ttymode(void *frontend, const char *mode); +char *get_ttymode(Frontend *frontend, const char *mode); /* * >0 = `got all results, carry on' * 0 = `user cancelled' (FIXME distinguish "give up entirely" and "next auth"?) @@ -730,15 +730,15 @@ char *get_ttymode(void *frontend, const char *mode); int get_userpass_input(prompts_t *p, bufchain *input); #define OPTIMISE_IS_SCROLL 1 -void set_iconic(void *frontend, int iconic); -void move_window(void *frontend, int x, int y); -void set_zorder(void *frontend, int top); -void refresh_window(void *frontend); -void set_zoomed(void *frontend, int zoomed); -int is_iconic(void *frontend); -void get_window_pos(void *frontend, int *x, int *y); -void get_window_pixels(void *frontend, int *x, int *y); -char *get_window_title(void *frontend, int icon); +void set_iconic(Frontend *frontend, int iconic); +void move_window(Frontend *frontend, int x, int y); +void set_zorder(Frontend *frontend, int top); +void refresh_window(Frontend *frontend); +void set_zoomed(Frontend *frontend, int zoomed); +int is_iconic(Frontend *frontend); +void get_window_pos(Frontend *frontend, int *x, int *y); +void get_window_pixels(Frontend *frontend, int *x, int *y); +char *get_window_title(Frontend *frontend, int icon); /* Hint from backend to frontend about time-consuming operations. * Initial state is assumed to be BUSY_NOT. */ enum { @@ -748,8 +748,8 @@ enum { stuff is suspended */ BUSY_CPU /* Locally busy (e.g. crypto); user interaction suspended */ }; -void set_busy_status(void *frontend, int status); -int frontend_is_utf8(void *frontend); +void set_busy_status(Frontend *frontend, int status); +int frontend_is_utf8(Frontend *frontend); void cleanup_exit(int); @@ -1105,7 +1105,7 @@ FontSpec *platform_default_fontspec(const char *name); * Exports from terminal.c. */ -Terminal *term_init(Conf *, struct unicode_data *, void *); +Terminal *term_init(Conf *, struct unicode_data *, Frontend *); void term_free(Terminal *); void term_size(Terminal *, int, int, int); void term_paint(Terminal *, Context, int, int, int, int, int); @@ -1142,7 +1142,7 @@ int format_arrow_key(char *buf, Terminal *term, int xkey, int ctrl); /* * Exports from logging.c. */ -LogContext *log_init(void *frontend, Conf *conf); +LogContext *log_init(Frontend *frontend, Conf *conf); void log_free(LogContext *logctx); void log_reconfig(LogContext *logctx, Conf *conf); void logfopen(LogContext *logctx); @@ -1196,7 +1196,7 @@ extern const struct Backend_vtable ssh_backend; /* * Exports from ldisc.c. */ -Ldisc *ldisc_create(Conf *, Terminal *, Backend *, void *); +Ldisc *ldisc_create(Conf *, Terminal *, Backend *, Frontend *); void ldisc_configure(Ldisc *, Conf *); void ldisc_free(Ldisc *); void ldisc_send(Ldisc *, const void *buf, int len, int interactive); @@ -1324,7 +1324,7 @@ int wc_unescape(char *output, const char *wildcard); /* * Exports from frontend (windlg.c etc) */ -void logevent(void *frontend, const char *); +void logevent(Frontend *frontend, const char *); void pgp_fingerprints(void); /* * verify_ssh_host_key() can return one of three values: @@ -1338,7 +1338,7 @@ void pgp_fingerprints(void); * back via the provided function with a result that's either 0 * or +1'. */ -int verify_ssh_host_key(void *frontend, char *host, int port, +int verify_ssh_host_key(Frontend *frontend, char *host, int port, const char *keytype, char *keystr, char *fingerprint, void (*callback)(void *ctx, int result), void *ctx); /* @@ -1354,9 +1354,9 @@ int have_ssh_host_key(const char *host, int port, const char *keytype); * warning threshold because that's all we have cached, but at least * one acceptable algorithm is available that we don't have cached.) */ -int askalg(void *frontend, const char *algtype, const char *algname, +int askalg(Frontend *frontend, const char *algtype, const char *algname, void (*callback)(void *ctx, int result), void *ctx); -int askhk(void *frontend, const char *algname, const char *betteralgs, +int askhk(Frontend *frontend, const char *algname, const char *betteralgs, void (*callback)(void *ctx, int result), void *ctx); /* * askappend can return four values: @@ -1366,7 +1366,7 @@ int askhk(void *frontend, const char *algname, const char *betteralgs, * - 0 means cancel logging for this session * - -1 means please wait. */ -int askappend(void *frontend, Filename *filename, +int askappend(Frontend *frontend, Filename *filename, void (*callback)(void *ctx, int result), void *ctx); /* @@ -1631,9 +1631,9 @@ struct IdempotentCallback { }; void queue_idempotent_callback(struct IdempotentCallback *ic); -typedef void (*toplevel_callback_notify_fn_t)(void *frontend); +typedef void (*toplevel_callback_notify_fn_t)(void *ctx); void request_callback_notifications(toplevel_callback_notify_fn_t notify, - void *frontend); + void *ctx); /* * Define no-op macros for the jump list functions, on platforms that diff --git a/raw.c b/raw.c index 56eb0385..df280139 100644 --- a/raw.c +++ b/raw.c @@ -14,7 +14,7 @@ typedef struct raw_backend_data { Socket s; int closed_on_socket_error; int bufsize; - void *frontend; + Frontend *frontend; int sent_console_eof, sent_socket_eof, session_started; Conf *conf; @@ -117,7 +117,7 @@ static const Plug_vtable Raw_plugvt = { * Also places the canonical host name into `realhost'. It must be * freed by the caller. */ -static const char *raw_init(void *frontend_handle, Backend **backend_handle, +static const char *raw_init(Frontend *frontend, Backend **backend_handle, Conf *conf, const char *host, int port, char **realhost, int nodelay, int keepalive) @@ -139,7 +139,7 @@ static const char *raw_init(void *frontend_handle, Backend **backend_handle, raw->session_started = FALSE; raw->conf = conf_copy(conf); - raw->frontend = frontend_handle; + raw->frontend = frontend; addressfamily = conf_get_int(conf, CONF_addressfamily); /* diff --git a/rlogin.c b/rlogin.c index 978e3084..05dd7dbb 100644 --- a/rlogin.c +++ b/rlogin.c @@ -18,7 +18,7 @@ typedef struct rlogin_tag { int firstbyte; int cansize; int term_width, term_height; - void *frontend; + Frontend *frontend; Conf *conf; @@ -148,7 +148,7 @@ static const Plug_vtable Rlogin_plugvt = { * Also places the canonical host name into `realhost'. It must be * freed by the caller. */ -static const char *rlogin_init(void *frontend_handle, Backend **backend_handle, +static const char *rlogin_init(Frontend *frontend, Backend **backend_handle, Conf *conf, const char *host, int port, char **realhost, int nodelay, int keepalive) @@ -165,7 +165,7 @@ static const char *rlogin_init(void *frontend_handle, Backend **backend_handle, rlogin->backend.vt = &rlogin_backend; rlogin->s = NULL; rlogin->closed_on_socket_error = FALSE; - rlogin->frontend = frontend_handle; + rlogin->frontend = frontend; rlogin->term_width = conf_get_int(conf, CONF_width); rlogin->term_height = conf_get_int(conf, CONF_height); rlogin->firstbyte = 1; diff --git a/ssh.c b/ssh.c index 952b901f..1009e038 100644 --- a/ssh.c +++ b/ssh.c @@ -729,7 +729,7 @@ struct ssh_tag { int echoing, editing; int session_started; - void *frontend; + Frontend *frontend; int ospeed, ispeed; /* temporaries */ int term_width, term_height; @@ -10665,7 +10665,7 @@ static void ssh_cache_conf_values(Ssh ssh) * * Returns an error message, or NULL on success. */ -static const char *ssh_init(void *frontend_handle, Backend **backend_handle, +static const char *ssh_init(Frontend *frontend, Backend **backend_handle, Conf *conf, const char *host, int port, char **realhost, int nodelay, int keepalive) @@ -10781,7 +10781,7 @@ static const char *ssh_init(void *frontend_handle, Backend **backend_handle, ssh->backend.vt = &ssh_backend; *backend_handle = &ssh->backend; - ssh->frontend = frontend_handle; + ssh->frontend = frontend; ssh->term_width = conf_get_int(ssh->conf, CONF_width); ssh->term_height = conf_get_int(ssh->conf, CONF_height); diff --git a/ssh.h b/ssh.h index 4529bbcc..3fe8266b 100644 --- a/ssh.h +++ b/ssh.h @@ -660,7 +660,7 @@ int random_byte(void); void random_add_noise(void *noise, int length); void random_add_heavynoise(void *noise, int length); -void logevent(void *, const char *); +void logevent(Frontend *, const char *); struct PortForwarding; diff --git a/telnet.c b/telnet.c index 673c152f..7e62e301 100644 --- a/telnet.c +++ b/telnet.c @@ -172,7 +172,7 @@ typedef struct telnet_tag { Socket s; int closed_on_socket_error; - void *frontend; + Frontend *frontend; Ldisc *ldisc; int term_width, term_height; @@ -705,7 +705,7 @@ static const Plug_vtable Telnet_plugvt = { * Also places the canonical host name into `realhost'. It must be * freed by the caller. */ -static const char *telnet_init(void *frontend_handle, Backend **backend_handle, +static const char *telnet_init(Frontend *frontend, Backend **backend_handle, Conf *conf, const char *host, int port, char **realhost, int nodelay, int keepalive) { @@ -726,7 +726,7 @@ static const char *telnet_init(void *frontend_handle, Backend **backend_handle, telnet->activated = FALSE; telnet->sb_buf = NULL; telnet->sb_size = 0; - telnet->frontend = frontend_handle; + telnet->frontend = frontend; telnet->term_width = conf_get_int(telnet->conf, CONF_width); telnet->term_height = conf_get_int(telnet->conf, CONF_height); telnet->state = TOP_LEVEL; diff --git a/terminal.c b/terminal.c index 1dc83dc1..a8bd6fc7 100644 --- a/terminal.c +++ b/terminal.c @@ -1639,7 +1639,7 @@ const optionalrgb optionalrgb_none = {0, 0, 0, 0}; * Initialise the terminal. */ Terminal *term_init(Conf *myconf, struct unicode_data *ucsdata, - void *frontend) + Frontend *frontend) { Terminal *term; diff --git a/terminal.h b/terminal.h index 8ec256d4..f0727cf2 100644 --- a/terminal.h +++ b/terminal.h @@ -231,7 +231,7 @@ struct terminal_tag { Ldisc *ldisc; - void *frontend; + Frontend *frontend; LogContext *logctx; diff --git a/testback.c b/testback.c index f3e9e35f..01a7e6e0 100644 --- a/testback.c +++ b/testback.c @@ -32,9 +32,9 @@ #include "putty.h" -static const char *null_init(void *, Backend **, Conf *, const char *, int, +static const char *null_init(Frontend *, Backend **, Conf *, const char *, int, char **, int, int); -static const char *loop_init(void *, Backend **, Conf *, const char *, int, +static const char *loop_init(Frontend *, Backend **, Conf *, const char *, int, char **, int, int); static void null_free(Backend *); static void loop_free(Backend *); @@ -69,23 +69,23 @@ const struct Backend_vtable loop_backend = { }; struct loop_state { - Terminal *term; + Frontend *frontend; Backend backend; }; -static const char *null_init(void *frontend_handle, Backend **backend_handle, +static const char *null_init(Frontend *frontend, Backend **backend_handle, Conf *conf, const char *host, int port, char **realhost, int nodelay, int keepalive) { *backend_handle = NULL; return NULL; } -static const char *loop_init(void *frontend_handle, Backend **backend_handle, +static const char *loop_init(Frontend *frontend, Backend **backend_handle, Conf *conf, const char *host, int port, char **realhost, int nodelay, int keepalive) { struct loop_state *st = snew(struct loop_state); - st->term = frontend_handle; + st->frontend = frontend; *backend_handle = &st->backend; return NULL; } @@ -114,7 +114,7 @@ static int null_send(Backend *be, const char *buf, int len) { static int loop_send(Backend *be, const char *buf, int len) { struct loop_state *st = FROMFIELD(be, struct loop_state, backend); - return from_backend(st->term, 0, buf, len); + return from_backend(st->frontend, 0, buf, len); } static int null_sendbuffer(Backend *be) { diff --git a/unix/gtkapp.c b/unix/gtkapp.c index d520565d..f79e5e9a 100644 --- a/unix/gtkapp.c +++ b/unix/gtkapp.c @@ -99,7 +99,7 @@ int main(int argc, char **argv) fprintf(stderr, "GtkApplication frontend doesn't work pre-GTK3\n"); return 1; } -GtkWidget *make_gtk_toplevel_window(void *frontend) { return NULL; } +GtkWidget *make_gtk_toplevel_window(Frontend *frontend) { return NULL; } void launch_duplicate_session(Conf *conf) {} void launch_new_session(void) {} void launch_saved_session(const char *str) {} @@ -204,7 +204,7 @@ WIN_ACTION_LIST(WIN_ACTION_ENTRY) }; static GtkApplication *app; -GtkWidget *make_gtk_toplevel_window(void *frontend) +GtkWidget *make_gtk_toplevel_window(Frontend *frontend) { GtkWidget *win = gtk_application_window_new(app); g_action_map_add_action_entries(G_ACTION_MAP(win), diff --git a/unix/gtkcomm.c b/unix/gtkcomm.c index 9c3d1c53..6b6d19bb 100644 --- a/unix/gtkcomm.c +++ b/unix/gtkcomm.c @@ -221,7 +221,7 @@ static gint idle_toplevel_callback_func(gpointer data) return TRUE; } -static void notify_toplevel_callback(void *frontend) +static void notify_toplevel_callback(void *vctx) { if (!idle_fn_scheduled) { toplevel_callback_idle_id = diff --git a/unix/gtkdlg.c b/unix/gtkdlg.c index 737163f2..f1425daf 100644 --- a/unix/gtkdlg.c +++ b/unix/gtkdlg.c @@ -3442,7 +3442,7 @@ struct verify_ssh_host_key_result_ctx { char *keystr; void (*callback)(void *callback_ctx, int result); void *callback_ctx; - void *frontend; + Frontend *frontend; }; static void verify_ssh_host_key_result_callback(void *vctx, int result) @@ -3483,7 +3483,7 @@ static void verify_ssh_host_key_result_callback(void *vctx, int result) sfree(ctx); } -int verify_ssh_host_key(void *frontend, char *host, int port, +int verify_ssh_host_key(Frontend *frontend, char *host, int port, const char *keytype, char *keystr, char *fingerprint, void (*callback)(void *ctx, int result), void *ctx) { @@ -3560,7 +3560,7 @@ int verify_ssh_host_key(void *frontend, char *host, int port, struct simple_prompt_result_ctx { void (*callback)(void *callback_ctx, int result); void *callback_ctx; - void *frontend; + Frontend *frontend; enum DialogSlot dialog_slot; }; @@ -3584,7 +3584,7 @@ static void simple_prompt_result_callback(void *vctx, int result) * Ask whether the selected algorithm is acceptable (since it was * below the configured 'warn' threshold). */ -int askalg(void *frontend, const char *algtype, const char *algname, +int askalg(Frontend *frontend, const char *algtype, const char *algname, void (*callback)(void *ctx, int result), void *ctx) { static const char msg[] = @@ -3616,7 +3616,7 @@ int askalg(void *frontend, const char *algtype, const char *algname, return -1; /* dialog still in progress */ } -int askhk(void *frontend, const char *algname, const char *betteralgs, +int askhk(Frontend *frontend, const char *algname, const char *betteralgs, void (*callback)(void *ctx, int result), void *ctx) { static const char msg[] = @@ -4059,7 +4059,7 @@ void logevent_dlg(void *estuff, const char *string) } } -int askappend(void *frontend, Filename *filename, +int askappend(Frontend *frontend, Filename *filename, void (*callback)(void *ctx, int result), void *ctx) { static const char msgtemplate[] = diff --git a/unix/gtkmain.c b/unix/gtkmain.c index 906d029a..a97f7415 100644 --- a/unix/gtkmain.c +++ b/unix/gtkmain.c @@ -549,7 +549,7 @@ int do_cmdline(int argc, char **argv, int do_everything, Conf *conf) return err; } -GtkWidget *make_gtk_toplevel_window(void *frontend) +GtkWidget *make_gtk_toplevel_window(Frontend *frontend) { return gtk_window_new(GTK_WINDOW_TOPLEVEL); } diff --git a/unix/gtkwin.c b/unix/gtkwin.c index 6867ac07..aebeff8f 100644 --- a/unix/gtkwin.c +++ b/unix/gtkwin.c @@ -76,7 +76,7 @@ struct clipboard_data_instance { #endif struct clipboard_state { - struct gui_data *inst; + Frontend *inst; int clipboard; GdkAtom atom; #ifdef JUST_USE_GTK_CLIPBOARD_UTF8 @@ -88,7 +88,7 @@ struct clipboard_state { #endif }; -struct gui_data { +struct Frontend { GtkWidget *window, *area, *sbar; gboolean sbar_visible; gboolean drawing_area_got_size, drawing_area_realised; @@ -182,7 +182,7 @@ struct gui_data { #endif }; -static void cache_conf_values(struct gui_data *inst) +static void cache_conf_values(Frontend *inst) { inst->bold_style = conf_get_int(inst->conf, CONF_bold_style); inst->window_border = conf_get_int(inst->conf, CONF_window_border); @@ -200,31 +200,31 @@ static void cache_conf_values(struct gui_data *inst) } struct draw_ctx { - struct gui_data *inst; + Frontend *inst; unifont_drawctx uctx; }; static int send_raw_mouse; -static void start_backend(struct gui_data *inst); +static void start_backend(Frontend *inst); static void exit_callback(void *vinst); -static void destroy_inst_connection(struct gui_data *inst); -static void delete_inst(struct gui_data *inst); +static void destroy_inst_connection(Frontend *inst); +static void delete_inst(Frontend *inst); static void post_fatal_message_box_toplevel(void *vctx) { - struct gui_data *inst = (struct gui_data *)vctx; + Frontend *inst = (Frontend *)vctx; gtk_widget_destroy(inst->window); } static void post_fatal_message_box(void *vctx, int result) { - struct gui_data *inst = (struct gui_data *)vctx; + Frontend *inst = (Frontend *)vctx; unregister_dialog(inst, DIALOG_SLOT_CONNECTION_FATAL); queue_toplevel_callback(post_fatal_message_box_toplevel, inst); } -void fatal_message_box(struct gui_data *inst, const char *msg) +void fatal_message_box(Frontend *inst, const char *msg) { char *title = dupcat(appname, " Fatal Error", NULL); GtkWidget *dialog = create_message_box( @@ -235,16 +235,14 @@ void fatal_message_box(struct gui_data *inst, const char *msg) sfree(title); } -static void connection_fatal_callback(void *vinst) +static void connection_fatal_callback(void *vctx) { - struct gui_data *inst = (struct gui_data *)vinst; + Frontend *inst = (Frontend *)vctx; destroy_inst_connection(inst); } -void connection_fatal(void *frontend, const char *p, ...) +void connection_fatal(Frontend *inst, const char *p, ...) { - struct gui_data *inst = (struct gui_data *)frontend; - va_list ap; char *msg; va_start(ap, p); @@ -254,7 +252,7 @@ void connection_fatal(void *frontend, const char *p, ...) sfree(msg); inst->exited = TRUE; /* suppress normal exit handling */ - queue_toplevel_callback(connection_fatal_callback, frontend); + queue_toplevel_callback(connection_fatal_callback, inst); } /* @@ -293,36 +291,33 @@ int platform_default_i(const char *name, int def) } /* Dummy routine, only required in plink. */ -void frontend_echoedit_update(void *frontend, int echo, int edit) +void frontend_echoedit_update(Frontend *inst, int echo, int edit) { } -char *get_ttymode(void *frontend, const char *mode) +char *get_ttymode(Frontend *inst, const char *mode) { - struct gui_data *inst = (struct gui_data *)frontend; return term_get_ttymode(inst->term, mode); } -int from_backend(void *frontend, int is_stderr, const void *data, int len) +int from_backend(Frontend *inst, int is_stderr, const void *data, int len) { - struct gui_data *inst = (struct gui_data *)frontend; return term_data(inst->term, is_stderr, data, len); } -int from_backend_untrusted(void *frontend, const void *data, int len) +int from_backend_untrusted(Frontend *inst, const void *data, int len) { - struct gui_data *inst = (struct gui_data *)frontend; return term_data_untrusted(inst->term, data, len); } -int from_backend_eof(void *frontend) +int from_backend_eof(Frontend *inst) { return TRUE; /* do respond to incoming EOF with outgoing */ } int get_userpass_input(prompts_t *p, bufchain *input) { - struct gui_data *inst = (struct gui_data *)p->frontend; + Frontend *inst = p->frontend; int ret; ret = cmdline_get_passwd_input(p); if (ret == -1) @@ -330,19 +325,15 @@ int get_userpass_input(prompts_t *p, bufchain *input) return ret; } -void logevent(void *frontend, const char *string) +void logevent(Frontend *inst, const char *string) { - struct gui_data *inst = (struct gui_data *)frontend; - log_eventlog(inst->logctx, string); logevent_dlg(inst->eventlogstuff, string); } -int font_dimension(void *frontend, int which)/* 0 for width, 1 for height */ +int font_dimension(Frontend *inst, int which) /* 0 for width, 1 for height */ { - struct gui_data *inst = (struct gui_data *)frontend; - if (which) return inst->font_height; else @@ -360,8 +351,6 @@ int font_dimension(void *frontend, int which)/* 0 for width, 1 for height */ */ static Mouse_Button translate_button(Mouse_Button button) { - /* struct gui_data *inst = (struct gui_data *)frontend; */ - if (button == MBT_LEFT) return MBT_SELECT; if (button == MBT_MIDDLE) @@ -375,9 +364,8 @@ static Mouse_Button translate_button(Mouse_Button button) * Return the top-level GtkWindow associated with a particular * front end instance. */ -GtkWidget *get_window(void *frontend) +GtkWidget *get_window(Frontend *inst) { - struct gui_data *inst = (struct gui_data *)frontend; return inst->window; } @@ -386,16 +374,14 @@ GtkWidget *get_window(void *frontend) * network code wanting to ask an asynchronous user question (e.g. * 'what about this dodgy host key, then?'). */ -void register_dialog(void *frontend, enum DialogSlot slot, GtkWidget *dialog) +void register_dialog(Frontend *inst, enum DialogSlot slot, GtkWidget *dialog) { - struct gui_data *inst = (struct gui_data *)frontend; assert(slot < DIALOG_SLOT_LIMIT); assert(!inst->dialogs[slot]); inst->dialogs[slot] = dialog; } -void unregister_dialog(void *frontend, enum DialogSlot slot) +void unregister_dialog(Frontend *inst, enum DialogSlot slot) { - struct gui_data *inst = (struct gui_data *)frontend; assert(slot < DIALOG_SLOT_LIMIT); assert(inst->dialogs[slot]); inst->dialogs[slot] = NULL; @@ -405,13 +391,12 @@ void unregister_dialog(void *frontend, enum DialogSlot slot) * Minimise or restore the window in response to a server-side * request. */ -void set_iconic(void *frontend, int iconic) +void set_iconic(Frontend *inst, int iconic) { /* * GTK 1.2 doesn't know how to do this. */ #if GTK_CHECK_VERSION(2,0,0) - struct gui_data *inst = (struct gui_data *)frontend; if (iconic) gtk_window_iconify(GTK_WINDOW(inst->window)); else @@ -422,9 +407,8 @@ void set_iconic(void *frontend, int iconic) /* * Move the window in response to a server-side request. */ -void move_window(void *frontend, int x, int y) +void move_window(Frontend *inst, int x, int y) { - struct gui_data *inst = (struct gui_data *)frontend; /* * I assume that when the GTK version of this call is available * we should use it. Not sure how it differs from the GDK one, @@ -443,9 +427,8 @@ void move_window(void *frontend, int x, int y) * Move the window to the top or bottom of the z-order in response * to a server-side request. */ -void set_zorder(void *frontend, int top) +void set_zorder(Frontend *inst, int top) { - struct gui_data *inst = (struct gui_data *)frontend; if (top) gdk_window_raise(gtk_widget_get_window(inst->window)); else @@ -455,9 +438,8 @@ void set_zorder(void *frontend, int top) /* * Refresh the window in response to a server-side request. */ -void refresh_window(void *frontend) +void refresh_window(Frontend *inst) { - struct gui_data *inst = (struct gui_data *)frontend; term_invalidate(inst->term); } @@ -465,13 +447,12 @@ void refresh_window(void *frontend) * Maximise or restore the window in response to a server-side * request. */ -void set_zoomed(void *frontend, int zoomed) +void set_zoomed(Frontend *inst, int zoomed) { /* * GTK 1.2 doesn't know how to do this. */ #if GTK_CHECK_VERSION(2,0,0) - struct gui_data *inst = (struct gui_data *)frontend; if (zoomed) gtk_window_maximize(GTK_WINDOW(inst->window)); else @@ -482,18 +463,16 @@ void set_zoomed(void *frontend, int zoomed) /* * Report whether the window is iconic, for terminal reports. */ -int is_iconic(void *frontend) +int is_iconic(Frontend *inst) { - struct gui_data *inst = (struct gui_data *)frontend; return !gdk_window_is_viewable(gtk_widget_get_window(inst->window)); } /* * Report the window's position, for terminal reports. */ -void get_window_pos(void *frontend, int *x, int *y) +void get_window_pos(Frontend *inst, int *x, int *y) { - struct gui_data *inst = (struct gui_data *)frontend; /* * I assume that when the GTK version of this call is available * we should use it. Not sure how it differs from the GDK one, @@ -509,9 +488,8 @@ void get_window_pos(void *frontend, int *x, int *y) /* * Report the window's pixel size, for terminal reports. */ -void get_window_pixels(void *frontend, int *x, int *y) +void get_window_pixels(Frontend *inst, int *x, int *y) { - struct gui_data *inst = (struct gui_data *)frontend; /* * I assume that when the GTK version of this call is available * we should use it. Not sure how it differs from the GDK one, @@ -530,7 +508,7 @@ void get_window_pixels(void *frontend, int *x, int *y) * raise it, so that the user realises they've already been asked this * question. */ -static int find_and_raise_dialog(struct gui_data *inst, enum DialogSlot slot) +static int find_and_raise_dialog(Frontend *inst, enum DialogSlot slot) { GtkWidget *dialog = inst->dialogs[slot]; if (!dialog) @@ -546,15 +524,14 @@ static int find_and_raise_dialog(struct gui_data *inst, enum DialogSlot slot) /* * Return the window or icon title. */ -char *get_window_title(void *frontend, int icon) +char *get_window_title(Frontend *inst, int icon) { - struct gui_data *inst = (struct gui_data *)frontend; return icon ? inst->icontitle : inst->wintitle; } static void warn_on_close_callback(void *vctx, int result) { - struct gui_data *inst = (struct gui_data *)vctx; + Frontend *inst = (Frontend *)vctx; unregister_dialog(inst, DIALOG_SLOT_WARN_ON_CLOSE); if (result) gtk_widget_destroy(inst->window); @@ -570,9 +547,8 @@ static void warn_on_close_callback(void *vctx, int result) * handler need not do anything', i.e. 'suppress default handler', * i.e. 'do not close the window'.) */ -gint delete_window(GtkWidget *widget, GdkEvent *event, gpointer data) +gint delete_window(GtkWidget *widget, GdkEvent *event, Frontend *inst) { - struct gui_data *inst = (struct gui_data *)data; if (!inst->exited && conf_get_int(inst->conf, CONF_warn_on_close)) { /* * We're not going to exit right now. We must put up a @@ -594,7 +570,7 @@ gint delete_window(GtkWidget *widget, GdkEvent *event, gpointer data) return FALSE; } -static void update_mouseptr(struct gui_data *inst) +static void update_mouseptr(Frontend *inst) { switch (inst->busy_status) { case BUSY_NOT: @@ -620,7 +596,7 @@ static void update_mouseptr(struct gui_data *inst) } } -static void show_mouseptr(struct gui_data *inst, int show) +static void show_mouseptr(Frontend *inst, int show) { if (!conf_get_int(inst->conf, CONF_hide_mouseptr)) show = 1; @@ -628,9 +604,9 @@ static void show_mouseptr(struct gui_data *inst, int show) update_mouseptr(inst); } -static void draw_backing_rect(struct gui_data *inst); +static void draw_backing_rect(Frontend *inst); -static void drawing_area_setup(struct gui_data *inst, int width, int height) +static void drawing_area_setup(Frontend *inst, int width, int height) { int w, h, new_scale, need_size = 0; @@ -719,7 +695,7 @@ static void drawing_area_setup(struct gui_data *inst, int width, int height) #endif } -static void drawing_area_setup_simple(struct gui_data *inst) +static void drawing_area_setup_simple(Frontend *inst) { /* * Wrapper on drawing_area_setup which fetches the width and @@ -736,10 +712,8 @@ static void drawing_area_setup_simple(struct gui_data *inst) drawing_area_setup(inst, alloc.width, alloc.height); } -static void area_realised(GtkWidget *widget, gpointer data) +static void area_realised(GtkWidget *widget, Frontend *inst) { - struct gui_data *inst = (struct gui_data *)data; - inst->drawing_area_realised = TRUE; if (inst->drawing_area_realised && inst->drawing_area_got_size && inst->drawing_area_setup_needed) @@ -747,17 +721,15 @@ static void area_realised(GtkWidget *widget, gpointer data) } static void area_size_allocate( - GtkWidget *widget, GdkRectangle *alloc, gpointer data) + GtkWidget *widget, GdkRectangle *alloc, Frontend *inst) { - struct gui_data *inst = (struct gui_data *)data; - inst->drawing_area_got_size = TRUE; if (inst->drawing_area_realised && inst->drawing_area_got_size) drawing_area_setup(inst, alloc->width, alloc->height); } #if GTK_CHECK_VERSION(3,10,0) -static void area_check_scale(struct gui_data *inst) +static void area_check_scale(Frontend *inst) { if (!inst->drawing_area_setup_needed && inst->scale != gtk_widget_get_scale_factor(inst->area)) { @@ -774,7 +746,7 @@ static void area_check_scale(struct gui_data *inst) static gboolean area_configured( GtkWidget *widget, GdkEventConfigure *event, gpointer data) { - struct gui_data *inst = (struct gui_data *)data; + Frontend *inst = (Frontend *)data; area_check_scale(inst); return FALSE; } @@ -799,7 +771,7 @@ static void cairo_setup_dctx(struct draw_ctx *dctx) #if GTK_CHECK_VERSION(3,0,0) static gint draw_area(GtkWidget *widget, cairo_t *cr, gpointer data) { - struct gui_data *inst = (struct gui_data *)data; + Frontend *inst = (Frontend *)data; #if GTK_CHECK_VERSION(3,10,0) /* @@ -862,7 +834,7 @@ static gint draw_area(GtkWidget *widget, cairo_t *cr, gpointer data) #else gint expose_area(GtkWidget *widget, GdkEventExpose *event, gpointer data) { - struct gui_data *inst = (struct gui_data *)data; + Frontend *inst = (Frontend *)data; #ifndef NO_BACKING_PIXMAPS /* @@ -912,11 +884,11 @@ char *dup_keyval_name(guint keyval) } #endif -static void change_font_size(struct gui_data *inst, int increment); +static void change_font_size(Frontend *inst, int increment); gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) { - struct gui_data *inst = (struct gui_data *)data; + Frontend *inst = (Frontend *)data; char output[256]; wchar_t ucsoutput[2]; int ucsval, start, end, special, output_charset, use_ucsoutput; @@ -2146,7 +2118,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) #if GTK_CHECK_VERSION(2,0,0) void input_method_commit_event(GtkIMContext *imc, gchar *str, gpointer data) { - struct gui_data *inst = (struct gui_data *)data; + Frontend *inst = (Frontend *)data; #ifdef KEY_EVENT_DIAGNOSTICS char *string_string = dupstr(""); @@ -2173,7 +2145,7 @@ void input_method_commit_event(GtkIMContext *imc, gchar *str, gpointer data) #define SCROLL_INCREMENT_LINES 5 #if GTK_CHECK_VERSION(3,4,0) -gboolean scroll_internal(struct gui_data *inst, gdouble delta, guint state, +gboolean scroll_internal(Frontend *inst, gdouble delta, guint state, gdouble ex, gdouble ey) { int shift, ctrl, alt, x, y, raw_mouse_mode; @@ -2225,7 +2197,7 @@ gboolean scroll_internal(struct gui_data *inst, gdouble delta, guint state, } #endif -static gboolean button_internal(struct gui_data *inst, GdkEventButton *event) +static gboolean button_internal(Frontend *inst, GdkEventButton *event) { int shift, ctrl, alt, x, y, button, act, raw_mouse_mode; @@ -2298,7 +2270,7 @@ static gboolean button_internal(struct gui_data *inst, GdkEventButton *event) gboolean button_event(GtkWidget *widget, GdkEventButton *event, gpointer data) { - struct gui_data *inst = (struct gui_data *)data; + Frontend *inst = (Frontend *)data; return button_internal(inst, event); } @@ -2310,7 +2282,7 @@ gboolean button_event(GtkWidget *widget, GdkEventButton *event, gpointer data) */ gboolean scroll_event(GtkWidget *widget, GdkEventScroll *event, gpointer data) { - struct gui_data *inst = (struct gui_data *)data; + Frontend *inst = (Frontend *)data; #if GTK_CHECK_VERSION(3,4,0) gdouble dx, dy; @@ -2351,7 +2323,7 @@ gboolean scroll_event(GtkWidget *widget, GdkEventScroll *event, gpointer data) gint motion_event(GtkWidget *widget, GdkEventMotion *event, gpointer data) { - struct gui_data *inst = (struct gui_data *)data; + Frontend *inst = (Frontend *)data; int shift, ctrl, alt, x, y, button; /* Remember the timestamp. */ @@ -2380,10 +2352,8 @@ gint motion_event(GtkWidget *widget, GdkEventMotion *event, gpointer data) return TRUE; } -void frontend_keypress(void *handle) +void frontend_keypress(Frontend *inst) { - struct gui_data *inst = (struct gui_data *)handle; - /* * If our child process has exited but not closed, terminate on * any keypress. @@ -2392,9 +2362,9 @@ void frontend_keypress(void *handle) gtk_widget_destroy(inst->window); } -static void exit_callback(void *vinst) +static void exit_callback(void *vctx) { - struct gui_data *inst = (struct gui_data *)vinst; + Frontend *inst = (Frontend *)vctx; int exitcode, close_on_exit; if (!inst->exited && @@ -2409,14 +2379,12 @@ static void exit_callback(void *vinst) } } -void notify_remote_exit(void *frontend) +void notify_remote_exit(Frontend *inst) { - struct gui_data *inst = (struct gui_data *)frontend; - queue_toplevel_callback(exit_callback, inst); } -static void destroy_inst_connection(struct gui_data *inst) +static void destroy_inst_connection(Frontend *inst) { inst->exited = TRUE; if (inst->ldisc) { @@ -2435,7 +2403,7 @@ static void destroy_inst_connection(struct gui_data *inst) } } -static void delete_inst(struct gui_data *inst) +static void delete_inst(Frontend *inst) { int dialog_slot; for (dialog_slot = 0; dialog_slot < DIALOG_SLOT_LIMIT; dialog_slot++) { @@ -2496,7 +2464,7 @@ static void delete_inst(struct gui_data *inst) void destroy(GtkWidget *widget, gpointer data) { - struct gui_data *inst = (struct gui_data *)data; + Frontend *inst = (Frontend *)data; inst->window = NULL; delete_inst(inst); session_window_closed(); @@ -2504,16 +2472,15 @@ void destroy(GtkWidget *widget, gpointer data) gint focus_event(GtkWidget *widget, GdkEventFocus *event, gpointer data) { - struct gui_data *inst = (struct gui_data *)data; + Frontend *inst = (Frontend *)data; term_set_focus(inst->term, event->in); term_update(inst->term); show_mouseptr(inst, 1); return FALSE; } -void set_busy_status(void *frontend, int status) +void set_busy_status(Frontend *inst, int status) { - struct gui_data *inst = (struct gui_data *)frontend; inst->busy_status = status; update_mouseptr(inst); } @@ -2521,24 +2488,21 @@ void set_busy_status(void *frontend, int status) /* * set or clear the "raw mouse message" mode */ -void set_raw_mouse_mode(void *frontend, int activate) +void set_raw_mouse_mode(Frontend *inst, int activate) { - struct gui_data *inst = (struct gui_data *)frontend; activate = activate && !conf_get_int(inst->conf, CONF_no_mouse_rep); send_raw_mouse = activate; update_mouseptr(inst); } #if GTK_CHECK_VERSION(2,0,0) -static void compute_whole_window_size(struct gui_data *inst, +static void compute_whole_window_size(Frontend *inst, int wchars, int hchars, int *wpix, int *hpix); #endif -void request_resize(void *frontend, int w, int h) +void request_resize(Frontend *inst, int w, int h) { - struct gui_data *inst = (struct gui_data *)frontend; - #if !GTK_CHECK_VERSION(3,0,0) int large_x, large_y; @@ -2624,7 +2588,7 @@ void request_resize(void *frontend, int w, int h) } -static void real_palette_set(struct gui_data *inst, int n, int r, int g, int b) +static void real_palette_set(Frontend *inst, int n, int r, int g, int b) { inst->cols[n].red = r * 0x0101; inst->cols[n].green = g * 0x0101; @@ -2678,7 +2642,7 @@ void set_gtk_widget_background(GtkWidget *widget, const GdkColor *col) #endif } -void set_window_background(struct gui_data *inst) +void set_window_background(Frontend *inst) { if (inst->area) set_gtk_widget_background(GTK_WIDGET(inst->area), &inst->cols[258]); @@ -2686,9 +2650,8 @@ void set_window_background(struct gui_data *inst) set_gtk_widget_background(GTK_WIDGET(inst->window), &inst->cols[258]); } -void palette_set(void *frontend, int n, int r, int g, int b) +void palette_set(Frontend *inst, int n, int r, int g, int b) { - struct gui_data *inst = (struct gui_data *)frontend; if (n >= 16) n += 256 - 16; if (n >= NALLCOLOURS) @@ -2703,9 +2666,8 @@ void palette_set(void *frontend, int n, int r, int g, int b) } } -int palette_get(void *frontend, int n, int *r, int *g, int *b) +int palette_get(Frontend *inst, int n, int *r, int *g, int *b) { - struct gui_data *inst = (struct gui_data *)frontend; if (n < 0 || n >= NALLCOLOURS) return FALSE; *r = inst->cols[n].red >> 8; @@ -2714,9 +2676,8 @@ int palette_get(void *frontend, int n, int *r, int *g, int *b) return TRUE; } -void palette_reset(void *frontend) +void palette_reset(Frontend *inst) { - struct gui_data *inst = (struct gui_data *)frontend; /* This maps colour indices in inst->conf to those used in inst->cols. */ static const int ww[] = { 256, 257, 258, 259, 260, 261, @@ -2784,7 +2745,7 @@ void palette_reset(void *frontend) } static struct clipboard_state *clipboard_from_atom( - struct gui_data *inst, GdkAtom atom) + Frontend *inst, GdkAtom atom) { int i; @@ -2806,7 +2767,7 @@ static struct clipboard_state *clipboard_from_atom( * formats it feels like. */ -void set_clipboard_atom(struct gui_data *inst, int clipboard, GdkAtom atom) +void set_clipboard_atom(Frontend *inst, int clipboard, GdkAtom atom) { struct clipboard_state *state = &inst->clipstates[clipboard]; @@ -2823,7 +2784,7 @@ void set_clipboard_atom(struct gui_data *inst, int clipboard, GdkAtom atom) } } -int init_clipboard(struct gui_data *inst) +int init_clipboard(Frontend *inst) { set_clipboard_atom(inst, CLIP_PRIMARY, GDK_SELECTION_PRIMARY); set_clipboard_atom(inst, CLIP_CLIPBOARD, clipboard_atom); @@ -2861,11 +2822,10 @@ static void clipboard_clear(GtkClipboard *clipboard, gpointer data) sfree(cdi); } -void write_clip(void *frontend, int clipboard, +void write_clip(Frontend *inst, int clipboard, wchar_t *data, int *attr, truecolour *truecolour, int len, int must_deselect) { - struct gui_data *inst = (struct gui_data *)frontend; struct clipboard_state *state = &inst->clipstates[clipboard]; struct clipboard_data_instance *cdi; @@ -2922,7 +2882,7 @@ void write_clip(void *frontend, int clipboard, static void clipboard_text_received(GtkClipboard *clipboard, const gchar *text, gpointer data) { - struct gui_data *inst = (struct gui_data *)data; + Frontend *inst = (Frontend *)data; wchar_t *paste; int paste_len; int length; @@ -2940,9 +2900,8 @@ static void clipboard_text_received(GtkClipboard *clipboard, sfree(paste); } -void frontend_request_paste(void *frontend, int clipboard) +void frontend_request_paste(Frontend *inst, int clipboard) { - struct gui_data *inst = (struct gui_data *)frontend; struct clipboard_state *state = &inst->clipstates[clipboard]; if (!state->gtkclipboard) @@ -2975,7 +2934,7 @@ void frontend_request_paste(void *frontend, int clipboard) */ /* Store the data in a cut-buffer. */ -static void store_cutbuffer(struct gui_data *inst, char *ptr, int len) +static void store_cutbuffer(Frontend *inst, char *ptr, int len) { #ifndef NOT_X_WINDOWS if (inst->disp) { @@ -2989,7 +2948,7 @@ static void store_cutbuffer(struct gui_data *inst, char *ptr, int len) /* Retrieve data from a cut-buffer. * Returned data needs to be freed with XFree(). */ -static char *retrieve_cutbuffer(struct gui_data *inst, int *nbytes) +static char *retrieve_cutbuffer(Frontend *inst, int *nbytes) { #ifndef NOT_X_WINDOWS char *ptr; @@ -3009,11 +2968,10 @@ static char *retrieve_cutbuffer(struct gui_data *inst, int *nbytes) #endif } -void write_clip(void *frontend, int clipboard, +void write_clip(Frontend *inst, int clipboard, wchar_t *data, int *attr, truecolour *truecolour, int len, int must_deselect) { - struct gui_data *inst = (struct gui_data *)frontend; struct clipboard_state *state = &inst->clipstates[clipboard]; if (state->pasteout_data) @@ -3115,7 +3073,7 @@ void write_clip(void *frontend, int clipboard, static void selection_get(GtkWidget *widget, GtkSelectionData *seldata, guint info, guint time_stamp, gpointer data) { - struct gui_data *inst = (struct gui_data *)data; + Frontend *inst = (Frontend *)data; GdkAtom target = gtk_selection_data_get_target(seldata); struct clipboard_state *state = clipboard_from_atom( inst, gtk_selection_data_get_selection(seldata)); @@ -3140,7 +3098,7 @@ static void selection_get(GtkWidget *widget, GtkSelectionData *seldata, static gint selection_clear(GtkWidget *widget, GdkEventSelection *seldata, gpointer data) { - struct gui_data *inst = (struct gui_data *)data; + Frontend *inst = (Frontend *)data; struct clipboard_state *state = clipboard_from_atom( inst, seldata->selection); @@ -3163,9 +3121,8 @@ static gint selection_clear(GtkWidget *widget, GdkEventSelection *seldata, return TRUE; } -void frontend_request_paste(void *frontend, int clipboard) +void frontend_request_paste(Frontend *inst, int clipboard) { - struct gui_data *inst = (struct gui_data *)frontend; struct clipboard_state *state = &inst->clipstates[clipboard]; /* @@ -3198,7 +3155,7 @@ void frontend_request_paste(void *frontend, int clipboard) static void selection_received(GtkWidget *widget, GtkSelectionData *seldata, guint time, gpointer data) { - struct gui_data *inst = (struct gui_data *)data; + Frontend *inst = (Frontend *)data; char *text; int length; #ifndef NOT_X_WINDOWS @@ -3320,7 +3277,7 @@ static void selection_received(GtkWidget *widget, GtkSelectionData *seldata, #endif } -static void init_one_clipboard(struct gui_data *inst, int clipboard) +static void init_one_clipboard(Frontend *inst, int clipboard) { struct clipboard_state *state = &inst->clipstates[clipboard]; @@ -3328,7 +3285,7 @@ static void init_one_clipboard(struct gui_data *inst, int clipboard) state->clipboard = clipboard; } -void set_clipboard_atom(struct gui_data *inst, int clipboard, GdkAtom atom) +void set_clipboard_atom(Frontend *inst, int clipboard, GdkAtom atom) { struct clipboard_state *state = &inst->clipstates[clipboard]; @@ -3338,7 +3295,7 @@ void set_clipboard_atom(struct gui_data *inst, int clipboard, GdkAtom atom) state->atom = atom; } -void init_clipboard(struct gui_data *inst) +void init_clipboard(Frontend *inst) { #ifndef NOT_X_WINDOWS /* @@ -3394,7 +3351,7 @@ void init_clipboard(struct gui_data *inst) #endif /* JUST_USE_GTK_CLIPBOARD_UTF8 */ -static void set_window_titles(struct gui_data *inst) +static void set_window_titles(Frontend *inst) { /* * We must always call set_icon_name after calling set_title, @@ -3407,25 +3364,22 @@ static void set_window_titles(struct gui_data *inst) inst->icontitle); } -void set_title(void *frontend, char *title) +void set_title(Frontend *inst, char *title) { - struct gui_data *inst = (struct gui_data *)frontend; sfree(inst->wintitle); inst->wintitle = dupstr(title); set_window_titles(inst); } -void set_icon(void *frontend, char *title) +void set_icon(Frontend *inst, char *title) { - struct gui_data *inst = (struct gui_data *)frontend; sfree(inst->icontitle); inst->icontitle = dupstr(title); set_window_titles(inst); } -void set_title_and_icon(void *frontend, char *title, char *icon) +void set_title_and_icon(Frontend *inst, char *title, char *icon) { - struct gui_data *inst = (struct gui_data *)frontend; sfree(inst->wintitle); inst->wintitle = dupstr(title); sfree(inst->icontitle); @@ -3433,9 +3387,8 @@ void set_title_and_icon(void *frontend, char *title, char *icon) set_window_titles(inst); } -void set_sbar(void *frontend, int total, int start, int page) +void set_sbar(Frontend *inst, int total, int start, int page) { - struct gui_data *inst = (struct gui_data *)frontend; if (!conf_get_int(inst->conf, CONF_scrollbar)) return; inst->ignore_sbar = TRUE; @@ -3451,17 +3404,15 @@ void set_sbar(void *frontend, int total, int start, int page) inst->ignore_sbar = FALSE; } -void scrollbar_moved(GtkAdjustment *adj, gpointer data) +void scrollbar_moved(GtkAdjustment *adj, Frontend *inst) { - struct gui_data *inst = (struct gui_data *)data; - if (!conf_get_int(inst->conf, CONF_scrollbar)) return; if (!inst->ignore_sbar) term_scroll(inst->term, 1, (int)gtk_adjustment_get_value(adj)); } -static void show_scrollbar(struct gui_data *inst, gboolean visible) +static void show_scrollbar(Frontend *inst, gboolean visible) { inst->sbar_visible = visible; if (visible) @@ -3470,7 +3421,7 @@ static void show_scrollbar(struct gui_data *inst, gboolean visible) gtk_widget_hide(inst->sbar); } -void sys_cursor(void *frontend, int x, int y) +void sys_cursor(Frontend *frontend, int x, int y) { /* * This is meaningless under X. @@ -3483,7 +3434,7 @@ void sys_cursor(void *frontend, int x, int y) * may want to perform additional actions on any kind of bell (for * example, taskbar flashing in Windows). */ -void do_beep(void *frontend, int mode) +void do_beep(Frontend *frontend, int mode) { if (mode == BELL_DEFAULT) gdk_display_beep(gdk_display_get_default()); @@ -3498,9 +3449,8 @@ int char_width(Context ctx, int uc) return 1; } -Context get_ctx(void *frontend) +Context get_ctx(Frontend *inst) { - struct gui_data *inst = (struct gui_data *)frontend; struct draw_ctx *dctx; if (!gtk_widget_get_window(inst->area)) @@ -3534,7 +3484,7 @@ Context get_ctx(void *frontend) void free_ctx(Context ctx) { struct draw_ctx *dctx = (struct draw_ctx *)ctx; - /* struct gui_data *inst = dctx->inst; */ + /* Frontend *inst = dctx->inst; */ #ifdef DRAW_TEXT_GDK if (dctx->uctx.type == DRAWTYPE_GDK) { gdk_gc_unref(dctx->uctx.u.gdk.gc); @@ -3824,7 +3774,7 @@ static void draw_stretch_after(struct draw_ctx *dctx, int x, int y, #endif } -static void draw_backing_rect(struct gui_data *inst) +static void draw_backing_rect(Frontend *inst) { int w, h; struct draw_ctx *dctx = get_ctx(inst); @@ -3850,7 +3800,7 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, unsigned long attr, int lattr, truecolour truecolour) { struct draw_ctx *dctx = (struct draw_ctx *)ctx; - struct gui_data *inst = dctx->inst; + Frontend *inst = dctx->inst; int ncombining; int nfg, nbg, t, fontid, shadow, rlen, widefactor, bold; int monochrome = @@ -4007,7 +3957,7 @@ void do_text(Context ctx, int x, int y, wchar_t *text, int len, unsigned long attr, int lattr, truecolour truecolour) { struct draw_ctx *dctx = (struct draw_ctx *)ctx; - struct gui_data *inst = dctx->inst; + Frontend *inst = dctx->inst; int widefactor; do_text_internal(ctx, x, y, text, len, attr, lattr, truecolour); @@ -4037,7 +3987,7 @@ void do_cursor(Context ctx, int x, int y, wchar_t *text, int len, unsigned long attr, int lattr, truecolour truecolour) { struct draw_ctx *dctx = (struct draw_ctx *)ctx; - struct gui_data *inst = dctx->inst; + Frontend *inst = dctx->inst; int active, passive, widefactor; @@ -4149,7 +4099,7 @@ void do_cursor(Context ctx, int x, int y, wchar_t *text, int len, #endif } -GdkCursor *make_mouse_ptr(struct gui_data *inst, int cursor_val) +GdkCursor *make_mouse_ptr(Frontend *inst, int cursor_val) { if (cursor_val == -1) { #if GTK_CHECK_VERSION(2,16,0) @@ -4186,15 +4136,14 @@ void modalfatalbox(const char *p, ...) exit(1); } -const char *get_x_display(void *frontend) +const char *get_x_display(Frontend *frontend) { return gdk_get_display(); } #ifndef NOT_X_WINDOWS -int get_windowid(void *frontend, long *id) +int get_windowid(Frontend *inst, long *id) { - struct gui_data *inst = (struct gui_data *)frontend; GdkWindow *window = gtk_widget_get_window(inst->area); if (!GDK_IS_X11_WINDOW(window)) return FALSE; @@ -4203,13 +4152,12 @@ int get_windowid(void *frontend, long *id) } #endif -int frontend_is_utf8(void *frontend) +int frontend_is_utf8(Frontend *inst) { - struct gui_data *inst = (struct gui_data *)frontend; return inst->ucsdata.line_codepage == CS_UTF8; } -char *setup_fonts_ucs(struct gui_data *inst) +char *setup_fonts_ucs(Frontend *inst) { int shadowbold = conf_get_int(inst->conf, CONF_shadowbold); int shadowboldoffset = conf_get_int(inst->conf, CONF_shadowboldoffset); @@ -4312,7 +4260,7 @@ static void find_app_menu_bar(GtkWidget *widget, gpointer data) } #endif -static void compute_geom_hints(struct gui_data *inst, GdkGeometry *geom) +static void compute_geom_hints(Frontend *inst, GdkGeometry *geom) { /* * Unused fields in geom. @@ -4413,7 +4361,7 @@ static void compute_geom_hints(struct gui_data *inst, GdkGeometry *geom) #endif } -void set_geom_hints(struct gui_data *inst) +void set_geom_hints(Frontend *inst) { GdkGeometry geom; gint flags = GDK_HINT_MIN_SIZE | GDK_HINT_BASE_SIZE | GDK_HINT_RESIZE_INC; @@ -4427,7 +4375,7 @@ void set_geom_hints(struct gui_data *inst) } #if GTK_CHECK_VERSION(2,0,0) -static void compute_whole_window_size(struct gui_data *inst, +static void compute_whole_window_size(Frontend *inst, int wchars, int hchars, int *wpix, int *hpix) { @@ -4440,13 +4388,13 @@ static void compute_whole_window_size(struct gui_data *inst, void clear_scrollback_menuitem(GtkMenuItem *item, gpointer data) { - struct gui_data *inst = (struct gui_data *)data; + Frontend *inst = (Frontend *)data; term_clrsb(inst->term); } void reset_terminal_menuitem(GtkMenuItem *item, gpointer data) { - struct gui_data *inst = (struct gui_data *)data; + Frontend *inst = (Frontend *)data; term_pwron(inst->term, TRUE); if (inst->ldisc) ldisc_echoedit_update(inst->ldisc); @@ -4454,27 +4402,27 @@ void reset_terminal_menuitem(GtkMenuItem *item, gpointer data) void copy_clipboard_menuitem(GtkMenuItem *item, gpointer data) { - struct gui_data *inst = (struct gui_data *)data; + Frontend *inst = (Frontend *)data; static const int clips[] = { MENU_CLIPBOARD }; term_request_copy(inst->term, clips, lenof(clips)); } void paste_clipboard_menuitem(GtkMenuItem *item, gpointer data) { - struct gui_data *inst = (struct gui_data *)data; + Frontend *inst = (Frontend *)data; term_request_paste(inst->term, MENU_CLIPBOARD); } void copy_all_menuitem(GtkMenuItem *item, gpointer data) { - struct gui_data *inst = (struct gui_data *)data; + Frontend *inst = (Frontend *)data; static const int clips[] = { COPYALL_CLIPBOARDS }; term_copyall(inst->term, clips, lenof(clips)); } void special_menuitem(GtkMenuItem *item, gpointer data) { - struct gui_data *inst = (struct gui_data *)data; + Frontend *inst = (Frontend *)data; int code = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(item), "user-data")); @@ -4484,17 +4432,17 @@ void special_menuitem(GtkMenuItem *item, gpointer data) void about_menuitem(GtkMenuItem *item, gpointer data) { - struct gui_data *inst = (struct gui_data *)data; + Frontend *inst = (Frontend *)data; about_box(inst->window); } void event_log_menuitem(GtkMenuItem *item, gpointer data) { - struct gui_data *inst = (struct gui_data *)data; + Frontend *inst = (Frontend *)data; showeventlog(inst->eventlogstuff, inst->window); } -void setup_clipboards(struct gui_data *inst, Terminal *term, Conf *conf) +void setup_clipboards(Frontend *inst, Terminal *term, Conf *conf) { assert(term->mouse_select_clipboards[0] == CLIP_LOCAL); @@ -4556,7 +4504,7 @@ void setup_clipboards(struct gui_data *inst, Terminal *term, Conf *conf) } struct after_change_settings_dialog_ctx { - struct gui_data *inst; + Frontend *inst; Conf *newconf; }; @@ -4564,7 +4512,7 @@ static void after_change_settings_dialog(void *vctx, int retval); void change_settings_menuitem(GtkMenuItem *item, gpointer data) { - struct gui_data *inst = (struct gui_data *)data; + Frontend *inst = (Frontend *)data; struct after_change_settings_dialog_ctx *ctx; GtkWidget *dialog; char *title; @@ -4597,7 +4545,7 @@ static void after_change_settings_dialog(void *vctx, int retval) }; struct after_change_settings_dialog_ctx ctx = *(struct after_change_settings_dialog_ctx *)vctx; - struct gui_data *inst = ctx.inst; + Frontend *inst = ctx.inst; Conf *oldconf = inst->conf, *newconf = ctx.newconf; int i, j, need_size; @@ -4772,7 +4720,7 @@ static void after_change_settings_dialog(void *vctx, int retval) } } -static void change_font_size(struct gui_data *inst, int increment) +static void change_font_size(Frontend *inst, int increment) { static const int conf_keys[lenof(inst->fonts)] = { CONF_font, CONF_boldfont, CONF_widefont, CONF_wideboldfont, @@ -4835,7 +4783,7 @@ static void change_font_size(struct gui_data *inst, int increment) void dup_session_menuitem(GtkMenuItem *item, gpointer gdata) { - struct gui_data *inst = (struct gui_data *)gdata; + Frontend *inst = (Frontend *)gdata; launch_duplicate_session(inst->conf); } @@ -4847,7 +4795,7 @@ void new_session_menuitem(GtkMenuItem *item, gpointer data) void restart_session_menuitem(GtkMenuItem *item, gpointer data) { - struct gui_data *inst = (struct gui_data *)data; + Frontend *inst = (Frontend *)data; if (!inst->backend) { logevent(inst, "----- Session restarted -----"); @@ -4871,9 +4819,9 @@ void saved_session_freedata(GtkMenuItem *item, gpointer data) sfree(str); } -void app_menu_action(void *frontend, enum MenuAction action) +void app_menu_action(Frontend *frontend, enum MenuAction action) { - struct gui_data *inst = (struct gui_data *)frontend; + Frontend *inst = (Frontend *)frontend; switch (action) { case MA_COPY: copy_clipboard_menuitem(NULL, inst); @@ -4907,7 +4855,7 @@ void app_menu_action(void *frontend, enum MenuAction action) static void update_savedsess_menu(GtkMenuItem *menuitem, gpointer data) { - struct gui_data *inst = (struct gui_data *)data; + Frontend *inst = (Frontend *)data; struct sesslist sesslist; int i; @@ -4976,10 +4924,8 @@ void set_window_icon(GtkWidget *window, const char *const *const *icon, #endif } -void update_specials_menu(void *frontend) +void update_specials_menu(Frontend *inst) { - struct gui_data *inst = (struct gui_data *)frontend; - const struct telnet_special *specials; if (inst->backend) @@ -5041,7 +4987,7 @@ void update_specials_menu(void *frontend) } } -static void start_backend(struct gui_data *inst) +static void start_backend(Frontend *inst) { const struct Backend_vtable *vt; char *realhost; @@ -5114,14 +5060,14 @@ static void get_monitor_geometry(GtkWidget *widget, GdkRectangle *geometry) void new_session_window(Conf *conf, const char *geometry_string) { - struct gui_data *inst; + Frontend *inst; prepare_session(conf); /* * Create an instance structure and initialise to zeroes */ - inst = snew(struct gui_data); + inst = snew(Frontend); memset(inst, 0, sizeof(*inst)); #ifdef JUST_USE_GTK_CLIPBOARD_UTF8 inst->cdi_headtail.next = inst->cdi_headtail.prev = &inst->cdi_headtail; diff --git a/unix/unix.h b/unix/unix.h index f9ff3c68..3dd2864a 100644 --- a/unix/unix.h +++ b/unix/unix.h @@ -175,7 +175,7 @@ void launch_saved_session(const char *str); void session_window_closed(void); void window_setup_error(const char *errmsg); #ifdef MAY_REFER_TO_GTK_IN_HEADERS -GtkWidget *make_gtk_toplevel_window(void *frontend); +GtkWidget *make_gtk_toplevel_window(Frontend *frontend); #endif const struct Backend_vtable *select_backend(Conf *conf); @@ -189,16 +189,16 @@ enum MenuAction { MA_RESTART_SESSION, MA_CHANGE_SETTINGS, MA_CLEAR_SCROLLBACK, MA_RESET_TERMINAL, MA_EVENT_LOG }; -void app_menu_action(void *frontend, enum MenuAction); +void app_menu_action(Frontend *frontend, enum MenuAction); /* Things pty.c needs from pterm.c */ -const char *get_x_display(void *frontend); -int font_dimension(void *frontend, int which);/* 0 for width, 1 for height */ -int get_windowid(void *frontend, long *id); +const char *get_x_display(Frontend *frontend); +int font_dimension(Frontend *frontend, int which);/* 0 for width, 1 for height */ +int get_windowid(Frontend *frontend, long *id); /* Things gtkdlg.c needs from pterm.c */ #ifdef MAY_REFER_TO_GTK_IN_HEADERS -GtkWidget *get_window(void *frontend); +GtkWidget *get_window(Frontend *frontend); enum DialogSlot { DIALOG_SLOT_RECONFIGURE, DIALOG_SLOT_NETWORK_PROMPT, @@ -207,8 +207,8 @@ enum DialogSlot { DIALOG_SLOT_CONNECTION_FATAL, DIALOG_SLOT_LIMIT /* must remain last */ }; -void register_dialog(void *frontend, enum DialogSlot slot, GtkWidget *dialog); -void unregister_dialog(void *frontend, enum DialogSlot slot); +void register_dialog(Frontend *frontend, enum DialogSlot slot, GtkWidget *dialog); +void unregister_dialog(Frontend *frontend, enum DialogSlot slot); #endif /* Things pterm.c needs from gtkdlg.c */ diff --git a/unix/uxcons.c b/unix/uxcons.c index e7f531dc..b4fecce1 100644 --- a/unix/uxcons.c +++ b/unix/uxcons.c @@ -63,15 +63,15 @@ void cleanup_exit(int code) exit(code); } -void set_busy_status(void *frontend, int status) +void set_busy_status(Frontend *frontend, int status) { } -void update_specials_menu(void *frontend) +void update_specials_menu(Frontend *frontend) { } -void notify_remote_exit(void *frontend) +void notify_remote_exit(Frontend *frontend) { } @@ -113,7 +113,7 @@ static int block_and_read(int fd, void *buf, size_t len) return ret; } -int verify_ssh_host_key(void *frontend, char *host, int port, +int verify_ssh_host_key(Frontend *frontend, char *host, int port, const char *keytype, char *keystr, char *fingerprint, void (*callback)(void *ctx, int result), void *ctx) { @@ -223,7 +223,7 @@ int verify_ssh_host_key(void *frontend, char *host, int port, * Ask whether the selected algorithm is acceptable (since it was * below the configured 'warn' threshold). */ -int askalg(void *frontend, const char *algtype, const char *algname, +int askalg(Frontend *frontend, const char *algtype, const char *algname, void (*callback)(void *ctx, int result), void *ctx) { static const char msg[] = @@ -270,7 +270,7 @@ int askalg(void *frontend, const char *algtype, const char *algname, } } -int askhk(void *frontend, const char *algname, const char *betteralgs, +int askhk(Frontend *frontend, const char *algname, const char *betteralgs, void (*callback)(void *ctx, int result), void *ctx) { static const char msg[] = @@ -327,7 +327,7 @@ int askhk(void *frontend, const char *algname, const char *betteralgs, * Ask whether to wipe a session log file before writing to it. * Returns 2 for wipe, 1 for append, 0 for cancel (don't log). */ -int askappend(void *frontend, Filename *filename, +int askappend(Frontend *frontend, Filename *filename, void (*callback)(void *ctx, int result), void *ctx) { static const char msgtemplate[] = @@ -410,7 +410,7 @@ void console_provide_logctx(LogContext *logctx) console_logctx = logctx; } -void logevent(void *frontend, const char *string) +void logevent(Frontend *frontend, const char *string) { struct termios cf; if ((flags & FLAG_STDERR) && (flags & FLAG_VERBOSE)) @@ -546,7 +546,7 @@ int console_get_userpass_input(prompts_t *p) return 1; /* success */ } -void frontend_keypress(void *handle) +void frontend_keypress(Frontend *frontend) { /* * This is nothing but a stub, in console code. diff --git a/unix/uxpgnt.c b/unix/uxpgnt.c index 07248d39..6445fd57 100644 --- a/unix/uxpgnt.c +++ b/unix/uxpgnt.c @@ -42,7 +42,7 @@ void nonfatal(const char *p, ...) va_end(ap); fputc('\n', stderr); } -void connection_fatal(void *frontend, const char *p, ...) +void connection_fatal(Frontend *frontend, const char *p, ...) { va_list ap; fprintf(stderr, "FATAL ERROR: "); @@ -93,7 +93,7 @@ FontSpec *platform_default_fontspec(const char *name) { return fontspec_new(""); Filename *platform_default_filename(const char *name) { return filename_from_str(""); } char *x_get_default(const char *key) { return NULL; } void log_eventlog(LogContext *logctx, const char *event) {} -int from_backend(void *frontend, int is_stderr, const void *data, int datalen) +int from_backend(Frontend *fe, int is_stderr, const void *data, int datalen) { assert(!"only here to satisfy notional call from backend_socket_log"); } /* diff --git a/unix/uxplink.c b/unix/uxplink.c index 7bcac362..56bdf533 100644 --- a/unix/uxplink.c +++ b/unix/uxplink.c @@ -58,7 +58,7 @@ void nonfatal(const char *p, ...) fputc('\n', stderr); postmsg(&cf); } -void connection_fatal(void *frontend, const char *p, ...) +void connection_fatal(Frontend *frontend, const char *p, ...) { struct termios cf; va_list ap; @@ -132,7 +132,7 @@ int term_ldisc(Terminal *term, int mode) { return FALSE; } -void frontend_echoedit_update(void *frontend, int echo, int edit) +void frontend_echoedit_update(Frontend *frontend, int echo, int edit) { /* Update stdin read mode to reflect changes in line discipline. */ struct termios mode; @@ -190,7 +190,7 @@ static char *get_ttychar(struct termios *t, int index) return dupprintf("^<%d>", c); } -char *get_ttymode(void *frontend, const char *mode) +char *get_ttymode(Frontend *frontend, const char *mode) { /* * Propagate appropriate terminal modes from the local terminal, @@ -400,7 +400,7 @@ int try_output(int is_stderr) return bufchain_size(&stdout_data) + bufchain_size(&stderr_data); } -int from_backend(void *frontend_handle, int is_stderr, +int from_backend(Frontend *frontend, int is_stderr, const void *data, int len) { if (is_stderr) { @@ -413,7 +413,7 @@ int from_backend(void *frontend_handle, int is_stderr, } } -int from_backend_untrusted(void *frontend_handle, const void *data, int len) +int from_backend_untrusted(Frontend *frontend, const void *data, int len) { /* * No "untrusted" output should get here (the way the code is @@ -423,7 +423,7 @@ int from_backend_untrusted(void *frontend_handle, const void *data, int len) return 0; /* not reached */ } -int from_backend_eof(void *frontend_handle) +int from_backend_eof(Frontend *frontend) { assert(outgoingeof == EOF_NO); outgoingeof = EOF_PENDING; diff --git a/unix/uxpty.c b/unix/uxpty.c index 870e5156..a5c770d4 100644 --- a/unix/uxpty.c +++ b/unix/uxpty.c @@ -71,7 +71,7 @@ static int pty_signal_pipe[2] = { -1, -1 }; /* obviously bogus initial val */ struct pty_tag { Conf *conf; int master_fd, slave_fd; - void *frontend; + Frontend *frontend; char name[FILENAME_MAX]; pid_t child_pid; int term_width, term_height; @@ -729,7 +729,7 @@ static void pty_uxsel_setup(Pty pty) * Also places the canonical host name into `realhost'. It must be * freed by the caller. */ -static const char *pty_init(void *frontend, Backend **backend_handle, +static const char *pty_init(Frontend *frontend, Backend **backend_handle, Conf *conf, const char *host, int port, char **realhost, int nodelay, int keepalive) { diff --git a/unix/uxser.c b/unix/uxser.c index e352f049..b02eb320 100644 --- a/unix/uxser.c +++ b/unix/uxser.c @@ -18,7 +18,7 @@ #define SERIAL_MAX_BACKLOG 4096 typedef struct serial_backend_data { - void *frontend; + Frontend *frontend; int fd; int finished; int inbufsize; @@ -288,7 +288,7 @@ static const char *serial_configure(Serial serial, Conf *conf) * Also places the canonical host name into `realhost'. It must be * freed by the caller. */ -static const char *serial_init(void *frontend_handle, Backend **backend_handle, +static const char *serial_init(Frontend *frontend, Backend **backend_handle, Conf *conf, const char *host, int port, char **realhost, int nodelay, int keepalive) @@ -301,7 +301,7 @@ static const char *serial_init(void *frontend_handle, Backend **backend_handle, serial->backend.vt = &serial_backend; *backend_handle = &serial->backend; - serial->frontend = frontend_handle; + serial->frontend = frontend; serial->finished = FALSE; serial->inbufsize = 0; bufchain_init(&serial->output_data); diff --git a/unix/uxsftp.c b/unix/uxsftp.c index eb1329cf..a0d5c71e 100644 --- a/unix/uxsftp.c +++ b/unix/uxsftp.c @@ -66,7 +66,7 @@ Filename *platform_default_filename(const char *name) return filename_from_str(""); } -char *get_ttymode(void *frontend, const char *mode) { return NULL; } +char *get_ttymode(Frontend *frontend, const char *mode) { return NULL; } int get_userpass_input(prompts_t *p, bufchain *input) { diff --git a/windows/wincons.c b/windows/wincons.c index a7cbeeac..10367be8 100644 --- a/windows/wincons.c +++ b/windows/wincons.c @@ -30,11 +30,11 @@ void cleanup_exit(int code) exit(code); } -void set_busy_status(void *frontend, int status) +void set_busy_status(Frontend *frontend, int status) { } -void notify_remote_exit(void *frontend) +void notify_remote_exit(Frontend *frontend) { } @@ -42,7 +42,7 @@ void timer_change_notify(unsigned long next) { } -int verify_ssh_host_key(void *frontend, char *host, int port, +int verify_ssh_host_key(Frontend *frontend, char *host, int port, const char *keytype, char *keystr, char *fingerprint, void (*callback)(void *ctx, int result), void *ctx) { @@ -147,7 +147,7 @@ int verify_ssh_host_key(void *frontend, char *host, int port, } } -void update_specials_menu(void *frontend) +void update_specials_menu(Frontend *frontend) { } @@ -155,7 +155,7 @@ void update_specials_menu(void *frontend) * Ask whether the selected algorithm is acceptable (since it was * below the configured 'warn' threshold). */ -int askalg(void *frontend, const char *algtype, const char *algname, +int askalg(Frontend *frontend, const char *algtype, const char *algname, void (*callback)(void *ctx, int result), void *ctx) { HANDLE hin; @@ -196,7 +196,7 @@ int askalg(void *frontend, const char *algtype, const char *algname, } } -int askhk(void *frontend, const char *algname, const char *betteralgs, +int askhk(Frontend *frontend, const char *algname, const char *betteralgs, void (*callback)(void *ctx, int result), void *ctx) { HANDLE hin; @@ -247,7 +247,7 @@ int askhk(void *frontend, const char *algname, const char *betteralgs, * Ask whether to wipe a session log file before writing to it. * Returns 2 for wipe, 1 for append, 0 for cancel (don't log). */ -int askappend(void *frontend, Filename *filename, +int askappend(Frontend *frontend, Filename *filename, void (*callback)(void *ctx, int result), void *ctx) { HANDLE hin; @@ -340,7 +340,7 @@ void console_provide_logctx(LogContext *logctx) console_logctx = logctx; } -void logevent(void *frontend, const char *string) +void logevent(Frontend *frontend, const char *string) { log_eventlog(console_logctx, string); } @@ -467,7 +467,7 @@ int console_get_userpass_input(prompts_t *p) return 1; /* success */ } -void frontend_keypress(void *handle) +void frontend_keypress(Frontend *frontend) { /* * This is nothing but a stub, in console code. diff --git a/windows/windlg.c b/windows/windlg.c index 352ae1fc..05ddfdd2 100644 --- a/windows/windlg.c +++ b/windows/windlg.c @@ -761,7 +761,7 @@ int do_reconfig(HWND hwnd, int protcfginfo) return ret; } -void logevent(void *frontend, const char *string) +void logevent(Frontend *frontend, const char *string) { char timebuf[40]; char **location; @@ -813,7 +813,7 @@ void showabout(HWND hwnd) DialogBox(hinst, MAKEINTRESOURCE(IDD_ABOUTBOX), hwnd, AboutProc); } -int verify_ssh_host_key(void *frontend, char *host, int port, +int verify_ssh_host_key(Frontend *frontend, char *host, int port, const char *keytype, char *keystr, char *fingerprint, void (*callback)(void *ctx, int result), void *ctx) { @@ -897,7 +897,7 @@ int verify_ssh_host_key(void *frontend, char *host, int port, * Ask whether the selected algorithm is acceptable (since it was * below the configured 'warn' threshold). */ -int askalg(void *frontend, const char *algtype, const char *algname, +int askalg(Frontend *frontend, const char *algtype, const char *algname, void (*callback)(void *ctx, int result), void *ctx) { static const char mbtitle[] = "%s Security Alert"; @@ -922,7 +922,7 @@ int askalg(void *frontend, const char *algtype, const char *algname, return 0; } -int askhk(void *frontend, const char *algname, const char *betteralgs, +int askhk(Frontend *frontend, const char *algname, const char *betteralgs, void (*callback)(void *ctx, int result), void *ctx) { static const char mbtitle[] = "%s Security Alert"; @@ -953,7 +953,7 @@ int askhk(void *frontend, const char *algname, const char *betteralgs, * Ask whether to wipe a session log file before writing to it. * Returns 2 for wipe, 1 for append, 0 for cancel (don't log). */ -int askappend(void *frontend, Filename *filename, +int askappend(Frontend *frontend, Filename *filename, void (*callback)(void *ctx, int result), void *ctx) { static const char msgtemplate[] = diff --git a/windows/window.c b/windows/window.c index 0d29b136..eb0f5e01 100644 --- a/windows/window.c +++ b/windows/window.c @@ -231,16 +231,16 @@ const int share_can_be_downstream = TRUE; const int share_can_be_upstream = TRUE; /* Dummy routine, only required in plink. */ -void frontend_echoedit_update(void *frontend, int echo, int edit) +void frontend_echoedit_update(Frontend *frontend, int echo, int edit) { } -int frontend_is_utf8(void *frontend) +int frontend_is_utf8(Frontend *frontend) { return ucsdata.line_codepage == CP_UTF8; } -char *get_ttymode(void *frontend, const char *mode) +char *get_ttymode(Frontend *frontend, const char *mode) { return term_get_ttymode(term, mode); } @@ -946,7 +946,7 @@ static void update_savedsess_menu(void) /* * Update the Special Commands submenu. */ -void update_specials_menu(void *frontend) +void update_specials_menu(Frontend *frontend) { HMENU new_menu; int i, j; @@ -1052,7 +1052,7 @@ static void update_mouse_pointer(void) } } -void set_busy_status(void *frontend, int status) +void set_busy_status(Frontend *frontend, int status) { busy_status = status; update_mouse_pointer(); @@ -1061,7 +1061,7 @@ void set_busy_status(void *frontend, int status) /* * set or clear the "raw mouse message" mode */ -void set_raw_mouse_mode(void *frontend, int activate) +void set_raw_mouse_mode(Frontend *frontend, int activate) { activate = activate && !conf_get_int(conf, CONF_no_mouse_rep); send_raw_mouse = activate; @@ -1071,7 +1071,7 @@ void set_raw_mouse_mode(void *frontend, int activate) /* * Print a message box and close the connection. */ -void connection_fatal(void *frontend, const char *fmt, ...) +void connection_fatal(Frontend *frontend, const char *fmt, ...) { va_list ap; char *stuff, morestuff[100]; @@ -1622,7 +1622,7 @@ static void deinit_fonts(void) } } -void request_resize(void *frontend, int w, int h) +void request_resize(Frontend *frontend, int w, int h) { int width, height; @@ -1970,7 +1970,7 @@ static int is_alt_pressed(void) static int resizing; -void notify_remote_exit(void *fe) +void notify_remote_exit(Frontend *frontend) { int exitcode, close_on_exit; @@ -3277,7 +3277,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, * helper software tracks the system caret, so we should arrange to * have one.) */ -void sys_cursor(void *frontend, int x, int y) +void sys_cursor(Frontend *frontend, int x, int y) { int cx, cy; @@ -4813,7 +4813,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, return -1; } -void set_title(void *frontend, char *title) +void set_title(Frontend *frontend, char *title) { sfree(window_name); window_name = snewn(1 + strlen(title), char); @@ -4822,7 +4822,7 @@ void set_title(void *frontend, char *title) SetWindowText(hwnd, title); } -void set_icon(void *frontend, char *title) +void set_icon(Frontend *frontend, char *title) { sfree(icon_name); icon_name = snewn(1 + strlen(title), char); @@ -4831,7 +4831,7 @@ void set_icon(void *frontend, char *title) SetWindowText(hwnd, title); } -void set_sbar(void *frontend, int total, int start, int page) +void set_sbar(Frontend *frontend, int total, int start, int page) { SCROLLINFO si; @@ -4849,7 +4849,7 @@ void set_sbar(void *frontend, int total, int start, int page) SetScrollInfo(hwnd, SB_VERT, &si, TRUE); } -Context get_ctx(void *frontend) +Context get_ctx(Frontend *frontend) { HDC hdc; if (hwnd) { @@ -4879,7 +4879,7 @@ static void real_palette_set(int n, int r, int g, int b) } } -int palette_get(void *frontend, int n, int *r, int *g, int *b) +int palette_get(Frontend *frontend, int n, int *r, int *g, int *b) { if (n < 0 || n >= NALLCOLOURS) return FALSE; @@ -4889,7 +4889,7 @@ int palette_get(void *frontend, int n, int *r, int *g, int *b) return TRUE; } -void palette_set(void *frontend, int n, int r, int g, int b) +void palette_set(Frontend *frontend, int n, int r, int g, int b) { if (n >= 16) n += 256 - 16; @@ -4910,7 +4910,7 @@ void palette_set(void *frontend, int n, int r, int g, int b) } } -void palette_reset(void *frontend) +void palette_reset(Frontend *frontend) { int i; @@ -4939,7 +4939,7 @@ void palette_reset(void *frontend) } } -void write_aclip(void *frontend, int clipboard, +void write_aclip(Frontend *frontend, int clipboard, char *data, int len, int must_deselect) { HGLOBAL clipdata; @@ -4987,7 +4987,7 @@ int cmpCOLORREF(void *va, void *vb) /* * Note: unlike write_aclip() this will not append a nul. */ -void write_clip(void *frontend, int clipboard, +void write_clip(Frontend *frontend, int clipboard, wchar_t *data, int *attr, truecolour *truecolour, int len, int must_deselect) { @@ -5458,7 +5458,7 @@ static void process_clipdata(HGLOBAL clipdata, int unicode) sfree(clipboard_contents); } -void frontend_request_paste(void *frontend, int clipboard) +void frontend_request_paste(Frontend *frontend, int clipboard) { assert(clipboard == CLIP_SYSTEM); @@ -5488,7 +5488,7 @@ void frontend_request_paste(void *frontend, int clipboard) * Move `lines' lines from position `from' to position `to' in the * window. */ -void optimised_move(void *frontend, int to, int from, int lines) +void optimised_move(Frontend *frontend, int to, int from, int lines) { RECT r; int min, max; @@ -5618,7 +5618,7 @@ static void flash_window(int mode) /* * Beep. */ -void do_beep(void *frontend, int mode) +void do_beep(Frontend *frontend, int mode) { if (mode == BELL_DEFAULT) { /* @@ -5680,7 +5680,7 @@ void do_beep(void *frontend, int mode) * Minimise or restore the window in response to a server-side * request. */ -void set_iconic(void *frontend, int iconic) +void set_iconic(Frontend *frontend, int iconic) { if (IsIconic(hwnd)) { if (!iconic) @@ -5694,7 +5694,7 @@ void set_iconic(void *frontend, int iconic) /* * Move the window in response to a server-side request. */ -void move_window(void *frontend, int x, int y) +void move_window(Frontend *frontend, int x, int y) { int resize_action = conf_get_int(conf, CONF_resize_action); if (resize_action == RESIZE_DISABLED || @@ -5709,7 +5709,7 @@ void move_window(void *frontend, int x, int y) * Move the window to the top or bottom of the z-order in response * to a server-side request. */ -void set_zorder(void *frontend, int top) +void set_zorder(Frontend *frontend, int top) { if (conf_get_int(conf, CONF_alwaysontop)) return; /* ignore */ @@ -5720,7 +5720,7 @@ void set_zorder(void *frontend, int top) /* * Refresh the window in response to a server-side request. */ -void refresh_window(void *frontend) +void refresh_window(Frontend *frontend) { InvalidateRect(hwnd, NULL, TRUE); } @@ -5729,7 +5729,7 @@ void refresh_window(void *frontend) * Maximise or restore the window in response to a server-side * request. */ -void set_zoomed(void *frontend, int zoomed) +void set_zoomed(Frontend *frontend, int zoomed) { if (IsZoomed(hwnd)) { if (!zoomed) @@ -5743,7 +5743,7 @@ void set_zoomed(void *frontend, int zoomed) /* * Report whether the window is iconic, for terminal reports. */ -int is_iconic(void *frontend) +int is_iconic(Frontend *frontend) { return IsIconic(hwnd); } @@ -5751,7 +5751,7 @@ int is_iconic(void *frontend) /* * Report the window's position, for terminal reports. */ -void get_window_pos(void *frontend, int *x, int *y) +void get_window_pos(Frontend *frontend, int *x, int *y) { RECT r; GetWindowRect(hwnd, &r); @@ -5762,7 +5762,7 @@ void get_window_pos(void *frontend, int *x, int *y) /* * Report the window's pixel size, for terminal reports. */ -void get_window_pixels(void *frontend, int *x, int *y) +void get_window_pixels(Frontend *frontend, int *x, int *y) { RECT r; GetWindowRect(hwnd, &r); @@ -5773,7 +5773,7 @@ void get_window_pixels(void *frontend, int *x, int *y) /* * Return the window or icon title. */ -char *get_window_title(void *frontend, int icon) +char *get_window_title(Frontend *frontend, int icon) { return icon ? icon_name : window_name; } @@ -5906,7 +5906,7 @@ static void flip_full_screen() } } -void frontend_keypress(void *handle) +void frontend_keypress(Frontend *frontend) { /* * Keypress termination in non-Close-On-Exit mode is not @@ -5917,17 +5917,17 @@ void frontend_keypress(void *handle) return; } -int from_backend(void *frontend, int is_stderr, const void *data, int len) +int from_backend(Frontend *frontend, int is_stderr, const void *data, int len) { return term_data(term, is_stderr, data, len); } -int from_backend_untrusted(void *frontend, const void *data, int len) +int from_backend_untrusted(Frontend *frontend, const void *data, int len) { return term_data_untrusted(term, data, len); } -int from_backend_eof(void *frontend) +int from_backend_eof(Frontend *frontend) { return TRUE; /* do respond to incoming EOF with outgoing */ } diff --git a/windows/winplink.c b/windows/winplink.c index 455b18a7..c156d740 100644 --- a/windows/winplink.c +++ b/windows/winplink.c @@ -45,7 +45,7 @@ void nonfatal(const char *p, ...) va_end(ap); fputc('\n', stderr); } -void connection_fatal(void *frontend, const char *p, ...) +void connection_fatal(Frontend *frontend, const char *p, ...) { va_list ap; fprintf(stderr, "FATAL ERROR: "); @@ -83,7 +83,7 @@ int term_ldisc(Terminal *term, int mode) { return FALSE; } -void frontend_echoedit_update(void *frontend, int echo, int edit) +void frontend_echoedit_update(Frontend *frontend, int echo, int edit) { /* Update stdin read mode to reflect changes in line discipline. */ DWORD mode; @@ -100,9 +100,9 @@ void frontend_echoedit_update(void *frontend, int echo, int edit) SetConsoleMode(inhandle, mode); } -char *get_ttymode(void *frontend, const char *mode) { return NULL; } +char *get_ttymode(Frontend *frontend, const char *mode) { return NULL; } -int from_backend(void *frontend_handle, int is_stderr, +int from_backend(Frontend *frontend, int is_stderr, const void *data, int len) { if (is_stderr) { @@ -114,7 +114,7 @@ int from_backend(void *frontend_handle, int is_stderr, return handle_backlog(stdout_handle) + handle_backlog(stderr_handle); } -int from_backend_untrusted(void *frontend_handle, const void *data, int len) +int from_backend_untrusted(Frontend *frontend, const void *data, int len) { /* * No "untrusted" output should get here (the way the code is @@ -124,7 +124,7 @@ int from_backend_untrusted(void *frontend_handle, const void *data, int len) return 0; /* not reached */ } -int from_backend_eof(void *frontend_handle) +int from_backend_eof(Frontend *frontend) { handle_write_eof(stdout_handle); return FALSE; /* do not respond to incoming EOF with outgoing */ diff --git a/windows/winser.c b/windows/winser.c index 1efac931..2a42ce21 100644 --- a/windows/winser.c +++ b/windows/winser.c @@ -13,7 +13,7 @@ typedef struct serial_backend_data { HANDLE port; struct handle *out, *in; - void *frontend; + Frontend *frontend; int bufsize; long clearbreak_time; int break_in_progress; @@ -199,7 +199,7 @@ static const char *serial_configure(Serial serial, HANDLE serport, Conf *conf) * Also places the canonical host name into `realhost'. It must be * freed by the caller. */ -static const char *serial_init(void *frontend_handle, Backend **backend_handle, +static const char *serial_init(Frontend *frontend, Backend **backend_handle, Conf *conf, const char *host, int port, char **realhost, int nodelay, int keepalive) { @@ -216,7 +216,7 @@ static const char *serial_init(void *frontend_handle, Backend **backend_handle, serial->backend.vt = &serial_backend; *backend_handle = &serial->backend; - serial->frontend = frontend_handle; + serial->frontend = frontend; serline = conf_get_str(conf, CONF_serline); { diff --git a/windows/winsftp.c b/windows/winsftp.c index e9d5d4cb..580e8d95 100644 --- a/windows/winsftp.c +++ b/windows/winsftp.c @@ -13,7 +13,7 @@ #include "int64.h" #include "winsecur.h" -char *get_ttymode(void *frontend, const char *mode) { return NULL; } +char *get_ttymode(Frontend *frontend, const char *mode) { return NULL; } int get_userpass_input(prompts_t *p, bufchain *input) { diff --git a/windows/winstuff.h b/windows/winstuff.h index 87dc48b6..1ecec333 100644 --- a/windows/winstuff.h +++ b/windows/winstuff.h @@ -247,7 +247,7 @@ GLOBAL LogContext *logctx; * which takes the data string in the system code page instead of * Unicode. */ -void write_aclip(void *frontend, int clipboard, char *, int, int); +void write_aclip(Frontend *frontend, int clipboard, char *, int, int); #define WM_NETEVENT (WM_APP + 5) From 6a8b9d38130503917cb2d2a7f2a036f3b8e616fc Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Wed, 12 Sep 2018 15:03:47 +0100 Subject: [PATCH 394/607] Replace enum+union of local channel types with a vtable. There's now an interface called 'Channel', which handles the local side of an SSH connection-layer channel, in terms of knowing where to send incoming channel data to, whether to close the channel, etc. Channel and the previous 'struct ssh_channel' mutually refer. The latter contains all the SSH-specific parts, and as much of the common logic as possible: in particular, Channel doesn't have to know anything about SSH packet formats, or which SSH protocol version is in use, or deal with all the fiddly stuff about window sizes - with the exception that x11fwd.c's implementation of it does have to be able to ask for a small fixed initial window size for the bodgy system that distinguishes upstream from downstream X forwardings. I've taken the opportunity to move the code implementing the detailed behaviour of agent forwarding out of ssh.c, now that all of it is on the far side of a uniform interface. (This also means that if I later implement agent forwarding directly to a Unix socket as an alternative, it'll be a matter of changing just the one call to agentf_new() that makes the Channel to plug into a forwarding.) --- Recipe | 2 +- agentf.c | 235 +++++++++++++++ defs.h | 2 + portfwd.c | 143 +++++---- ssh.c | 785 +++++++++++++++++++++----------------------------- ssh.h | 31 +- sshchan.h | 59 ++++ unix/uxpgnt.c | 6 +- x11fwd.c | 93 +++--- 9 files changed, 786 insertions(+), 570 deletions(-) create mode 100644 agentf.c create mode 100644 sshchan.h diff --git a/Recipe b/Recipe index 1b84885b..5af98117 100644 --- a/Recipe +++ b/Recipe @@ -254,7 +254,7 @@ SSH = ssh ssh1bpp ssh2bpp ssh2bpp-bare ssh1censor ssh2censor + sshcrc sshdes sshmd5 sshrsa sshrand sshsha sshblowf + sshdh sshcrcda sshpubk sshzlib sshdss x11fwd portfwd + sshaes sshccp sshsh256 sshsh512 sshbn wildcard pinger ssharcf - + sshgssc pgssapi sshshare sshecc aqsync marshal nullplug + + sshgssc pgssapi sshshare sshecc aqsync marshal nullplug agentf WINSSH = SSH winnoise wincapi winpgntc wingss winshare winnps winnpc + winhsock errsock UXSSH = SSH uxnoise uxagentc uxgss uxshare diff --git a/agentf.c b/agentf.c new file mode 100644 index 00000000..65a971da --- /dev/null +++ b/agentf.c @@ -0,0 +1,235 @@ +/* + * SSH agent forwarding. + */ + +#include +#include +#include + +#include "putty.h" +#include "ssh.h" +#include "pageant.h" +#include "sshchan.h" + +typedef struct agentf { + struct ssh_channel *c; + bufchain inbuffer; + agent_pending_query *pending; + int input_wanted; + int rcvd_eof; + + Channel chan; +} agentf; + +static void agentf_got_response(agentf *af, void *reply, int replylen) +{ + af->pending = NULL; + + if (!reply) { + /* The real agent didn't send any kind of reply at all for + * some reason, so fake an SSH_AGENT_FAILURE. */ + reply = "\0\0\0\1\5"; + replylen = 5; + } + + sshfwd_write(af->c, reply, replylen); +} + +static void agentf_callback(void *vctx, void *reply, int replylen); + +static void agentf_try_forward(agentf *af) +{ + unsigned datalen, length; + strbuf *message; + unsigned char msglen[4]; + void *reply; + int replylen; + + /* + * Don't try to parallelise agent requests. Wait for each one to + * return before attempting the next. + */ + if (af->pending) + return; + + /* + * If the outgoing side of the channel connection is currently + * throttled, don't submit any new forwarded requests to the real + * agent. This causes the input side of the agent forwarding not + * to be emptied, exerting the required back-pressure on the + * remote client, and encouraging it to read our responses before + * sending too many more requests. + */ + if (!af->input_wanted) + return; + + while (1) { + /* + * Try to extract a complete message from the input buffer. + */ + datalen = bufchain_size(&af->inbuffer); + if (datalen < 4) + break; /* not even a length field available yet */ + + bufchain_fetch(&af->inbuffer, msglen, 4); + length = GET_32BIT(msglen); + + if (length > AGENT_MAX_MSGLEN-4) { + /* + * If the remote has sent a message that's just _too_ + * long, we should reject it in advance of seeing the rest + * of the incoming message, and also close the connection + * for good measure (which avoids us having to faff about + * with carefully ignoring just the right number of bytes + * from the overlong message). + */ + agentf_got_response(af, NULL, 0); + sshfwd_write_eof(af->c); + return; + } + + if (length > datalen - 4) + break; /* a whole message is not yet available */ + + bufchain_consume(&af->inbuffer, 4); + + message = strbuf_new_for_agent_query(); + bufchain_fetch_consume( + &af->inbuffer, strbuf_append(message, length), length); + af->pending = agent_query( + message, &reply, &replylen, agentf_callback, af); + strbuf_free(message); + + if (af->pending) + return; /* agent_query promised to reply in due course */ + + /* + * If the agent gave us an answer immediately, pass it + * straight on and go round this loop again. + */ + agentf_got_response(af, reply, replylen); + sfree(reply); + } + + /* + * If we get here (i.e. we left the above while loop via 'break' + * rather than 'return'), that means we've determined that the + * input buffer for the agent forwarding connection doesn't + * contain a complete request. + * + * So if there's potentially more data to come, we can return now, + * and wait for the remote client to send it. But if the remote + * has sent EOF, it would be a mistake to do that, because we'd be + * waiting a long time. So this is the moment to check for EOF, + * and respond appropriately. + */ + if (af->rcvd_eof) + sshfwd_write_eof(af->c); +} + +static void agentf_callback(void *vctx, void *reply, int replylen) +{ + agentf *af = (agentf *)vctx; + + agentf_got_response(af, reply, replylen); + sfree(reply); + + /* + * Now try to extract and send further messages from the channel's + * input-side buffer. + */ + agentf_try_forward(af); +} + +static void agentf_free(Channel *chan); +static int agentf_send(Channel *chan, int is_stderr, const void *, int); +static void agentf_send_eof(Channel *chan); +static char *agentf_log_close_msg(Channel *chan); +static void agentf_set_input_wanted(Channel *chan, int wanted); + +static const struct ChannelVtable agentf_channelvt = { + agentf_free, + chan_remotely_opened_confirmation, + chan_remotely_opened_failure, + agentf_send, + agentf_send_eof, + agentf_set_input_wanted, + agentf_log_close_msg, + chan_no_eager_close, +}; + +Channel *agentf_new(struct ssh_channel *c) +{ + agentf *af = snew(agentf); + af->c = c; + af->chan.vt = &agentf_channelvt; + af->chan.initial_fixed_window_size = 0; + af->rcvd_eof = TRUE; + bufchain_init(&af->inbuffer); + af->pending = NULL; + af->input_wanted = TRUE; + return &af->chan; +} + +static void agentf_free(Channel *chan) +{ + assert(chan->vt == &agentf_channelvt); + agentf *af = FROMFIELD(chan, agentf, chan); + + if (af->pending) + agent_cancel_query(af->pending); + bufchain_clear(&af->inbuffer); + sfree(af); +} + +static int agentf_send(Channel *chan, int is_stderr, + const void *data, int length) +{ + assert(chan->vt == &agentf_channelvt); + agentf *af = FROMFIELD(chan, agentf, chan); + bufchain_add(&af->inbuffer, data, length); + agentf_try_forward(af); + + /* + * We exert back-pressure on an agent forwarding client if and + * only if we're waiting for the response to an asynchronous agent + * request. This prevents the client running out of window while + * receiving the _first_ message, but means that if any message + * takes time to process, the client will be discouraged from + * sending an endless stream of further ones after it. + */ + return (af->pending ? bufchain_size(&af->inbuffer) : 0); +} + +static void agentf_send_eof(Channel *chan) +{ + assert(chan->vt == &agentf_channelvt); + agentf *af = FROMFIELD(chan, agentf, chan); + + af->rcvd_eof = TRUE; + + /* Call try_forward, which will respond to the EOF now if + * appropriate, or wait until the queue of outstanding requests is + * dealt with if not. */ + agentf_try_forward(af); +} + +static char *agentf_log_close_msg(Channel *chan) +{ + return dupstr("Agent-forwarding connection closed"); +} + +static void agentf_set_input_wanted(Channel *chan, int wanted) +{ + assert(chan->vt == &agentf_channelvt); + agentf *af = FROMFIELD(chan, agentf, chan); + + af->input_wanted = wanted; + + /* Agent forwarding channels are buffer-managed by not asking the + * agent questions if the SSH channel isn't accepting input. So if + * it's started again, we should ask a question if we have one + * pending.. */ + if (wanted) + agentf_try_forward(af); +} diff --git a/defs.h b/defs.h index 53ded962..2c597953 100644 --- a/defs.h +++ b/defs.h @@ -53,6 +53,8 @@ typedef struct Frontend Frontend; typedef struct ssh_tag *Ssh; +typedef struct Channel Channel; + /* Note indirection: for historical reasons (it used to be closer to * the OS socket type), the type that most code uses for a socket is * 'Socket', not 'Socket *'. So an implementation of Socket or Plug diff --git a/portfwd.c b/portfwd.c index e6b06e14..d7ad74d2 100644 --- a/portfwd.c +++ b/portfwd.c @@ -8,6 +8,7 @@ #include "putty.h" #include "ssh.h" +#include "sshchan.h" /* * Enumeration of values that live in the 'socks_state' field of @@ -21,12 +22,12 @@ typedef enum { SOCKS_5_CONNECT /* expect a SOCKS 5 connection message */ } SocksState; -struct PortForwarding { +typedef struct PortForwarding { struct ssh_channel *c; /* channel structure held by ssh.c */ Ssh ssh; /* instance of SSH backend itself */ /* Note that ssh need not be filled in if c is non-NULL */ Socket s; - int throttled, throttle_override; + int input_wanted; int ready; SocksState socks_state; /* @@ -44,7 +45,8 @@ struct PortForwarding { size_t socksbuf_consumed; const Plug_vtable *plugvt; -}; + Channel chan; +} PortForwarding; struct PortListener { Ssh ssh; /* instance of SSH backend itself */ @@ -105,6 +107,8 @@ static void pfl_log(Plug plug, int type, SockAddr addr, int port, /* we have to dump these since we have no interface to logging.c */ } +static void pfd_close(struct PortForwarding *pf); + static void pfd_closing(Plug plug, const char *error_msg, int error_code, int calling_back) { @@ -142,10 +146,12 @@ static void pfl_closing(Plug plug, const char *error_msg, int error_code, pfl_terminate(pl); } -static void wrap_send_port_open(void *channel, const char *hostname, int port, - Socket s) +static struct ssh_channel *wrap_send_port_open( + Ssh ssh, const char *hostname, int port, Socket s, Channel *chan) { char *peerinfo, *description; + struct ssh_channel *toret; + peerinfo = sk_peer_info(s); if (peerinfo) { description = dupprintf("forwarding from %s", peerinfo); @@ -153,8 +159,11 @@ static void wrap_send_port_open(void *channel, const char *hostname, int port, } else { description = dupstr("forwarding"); } - ssh_send_port_open(channel, hostname, port, description); + + toret = ssh_send_port_open(ssh, hostname, port, description, chan); + sfree(description); + return toret; } static char *ipv4_to_string(unsigned ipv4) @@ -396,21 +405,11 @@ static void pfd_receive(Plug plug, int urgent, char *data, int len) */ sk_set_frozen(pf->s, 1); - pf->c = new_sock_channel(pf->ssh, pf); - if (pf->c == NULL) { - pfd_close(pf); - return; - } else { - /* asks to forward to the specified host/port for this */ - wrap_send_port_open(pf->c, pf->hostname, pf->port, pf->s); - } - } - if (pf->ready) { - if (sshfwd_write(pf->c, data, len) > 0) { - pf->throttled = 1; - sk_set_frozen(pf->s, 1); - } + pf->c = wrap_send_port_open(pf->ssh, pf->hostname, pf->port, pf->s, + &pf->chan); } + if (pf->ready) + sshfwd_write(pf->c, data, len); } static void pfd_sent(Plug plug, int bufsize) @@ -429,6 +428,25 @@ static const Plug_vtable PortForwarding_plugvt = { NULL }; +static void pfd_chan_free(Channel *chan); +static void pfd_open_confirmation(Channel *chan); +static void pfd_open_failure(Channel *chan, const char *errtext); +static int pfd_send(Channel *chan, int is_stderr, const void *data, int len); +static void pfd_send_eof(Channel *chan); +static void pfd_set_input_wanted(Channel *chan, int wanted); +static char *pfd_log_close_msg(Channel *chan); + +static const struct ChannelVtable PortForwarding_channelvt = { + pfd_chan_free, + pfd_open_confirmation, + pfd_open_failure, + pfd_send, + pfd_send_eof, + pfd_set_input_wanted, + pfd_log_close_msg, + chan_no_eager_close, +}; + /* * Called when receiving a PORT OPEN from the server to make a * connection to a destination host. @@ -436,8 +454,8 @@ static const Plug_vtable PortForwarding_plugvt = { * On success, returns NULL and fills in *pf_ret. On error, returns a * dynamically allocated error message string. */ -char *pfd_connect(struct PortForwarding **pf_ret, char *hostname,int port, - void *c, Conf *conf, int addressfamily) +char *pfd_connect(Channel **chan_ret, char *hostname,int port, + struct ssh_channel *c, Conf *conf, int addressfamily) { SockAddr addr; const char *err; @@ -459,9 +477,12 @@ char *pfd_connect(struct PortForwarding **pf_ret, char *hostname,int port, /* * Open socket. */ - pf = *pf_ret = new_portfwd_state(); + pf = new_portfwd_state(); + *chan_ret = &pf->chan; pf->plugvt = &PortForwarding_plugvt; - pf->throttled = pf->throttle_override = 0; + pf->chan.initial_fixed_window_size = 0; + pf->chan.vt = &PortForwarding_channelvt; + pf->input_wanted = TRUE; pf->ready = 1; pf->c = c; pf->ssh = NULL; /* we shouldn't need this */ @@ -474,7 +495,7 @@ char *pfd_connect(struct PortForwarding **pf_ret, char *hostname,int port, char *err_ret = dupstr(err); sk_close(pf->s); free_portfwd_state(pf); - *pf_ret = NULL; + *chan_ret = NULL; return err_ret; } @@ -495,6 +516,9 @@ static int pfl_accepting(Plug p, accept_fn_t constructor, accept_ctx_t ctx) pl = FROMFIELD(p, struct PortListener, plugvt); pf = new_portfwd_state(); pf->plugvt = &PortForwarding_plugvt; + pf->chan.initial_fixed_window_size = 0; + pf->chan.vt = &PortForwarding_channelvt; + pf->input_wanted = TRUE; pf->c = NULL; pf->ssh = pl->ssh; @@ -505,7 +529,7 @@ static int pfl_accepting(Plug p, accept_fn_t constructor, accept_ctx_t ctx) return err != NULL; } - pf->throttled = pf->throttle_override = 0; + pf->input_wanted = TRUE; pf->ready = 0; if (pl->is_dynamic) { @@ -518,15 +542,8 @@ static int pfl_accepting(Plug p, accept_fn_t constructor, accept_ctx_t ctx) pf->socks_state = SOCKS_NONE; pf->hostname = dupstr(pl->hostname); pf->port = pl->port; - pf->c = new_sock_channel(pl->ssh, pf); - - if (pf->c == NULL) { - free_portfwd_state(pf); - return 1; - } else { - /* asks to forward to the specified host/port for this */ - wrap_send_port_open(pf->c, pf->hostname, pf->port, s); - } + pf->c = wrap_send_port_open(pl->ssh, pf->hostname, pf->port, + s, &pf->chan); } return 0; @@ -580,7 +597,12 @@ char *pfl_listen(char *desthost, int destport, char *srcaddr, return NULL; } -void pfd_close(struct PortForwarding *pf) +static char *pfd_log_close_msg(Channel *chan) +{ + return dupstr("Forwarded port closed"); +} + +static void pfd_close(struct PortForwarding *pf) { if (!pf) return; @@ -601,43 +623,42 @@ void pfl_terminate(struct PortListener *pl) free_portlistener_state(pl); } -void pfd_unthrottle(struct PortForwarding *pf) +static void pfd_set_input_wanted(Channel *chan, int wanted) { - if (!pf) - return; - - pf->throttled = 0; - sk_set_frozen(pf->s, pf->throttled || pf->throttle_override); + assert(chan->vt == &PortForwarding_channelvt); + PortForwarding *pf = FROMFIELD(chan, PortForwarding, chan); + pf->input_wanted = wanted; + sk_set_frozen(pf->s, !pf->input_wanted); } -void pfd_override_throttle(struct PortForwarding *pf, int enable) +static void pfd_chan_free(Channel *chan) { - if (!pf) - return; - - pf->throttle_override = enable; - sk_set_frozen(pf->s, pf->throttled || pf->throttle_override); + assert(chan->vt == &PortForwarding_channelvt); + PortForwarding *pf = FROMFIELD(chan, PortForwarding, chan); + pfd_close(pf); } /* * Called to send data down the raw connection. */ -int pfd_send(struct PortForwarding *pf, const void *data, int len) +static int pfd_send(Channel *chan, int is_stderr, const void *data, int len) { - if (pf == NULL) - return 0; + assert(chan->vt == &PortForwarding_channelvt); + PortForwarding *pf = FROMFIELD(chan, PortForwarding, chan); return sk_write(pf->s, data, len); } -void pfd_send_eof(struct PortForwarding *pf) +static void pfd_send_eof(Channel *chan) { + assert(chan->vt == &PortForwarding_channelvt); + PortForwarding *pf = FROMFIELD(chan, PortForwarding, chan); sk_write_eof(pf->s); } -void pfd_confirm(struct PortForwarding *pf) +static void pfd_open_confirmation(Channel *chan) { - if (pf == NULL) - return; + assert(chan->vt == &PortForwarding_channelvt); + PortForwarding *pf = FROMFIELD(chan, PortForwarding, chan); pf->ready = 1; sk_set_frozen(pf->s, 0); @@ -649,3 +670,15 @@ void pfd_confirm(struct PortForwarding *pf) pf->socksbuf = NULL; } } + +static void pfd_open_failure(Channel *chan, const char *errtext) +{ + assert(chan->vt == &PortForwarding_channelvt); + PortForwarding *pf = FROMFIELD(chan, PortForwarding, chan); + + char *msg = dupprintf( + "Forwarded connection refused by server%s%s", + errtext ? ": " : "", errtext ? errtext : ""); + logevent(ssh_get_frontend(pf->ssh), msg); + sfree(msg); +} diff --git a/ssh.c b/ssh.c index 1009e038..bc2f7bf8 100644 --- a/ssh.c +++ b/ssh.c @@ -17,6 +17,7 @@ #include "ssh.h" #include "sshcr.h" #include "sshbpp.h" +#include "sshchan.h" #ifndef NO_GSSAPI #include "sshgssc.h" #include "sshgss.h" @@ -362,29 +363,6 @@ const static struct ssh_compress *const compressions[] = { &ssh_zlib, &ssh_comp_none }; -enum { /* channel types */ - CHAN_MAINSESSION, - CHAN_X11, - CHAN_AGENT, - CHAN_SOCKDATA, - /* - * CHAN_SHARING indicates a channel which is tracked here on - * behalf of a connection-sharing downstream. We do almost nothing - * with these channels ourselves: all messages relating to them - * get thrown straight to sshshare.c and passed on almost - * unmodified to downstream. - */ - CHAN_SHARING, - /* - * CHAN_ZOMBIE is used to indicate a channel for which we've - * already destroyed the local data source: for instance, if a - * forwarded port experiences a socket error on the local side, we - * immediately destroy its local socket and turn the SSH channel - * into CHAN_ZOMBIE. - */ - CHAN_ZOMBIE -}; - typedef void (*handler_fn_t)(Ssh ssh, PktIn *pktin); typedef void (*chandler_fn_t)(Ssh ssh, PktIn *pktin, void *ctx); typedef void (*cchandler_fn_t)(struct ssh_channel *, PktIn *, void *); @@ -452,6 +430,15 @@ struct ssh_channel { * throttled. */ int throttling_conn; + + /* + * True if we currently have backed-up data on the direction of + * this channel pointing out of the SSH connection, and therefore + * would prefer the 'Channel' implementation not to read further + * local input if possible. + */ + int throttled_by_backlog; + union { struct ssh2_data_channel { bufchain outbuffer; @@ -472,22 +459,9 @@ struct ssh_channel { enum { THROTTLED, UNTHROTTLING, UNTHROTTLED } throttle_state; } v2; } v; - union { - struct ssh_agent_channel { - bufchain inbuffer; - agent_pending_query *pending; - } a; - struct ssh_x11_channel { - struct X11Connection *xconn; - int initial; - } x11; - struct ssh_pfd_channel { - struct PortForwarding *pf; - } pfd; - struct ssh_sharing_channel { - void *ctx; - } sharing; - } u; + + void *sharectx; /* sharing context, if this is a downstream channel */ + Channel *chan; /* handle the client side of this channel, if not */ }; /* @@ -945,6 +919,11 @@ static const char *ssh_pkt_type(Ssh ssh, int type) return ssh2_pkt_type(ssh->pls.kctx, ssh->pls.actx, type); } +Frontend *ssh_get_frontend(Ssh ssh) +{ + return ssh->frontend; +} + #define logevent(s) logevent(ssh->frontend, s) /* logevent, only printf-formatted. */ @@ -2107,6 +2086,88 @@ static void ssh_process_user_input(void *ctx) ssh->current_user_input_fn(ssh); } +void chan_remotely_opened_confirmation(Channel *chan) +{ + assert(0 && "this channel type should never receive OPEN_CONFIRMATION"); +} + +void chan_remotely_opened_failure(Channel *chan, const char *errtext) +{ + assert(0 && "this channel type should never receive OPEN_FAILURE"); +} + +int chan_no_eager_close(Channel *chan, int sent_local_eof, int rcvd_remote_eof) +{ + return FALSE; /* default: never proactively ask for a close */ +} + +/* + * Trivial channel vtable for handling 'zombie channels' - those whose + * local source of data has already been shut down or otherwise + * stopped existing - so that we don't have to give them a null + * 'Channel *' and special-case that all over the place. + */ + +static void zombiechan_free(Channel *chan); +static int zombiechan_send(Channel *chan, int is_stderr, const void *, int); +static void zombiechan_set_input_wanted(Channel *chan, int wanted); +static void zombiechan_do_nothing(Channel *chan); +static void zombiechan_open_failure(Channel *chan, const char *); +static int zombiechan_want_close(Channel *chan, int sent_eof, int rcvd_eof); +static char *zombiechan_log_close_msg(Channel *chan) { return NULL; } + +static const struct ChannelVtable zombiechan_channelvt = { + zombiechan_free, + zombiechan_do_nothing, /* open_confirmation */ + zombiechan_open_failure, + zombiechan_send, + zombiechan_do_nothing, /* send_eof */ + zombiechan_set_input_wanted, + zombiechan_log_close_msg, + zombiechan_want_close, +}; + +Channel *zombiechan_new(void) +{ + Channel *chan = snew(Channel); + chan->vt = &zombiechan_channelvt; + chan->initial_fixed_window_size = 0; + return chan; +} + +static void zombiechan_free(Channel *chan) +{ + assert(chan->vt == &zombiechan_channelvt); + sfree(chan); +} + +static void zombiechan_do_nothing(Channel *chan) +{ + assert(chan->vt == &zombiechan_channelvt); +} + +static void zombiechan_open_failure(Channel *chan, const char *errtext) +{ + assert(chan->vt == &zombiechan_channelvt); +} + +static int zombiechan_send(Channel *chan, int is_stderr, + const void *data, int length) +{ + assert(chan->vt == &zombiechan_channelvt); + return 0; +} + +static void zombiechan_set_input_wanted(Channel *chan, int enable) +{ + assert(chan->vt == &zombiechan_channelvt); +} + +static int zombiechan_want_close(Channel *chan, int sent_eof, int rcvd_eof) +{ + return TRUE; +} + static int ssh_do_close(Ssh ssh, int notify_exit) { int ret = 0; @@ -2428,7 +2489,21 @@ static void ssh_throttle_conn(Ssh ssh, int adjust) } } -static void ssh_agentf_try_forward(struct ssh_channel *c); +static void ssh_channel_check_throttle(struct ssh_channel *c) +{ + /* + * We don't want this channel to read further input if this + * particular channel has a backed-up SSH window, or if the + * outgoing side of the whole SSH connection is currently + * throttled, or if this channel already has an outgoing EOF + * either sent or pending. + */ + chan_set_input_wanted(c->chan, + !c->throttled_by_backlog && + !c->ssh->throttled_all && + !c->pending_eof && + !(c->closes & CLOSES_SENT_EOF)); +} /* * Throttle or unthrottle _all_ local data streams (for when sends @@ -2445,29 +2520,8 @@ static void ssh_throttle_all(Ssh ssh, int enable, int bufsize) ssh->overall_bufsize = bufsize; if (!ssh->channels) return; - for (i = 0; NULL != (c = index234(ssh->channels, i)); i++) { - switch (c->type) { - case CHAN_MAINSESSION: - /* - * This is treated separately, outside the switch. - */ - break; - case CHAN_X11: - x11_override_throttle(c->u.x11.xconn, enable); - break; - case CHAN_AGENT: - /* Agent forwarding channels are buffer-managed by - * checking ssh->throttled_all in ssh_agentf_try_forward. - * So at the moment we _un_throttle again, we must make an - * attempt to do something. */ - if (!enable) - ssh_agentf_try_forward(c); - break; - case CHAN_SOCKDATA: - pfd_override_throttle(c->u.pfd.pf, enable); - break; - } - } + for (i = 0; NULL != (c = index234(ssh->channels, i)); i++) + ssh_channel_check_throttle(c); } static void ssh_agent_callback(void *sshv, void *reply, int replylen) @@ -2503,140 +2557,6 @@ static void ssh_dialog_callback(void *sshv, int ret) queue_idempotent_callback(&ssh->incoming_data_consumer); } -static void ssh_agentf_got_response(struct ssh_channel *c, - void *reply, int replylen) -{ - c->u.a.pending = NULL; - - assert(!(c->closes & CLOSES_SENT_EOF)); - - if (!reply) { - /* The real agent didn't send any kind of reply at all for - * some reason, so fake an SSH_AGENT_FAILURE. */ - reply = "\0\0\0\1\5"; - replylen = 5; - } - - ssh_send_channel_data(c, reply, replylen); -} - -static void ssh_agentf_callback(void *cv, void *reply, int replylen); - -static void ssh_agentf_try_forward(struct ssh_channel *c) -{ - unsigned datalen, length; - strbuf *message; - unsigned char msglen[4]; - void *reply; - int replylen; - - /* - * Don't try to parallelise agent requests. Wait for each one to - * return before attempting the next. - */ - if (c->u.a.pending) - return; - - /* - * If the outgoing side of the channel connection is currently - * throttled (for any reason, either that channel's window size or - * the entire SSH connection being throttled), don't submit any - * new forwarded requests to the real agent. This causes the input - * side of the agent forwarding not to be emptied, exerting the - * required back-pressure on the remote client, and encouraging it - * to read our responses before sending too many more requests. - */ - if (c->ssh->throttled_all || - (c->ssh->version == 2 && c->v.v2.remwindow == 0)) - return; - - if (c->closes & CLOSES_SENT_EOF) { - /* - * If we've already sent outgoing EOF, there's nothing we can - * do with incoming data except consume it and throw it away. - */ - bufchain_clear(&c->u.a.inbuffer); - return; - } - - while (1) { - /* - * Try to extract a complete message from the input buffer. - */ - datalen = bufchain_size(&c->u.a.inbuffer); - if (datalen < 4) - break; /* not even a length field available yet */ - - bufchain_fetch(&c->u.a.inbuffer, msglen, 4); - length = GET_32BIT(msglen); - - if (length > AGENT_MAX_MSGLEN-4) { - /* - * If the remote has sent a message that's just _too_ - * long, we should reject it in advance of seeing the rest - * of the incoming message, and also close the connection - * for good measure (which avoids us having to faff about - * with carefully ignoring just the right number of bytes - * from the overlong message). - */ - ssh_agentf_got_response(c, NULL, 0); - sshfwd_write_eof(c); - return; - } - - if (length > datalen - 4) - break; /* a whole message is not yet available */ - - bufchain_consume(&c->u.a.inbuffer, 4); - - message = strbuf_new_for_agent_query(); - bufchain_fetch_consume( - &c->u.a.inbuffer, strbuf_append(message, length), length); - c->u.a.pending = agent_query( - message, &reply, &replylen, ssh_agentf_callback, c); - strbuf_free(message); - - if (c->u.a.pending) - return; /* agent_query promised to reply in due course */ - - /* - * If the agent gave us an answer immediately, pass it - * straight on and go round this loop again. - */ - ssh_agentf_got_response(c, reply, replylen); - sfree(reply); - } - - /* - * If we get here (i.e. we left the above while loop via 'break' - * rather than 'return'), that means we've determined that the - * input buffer for the agent forwarding connection doesn't - * contain a complete request. - * - * So if there's potentially more data to come, we can return now, - * and wait for the remote client to send it. But if the remote - * has sent EOF, it would be a mistake to do that, because we'd be - * waiting a long time. So this is the moment to check for EOF, - * and respond appropriately. - */ - if (c->closes & CLOSES_RCVD_EOF) - sshfwd_write_eof(c); -} - -static void ssh_agentf_callback(void *cv, void *reply, int replylen) -{ - struct ssh_channel *c = (struct ssh_channel *)cv; - - ssh_agentf_got_response(c, reply, replylen); - sfree(reply); - - /* - * Now try to extract and send further messages from the channel's - * input-side buffer. - */ - ssh_agentf_try_forward(c); -} - /* * Client-initiated disconnection. Send a DISCONNECT if `wire_reason' * non-NULL, otherwise just close the connection. `client_reason' == NULL @@ -4297,10 +4217,9 @@ static void ssh1_smsg_x11_open(Ssh ssh, PktIn *pktin) c->ssh = ssh; ssh_channel_init(c); - c->u.x11.xconn = x11_init(ssh->x11authtree, c, NULL, -1); + c->chan = x11_new_channel(ssh->x11authtree, c, NULL, -1, FALSE); c->remoteid = remoteid; c->halfopen = FALSE; - c->type = CHAN_X11; /* identify channel type */ pkt = ssh_bpp_new_pktout(ssh->bpp, SSH1_MSG_CHANNEL_OPEN_CONFIRMATION); put_uint32(pkt, c->remoteid); put_uint32(pkt, c->localid); @@ -4328,9 +4247,7 @@ static void ssh1_smsg_agent_open(Ssh ssh, PktIn *pktin) ssh_channel_init(c); c->remoteid = remoteid; c->halfopen = FALSE; - c->type = CHAN_AGENT; /* identify channel type */ - c->u.a.pending = NULL; - bufchain_init(&c->u.a.inbuffer); + c->chan = agentf_new(c); pkt = ssh_bpp_new_pktout(ssh->bpp, SSH1_MSG_CHANNEL_OPEN_CONFIRMATION); put_uint32(pkt, c->remoteid); put_uint32(pkt, c->localid); @@ -4369,7 +4286,7 @@ static void ssh1_msg_port_open(Ssh ssh, PktIn *pktin) logeventf(ssh, "Received remote port open request for %s:%d", pf.dhost, port); - err = pfd_connect(&c->u.pfd.pf, pf.dhost, port, + err = pfd_connect(&c->chan, pf.dhost, port, c, ssh->conf, pfp->pfrec->addressfamily); if (err != NULL) { logeventf(ssh, "Port open failed: %s", err); @@ -4382,7 +4299,6 @@ static void ssh1_msg_port_open(Ssh ssh, PktIn *pktin) ssh_channel_init(c); c->remoteid = remoteid; c->halfopen = FALSE; - c->type = CHAN_SOCKDATA; /* identify channel type */ pkt = ssh_bpp_new_pktout( ssh->bpp, SSH1_MSG_CHANNEL_OPEN_CONFIRMATION); put_uint32(pkt, c->remoteid); @@ -4400,12 +4316,10 @@ static void ssh1_msg_channel_open_confirmation(Ssh ssh, PktIn *pktin) struct ssh_channel *c; c = ssh_channel_msg(ssh, pktin); - if (c && c->type == CHAN_SOCKDATA) { - c->remoteid = get_uint32(pktin); - c->halfopen = FALSE; - c->throttling_conn = 0; - pfd_confirm(c->u.pfd.pf); - } + chan_open_confirmation(c->chan); + c->remoteid = get_uint32(pktin); + c->halfopen = FALSE; + c->throttling_conn = 0; if (c && c->pending_eof) { /* @@ -4423,12 +4337,11 @@ static void ssh1_msg_channel_open_failure(Ssh ssh, PktIn *pktin) struct ssh_channel *c; c = ssh_channel_msg(ssh, pktin); - if (c && c->type == CHAN_SOCKDATA) { - logevent("Forwarded connection refused by server"); - pfd_close(c->u.pfd.pf); - del234(ssh->channels, c); - sfree(c); - } + chan_open_failed(c->chan, NULL); + chan_free(c->chan); + + del234(ssh->channels, c); + sfree(c); } static void ssh1_msg_channel_close(Ssh ssh, PktIn *pktin) @@ -4473,39 +4386,11 @@ static void ssh1_msg_channel_close(Ssh ssh, PktIn *pktin) } } -/* - * Handle incoming data on an SSH-1 or SSH-2 agent-forwarding channel. - */ -static int ssh_agent_channel_data(struct ssh_channel *c, const void *data, - int length) -{ - bufchain_add(&c->u.a.inbuffer, data, length); - ssh_agentf_try_forward(c); - - /* - * We exert back-pressure on an agent forwarding client if and - * only if we're waiting for the response to an asynchronous agent - * request. This prevents the client running out of window while - * receiving the _first_ message, but means that if any message - * takes time to process, the client will be discouraged from - * sending an endless stream of further ones after it. - */ - return (c->u.a.pending ? bufchain_size(&c->u.a.inbuffer) : 0); -} - static int ssh_channel_data(struct ssh_channel *c, int is_stderr, const void *data, int length) { - switch (c->type) { - case CHAN_MAINSESSION: - return from_backend(c->ssh->frontend, is_stderr, data, length); - case CHAN_X11: - return x11_send(c->u.x11.xconn, data, length); - case CHAN_SOCKDATA: - return pfd_send(c->u.pfd.pf, data, length); - case CHAN_AGENT: - return ssh_agent_channel_data(c, data, length); - } + if (c->chan) + chan_send(c->chan, is_stderr, data, length); return 0; } @@ -6933,6 +6818,8 @@ static void do_ssh2_transport(void *vctx) static int ssh_send_channel_data(struct ssh_channel *c, const char *buf, int len) { + assert(!(c->closes & CLOSES_SENT_EOF)); + if (c->ssh->version == 2) { bufchain_add(&c->v.v2.outbuffer, buf, len); return ssh2_try_send(c); @@ -7002,23 +6889,8 @@ static void ssh2_try_send_and_unthrottle(Ssh ssh, struct ssh_channel *c) return; /* don't send on channels we've EOFed */ bufsize = ssh2_try_send(c); if (bufsize == 0) { - switch (c->type) { - case CHAN_MAINSESSION: - /* stdin need not receive an unthrottle - * notification since it will be polled */ - break; - case CHAN_X11: - x11_unthrottle(c->u.x11.xconn); - break; - case CHAN_AGENT: - /* Now that we've successfully sent all the outgoing - * replies we had, try to process more incoming data. */ - ssh_agentf_try_forward(c); - break; - case CHAN_SOCKDATA: - pfd_unthrottle(c->u.pfd.pf); - break; - } + c->throttled_by_backlog = FALSE; + ssh_channel_check_throttle(c); } } @@ -7036,7 +6908,9 @@ static int ssh_is_simple(Ssh ssh) } /* - * Set up most of a new ssh_channel. + * Set up most of a new ssh_channel. Nulls out sharectx, but leaves + * chan untouched (since it will sometimes have been filled in before + * calling this). */ static void ssh_channel_init(struct ssh_channel *c) { @@ -7045,6 +6919,7 @@ static void ssh_channel_init(struct ssh_channel *c) c->closes = 0; c->pending_eof = FALSE; c->throttling_conn = FALSE; + c->sharectx = NULL; if (ssh->version == 2) { c->v.v2.locwindow = c->v.v2.locmaxwin = c->v.v2.remlocwin = ssh_is_simple(ssh) ? OUR_V2_BIGWIN : OUR_V2_WINSIZE; @@ -7162,11 +7037,12 @@ static void ssh2_set_window(struct ssh_channel *c, int newwin) return; /* - * Also, never widen the window for an X11 channel when we're - * still waiting to see its initial auth and may yet hand it off - * to a downstream. + * If the client-side Channel is in an initial setup phase with a + * fixed window size, e.g. for an X11 channel when we're still + * waiting to see its initial auth and may yet hand it off to a + * downstream, don't send any WINDOW_ADJUST either. */ - if (c->type == CHAN_X11 && c->u.x11.initial) + if (c->chan->initial_fixed_window_size) return; /* @@ -7241,7 +7117,13 @@ static struct ssh_channel *ssh_channel_msg(Ssh ssh, PktIn *pktin) halfopen_ok = (pktin->type == SSH2_MSG_CHANNEL_OPEN_CONFIRMATION || pktin->type == SSH2_MSG_CHANNEL_OPEN_FAILURE); c = find234(ssh->channels, &localid, ssh_channelfind); - if (!c || (c->type != CHAN_SHARING && (c->halfopen != halfopen_ok))) { + if (c && c->sharectx) { + share_got_pkt_from_server(c->sharectx, pktin->type, + BinarySource_UPCAST(pktin)->data, + BinarySource_UPCAST(pktin)->len); + return NULL; + } + if (!c || c->halfopen != halfopen_ok) { char *buf = dupprintf("Received %s for %s channel %u", ssh_pkt_type(ssh, pktin->type), !c ? "nonexistent" : @@ -7251,12 +7133,6 @@ static struct ssh_channel *ssh_channel_msg(Ssh ssh, PktIn *pktin) sfree(buf); return NULL; } - if (c->type == CHAN_SHARING) { - share_got_pkt_from_server(c->u.sharing.ctx, pktin->type, - BinarySource_UPCAST(pktin)->data, - BinarySource_UPCAST(pktin)->len); - return NULL; - } return c; } @@ -7421,36 +7297,20 @@ void ssh_sharing_logf(Ssh ssh, unsigned id, const char *logfmt, ...) /* * Close any local socket and free any local resources associated with - * a channel. This converts the channel into a CHAN_ZOMBIE. + * a channel. This converts the channel into a zombie. */ static void ssh_channel_close_local(struct ssh_channel *c, char const *reason) { Ssh ssh = c->ssh; - char const *msg = NULL; - - switch (c->type) { - case CHAN_MAINSESSION: - ssh->mainchan = NULL; - update_specials_menu(ssh->frontend); - break; - case CHAN_X11: - assert(c->u.x11.xconn != NULL); - x11_close(c->u.x11.xconn); - msg = "Forwarded X11 connection terminated"; - break; - case CHAN_AGENT: - if (c->u.a.pending) - agent_cancel_query(c->u.a.pending); - bufchain_clear(&c->u.a.inbuffer); - msg = "Agent-forwarding connection closed"; - break; - case CHAN_SOCKDATA: - assert(c->u.pfd.pf != NULL); - pfd_close(c->u.pfd.pf); - msg = "Forwarded port closed"; - break; - } - c->type = CHAN_ZOMBIE; + const char *msg = NULL; + + if (c->sharectx) + return; + + msg = chan_log_close_msg(c->chan); + chan_free(c->chan); + c->chan = zombiechan_new(); + if (msg != NULL) { if (reason != NULL) logeventf(ssh, "%s %s", msg, reason); @@ -7495,7 +7355,8 @@ static void ssh2_channel_check_close(struct ssh_channel *c) } if ((!((CLOSES_SENT_EOF | CLOSES_RCVD_EOF) & ~c->closes) || - c->type == CHAN_ZOMBIE) && + chan_want_close(c->chan, (c->closes & CLOSES_SENT_EOF), + (c->closes & CLOSES_RCVD_EOF))) && !c->v.v2.chanreq_head && !(c->closes & CLOSES_SENT_CLOSE)) { /* @@ -7526,34 +7387,7 @@ static void ssh_channel_got_eof(struct ssh_channel *c) return; /* already seen EOF */ c->closes |= CLOSES_RCVD_EOF; - if (c->type == CHAN_X11) { - assert(c->u.x11.xconn != NULL); - x11_send_eof(c->u.x11.xconn); - } else if (c->type == CHAN_AGENT) { - /* Just call try_forward, which will respond to the EOF now if - * appropriate, or wait until the queue of outstanding - * requests is dealt with if not */ - ssh_agentf_try_forward(c); - } else if (c->type == CHAN_SOCKDATA) { - assert(c->u.pfd.pf != NULL); - pfd_send_eof(c->u.pfd.pf); - } else if (c->type == CHAN_MAINSESSION) { - Ssh ssh = c->ssh; - - if (!ssh->sent_console_eof && - (from_backend_eof(ssh->frontend) || ssh->got_pty)) { - /* - * Either from_backend_eof told us that the front end - * wants us to close the outgoing side of the connection - * as soon as we see EOF from the far end, or else we've - * unilaterally decided to do that because we've allocated - * a remote pty and hence EOF isn't a particularly - * meaningful concept. - */ - sshfwd_write_eof(c); - } - ssh->sent_console_eof = TRUE; - } + chan_send_eof(c->chan); } static void ssh2_msg_channel_eof(Ssh ssh, PktIn *pktin) @@ -7604,22 +7438,6 @@ static void ssh2_msg_channel_close(Ssh ssh, PktIn *pktin) * it would have just sent CHANNEL_EOF.) */ if (!(c->closes & CLOSES_SENT_EOF)) { - /* - * Make sure we don't read any more from whatever our local - * data source is for this channel. - */ - switch (c->type) { - case CHAN_MAINSESSION: - ssh->send_ok = 0; /* stop trying to read from stdin */ - break; - case CHAN_X11: - x11_override_throttle(c->u.x11.xconn, 1); - break; - case CHAN_SOCKDATA: - pfd_override_throttle(c->u.pfd.pf, 1); - break; - } - /* * Abandon any buffered data we still wanted to send to this * channel. Receiving a CHANNEL_CLOSE is an indication that @@ -7633,6 +7451,13 @@ static void ssh2_msg_channel_close(Ssh ssh, PktIn *pktin) * Send outgoing EOF. */ sshfwd_write_eof(c); + + /* + * Make sure we don't read any more from whatever our local + * data source is for this channel. (This will pick up on the + * changes made by sshfwd_write_eof.) + */ + ssh_channel_check_throttle(c); } /* @@ -7657,32 +7482,22 @@ static void ssh2_msg_channel_open_confirmation(Ssh ssh, PktIn *pktin) c->v.v2.remwindow = get_uint32(pktin); c->v.v2.remmaxpkt = get_uint32(pktin); - if (c->type == CHAN_SOCKDATA) { - assert(c->u.pfd.pf != NULL); - pfd_confirm(c->u.pfd.pf); - } else if (c->type == CHAN_ZOMBIE) { - /* - * This case can occur if a local socket error occurred - * between us sending out CHANNEL_OPEN and receiving - * OPEN_CONFIRMATION. In this case, all we can do is - * immediately initiate close proceedings now that we know the - * server's id to put in the close message. - */ - ssh2_channel_check_close(c); - } else { - /* - * We never expect to receive OPEN_CONFIRMATION for any - * *other* channel type (since only local-to-remote port - * forwardings cause us to send CHANNEL_OPEN after the main - * channel is live - all other auxiliary channel types are - * initiated from the server end). It's safe to enforce this - * by assertion rather than by ssh_disconnect, because the - * real point is that we never constructed a half-open channel - * structure in the first place with any type other than the - * above. - */ - assert(!"Funny channel type in ssh2_msg_channel_open_confirmation"); - } + chan_open_confirmation(c->chan); + + /* + * Now that the channel is fully open, it's possible in principle + * to immediately close it. Check whether it wants us to! + * + * This can occur if a local socket error occurred between us + * sending out CHANNEL_OPEN and receiving OPEN_CONFIRMATION. If + * that happens, all we can do is immediately initiate close + * proceedings now that we know the server's id to put in the + * close message. We'll have handled that in this code by having + * already turned c->chan into a zombie, so its want_close method + * (which ssh2_channel_check_close will consult) will already be + * returning TRUE. + */ + ssh2_channel_check_close(c); if (c->pending_eof) ssh_channel_try_eof(c); /* in case we had a pending EOF */ @@ -7724,31 +7539,12 @@ static void ssh2_msg_channel_open_failure(Ssh ssh, PktIn *pktin) return; assert(c->halfopen); /* ssh_channel_msg will have enforced this */ - if (c->type == CHAN_SOCKDATA) { + { char *errtext = ssh2_channel_open_failure_error_text(pktin); - logeventf(ssh, "Forwarded connection refused by server: %s", errtext); + chan_open_failed(c->chan, errtext); sfree(errtext); - pfd_close(c->u.pfd.pf); - } else if (c->type == CHAN_ZOMBIE) { - /* - * This case can occur if a local socket error occurred - * between us sending out CHANNEL_OPEN and receiving - * OPEN_FAILURE. In this case, we need do nothing except allow - * the code below to throw the half-open channel away. - */ - } else { - /* - * We never expect to receive OPEN_FAILURE for any *other* - * channel type (since only local-to-remote port forwardings - * cause us to send CHANNEL_OPEN after the main channel is - * live - all other auxiliary channel types are initiated from - * the server end). It's safe to enforce this by assertion - * rather than by ssh_disconnect, because the real point is - * that we never constructed a half-open channel structure in - * the first place with any type other than the above. - */ - assert(!"Funny channel type in ssh2_msg_channel_open_failure"); } + chan_free(c->chan); del234(ssh->channels, c); sfree(c); @@ -7970,7 +7766,6 @@ static void ssh2_msg_channel_open(Ssh ssh, PktIn *pktin) const char *error = NULL; struct ssh_channel *c; unsigned remid, winsize, pktsize; - unsigned our_winsize_override = 0; PktOut *pktout; type = get_string(pktin); @@ -7991,22 +7786,8 @@ static void ssh2_msg_channel_open(Ssh ssh, PktIn *pktin) if (!ssh->X11_fwd_enabled && !ssh->connshare) error = "X11 forwarding is not enabled"; else { - c->u.x11.xconn = x11_init(ssh->x11authtree, c, - addrstr, peerport); - c->type = CHAN_X11; - c->u.x11.initial = TRUE; - - /* - * If we are a connection-sharing upstream, then we should - * initially present a very small window, adequate to take - * the X11 initial authorisation packet but not much more. - * Downstream will then present us a larger window (by - * fiat of the connection-sharing protocol) and we can - * guarantee to send a positive-valued WINDOW_ADJUST. - */ - if (ssh->connshare) - our_winsize_override = 128; - + c->chan = x11_new_channel(ssh->x11authtree, c, addrstr, peerport, + ssh->connshare != NULL); logevent("Opened X11 forward channel"); } @@ -8044,7 +7825,7 @@ static void ssh2_msg_channel_open(Ssh ssh, PktIn *pktin) return; } - err = pfd_connect(&c->u.pfd.pf, realpf->dhost, realpf->dport, + err = pfd_connect(&c->chan, realpf->dhost, realpf->dport, c, ssh->conf, realpf->pfrec->addressfamily); logeventf(ssh, "Attempting to forward remote port to " "%s:%d", realpf->dhost, realpf->dport); @@ -8054,17 +7835,13 @@ static void ssh2_msg_channel_open(Ssh ssh, PktIn *pktin) error = "Port open failed"; } else { logevent("Forwarded port opened successfully"); - c->type = CHAN_SOCKDATA; } } } else if (ptrlen_eq_string(type, "auth-agent@openssh.com")) { if (!ssh->agentfwd_enabled) error = "Agent forwarding is not enabled"; - else { - c->type = CHAN_AGENT; /* identify channel type */ - bufchain_init(&c->u.a.inbuffer); - c->u.a.pending = NULL; - } + else + c->chan = agentf_new(c); } else { error = "Unsupported channel type requested"; } @@ -8084,9 +7861,9 @@ static void ssh2_msg_channel_open(Ssh ssh, PktIn *pktin) ssh_channel_init(c); c->v.v2.remwindow = winsize; c->v.v2.remmaxpkt = pktsize; - if (our_winsize_override) { + if (c->chan->initial_fixed_window_size) { c->v.v2.locwindow = c->v.v2.locmaxwin = c->v.v2.remlocwin = - our_winsize_override; + c->chan->initial_fixed_window_size; } pktout = ssh_bpp_new_pktout( ssh->bpp, SSH2_MSG_CHANNEL_OPEN_CONFIRMATION); @@ -8108,30 +7885,28 @@ void sshfwd_x11_sharing_handover(struct ssh_channel *c, * This function is called when we've just discovered that an X * forwarding channel on which we'd been handling the initial auth * ourselves turns out to be destined for a connection-sharing - * downstream. So we turn the channel into a CHAN_SHARING, meaning + * downstream. So we turn the channel into a sharing one, meaning * that we completely stop tracking windows and buffering data and * just pass more or less unmodified SSH messages back and forth. */ - c->type = CHAN_SHARING; - c->u.sharing.ctx = share_cs; + c->sharectx = share_cs; share_setup_x11_channel(share_cs, share_chan, c->localid, c->remoteid, c->v.v2.remwindow, c->v.v2.remmaxpkt, c->v.v2.locwindow, peer_addr, peer_port, endian, protomajor, protominor, initial_data, initial_len); + chan_free(c->chan); + c->chan = NULL; } -void sshfwd_x11_is_local(struct ssh_channel *c) +void sshfwd_window_override_removed(struct ssh_channel *c) { /* - * This function is called when we've just discovered that an X - * forwarding channel is _not_ destined for a connection-sharing - * downstream but we're going to handle it ourselves. We stop - * presenting a cautiously small window and go into ordinary data - * exchange mode. + * This function is called when a client-side Channel has just + * stopped requiring an initial fixed-size window. */ - c->u.x11.initial = FALSE; + assert(!c->chan->initial_fixed_window_size); if (c->ssh->version == 2) ssh2_set_window( c, ssh_is_simple(c->ssh) ? OUR_V2_BIGWIN : OUR_V2_WINSIZE); @@ -9879,6 +9654,108 @@ static void ssh2_connection_setup(Ssh ssh) ssh->channels = newtree234(ssh_channelcmp); } +typedef struct mainchan { + Ssh ssh; + struct ssh_channel *c; + + Channel chan; +} mainchan; + +static void mainchan_free(Channel *chan); +static void mainchan_open_confirmation(Channel *chan); +static void mainchan_open_failure(Channel *chan, const char *errtext); +static int mainchan_send(Channel *chan, int is_stderr, const void *, int); +static void mainchan_send_eof(Channel *chan); +static void mainchan_set_input_wanted(Channel *chan, int wanted); +static char *mainchan_log_close_msg(Channel *chan); + +static const struct ChannelVtable mainchan_channelvt = { + mainchan_free, + mainchan_open_confirmation, + mainchan_open_failure, + mainchan_send, + mainchan_send_eof, + mainchan_set_input_wanted, + mainchan_log_close_msg, + chan_no_eager_close, +}; + +static mainchan *mainchan_new(Ssh ssh) +{ + mainchan *mc = snew(mainchan); + mc->ssh = ssh; + mc->c = NULL; + mc->chan.vt = &mainchan_channelvt; + mc->chan.initial_fixed_window_size = 0; + return mc; +} + +static void mainchan_free(Channel *chan) +{ + assert(chan->vt == &mainchan_channelvt); + mainchan *mc = FROMFIELD(chan, mainchan, chan); + mc->ssh->mainchan = NULL; + sfree(mc); +} + +static void mainchan_open_confirmation(Channel *chan) +{ + assert(FALSE && "OPEN_CONFIRMATION for main channel should be " + "handled by connection layer setup"); +} + +static void mainchan_open_failure(Channel *chan, const char *errtext) +{ + assert(FALSE && "OPEN_FAILURE for main channel should be " + "handled by connection layer setup"); +} + +static int mainchan_send(Channel *chan, int is_stderr, + const void *data, int length) +{ + assert(chan->vt == &mainchan_channelvt); + mainchan *mc = FROMFIELD(chan, mainchan, chan); + return from_backend(mc->ssh->frontend, is_stderr, data, length); +} + +static void mainchan_send_eof(Channel *chan) +{ + assert(chan->vt == &mainchan_channelvt); + mainchan *mc = FROMFIELD(chan, mainchan, chan); + + if (!mc->ssh->sent_console_eof && + (from_backend_eof(mc->ssh->frontend) || mc->ssh->got_pty)) { + /* + * Either from_backend_eof told us that the front end wants us + * to close the outgoing side of the connection as soon as we + * see EOF from the far end, or else we've unilaterally + * decided to do that because we've allocated a remote pty and + * hence EOF isn't a particularly meaningful concept. + */ + sshfwd_write_eof(mc->c); + } + mc->ssh->sent_console_eof = TRUE; +} + +static void mainchan_set_input_wanted(Channel *chan, int wanted) +{ + assert(chan->vt == &mainchan_channelvt); + mainchan *mc = FROMFIELD(chan, mainchan, chan); + + /* + * This is the main channel of the SSH session, i.e. the one tied + * to the standard input (or GUI) of the primary SSH client user + * interface. So ssh->send_ok is how we control whether we're + * reading from that input. + */ + mc->ssh->send_ok = wanted; +} + +static char *mainchan_log_close_msg(Channel *chan) +{ + return dupstr("Main session channel closed"); +} + static void do_ssh2_connection(void *vctx) { Ssh ssh = (Ssh)vctx; @@ -9907,22 +9784,23 @@ static void do_ssh2_connection(void *vctx) if (conf_get_int(ssh->conf, CONF_ssh_no_shell)) { ssh->mainchan = NULL; } else { - ssh->mainchan = snew(struct ssh_channel); - ssh->mainchan->ssh = ssh; - ssh->mainchan->type = CHAN_MAINSESSION; - ssh_channel_init(ssh->mainchan); + mainchan *mc = mainchan_new(ssh); if (*conf_get_str(ssh->conf, CONF_ssh_nc_host)) { /* * Just start a direct-tcpip channel and use it as the main * channel. */ - ssh_send_port_open(ssh->mainchan, - conf_get_str(ssh->conf, CONF_ssh_nc_host), - conf_get_int(ssh->conf, CONF_ssh_nc_port), - "main channel"); + ssh->mainchan = mc->c = ssh_send_port_open + (ssh, conf_get_str(ssh->conf, CONF_ssh_nc_host), + conf_get_int(ssh->conf, CONF_ssh_nc_port), + "main channel", &mc->chan); ssh->ncmode = TRUE; } else { + ssh->mainchan = mc->c = snew(struct ssh_channel); + ssh->mainchan->ssh = ssh; + ssh_channel_init(ssh->mainchan); + ssh->mainchan->chan = &mc->chan; s->pktout = ssh2_chanopen_init(ssh->mainchan, "session"); logevent("Opening session as main channel"); ssh2_pkt_send(ssh, s->pktout); @@ -11295,19 +11173,6 @@ static void ssh_special(Backend *be, Telnet_Special code) } } -void *new_sock_channel(Ssh ssh, struct PortForwarding *pf) -{ - struct ssh_channel *c; - c = snew(struct ssh_channel); - - c->ssh = ssh; - ssh_channel_init(c); - c->halfopen = TRUE; - c->type = CHAN_SOCKDATA;/* identify channel type */ - c->u.pfd.pf = pf; - return c; -} - unsigned ssh_alloc_sharing_channel(Ssh ssh, void *sharing_ctx) { struct ssh_channel *c; @@ -11315,8 +11180,8 @@ unsigned ssh_alloc_sharing_channel(Ssh ssh, void *sharing_ctx) c->ssh = ssh; ssh_channel_init(c); - c->type = CHAN_SHARING; - c->u.sharing.ctx = sharing_ctx; + c->chan = NULL; + c->sharectx = sharing_ctx; return c->localid; } @@ -11367,13 +11232,17 @@ static void ssh_unthrottle(Backend *be, int bufsize) queue_idempotent_callback(&ssh->incoming_data_consumer); } -void ssh_send_port_open(void *channel, const char *hostname, int port, - const char *org) +struct ssh_channel *ssh_send_port_open(Ssh ssh, const char *hostname, int port, + const char *org, Channel *chan) { - struct ssh_channel *c = (struct ssh_channel *)channel; - Ssh ssh = c->ssh; + struct ssh_channel *c = snew(struct ssh_channel); PktOut *pktout; + c->ssh = ssh; + ssh_channel_init(c); + c->halfopen = TRUE; + c->chan = chan; + logeventf(ssh, "Opening connection to %s:%d for %s", hostname, port, org); if (ssh->version == 1) { @@ -11405,6 +11274,8 @@ void ssh_send_port_open(void *channel, const char *hostname, int port, put_uint32(pktout, 0); ssh2_pkt_send(ssh, pktout); } + + return c; } static int ssh_connected(Backend *be) diff --git a/ssh.h b/ssh.h index 3fe8266b..82810d78 100644 --- a/ssh.h +++ b/ssh.h @@ -14,12 +14,12 @@ extern void sshfwd_write_eof(struct ssh_channel *c); extern void sshfwd_unclean_close(struct ssh_channel *c, const char *err); extern void sshfwd_unthrottle(struct ssh_channel *c, int bufsize); Conf *sshfwd_get_conf(struct ssh_channel *c); +void sshfwd_window_override_removed(struct ssh_channel *c); void sshfwd_x11_sharing_handover(struct ssh_channel *c, void *share_cs, void *share_chan, const char *peer_addr, int peer_port, int endian, int protomajor, int protominor, const void *initial_data, int initial_len); -void sshfwd_x11_is_local(struct ssh_channel *c); /* * Buffer management constants. There are several of these for @@ -185,6 +185,8 @@ void share_setup_x11_channel(void *csv, void *chanv, int protomajor, int protominor, const void *initial_data, int initial_len); +Frontend *ssh_get_frontend(Ssh ssh); + /* * Useful thing. */ @@ -665,19 +667,12 @@ void logevent(Frontend *, const char *); struct PortForwarding; /* Allocate and register a new channel for port forwarding */ -void *new_sock_channel(Ssh ssh, struct PortForwarding *pf); -void ssh_send_port_open(void *channel, const char *hostname, int port, - const char *org); +struct ssh_channel *ssh_send_port_open(Ssh ssh, const char *hostname, int port, + const char *org, Channel *chan); /* Exports from portfwd.c */ -extern char *pfd_connect(struct PortForwarding **pf, char *hostname, int port, - void *c, Conf *conf, int addressfamily); -extern void pfd_close(struct PortForwarding *); -extern int pfd_send(struct PortForwarding *, const void *data, int len); -extern void pfd_send_eof(struct PortForwarding *); -extern void pfd_confirm(struct PortForwarding *); -extern void pfd_unthrottle(struct PortForwarding *); -extern void pfd_override_throttle(struct PortForwarding *, int enable); +extern char *pfd_connect(Channel **chan_ret, char *hostname, int port, + struct ssh_channel *c, Conf *conf, int addressfamily); struct PortListener; /* desthost == NULL indicates dynamic (SOCKS) port forwarding */ extern char *pfl_listen(char *desthost, int destport, char *srcaddr, @@ -750,13 +745,9 @@ extern struct X11Display *x11_setup_display(const char *display, Conf *); void x11_free_display(struct X11Display *disp); struct X11FakeAuth *x11_invent_fake_auth(tree234 *t, int authtype); void x11_free_fake_auth(struct X11FakeAuth *auth); -struct X11Connection; /* opaque outside x11fwd.c */ -struct X11Connection *x11_init(tree234 *authtree, void *, const char *, int); -extern void x11_close(struct X11Connection *); -extern int x11_send(struct X11Connection *, const void *, int); -extern void x11_send_eof(struct X11Connection *s); -extern void x11_unthrottle(struct X11Connection *s); -extern void x11_override_throttle(struct X11Connection *s, int enable); +Channel *x11_new_channel(tree234 *authtree, struct ssh_channel *c, + const char *peeraddr, int peerport, + int connection_sharing_possible); char *x11_display(const char *display); /* Platform-dependent X11 functions */ extern void platform_get_x11_auth(struct X11Display *display, Conf *); @@ -786,6 +777,8 @@ void x11_get_auth_from_authfile(struct X11Display *display, int x11_identify_auth_proto(ptrlen protoname); void *x11_dehexify(ptrlen hex, int *outlen); +Channel *agentf_new(struct ssh_channel *c); + Bignum copybn(Bignum b); Bignum bn_power_2(int n); void bn_restore_invariant(Bignum b); diff --git a/sshchan.h b/sshchan.h new file mode 100644 index 00000000..26462bc6 --- /dev/null +++ b/sshchan.h @@ -0,0 +1,59 @@ +/* + * Abstraction of the various ways to handle the local end of an SSH + * connection-layer channel. + */ + +#ifndef PUTTY_SSHCHAN_H +#define PUTTY_SSHCHAN_H + +struct ChannelVtable { + void (*free)(Channel *); + + /* Called for channel types that were created at the same time as + * we sent an outgoing CHANNEL_OPEN, when the confirmation comes + * back from the server indicating that the channel has been + * opened, or the failure message indicating that it hasn't, + * respectively. In the latter case, this must _not_ free the + * Channel structure - the client will call the free method + * separately. But it might do logging or other local cleanup. */ + void (*open_confirmation)(Channel *); + void (*open_failed)(Channel *, const char *error_text); + + int (*send)(Channel *, int is_stderr, const void *buf, int len); + void (*send_eof)(Channel *); + void (*set_input_wanted)(Channel *, int wanted); + + char *(*log_close_msg)(Channel *); + + int (*want_close)(Channel *, int sent_local_eof, int rcvd_remote_eof); +}; + +struct Channel { + const struct ChannelVtable *vt; + unsigned initial_fixed_window_size; +}; + +#define chan_free(ch) ((ch)->vt->free(ch)) +#define chan_open_confirmation(ch) ((ch)->vt->open_confirmation(ch)) +#define chan_open_failed(ch, err) ((ch)->vt->open_failed(ch, err)) +#define chan_send(ch, err, buf, len) ((ch)->vt->send(ch, err, buf, len)) +#define chan_send_eof(ch) ((ch)->vt->send_eof(ch)) +#define chan_set_input_wanted(ch, wanted) \ + ((ch)->vt->set_input_wanted(ch, wanted)) +#define chan_log_close_msg(ch) ((ch)->vt->send_eof(ch)) +#define chan_want_close(ch, leof, reof) ((ch)->vt->want_close(ch, leof, reof)) + +/* + * Reusable methods you can put in vtables to give default handling of + * some of those functions. + */ + +/* open_confirmation / open_failed for any channel it doesn't apply to */ +void chan_remotely_opened_confirmation(Channel *chan); +void chan_remotely_opened_failure(Channel *chan, const char *errtext); + +/* want_close for any channel that wants the default behaviour of not + * closing until both directions have had an EOF */ +int chan_no_eager_close(Channel *, int, int); + +#endif /* PUTTY_SSHCHAN_H */ diff --git a/unix/uxpgnt.c b/unix/uxpgnt.c index 6445fd57..a694bc44 100644 --- a/unix/uxpgnt.c +++ b/unix/uxpgnt.c @@ -161,13 +161,17 @@ int sshfwd_write(struct ssh_channel *c, const void *data, int len) void sshfwd_write_eof(struct ssh_channel *c) { } void sshfwd_unclean_close(struct ssh_channel *c, const char *err) { } void sshfwd_unthrottle(struct ssh_channel *c, int bufsize) {} +void sshfwd_window_override_removed(struct ssh_channel *c) { } +void chan_remotely_opened_confirmation(Channel *chan) { } +void chan_remotely_opened_failure(Channel *chan, const char *err) { } +int chan_no_eager_close(Channel *chan, int s, int r) { return FALSE; } + Conf *sshfwd_get_conf(struct ssh_channel *c) { return NULL; } void sshfwd_x11_sharing_handover(struct ssh_channel *c, void *share_cs, void *share_chan, const char *peer_addr, int peer_port, int endian, int protomajor, int protominor, const void *initial_data, int initial_len) {} -void sshfwd_x11_is_local(struct ssh_channel *c) {} /* * These functions are part of the plug for our connection to the X diff --git a/x11fwd.c b/x11fwd.c index 190b6f68..419d4968 100644 --- a/x11fwd.c +++ b/x11fwd.c @@ -9,6 +9,7 @@ #include "putty.h" #include "ssh.h" +#include "sshchan.h" #include "tree234.h" #define GET_16BIT(endian, cp) \ @@ -26,7 +27,7 @@ struct XDMSeen { unsigned char clientid[6]; }; -struct X11Connection { +typedef struct X11Connection { unsigned char firstpkt[12]; /* first X data packet */ tree234 *authtree; struct X11Display *disp; @@ -34,7 +35,7 @@ struct X11Connection { unsigned char *auth_data; int data_read, auth_plen, auth_psize, auth_dlen, auth_dsize; int verified; - int throttled, throttle_override; + int input_wanted; int no_data_sent_to_x_client; char *peer_addr; int peer_port; @@ -42,7 +43,8 @@ struct X11Connection { Socket s; const Plug_vtable *plugvt; -}; + Channel chan; +} X11Connection; static int xdmseen_cmp(void *a, void *b) { @@ -666,11 +668,8 @@ static void x11_receive(Plug plug, int urgent, char *data, int len) struct X11Connection *xconn = FROMFIELD( plug, struct X11Connection, plugvt); - if (sshfwd_write(xconn->c, data, len) > 0) { - xconn->throttled = 1; - xconn->no_data_sent_to_x_client = FALSE; - sk_set_frozen(xconn->s, 1); - } + xconn->no_data_sent_to_x_client = FALSE; + sshfwd_write(xconn->c, data, len); } static void x11_sent(Plug plug, int bufsize) @@ -707,12 +706,30 @@ static const Plug_vtable X11Connection_plugvt = { NULL }; +static void x11_chan_free(Channel *chan); +static int x11_send(Channel *chan, int is_stderr, const void *vdata, int len); +static void x11_send_eof(Channel *chan); +static void x11_set_input_wanted(Channel *chan, int wanted); +static char *x11_log_close_msg(Channel *chan); + +static const struct ChannelVtable X11Connection_channelvt = { + x11_chan_free, + chan_remotely_opened_confirmation, + chan_remotely_opened_failure, + x11_send, + x11_send_eof, + x11_set_input_wanted, + x11_log_close_msg, + chan_no_eager_close, +}; + /* * Called to set up the X11Connection structure, though this does not * yet connect to an actual server. */ -struct X11Connection *x11_init(tree234 *authtree, void *c, - const char *peeraddr, int peerport) +Channel *x11_new_channel(tree234 *authtree, struct ssh_channel *c, + const char *peeraddr, int peerport, + int connection_sharing_possible) { struct X11Connection *xconn; @@ -721,11 +738,14 @@ struct X11Connection *x11_init(tree234 *authtree, void *c, */ xconn = snew(struct X11Connection); xconn->plugvt = &X11Connection_plugvt; + xconn->chan.vt = &X11Connection_channelvt; + xconn->chan.initial_fixed_window_size = + (connection_sharing_possible ? 128 : 0); xconn->auth_protocol = NULL; xconn->authtree = authtree; xconn->verified = 0; xconn->data_read = 0; - xconn->throttled = xconn->throttle_override = 0; + xconn->input_wanted = TRUE; xconn->no_data_sent_to_x_client = TRUE; xconn->c = c; @@ -746,13 +766,13 @@ struct X11Connection *x11_init(tree234 *authtree, void *c, xconn->peer_addr = peeraddr ? dupstr(peeraddr) : NULL; xconn->peer_port = peerport; - return xconn; + return &xconn->chan; } -void x11_close(struct X11Connection *xconn) +static void x11_chan_free(Channel *chan) { - if (!xconn) - return; + assert(chan->vt == &X11Connection_channelvt); + X11Connection *xconn = FROMFIELD(chan, X11Connection, chan); if (xconn->auth_protocol) { sfree(xconn->auth_protocol); @@ -766,24 +786,14 @@ void x11_close(struct X11Connection *xconn) sfree(xconn); } -void x11_unthrottle(struct X11Connection *xconn) +static void x11_set_input_wanted(Channel *chan, int wanted) { - if (!xconn) - return; + assert(chan->vt == &X11Connection_channelvt); + X11Connection *xconn = FROMFIELD(chan, X11Connection, chan); - xconn->throttled = 0; + xconn->input_wanted = wanted; if (xconn->s) - sk_set_frozen(xconn->s, xconn->throttled || xconn->throttle_override); -} - -void x11_override_throttle(struct X11Connection *xconn, int enable) -{ - if (!xconn) - return; - - xconn->throttle_override = enable; - if (xconn->s) - sk_set_frozen(xconn->s, xconn->throttled || xconn->throttle_override); + sk_set_frozen(xconn->s, !xconn->input_wanted); } static void x11_send_init_error(struct X11Connection *xconn, @@ -831,13 +841,12 @@ static int x11_parse_ip(const char *addr_string, unsigned long *ip) /* * Called to send data down the raw connection. */ -int x11_send(struct X11Connection *xconn, const void *vdata, int len) +static int x11_send(Channel *chan, int is_stderr, const void *vdata, int len) { + assert(chan->vt == &X11Connection_channelvt); + X11Connection *xconn = FROMFIELD(chan, X11Connection, chan); const char *data = (const char *)vdata; - if (!xconn) - return 0; - /* * Read the first packet. */ @@ -914,7 +923,8 @@ int x11_send(struct X11Connection *xconn, const void *vdata, int len) /* * If this auth points to a connection-sharing downstream * rather than an X display we know how to connect to - * directly, pass it off to the sharing module now. + * directly, pass it off to the sharing module now. (This will + * have the side effect of freeing xconn.) */ if (auth_matched->share_cs) { sshfwd_x11_sharing_handover(xconn->c, auth_matched->share_cs, @@ -929,7 +939,8 @@ int x11_send(struct X11Connection *xconn, const void *vdata, int len) * Now we know we're going to accept the connection, and what * X display to connect to. Actually connect to it. */ - sshfwd_x11_is_local(xconn->c); + xconn->chan.initial_fixed_window_size = 0; + sshfwd_window_override_removed(xconn->c); xconn->disp = auth_matched->disp; xconn->s = new_connection(sk_addr_dup(xconn->disp->addr), xconn->disp->realhost, xconn->disp->port, @@ -984,8 +995,11 @@ int x11_send(struct X11Connection *xconn, const void *vdata, int len) return sk_write(xconn->s, data, len); } -void x11_send_eof(struct X11Connection *xconn) +static void x11_send_eof(Channel *chan) { + assert(chan->vt == &X11Connection_channelvt); + X11Connection *xconn = FROMFIELD(chan, X11Connection, chan); + if (xconn->s) { sk_write_eof(xconn->s); } else { @@ -1000,6 +1014,11 @@ void x11_send_eof(struct X11Connection *xconn) } } +static char *x11_log_close_msg(Channel *chan) +{ + return dupstr("Forwarded X11 connection terminated"); +} + /* * Utility functions used by connection sharing to convert textual * representations of an X11 auth protocol name + hex cookie into our From 08b43c0ccaa7a80515a0829a09a247aa5b3c0634 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Thu, 13 Sep 2018 09:09:10 +0100 Subject: [PATCH 395/607] Expose structure tags for the connection-sharing data types. This was a particularly confusing piece of type-danger, because three different types were passed outside sshshare.c as 'void *' and only human vigilance prevented one coming back as the wrong one. Now they all keep their opaque structure tags when they move through other parts of the code. --- defs.h | 4 ++++ ssh.c | 27 +++++++++++++++------------ ssh.h | 34 +++++++++++++++++++--------------- sshshare.c | 32 +++++++++++++------------------- unix/uxpgnt.c | 3 ++- x11fwd.c | 3 ++- 6 files changed, 55 insertions(+), 48 deletions(-) diff --git a/defs.h b/defs.h index 2c597953..329883d9 100644 --- a/defs.h +++ b/defs.h @@ -55,6 +55,10 @@ typedef struct ssh_tag *Ssh; typedef struct Channel Channel; +typedef struct ssh_sharing_state ssh_sharing_state; +typedef struct ssh_sharing_connstate ssh_sharing_connstate; +typedef struct share_channel share_channel; + /* Note indirection: for historical reasons (it used to be closer to * the OS socket type), the type that most code uses for a socket is * 'Socket', not 'Socket *'. So an implementation of Socket or Plug diff --git a/ssh.c b/ssh.c index bc2f7bf8..dd1d1c1f 100644 --- a/ssh.c +++ b/ssh.c @@ -460,7 +460,8 @@ struct ssh_channel { } v2; } v; - void *sharectx; /* sharing context, if this is a downstream channel */ + ssh_sharing_connstate *sharectx; /* sharing context, if this is a + * downstream channel */ Channel *chan; /* handle the client side of this channel, if not */ }; @@ -497,7 +498,7 @@ struct ssh_rportfwd { unsigned sport, dport; char *shost, *dhost; char *sportdesc; - void *share_ctx; + ssh_sharing_connstate *share_ctx; struct ssh_portfwd *pfrec; }; @@ -695,7 +696,7 @@ struct ssh_tag { int bare_connection; int attempting_connshare; - void *connshare; + ssh_sharing_state *connshare; char *savedhost; int savedport; @@ -3800,7 +3801,7 @@ static void ssh_rportfwd_succfail(Ssh ssh, PktIn *pktin, void *ctx) } int ssh_alloc_sharing_rportfwd(Ssh ssh, const char *shost, int sport, - void *share_ctx) + ssh_sharing_connstate *share_ctx) { struct ssh_rportfwd *pf = snew(struct ssh_rportfwd); pf->dhost = NULL; @@ -3822,7 +3823,7 @@ int ssh_alloc_sharing_rportfwd(Ssh ssh, const char *shost, int sport, } void ssh_remove_sharing_rportfwd(Ssh ssh, const char *shost, int sport, - void *share_ctx) + ssh_sharing_connstate *share_ctx) { struct ssh_rportfwd pf, *realpf; @@ -3844,7 +3845,8 @@ static void ssh_sharing_global_request_response(Ssh ssh, PktIn *pktin, BinarySource_UPCAST(pktin)->len); } -void ssh_sharing_queue_global_request(Ssh ssh, void *share_ctx) +void ssh_sharing_queue_global_request(Ssh ssh, + ssh_sharing_connstate *share_ctx) { ssh_queue_handler(ssh, SSH2_MSG_REQUEST_SUCCESS, SSH2_MSG_REQUEST_FAILURE, ssh_sharing_global_request_response, share_ctx); @@ -7735,9 +7737,9 @@ static void ssh2_msg_global_request(Ssh ssh, PktIn *pktin) } } -struct X11FakeAuth *ssh_sharing_add_x11_display(Ssh ssh, int authtype, - void *share_cs, - void *share_chan) +struct X11FakeAuth *ssh_sharing_add_x11_display( + Ssh ssh, int authtype, ssh_sharing_connstate *share_cs, + share_channel *share_chan) { struct X11FakeAuth *auth; @@ -7876,7 +7878,8 @@ static void ssh2_msg_channel_open(Ssh ssh, PktIn *pktin) } void sshfwd_x11_sharing_handover(struct ssh_channel *c, - void *share_cs, void *share_chan, + ssh_sharing_connstate *share_cs, + share_channel *share_chan, const char *peer_addr, int peer_port, int endian, int protomajor, int protominor, const void *initial_data, int initial_len) @@ -11173,7 +11176,7 @@ static void ssh_special(Backend *be, Telnet_Special code) } } -unsigned ssh_alloc_sharing_channel(Ssh ssh, void *sharing_ctx) +unsigned ssh_alloc_sharing_channel(Ssh ssh, ssh_sharing_connstate *connstate) { struct ssh_channel *c; c = snew(struct ssh_channel); @@ -11181,7 +11184,7 @@ unsigned ssh_alloc_sharing_channel(Ssh ssh, void *sharing_ctx) c->ssh = ssh; ssh_channel_init(c); c->chan = NULL; - c->sharectx = sharing_ctx; + c->sharectx = connstate; return c->localid; } diff --git a/ssh.h b/ssh.h index 82810d78..4fee36bf 100644 --- a/ssh.h +++ b/ssh.h @@ -16,7 +16,8 @@ extern void sshfwd_unthrottle(struct ssh_channel *c, int bufsize); Conf *sshfwd_get_conf(struct ssh_channel *c); void sshfwd_window_override_removed(struct ssh_channel *c); void sshfwd_x11_sharing_handover(struct ssh_channel *c, - void *share_cs, void *share_chan, + ssh_sharing_connstate *share_cs, + share_channel *share_chan, const char *peer_addr, int peer_port, int endian, int protomajor, int protominor, const void *initial_data, int initial_len); @@ -148,26 +149,28 @@ void ssh_free_pktout(PktOut *pkt); extern Socket ssh_connection_sharing_init( const char *host, int port, Conf *conf, Ssh ssh, Plug sshplug, - void **state); + ssh_sharing_state **state); int ssh_share_test_for_upstream(const char *host, int port, Conf *conf); -void share_got_pkt_from_server(void *ctx, int type, +void share_got_pkt_from_server(ssh_sharing_connstate *ctx, int type, const void *pkt, int pktlen); -void share_activate(void *state, const char *server_verstring); -void sharestate_free(void *state); -int share_ndownstreams(void *state); +void share_activate(ssh_sharing_state *sharestate, + const char *server_verstring); +void sharestate_free(ssh_sharing_state *state); +int share_ndownstreams(ssh_sharing_state *state); void ssh_connshare_log(Ssh ssh, int event, const char *logtext, const char *ds_err, const char *us_err); -unsigned ssh_alloc_sharing_channel(Ssh ssh, void *sharing_ctx); +unsigned ssh_alloc_sharing_channel(Ssh ssh, ssh_sharing_connstate *connstate); void ssh_delete_sharing_channel(Ssh ssh, unsigned localid); int ssh_alloc_sharing_rportfwd(Ssh ssh, const char *shost, int sport, - void *share_ctx); + ssh_sharing_connstate *connstate); void ssh_remove_sharing_rportfwd(Ssh ssh, const char *shost, int sport, - void *share_ctx); -void ssh_sharing_queue_global_request(Ssh ssh, void *share_ctx); -struct X11FakeAuth *ssh_sharing_add_x11_display(Ssh ssh, int authtype, - void *share_cs, - void *share_chan); + ssh_sharing_connstate *connstate); +void ssh_sharing_queue_global_request( + Ssh ssh, ssh_sharing_connstate *connstate); +struct X11FakeAuth *ssh_sharing_add_x11_display( + Ssh ssh, int authtype, ssh_sharing_connstate *share_cs, + share_channel *share_chan); void ssh_sharing_remove_x11_display(Ssh ssh, struct X11FakeAuth *auth); void ssh_send_packet_from_downstream(Ssh ssh, unsigned id, int type, const void *pkt, int pktlen, @@ -177,7 +180,7 @@ void ssh_sharing_downstream_connected(Ssh ssh, unsigned id, void ssh_sharing_downstream_disconnected(Ssh ssh, unsigned id); void ssh_sharing_logf(Ssh ssh, unsigned id, const char *logfmt, ...); int ssh_agent_forwarding_permitted(Ssh ssh); -void share_setup_x11_channel(void *csv, void *chanv, +void share_setup_x11_channel(ssh_sharing_connstate *cs, share_channel *chan, unsigned upstream_id, unsigned server_id, unsigned server_currwin, unsigned server_maxpkt, unsigned client_adjusted_window, @@ -727,7 +730,8 @@ struct X11FakeAuth { * What to do with an X connection matching this auth data. */ struct X11Display *disp; - void *share_cs, *share_chan; + ssh_sharing_connstate *share_cs; + share_channel *share_chan; }; void *x11_make_greeting(int endian, int protomajor, int protominor, int auth_proto, const void *auth_data, int auth_len, diff --git a/sshshare.c b/sshshare.c index 30fe7360..22611e7d 100644 --- a/sshshare.c +++ b/sshshare.c @@ -507,9 +507,8 @@ static void share_connstate_free(struct ssh_sharing_connstate *cs) sfree(cs); } -void sharestate_free(void *v) +void sharestate_free(ssh_sharing_state *sharestate) { - struct ssh_sharing_state *sharestate = (struct ssh_sharing_state *)v; struct ssh_sharing_connstate *cs; platform_ssh_share_cleanup(sharestate->sockname); @@ -1061,7 +1060,7 @@ void share_xchannel_failure(struct ssh_sharing_connstate *cs, share_dead_xchannel_respond(cs, xc); } -void share_setup_x11_channel(void *csv, void *chanv, +void share_setup_x11_channel(ssh_sharing_connstate *cs, share_channel *chan, unsigned upstream_id, unsigned server_id, unsigned server_currwin, unsigned server_maxpkt, unsigned client_adjusted_window, @@ -1069,8 +1068,6 @@ void share_setup_x11_channel(void *csv, void *chanv, int protomajor, int protominor, const void *initial_data, int initial_len) { - struct ssh_sharing_connstate *cs = (struct ssh_sharing_connstate *)csv; - struct share_channel *chan = (struct share_channel *)chanv; struct share_xchannel *xc; void *greeting; int greeting_len; @@ -1128,11 +1125,10 @@ void share_setup_x11_channel(void *csv, void *chanv, } } -void share_got_pkt_from_server(void *csv, int type, +void share_got_pkt_from_server(ssh_sharing_connstate *cs, int type, const void *vpkt, int pktlen) { const unsigned char *pkt = (const unsigned char *)vpkt; - struct ssh_sharing_connstate *cs = (struct ssh_sharing_connstate *)csv; struct share_globreq *globreq; size_t id_pos; unsigned upstream_id, server_id; @@ -1718,8 +1714,8 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs, static void share_receive(Plug plug, int urgent, char *data, int len) { - struct ssh_sharing_connstate *cs = FROMFIELD( - plug, struct ssh_sharing_connstate, plugvt); + ssh_sharing_connstate *cs = FROMFIELD( + plug, ssh_sharing_connstate, plugvt); static const char expected_verstring_prefix[] = "SSHCONNECTION@putty.projects.tartarus.org-2.0-"; unsigned char c; @@ -1795,8 +1791,8 @@ static void share_receive(Plug plug, int urgent, char *data, int len) static void share_sent(Plug plug, int bufsize) { - /* struct ssh_sharing_connstate *cs = FROMFIELD( - plug, struct ssh_sharing_connstate, plugvt); */ + /* ssh_sharing_connstate *cs = FROMFIELD( + plug, ssh_sharing_connstate, plugvt); */ /* * We do nothing here, because we expect that there won't be a @@ -1811,8 +1807,7 @@ static void share_sent(Plug plug, int bufsize) static void share_listen_closing(Plug plug, const char *error_msg, int error_code, int calling_back) { - struct ssh_sharing_state *sharestate = FROMFIELD( - plug, struct ssh_sharing_state, plugvt); + ssh_sharing_state *sharestate = FROMFIELD(plug, ssh_sharing_state, plugvt); if (error_msg) ssh_sharing_logf(sharestate->ssh, 0, "listening socket: %s", error_msg); @@ -1820,7 +1815,7 @@ static void share_listen_closing(Plug plug, const char *error_msg, sharestate->listensock = NULL; } -static void share_send_verstring(struct ssh_sharing_connstate *cs) +static void share_send_verstring(ssh_sharing_connstate *cs) { char *fullstring = dupcat("SSHCONNECTION@putty.projects.tartarus.org-2.0-", cs->parent->server_verstring, "\015\012", NULL); @@ -1830,19 +1825,18 @@ static void share_send_verstring(struct ssh_sharing_connstate *cs) cs->sent_verstring = TRUE; } -int share_ndownstreams(void *state) +int share_ndownstreams(ssh_sharing_state *sharestate) { - struct ssh_sharing_state *sharestate = (struct ssh_sharing_state *)state; return count234(sharestate->connections); } -void share_activate(void *state, const char *server_verstring) +void share_activate(ssh_sharing_state *sharestate, + const char *server_verstring) { /* * Indication from ssh.c that we are now ready to begin serving * any downstreams that have already connected to us. */ - struct ssh_sharing_state *sharestate = (struct ssh_sharing_state *)state; struct ssh_sharing_connstate *cs; int i; @@ -2028,7 +2022,7 @@ static const Plug_vtable ssh_sharing_listen_plugvt = { */ Socket ssh_connection_sharing_init(const char *host, int port, Conf *conf, Ssh ssh, Plug sshplug, - void **state) + ssh_sharing_state **state) { int result, can_upstream, can_downstream; char *logtext, *ds_err, *us_err; diff --git a/unix/uxpgnt.c b/unix/uxpgnt.c index a694bc44..efd93726 100644 --- a/unix/uxpgnt.c +++ b/unix/uxpgnt.c @@ -168,7 +168,8 @@ int chan_no_eager_close(Channel *chan, int s, int r) { return FALSE; } Conf *sshfwd_get_conf(struct ssh_channel *c) { return NULL; } void sshfwd_x11_sharing_handover(struct ssh_channel *c, - void *share_cs, void *share_chan, + ssh_sharing_connstate *share_cs, + share_channel *share_chan, const char *peer_addr, int peer_port, int endian, int protomajor, int protominor, const void *initial_data, int initial_len) {} diff --git a/x11fwd.c b/x11fwd.c index 419d4968..f3ea5397 100644 --- a/x11fwd.c +++ b/x11fwd.c @@ -128,7 +128,8 @@ struct X11FakeAuth *x11_invent_fake_auth(tree234 *authtree, int authtype) auth->data[i]); auth->disp = NULL; - auth->share_cs = auth->share_chan = NULL; + auth->share_cs = NULL; + auth->share_chan = NULL; return auth; } From fc375c0b6ad8a7a088e5f3144fe32fbf74232ec3 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Thu, 13 Sep 2018 12:33:26 +0100 Subject: [PATCH 396/607] Remove some redundant utility macros. ATOFFSET in dialog.h became obsolete when the old 'struct Config' gave way to the new Conf, because its only use was to identify fields in struct Config for the generic control handlers to update. And lenof in ssh.h is redundant because there's also a copy in misc.h. (Which is already included _everywhere_ that lenof is used - I didn't even need to add any instances of #include "misc.h" after removing the copy in ssh.h.) --- dialog.h | 6 ------ ssh.h | 7 ------- 2 files changed, 13 deletions(-) diff --git a/dialog.h b/dialog.h index 9ac355c6..68f7dff1 100644 --- a/dialog.h +++ b/dialog.h @@ -2,12 +2,6 @@ * Exports and types from dialog.c. */ -/* - * This will come in handy for generic control handlers. Anyone - * knows how to make this more portable, let me know :-) - */ -#define ATOFFSET(data, offset) ( (void *) ( (char *)(data) + (offset) ) ) - /* * This is the big union which defines a single control, of any * type. diff --git a/ssh.h b/ssh.h index 4fee36bf..2d285d23 100644 --- a/ssh.h +++ b/ssh.h @@ -190,13 +190,6 @@ void share_setup_x11_channel(ssh_sharing_connstate *cs, share_channel *chan, Frontend *ssh_get_frontend(Ssh ssh); -/* - * Useful thing. - */ -#ifndef lenof -#define lenof(x) ( (sizeof((x))) / (sizeof(*(x)))) -#endif - #define SSH_CIPHER_IDEA 1 #define SSH_CIPHER_DES 2 #define SSH_CIPHER_3DES 3 From 3aae1f9d762497cd182f6c7e45981560e0694f9f Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Thu, 13 Sep 2018 12:58:44 +0100 Subject: [PATCH 397/607] Expose the structure tag 'dlgparam'. This continues my ongoing crusade against dangerous 'void *' parameters. --- config.c | 52 ++++++++++----------- defs.h | 2 + dialog.h | 62 ++++++++++++------------- putty.h | 10 ++-- sercfg.c | 6 +-- unix/gtkcfg.c | 2 +- unix/gtkdlg.c | 112 +++++++++++++++++---------------------------- windows/wincfg.c | 6 +-- windows/winctrls.c | 99 +++++++++++++-------------------------- windows/winstuff.h | 6 +-- 10 files changed, 150 insertions(+), 207 deletions(-) diff --git a/config.c b/config.c index fac7dc3d..bdffd6bb 100644 --- a/config.c +++ b/config.c @@ -15,7 +15,7 @@ #define HOST_BOX_TITLE "Host Name (or IP address)" #define PORT_BOX_TITLE "Port" -void conf_radiobutton_handler(union control *ctrl, void *dlg, +void conf_radiobutton_handler(union control *ctrl, dlgparam *dlg, void *data, int event) { int button; @@ -44,7 +44,7 @@ void conf_radiobutton_handler(union control *ctrl, void *dlg, } #define CHECKBOX_INVERT (1<<30) -void conf_checkbox_handler(union control *ctrl, void *dlg, +void conf_checkbox_handler(union control *ctrl, dlgparam *dlg, void *data, int event) { int key, invert; @@ -75,7 +75,7 @@ void conf_checkbox_handler(union control *ctrl, void *dlg, } } -void conf_editbox_handler(union control *ctrl, void *dlg, +void conf_editbox_handler(union control *ctrl, dlgparam *dlg, void *data, int event) { /* @@ -124,7 +124,7 @@ void conf_editbox_handler(union control *ctrl, void *dlg, } } -void conf_filesel_handler(union control *ctrl, void *dlg, +void conf_filesel_handler(union control *ctrl, dlgparam *dlg, void *data, int event) { int key = ctrl->fileselect.context.i; @@ -139,7 +139,7 @@ void conf_filesel_handler(union control *ctrl, void *dlg, } } -void conf_fontsel_handler(union control *ctrl, void *dlg, +void conf_fontsel_handler(union control *ctrl, dlgparam *dlg, void *data, int event) { int key = ctrl->fontselect.context.i; @@ -154,7 +154,7 @@ void conf_fontsel_handler(union control *ctrl, void *dlg, } } -static void config_host_handler(union control *ctrl, void *dlg, +static void config_host_handler(union control *ctrl, dlgparam *dlg, void *data, int event) { Conf *conf = (Conf *)data; @@ -186,7 +186,7 @@ static void config_host_handler(union control *ctrl, void *dlg, } } -static void config_port_handler(union control *ctrl, void *dlg, +static void config_port_handler(union control *ctrl, dlgparam *dlg, void *data, int event) { Conf *conf = (Conf *)data; @@ -235,7 +235,7 @@ struct hostport { * routines can use it to conveniently identify the protocol radio * buttons in order to add to them. */ -void config_protocolbuttons_handler(union control *ctrl, void *dlg, +void config_protocolbuttons_handler(union control *ctrl, dlgparam *dlg, void *data, int event) { int button; @@ -289,7 +289,7 @@ void config_protocolbuttons_handler(union control *ctrl, void *dlg, } } -static void loggingbuttons_handler(union control *ctrl, void *dlg, +static void loggingbuttons_handler(union control *ctrl, dlgparam *dlg, void *data, int event) { int button; @@ -318,7 +318,7 @@ static void loggingbuttons_handler(union control *ctrl, void *dlg, } } -static void numeric_keypad_handler(union control *ctrl, void *dlg, +static void numeric_keypad_handler(union control *ctrl, dlgparam *dlg, void *data, int event) { int button; @@ -349,7 +349,7 @@ static void numeric_keypad_handler(union control *ctrl, void *dlg, } } -static void cipherlist_handler(union control *ctrl, void *dlg, +static void cipherlist_handler(union control *ctrl, dlgparam *dlg, void *data, int event) { Conf *conf = (Conf *)data; @@ -395,7 +395,7 @@ static void cipherlist_handler(union control *ctrl, void *dlg, } #ifndef NO_GSSAPI -static void gsslist_handler(union control *ctrl, void *dlg, +static void gsslist_handler(union control *ctrl, dlgparam *dlg, void *data, int event) { Conf *conf = (Conf *)data; @@ -422,7 +422,7 @@ static void gsslist_handler(union control *ctrl, void *dlg, } #endif -static void kexlist_handler(union control *ctrl, void *dlg, +static void kexlist_handler(union control *ctrl, dlgparam *dlg, void *data, int event) { Conf *conf = (Conf *)data; @@ -466,7 +466,7 @@ static void kexlist_handler(union control *ctrl, void *dlg, } } -static void hklist_handler(union control *ctrl, void *dlg, +static void hklist_handler(union control *ctrl, dlgparam *dlg, void *data, int event) { Conf *conf = (Conf *)data; @@ -509,7 +509,7 @@ static void hklist_handler(union control *ctrl, void *dlg, } } -static void printerbox_handler(union control *ctrl, void *dlg, +static void printerbox_handler(union control *ctrl, dlgparam *dlg, void *data, int event) { Conf *conf = (Conf *)data; @@ -545,7 +545,7 @@ static void printerbox_handler(union control *ctrl, void *dlg, } } -static void codepage_handler(union control *ctrl, void *dlg, +static void codepage_handler(union control *ctrl, dlgparam *dlg, void *data, int event) { Conf *conf = (Conf *)data; @@ -569,7 +569,7 @@ static void codepage_handler(union control *ctrl, void *dlg, } } -static void sshbug_handler(union control *ctrl, void *dlg, +static void sshbug_handler(union control *ctrl, dlgparam *dlg, void *data, int event) { Conf *conf = (Conf *)data; @@ -624,7 +624,7 @@ static void sessionsaver_data_free(void *ssdv) * failure. */ static int load_selected_session(struct sessionsaver_data *ssd, - void *dlg, Conf *conf, int *maybe_launch) + dlgparam *dlg, Conf *conf, int *maybe_launch) { int i = dlg_listbox_index(ssd->listbox, dlg); int isdef; @@ -645,7 +645,7 @@ static int load_selected_session(struct sessionsaver_data *ssd, return 1; } -static void sessionsaver_handler(union control *ctrl, void *dlg, +static void sessionsaver_handler(union control *ctrl, dlgparam *dlg, void *data, int event) { Conf *conf = (Conf *)data; @@ -786,7 +786,7 @@ struct charclass_data { union control *listbox, *editbox, *button; }; -static void charclass_handler(union control *ctrl, void *dlg, +static void charclass_handler(union control *ctrl, dlgparam *dlg, void *data, int event) { Conf *conf = (Conf *)data; @@ -841,7 +841,7 @@ static const char *const colours[] = { "ANSI White", "ANSI White Bold" }; -static void colour_handler(union control *ctrl, void *dlg, +static void colour_handler(union control *ctrl, dlgparam *dlg, void *data, int event) { Conf *conf = (Conf *)data; @@ -949,7 +949,7 @@ struct ttymodes_data { union control *valradio, *valbox, *setbutton, *listbox; }; -static void ttymodes_handler(union control *ctrl, void *dlg, +static void ttymodes_handler(union control *ctrl, dlgparam *dlg, void *data, int event) { Conf *conf = (Conf *)data; @@ -1034,7 +1034,7 @@ struct environ_data { union control *varbox, *valbox, *addbutton, *rembutton, *listbox; }; -static void environ_handler(union control *ctrl, void *dlg, +static void environ_handler(union control *ctrl, dlgparam *dlg, void *data, int event) { Conf *conf = (Conf *)data; @@ -1110,7 +1110,7 @@ struct portfwd_data { #endif }; -static void portfwd_handler(union control *ctrl, void *dlg, +static void portfwd_handler(union control *ctrl, dlgparam *dlg, void *data, int event) { Conf *conf = (Conf *)data; @@ -1274,7 +1274,7 @@ struct manual_hostkey_data { union control *addbutton, *rembutton, *listbox, *keybox; }; -static void manual_hostkey_handler(union control *ctrl, void *dlg, +static void manual_hostkey_handler(union control *ctrl, dlgparam *dlg, void *data, int event) { Conf *conf = (Conf *)data; @@ -1337,7 +1337,7 @@ static void manual_hostkey_handler(union control *ctrl, void *dlg, } } -static void clipboard_selector_handler(union control *ctrl, void *dlg, +static void clipboard_selector_handler(union control *ctrl, dlgparam *dlg, void *data, int event) { Conf *conf = (Conf *)data; diff --git a/defs.h b/defs.h index 329883d9..1bc8f9b8 100644 --- a/defs.h +++ b/defs.h @@ -59,6 +59,8 @@ typedef struct ssh_sharing_state ssh_sharing_state; typedef struct ssh_sharing_connstate ssh_sharing_connstate; typedef struct share_channel share_channel; +typedef struct dlgparam dlgparam; + /* Note indirection: for historical reasons (it used to be closer to * the OS socket type), the type that most code uses for a socket is * 'Socket', not 'Socket *'. So an implementation of Socket or Plug diff --git a/dialog.h b/dialog.h index 68f7dff1..4b708489 100644 --- a/dialog.h +++ b/dialog.h @@ -103,7 +103,7 @@ enum { EVENT_SELCHANGE, EVENT_CALLBACK }; -typedef void (*handler_fn)(union control *ctrl, void *dlg, +typedef void (*handler_fn)(union control *ctrl, dlgparam *dp, void *data, int event); #define STANDARD_PREFIX \ @@ -534,16 +534,16 @@ union control *ctrl_tabdelay(struct controlset *, union control *); * Routines the platform-independent dialog code can call to read * and write the values of controls. */ -void dlg_radiobutton_set(union control *ctrl, void *dlg, int whichbutton); -int dlg_radiobutton_get(union control *ctrl, void *dlg); -void dlg_checkbox_set(union control *ctrl, void *dlg, int checked); -int dlg_checkbox_get(union control *ctrl, void *dlg); -void dlg_editbox_set(union control *ctrl, void *dlg, char const *text); -char *dlg_editbox_get(union control *ctrl, void *dlg); /* result must be freed by caller */ +void dlg_radiobutton_set(union control *ctrl, dlgparam *dp, int whichbutton); +int dlg_radiobutton_get(union control *ctrl, dlgparam *dp); +void dlg_checkbox_set(union control *ctrl, dlgparam *dp, int checked); +int dlg_checkbox_get(union control *ctrl, dlgparam *dp); +void dlg_editbox_set(union control *ctrl, dlgparam *dp, char const *text); +char *dlg_editbox_get(union control *ctrl, dlgparam *dp); /* result must be freed by caller */ /* The `listbox' functions can also apply to combo boxes. */ -void dlg_listbox_clear(union control *ctrl, void *dlg); -void dlg_listbox_del(union control *ctrl, void *dlg, int index); -void dlg_listbox_add(union control *ctrl, void *dlg, char const *text); +void dlg_listbox_clear(union control *ctrl, dlgparam *dp); +void dlg_listbox_del(union control *ctrl, dlgparam *dp, int index); +void dlg_listbox_add(union control *ctrl, dlgparam *dp, char const *text); /* * Each listbox entry may have a numeric id associated with it. * Note that some front ends only permit a string to be stored at @@ -551,53 +551,53 @@ void dlg_listbox_add(union control *ctrl, void *dlg, char const *text); * strings in any listbox then you MUST not assign them different * IDs and expect to get meaningful results back. */ -void dlg_listbox_addwithid(union control *ctrl, void *dlg, +void dlg_listbox_addwithid(union control *ctrl, dlgparam *dp, char const *text, int id); -int dlg_listbox_getid(union control *ctrl, void *dlg, int index); +int dlg_listbox_getid(union control *ctrl, dlgparam *dp, int index); /* dlg_listbox_index returns <0 if no single element is selected. */ -int dlg_listbox_index(union control *ctrl, void *dlg); -int dlg_listbox_issel(union control *ctrl, void *dlg, int index); -void dlg_listbox_select(union control *ctrl, void *dlg, int index); -void dlg_text_set(union control *ctrl, void *dlg, char const *text); -void dlg_filesel_set(union control *ctrl, void *dlg, Filename *fn); -Filename *dlg_filesel_get(union control *ctrl, void *dlg); -void dlg_fontsel_set(union control *ctrl, void *dlg, FontSpec *fn); -FontSpec *dlg_fontsel_get(union control *ctrl, void *dlg); +int dlg_listbox_index(union control *ctrl, dlgparam *dp); +int dlg_listbox_issel(union control *ctrl, dlgparam *dp, int index); +void dlg_listbox_select(union control *ctrl, dlgparam *dp, int index); +void dlg_text_set(union control *ctrl, dlgparam *dp, char const *text); +void dlg_filesel_set(union control *ctrl, dlgparam *dp, Filename *fn); +Filename *dlg_filesel_get(union control *ctrl, dlgparam *dp); +void dlg_fontsel_set(union control *ctrl, dlgparam *dp, FontSpec *fn); +FontSpec *dlg_fontsel_get(union control *ctrl, dlgparam *dp); /* * Bracketing a large set of updates in these two functions will * cause the front end (if possible) to delay updating the screen * until it's all complete, thus avoiding flicker. */ -void dlg_update_start(union control *ctrl, void *dlg); -void dlg_update_done(union control *ctrl, void *dlg); +void dlg_update_start(union control *ctrl, dlgparam *dp); +void dlg_update_done(union control *ctrl, dlgparam *dp); /* * Set input focus into a particular control. */ -void dlg_set_focus(union control *ctrl, void *dlg); +void dlg_set_focus(union control *ctrl, dlgparam *dp); /* * Change the label text on a control. */ -void dlg_label_change(union control *ctrl, void *dlg, char const *text); +void dlg_label_change(union control *ctrl, dlgparam *dp, char const *text); /* * Return the `ctrl' structure for the most recent control that had * the input focus apart from the one mentioned. This is NOT * GUARANTEED to work on all platforms, so don't base any critical * functionality on it! */ -union control *dlg_last_focused(union control *ctrl, void *dlg); +union control *dlg_last_focused(union control *ctrl, dlgparam *dp); /* * During event processing, you might well want to give an error * indication to the user. dlg_beep() is a quick and easy generic * error; dlg_error() puts up a message-box or equivalent. */ -void dlg_beep(void *dlg); -void dlg_error_msg(void *dlg, const char *msg); +void dlg_beep(dlgparam *dp); +void dlg_error_msg(dlgparam *dp, const char *msg); /* * This function signals to the front end that the dialog's * processing is completed, and passes an integer value (typically * a success status). */ -void dlg_end(void *dlg, int value); +void dlg_end(dlgparam *dp, int value); /* * Routines to manage a (per-platform) colour selector. @@ -612,9 +612,9 @@ void dlg_end(void *dlg, int value); * dlg_coloursel_start() accepts an RGB triple which is used to * initialise the colour selector to its starting value. */ -void dlg_coloursel_start(union control *ctrl, void *dlg, +void dlg_coloursel_start(union control *ctrl, dlgparam *dp, int r, int g, int b); -int dlg_coloursel_results(union control *ctrl, void *dlg, +int dlg_coloursel_results(union control *ctrl, dlgparam *dp, int *r, int *g, int *b); /* @@ -626,7 +626,7 @@ int dlg_coloursel_results(union control *ctrl, void *dlg, * If `ctrl' is NULL, _all_ controls in the dialog get refreshed * (for loading or saving entire sets of settings). */ -void dlg_refresh(union control *ctrl, void *dlg); +void dlg_refresh(union control *ctrl, dlgparam *dp); /* * Standard helper functions for reading a controlbox structure. diff --git a/putty.h b/putty.h index 1a8c30ce..7b1f90e4 100644 --- a/putty.h +++ b/putty.h @@ -1421,16 +1421,16 @@ void cmdline_error(const char *, ...); */ struct controlbox; union control; -void conf_radiobutton_handler(union control *ctrl, void *dlg, +void conf_radiobutton_handler(union control *ctrl, dlgparam *dlg, void *data, int event); #define CHECKBOX_INVERT (1<<30) -void conf_checkbox_handler(union control *ctrl, void *dlg, +void conf_checkbox_handler(union control *ctrl, dlgparam *dlg, void *data, int event); -void conf_editbox_handler(union control *ctrl, void *dlg, +void conf_editbox_handler(union control *ctrl, dlgparam *dlg, void *data, int event); -void conf_filesel_handler(union control *ctrl, void *dlg, +void conf_filesel_handler(union control *ctrl, dlgparam *dlg, void *data, int event); -void conf_fontsel_handler(union control *ctrl, void *dlg, +void conf_fontsel_handler(union control *ctrl, dlgparam *dlg, void *data, int event); void setup_config_box(struct controlbox *b, int midsession, int protocol, int protcfginfo); diff --git a/sercfg.c b/sercfg.c index fef910f3..71462100 100644 --- a/sercfg.c +++ b/sercfg.c @@ -16,7 +16,7 @@ #include "dialog.h" #include "storage.h" -static void serial_parity_handler(union control *ctrl, void *dlg, +static void serial_parity_handler(union control *ctrl, dlgparam *dlg, void *data, int event) { static const struct { @@ -71,7 +71,7 @@ static void serial_parity_handler(union control *ctrl, void *dlg, } } -static void serial_flow_handler(union control *ctrl, void *dlg, +static void serial_flow_handler(union control *ctrl, dlgparam *dlg, void *data, int event) { static const struct { @@ -132,7 +132,7 @@ void ser_setup_config_box(struct controlbox *b, int midsession, if (!midsession) { int i; - extern void config_protocolbuttons_handler(union control *, void *, + extern void config_protocolbuttons_handler(union control *, dlgparam *, void *, int); /* diff --git a/unix/gtkcfg.c b/unix/gtkcfg.c index 4307176f..bbde8d2a 100644 --- a/unix/gtkcfg.c +++ b/unix/gtkcfg.c @@ -10,7 +10,7 @@ #include "dialog.h" #include "storage.h" -static void about_handler(union control *ctrl, void *dlg, +static void about_handler(union control *ctrl, dlgparam *dlg, void *data, int event) { if (event == EVENT_ACTION) { diff --git a/unix/gtkdlg.c b/unix/gtkdlg.c index f1425daf..6ffb5b5c 100644 --- a/unix/gtkdlg.c +++ b/unix/gtkdlg.c @@ -252,27 +252,24 @@ static struct uctrl *dlg_find_bywidget(struct dlgparam *dp, GtkWidget *w) return ret; } -union control *dlg_last_focused(union control *ctrl, void *dlg) +union control *dlg_last_focused(union control *ctrl, dlgparam *dp) { - struct dlgparam *dp = (struct dlgparam *)dlg; if (dp->currfocus != ctrl) return dp->currfocus; else return dp->lastfocus; } -void dlg_radiobutton_set(union control *ctrl, void *dlg, int which) +void dlg_radiobutton_set(union control *ctrl, dlgparam *dp, int which) { - struct dlgparam *dp = (struct dlgparam *)dlg; struct uctrl *uc = dlg_find_byctrl(dp, ctrl); assert(uc->ctrl->generic.type == CTRL_RADIO); assert(uc->buttons != NULL); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(uc->buttons[which]), TRUE); } -int dlg_radiobutton_get(union control *ctrl, void *dlg) +int dlg_radiobutton_get(union control *ctrl, dlgparam *dp) { - struct dlgparam *dp = (struct dlgparam *)dlg; struct uctrl *uc = dlg_find_byctrl(dp, ctrl); int i; @@ -284,25 +281,22 @@ int dlg_radiobutton_get(union control *ctrl, void *dlg) return 0; /* got to return something */ } -void dlg_checkbox_set(union control *ctrl, void *dlg, int checked) +void dlg_checkbox_set(union control *ctrl, dlgparam *dp, int checked) { - struct dlgparam *dp = (struct dlgparam *)dlg; struct uctrl *uc = dlg_find_byctrl(dp, ctrl); assert(uc->ctrl->generic.type == CTRL_CHECKBOX); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(uc->toplevel), checked); } -int dlg_checkbox_get(union control *ctrl, void *dlg) +int dlg_checkbox_get(union control *ctrl, dlgparam *dp) { - struct dlgparam *dp = (struct dlgparam *)dlg; struct uctrl *uc = dlg_find_byctrl(dp, ctrl); assert(uc->ctrl->generic.type == CTRL_CHECKBOX); return gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(uc->toplevel)); } -void dlg_editbox_set(union control *ctrl, void *dlg, char const *text) +void dlg_editbox_set(union control *ctrl, dlgparam *dp, char const *text) { - struct dlgparam *dp = (struct dlgparam *)dlg; struct uctrl *uc = dlg_find_byctrl(dp, ctrl); GtkWidget *entry; char *tmpstring; @@ -339,9 +333,8 @@ void dlg_editbox_set(union control *ctrl, void *dlg, char const *text) sfree(tmpstring); } -char *dlg_editbox_get(union control *ctrl, void *dlg) +char *dlg_editbox_get(union control *ctrl, dlgparam *dp) { - struct dlgparam *dp = (struct dlgparam *)dlg; struct uctrl *uc = dlg_find_byctrl(dp, ctrl); assert(uc->ctrl->generic.type == CTRL_EDITBOX); @@ -369,9 +362,8 @@ static void container_remove_and_destroy(GtkWidget *w, gpointer data) #endif /* The `listbox' functions can also apply to combo boxes. */ -void dlg_listbox_clear(union control *ctrl, void *dlg) +void dlg_listbox_clear(union control *ctrl, dlgparam *dp) { - struct dlgparam *dp = (struct dlgparam *)dlg; struct uctrl *uc = dlg_find_byctrl(dp, ctrl); assert(uc->ctrl->generic.type == CTRL_EDITBOX || @@ -398,9 +390,8 @@ void dlg_listbox_clear(union control *ctrl, void *dlg) assert(!"We shouldn't get here"); } -void dlg_listbox_del(union control *ctrl, void *dlg, int index) +void dlg_listbox_del(union control *ctrl, dlgparam *dp, int index) { - struct dlgparam *dp = (struct dlgparam *)dlg; struct uctrl *uc = dlg_find_byctrl(dp, ctrl); assert(uc->ctrl->generic.type == CTRL_EDITBOX || @@ -433,9 +424,9 @@ void dlg_listbox_del(union control *ctrl, void *dlg, int index) assert(!"We shouldn't get here"); } -void dlg_listbox_add(union control *ctrl, void *dlg, char const *text) +void dlg_listbox_add(union control *ctrl, dlgparam *dp, char const *text) { - dlg_listbox_addwithid(ctrl, dlg, text, 0); + dlg_listbox_addwithid(ctrl, dp, text, 0); } /* @@ -445,10 +436,9 @@ void dlg_listbox_add(union control *ctrl, void *dlg, char const *text) * strings in any listbox then you MUST not assign them different * IDs and expect to get meaningful results back. */ -void dlg_listbox_addwithid(union control *ctrl, void *dlg, +void dlg_listbox_addwithid(union control *ctrl, dlgparam *dp, char const *text, int id) { - struct dlgparam *dp = (struct dlgparam *)dlg; struct uctrl *uc = dlg_find_byctrl(dp, ctrl); assert(uc->ctrl->generic.type == CTRL_EDITBOX || @@ -594,9 +584,8 @@ void dlg_listbox_addwithid(union control *ctrl, void *dlg, dp->flags &= ~FLAG_UPDATING_COMBO_LIST; } -int dlg_listbox_getid(union control *ctrl, void *dlg, int index) +int dlg_listbox_getid(union control *ctrl, dlgparam *dp, int index) { - struct dlgparam *dp = (struct dlgparam *)dlg; struct uctrl *uc = dlg_find_byctrl(dp, ctrl); assert(uc->ctrl->generic.type == CTRL_EDITBOX || @@ -634,9 +623,8 @@ int dlg_listbox_getid(union control *ctrl, void *dlg, int index) } /* dlg_listbox_index returns <0 if no single element is selected. */ -int dlg_listbox_index(union control *ctrl, void *dlg) +int dlg_listbox_index(union control *ctrl, dlgparam *dp) { - struct dlgparam *dp = (struct dlgparam *)dlg; struct uctrl *uc = dlg_find_byctrl(dp, ctrl); assert(uc->ctrl->generic.type == CTRL_EDITBOX || @@ -719,9 +707,8 @@ int dlg_listbox_index(union control *ctrl, void *dlg) return -1; /* placate dataflow analysis */ } -int dlg_listbox_issel(union control *ctrl, void *dlg, int index) +int dlg_listbox_issel(union control *ctrl, dlgparam *dp, int index) { - struct dlgparam *dp = (struct dlgparam *)dlg; struct uctrl *uc = dlg_find_byctrl(dp, ctrl); assert(uc->ctrl->generic.type == CTRL_EDITBOX || @@ -777,9 +764,8 @@ int dlg_listbox_issel(union control *ctrl, void *dlg, int index) return -1; /* placate dataflow analysis */ } -void dlg_listbox_select(union control *ctrl, void *dlg, int index) +void dlg_listbox_select(union control *ctrl, dlgparam *dp, int index) { - struct dlgparam *dp = (struct dlgparam *)dlg; struct uctrl *uc = dlg_find_byctrl(dp, ctrl); assert(uc->ctrl->generic.type == CTRL_EDITBOX || @@ -846,9 +832,8 @@ void dlg_listbox_select(union control *ctrl, void *dlg, int index) assert(!"We shouldn't get here"); } -void dlg_text_set(union control *ctrl, void *dlg, char const *text) +void dlg_text_set(union control *ctrl, dlgparam *dp, char const *text) { - struct dlgparam *dp = (struct dlgparam *)dlg; struct uctrl *uc = dlg_find_byctrl(dp, ctrl); assert(uc->ctrl->generic.type == CTRL_TEXT); @@ -857,9 +842,8 @@ void dlg_text_set(union control *ctrl, void *dlg, char const *text) gtk_label_set_text(GTK_LABEL(uc->text), text); } -void dlg_label_change(union control *ctrl, void *dlg, char const *text) +void dlg_label_change(union control *ctrl, dlgparam *dp, char const *text) { - struct dlgparam *dp = (struct dlgparam *)dlg; struct uctrl *uc = dlg_find_byctrl(dp, ctrl); switch (uc->ctrl->generic.type) { @@ -897,9 +881,8 @@ void dlg_label_change(union control *ctrl, void *dlg, char const *text) } } -void dlg_filesel_set(union control *ctrl, void *dlg, Filename *fn) +void dlg_filesel_set(union control *ctrl, dlgparam *dp, Filename *fn) { - struct dlgparam *dp = (struct dlgparam *)dlg; struct uctrl *uc = dlg_find_byctrl(dp, ctrl); /* We must copy fn->path before passing it to gtk_entry_set_text. * See comment in dlg_editbox_set() for the reasons. */ @@ -910,18 +893,16 @@ void dlg_filesel_set(union control *ctrl, void *dlg, Filename *fn) sfree(duppath); } -Filename *dlg_filesel_get(union control *ctrl, void *dlg) +Filename *dlg_filesel_get(union control *ctrl, dlgparam *dp) { - struct dlgparam *dp = (struct dlgparam *)dlg; struct uctrl *uc = dlg_find_byctrl(dp, ctrl); assert(uc->ctrl->generic.type == CTRL_FILESELECT); assert(uc->entry != NULL); return filename_from_str(gtk_entry_get_text(GTK_ENTRY(uc->entry))); } -void dlg_fontsel_set(union control *ctrl, void *dlg, FontSpec *fs) +void dlg_fontsel_set(union control *ctrl, dlgparam *dp, FontSpec *fs) { - struct dlgparam *dp = (struct dlgparam *)dlg; struct uctrl *uc = dlg_find_byctrl(dp, ctrl); /* We must copy fs->name before passing it to gtk_entry_set_text. * See comment in dlg_editbox_set() for the reasons. */ @@ -932,9 +913,8 @@ void dlg_fontsel_set(union control *ctrl, void *dlg, FontSpec *fs) sfree(dupname); } -FontSpec *dlg_fontsel_get(union control *ctrl, void *dlg) +FontSpec *dlg_fontsel_get(union control *ctrl, dlgparam *dp) { - struct dlgparam *dp = (struct dlgparam *)dlg; struct uctrl *uc = dlg_find_byctrl(dp, ctrl); assert(uc->ctrl->generic.type == CTRL_FONTSELECT); assert(uc->entry != NULL); @@ -946,7 +926,7 @@ FontSpec *dlg_fontsel_get(union control *ctrl, void *dlg) * cause the front end (if possible) to delay updating the screen * until it's all complete, thus avoiding flicker. */ -void dlg_update_start(union control *ctrl, void *dlg) +void dlg_update_start(union control *ctrl, dlgparam *dp) { /* * Apparently we can't do this at all in GTK. GtkCList supports @@ -954,7 +934,7 @@ void dlg_update_start(union control *ctrl, void *dlg) */ } -void dlg_update_done(union control *ctrl, void *dlg) +void dlg_update_done(union control *ctrl, dlgparam *dp) { /* * Apparently we can't do this at all in GTK. GtkCList supports @@ -962,9 +942,8 @@ void dlg_update_done(union control *ctrl, void *dlg) */ } -void dlg_set_focus(union control *ctrl, void *dlg) +void dlg_set_focus(union control *ctrl, dlgparam *dp) { - struct dlgparam *dp = (struct dlgparam *)dlg; struct uctrl *uc = dlg_find_byctrl(dp, ctrl); switch (ctrl->generic.type) { @@ -1039,7 +1018,7 @@ void dlg_set_focus(union control *ctrl, void *dlg) * indication to the user. dlg_beep() is a quick and easy generic * error; dlg_error() puts up a message-box or equivalent. */ -void dlg_beep(void *dlg) +void dlg_beep(dlgparam *dp) { gdk_display_beep(gdk_display_get_default()); } @@ -1079,9 +1058,8 @@ void trivial_post_dialog_fn(void *vctx, int result) { } -void dlg_error_msg(void *dlg, const char *msg) +void dlg_error_msg(dlgparam *dp, const char *msg) { - struct dlgparam *dp = (struct dlgparam *)dlg; create_message_box( dp->window, "Error", msg, string_width("Some sort of text about a config-box error message"), @@ -1093,16 +1071,14 @@ void dlg_error_msg(void *dlg, const char *msg) * processing is completed, and passes an integer value (typically * a success status). */ -void dlg_end(void *dlg, int value) +void dlg_end(dlgparam *dp, int value) { - struct dlgparam *dp = (struct dlgparam *)dlg; dp->retval = value; gtk_widget_destroy(dp->window); } -void dlg_refresh(union control *ctrl, void *dlg) +void dlg_refresh(union control *ctrl, dlgparam *dp) { - struct dlgparam *dp = (struct dlgparam *)dlg; struct uctrl *uc; if (ctrl) { @@ -1120,9 +1096,8 @@ void dlg_refresh(union control *ctrl, void *dlg) } } -void dlg_coloursel_start(union control *ctrl, void *dlg, int r, int g, int b) +void dlg_coloursel_start(union control *ctrl, dlgparam *dp, int r, int g, int b) { - struct dlgparam *dp = (struct dlgparam *)dlg; struct uctrl *uc = dlg_find_byctrl(dp, ctrl); #if GTK_CHECK_VERSION(3,0,0) @@ -1206,10 +1181,9 @@ void dlg_coloursel_start(union control *ctrl, void *dlg, int r, int g, int b) gtk_widget_show(coloursel); } -int dlg_coloursel_results(union control *ctrl, void *dlg, +int dlg_coloursel_results(union control *ctrl, dlgparam *dp, int *r, int *g, int *b) { - struct dlgparam *dp = (struct dlgparam *)dlg; if (dp->coloursel_result.ok) { *r = dp->coloursel_result.r; *g = dp->coloursel_result.g; @@ -3283,11 +3257,11 @@ static void dlgparam_destroy(GtkWidget *widget, gpointer data) sfree(dp); } -static void messagebox_handler(union control *ctrl, void *dlg, +static void messagebox_handler(union control *ctrl, dlgparam *dp, void *data, int event) { if (event == EVENT_ACTION) - dlg_end(dlg, ctrl->generic.context.i); + dlg_end(dp, ctrl->generic.context.i); } const struct message_box_button button_array_yn[] = { @@ -3806,13 +3780,13 @@ static void eventlog_destroy(GtkWidget *widget, gpointer data) dlg_cleanup(&es->dp); ctrl_free_box(es->eventbox); } -static void eventlog_ok_handler(union control *ctrl, void *dlg, +static void eventlog_ok_handler(union control *ctrl, dlgparam *dp, void *data, int event) { if (event == EVENT_ACTION) - dlg_end(dlg, 0); + dlg_end(dp, 0); } -static void eventlog_list_handler(union control *ctrl, void *dlg, +static void eventlog_list_handler(union control *ctrl, dlgparam *dp, void *data, int event) { struct eventlog_stuff *es = (struct eventlog_stuff *)data; @@ -3820,15 +3794,15 @@ static void eventlog_list_handler(union control *ctrl, void *dlg, if (event == EVENT_REFRESH) { int i; - dlg_update_start(ctrl, dlg); - dlg_listbox_clear(ctrl, dlg); + dlg_update_start(ctrl, dp); + dlg_listbox_clear(ctrl, dp); for (i = 0; i < es->ninitial; i++) { - dlg_listbox_add(ctrl, dlg, es->events_initial[i]); + dlg_listbox_add(ctrl, dp, es->events_initial[i]); } for (i = 0; i < es->ncircular; i++) { - dlg_listbox_add(ctrl, dlg, es->events_circular[(es->circular_first + i) % LOGEVENT_CIRCULAR_MAX]); + dlg_listbox_add(ctrl, dp, es->events_circular[(es->circular_first + i) % LOGEVENT_CIRCULAR_MAX]); } - dlg_update_done(ctrl, dlg); + dlg_update_done(ctrl, dp); } else if (event == EVENT_SELCHANGE) { int i; int selsize = 0; @@ -3849,7 +3823,7 @@ static void eventlog_list_handler(union control *ctrl, void *dlg, es->seldata = NULL; es->sellen = 0; for (i = 0; i < es->ninitial; i++) { - if (dlg_listbox_issel(ctrl, dlg, i)) { + if (dlg_listbox_issel(ctrl, dp, i)) { int extralen = strlen(es->events_initial[i]); if (es->sellen + extralen + 2 > selsize) { @@ -3863,7 +3837,7 @@ static void eventlog_list_handler(union control *ctrl, void *dlg, } } for (i = 0; i < es->ncircular; i++) { - if (dlg_listbox_issel(ctrl, dlg, es->ninitial + i)) { + if (dlg_listbox_issel(ctrl, dp, es->ninitial + i)) { int j = (es->circular_first + i) % LOGEVENT_CIRCULAR_MAX; int extralen = strlen(es->events_circular[j]); diff --git a/windows/wincfg.c b/windows/wincfg.c index 9e242875..8131883c 100644 --- a/windows/wincfg.c +++ b/windows/wincfg.c @@ -10,7 +10,7 @@ #include "dialog.h" #include "storage.h" -static void about_handler(union control *ctrl, void *dlg, +static void about_handler(union control *ctrl, dlgparam *dlg, void *data, int event) { HWND *hwndp = (HWND *)ctrl->generic.context.p; @@ -20,7 +20,7 @@ static void about_handler(union control *ctrl, void *dlg, } } -static void help_handler(union control *ctrl, void *dlg, +static void help_handler(union control *ctrl, dlgparam *dlg, void *data, int event) { HWND *hwndp = (HWND *)ctrl->generic.context.p; @@ -30,7 +30,7 @@ static void help_handler(union control *ctrl, void *dlg, } } -static void variable_pitch_handler(union control *ctrl, void *dlg, +static void variable_pitch_handler(union control *ctrl, dlgparam *dlg, void *data, int event) { if (event == EVENT_REFRESH) { diff --git a/windows/winctrls.c b/windows/winctrls.c index da2fac62..1b51598f 100644 --- a/windows/winctrls.c +++ b/windows/winctrls.c @@ -1722,9 +1722,8 @@ static void winctrl_set_focus(union control *ctrl, struct dlgparam *dp, } } -union control *dlg_last_focused(union control *ctrl, void *dlg) +union control *dlg_last_focused(union control *ctrl, dlgparam *dp) { - struct dlgparam *dp = (struct dlgparam *)dlg; return dp->focused == ctrl ? dp->lastfocused : dp->focused; } @@ -2067,9 +2066,8 @@ static struct winctrl *dlg_findbyctrl(struct dlgparam *dp, union control *ctrl) return NULL; } -void dlg_radiobutton_set(union control *ctrl, void *dlg, int whichbutton) +void dlg_radiobutton_set(union control *ctrl, dlgparam *dp, int whichbutton) { - struct dlgparam *dp = (struct dlgparam *)dlg; struct winctrl *c = dlg_findbyctrl(dp, ctrl); assert(c && c->ctrl->generic.type == CTRL_RADIO); CheckRadioButton(dp->hwnd, @@ -2078,9 +2076,8 @@ void dlg_radiobutton_set(union control *ctrl, void *dlg, int whichbutton) c->base_id + 1 + whichbutton); } -int dlg_radiobutton_get(union control *ctrl, void *dlg) +int dlg_radiobutton_get(union control *ctrl, dlgparam *dp) { - struct dlgparam *dp = (struct dlgparam *)dlg; struct winctrl *c = dlg_findbyctrl(dp, ctrl); int i; assert(c && c->ctrl->generic.type == CTRL_RADIO); @@ -2091,42 +2088,37 @@ int dlg_radiobutton_get(union control *ctrl, void *dlg) return 0; } -void dlg_checkbox_set(union control *ctrl, void *dlg, int checked) +void dlg_checkbox_set(union control *ctrl, dlgparam *dp, int checked) { - struct dlgparam *dp = (struct dlgparam *)dlg; struct winctrl *c = dlg_findbyctrl(dp, ctrl); assert(c && c->ctrl->generic.type == CTRL_CHECKBOX); CheckDlgButton(dp->hwnd, c->base_id, (checked != 0)); } -int dlg_checkbox_get(union control *ctrl, void *dlg) +int dlg_checkbox_get(union control *ctrl, dlgparam *dp) { - struct dlgparam *dp = (struct dlgparam *)dlg; struct winctrl *c = dlg_findbyctrl(dp, ctrl); assert(c && c->ctrl->generic.type == CTRL_CHECKBOX); return 0 != IsDlgButtonChecked(dp->hwnd, c->base_id); } -void dlg_editbox_set(union control *ctrl, void *dlg, char const *text) +void dlg_editbox_set(union control *ctrl, dlgparam *dp, char const *text) { - struct dlgparam *dp = (struct dlgparam *)dlg; struct winctrl *c = dlg_findbyctrl(dp, ctrl); assert(c && c->ctrl->generic.type == CTRL_EDITBOX); SetDlgItemText(dp->hwnd, c->base_id+1, text); } -char *dlg_editbox_get(union control *ctrl, void *dlg) +char *dlg_editbox_get(union control *ctrl, dlgparam *dp) { - struct dlgparam *dp = (struct dlgparam *)dlg; struct winctrl *c = dlg_findbyctrl(dp, ctrl); assert(c && c->ctrl->generic.type == CTRL_EDITBOX); return GetDlgItemText_alloc(dp->hwnd, c->base_id+1); } /* The `listbox' functions can also apply to combo boxes. */ -void dlg_listbox_clear(union control *ctrl, void *dlg) +void dlg_listbox_clear(union control *ctrl, dlgparam *dp) { - struct dlgparam *dp = (struct dlgparam *)dlg; struct winctrl *c = dlg_findbyctrl(dp, ctrl); int msg; assert(c && @@ -2138,9 +2130,8 @@ void dlg_listbox_clear(union control *ctrl, void *dlg) SendDlgItemMessage(dp->hwnd, c->base_id+1, msg, 0, 0); } -void dlg_listbox_del(union control *ctrl, void *dlg, int index) +void dlg_listbox_del(union control *ctrl, dlgparam *dp, int index) { - struct dlgparam *dp = (struct dlgparam *)dlg; struct winctrl *c = dlg_findbyctrl(dp, ctrl); int msg; assert(c && @@ -2152,9 +2143,8 @@ void dlg_listbox_del(union control *ctrl, void *dlg, int index) SendDlgItemMessage(dp->hwnd, c->base_id+1, msg, index, 0); } -void dlg_listbox_add(union control *ctrl, void *dlg, char const *text) +void dlg_listbox_add(union control *ctrl, dlgparam *dp, char const *text) { - struct dlgparam *dp = (struct dlgparam *)dlg; struct winctrl *c = dlg_findbyctrl(dp, ctrl); int msg; assert(c && @@ -2173,10 +2163,9 @@ void dlg_listbox_add(union control *ctrl, void *dlg, char const *text) * strings in any listbox then you MUST not assign them different * IDs and expect to get meaningful results back. */ -void dlg_listbox_addwithid(union control *ctrl, void *dlg, +void dlg_listbox_addwithid(union control *ctrl, dlgparam *dp, char const *text, int id) { - struct dlgparam *dp = (struct dlgparam *)dlg; struct winctrl *c = dlg_findbyctrl(dp, ctrl); int msg, msg2, index; assert(c && @@ -2191,9 +2180,8 @@ void dlg_listbox_addwithid(union control *ctrl, void *dlg, SendDlgItemMessage(dp->hwnd, c->base_id+1, msg2, index, (LPARAM)id); } -int dlg_listbox_getid(union control *ctrl, void *dlg, int index) +int dlg_listbox_getid(union control *ctrl, dlgparam *dp, int index) { - struct dlgparam *dp = (struct dlgparam *)dlg; struct winctrl *c = dlg_findbyctrl(dp, ctrl); int msg; assert(c && c->ctrl->generic.type == CTRL_LISTBOX); @@ -2203,9 +2191,8 @@ int dlg_listbox_getid(union control *ctrl, void *dlg, int index) } /* dlg_listbox_index returns <0 if no single element is selected. */ -int dlg_listbox_index(union control *ctrl, void *dlg) +int dlg_listbox_index(union control *ctrl, dlgparam *dp) { - struct dlgparam *dp = (struct dlgparam *)dlg; struct winctrl *c = dlg_findbyctrl(dp, ctrl); int msg, ret; assert(c && c->ctrl->generic.type == CTRL_LISTBOX); @@ -2223,9 +2210,8 @@ int dlg_listbox_index(union control *ctrl, void *dlg) return ret; } -int dlg_listbox_issel(union control *ctrl, void *dlg, int index) +int dlg_listbox_issel(union control *ctrl, dlgparam *dp, int index) { - struct dlgparam *dp = (struct dlgparam *)dlg; struct winctrl *c = dlg_findbyctrl(dp, ctrl); assert(c && c->ctrl->generic.type == CTRL_LISTBOX && c->ctrl->listbox.multisel && @@ -2234,9 +2220,8 @@ int dlg_listbox_issel(union control *ctrl, void *dlg, int index) SendDlgItemMessage(dp->hwnd, c->base_id+1, LB_GETSEL, index, 0); } -void dlg_listbox_select(union control *ctrl, void *dlg, int index) +void dlg_listbox_select(union control *ctrl, dlgparam *dp, int index) { - struct dlgparam *dp = (struct dlgparam *)dlg; struct winctrl *c = dlg_findbyctrl(dp, ctrl); int msg; assert(c && c->ctrl->generic.type == CTRL_LISTBOX && @@ -2245,17 +2230,15 @@ void dlg_listbox_select(union control *ctrl, void *dlg, int index) SendDlgItemMessage(dp->hwnd, c->base_id+1, msg, index, 0); } -void dlg_text_set(union control *ctrl, void *dlg, char const *text) +void dlg_text_set(union control *ctrl, dlgparam *dp, char const *text) { - struct dlgparam *dp = (struct dlgparam *)dlg; struct winctrl *c = dlg_findbyctrl(dp, ctrl); assert(c && c->ctrl->generic.type == CTRL_TEXT); SetDlgItemText(dp->hwnd, c->base_id, text); } -void dlg_label_change(union control *ctrl, void *dlg, char const *text) +void dlg_label_change(union control *ctrl, dlgparam *dp, char const *text) { - struct dlgparam *dp = (struct dlgparam *)dlg; struct winctrl *c = dlg_findbyctrl(dp, ctrl); char *escaped = NULL; int id = -1; @@ -2300,17 +2283,15 @@ void dlg_label_change(union control *ctrl, void *dlg, char const *text) } } -void dlg_filesel_set(union control *ctrl, void *dlg, Filename *fn) +void dlg_filesel_set(union control *ctrl, dlgparam *dp, Filename *fn) { - struct dlgparam *dp = (struct dlgparam *)dlg; struct winctrl *c = dlg_findbyctrl(dp, ctrl); assert(c && c->ctrl->generic.type == CTRL_FILESELECT); SetDlgItemText(dp->hwnd, c->base_id+1, fn->path); } -Filename *dlg_filesel_get(union control *ctrl, void *dlg) +Filename *dlg_filesel_get(union control *ctrl, dlgparam *dp) { - struct dlgparam *dp = (struct dlgparam *)dlg; struct winctrl *c = dlg_findbyctrl(dp, ctrl); char *tmp; Filename *ret; @@ -2321,10 +2302,9 @@ Filename *dlg_filesel_get(union control *ctrl, void *dlg) return ret; } -void dlg_fontsel_set(union control *ctrl, void *dlg, FontSpec *fs) +void dlg_fontsel_set(union control *ctrl, dlgparam *dp, FontSpec *fs) { char *buf, *boldstr; - struct dlgparam *dp = (struct dlgparam *)dlg; struct winctrl *c = dlg_findbyctrl(dp, ctrl); assert(c && c->ctrl->generic.type == CTRL_FONTSELECT); @@ -2344,9 +2324,8 @@ void dlg_fontsel_set(union control *ctrl, void *dlg, FontSpec *fs) dlg_auto_set_fixed_pitch_flag(dp); } -FontSpec *dlg_fontsel_get(union control *ctrl, void *dlg) +FontSpec *dlg_fontsel_get(union control *ctrl, dlgparam *dp) { - struct dlgparam *dp = (struct dlgparam *)dlg; struct winctrl *c = dlg_findbyctrl(dp, ctrl); assert(c && c->ctrl->generic.type == CTRL_FONTSELECT); return fontspec_copy((FontSpec *)c->data); @@ -2357,18 +2336,16 @@ FontSpec *dlg_fontsel_get(union control *ctrl, void *dlg) * cause the front end (if possible) to delay updating the screen * until it's all complete, thus avoiding flicker. */ -void dlg_update_start(union control *ctrl, void *dlg) +void dlg_update_start(union control *ctrl, dlgparam *dp) { - struct dlgparam *dp = (struct dlgparam *)dlg; struct winctrl *c = dlg_findbyctrl(dp, ctrl); if (c && c->ctrl->generic.type == CTRL_LISTBOX) { SendDlgItemMessage(dp->hwnd, c->base_id+1, WM_SETREDRAW, FALSE, 0); } } -void dlg_update_done(union control *ctrl, void *dlg) +void dlg_update_done(union control *ctrl, dlgparam *dp) { - struct dlgparam *dp = (struct dlgparam *)dlg; struct winctrl *c = dlg_findbyctrl(dp, ctrl); if (c && c->ctrl->generic.type == CTRL_LISTBOX) { HWND hw = GetDlgItem(dp->hwnd, c->base_id+1); @@ -2377,9 +2354,8 @@ void dlg_update_done(union control *ctrl, void *dlg) } } -void dlg_set_focus(union control *ctrl, void *dlg) +void dlg_set_focus(union control *ctrl, dlgparam *dp) { - struct dlgparam *dp = (struct dlgparam *)dlg; struct winctrl *c = dlg_findbyctrl(dp, ctrl); int id; HWND ctl; @@ -2413,15 +2389,13 @@ void dlg_set_focus(union control *ctrl, void *dlg) * indication to the user. dlg_beep() is a quick and easy generic * error; dlg_error() puts up a message-box or equivalent. */ -void dlg_beep(void *dlg) +void dlg_beep(dlgparam *dp) { - /* struct dlgparam *dp = (struct dlgparam *)dlg; */ MessageBeep(0); } -void dlg_error_msg(void *dlg, const char *msg) +void dlg_error_msg(dlgparam *dp, const char *msg) { - struct dlgparam *dp = (struct dlgparam *)dlg; MessageBox(dp->hwnd, msg, dp->errtitle ? dp->errtitle : NULL, MB_OK | MB_ICONERROR); @@ -2432,16 +2406,14 @@ void dlg_error_msg(void *dlg, const char *msg) * processing is completed, and passes an integer value (typically * a success status). */ -void dlg_end(void *dlg, int value) +void dlg_end(dlgparam *dp, int value) { - struct dlgparam *dp = (struct dlgparam *)dlg; dp->ended = TRUE; dp->endresult = value; } -void dlg_refresh(union control *ctrl, void *dlg) +void dlg_refresh(union control *ctrl, dlgparam *dp) { - struct dlgparam *dp = (struct dlgparam *)dlg; int i, j; struct winctrl *c; @@ -2467,19 +2439,17 @@ void dlg_refresh(union control *ctrl, void *dlg) } } -void dlg_coloursel_start(union control *ctrl, void *dlg, int r, int g, int b) +void dlg_coloursel_start(union control *ctrl, dlgparam *dp, int r, int g, int b) { - struct dlgparam *dp = (struct dlgparam *)dlg; dp->coloursel_wanted = TRUE; dp->coloursel_result.r = r; dp->coloursel_result.g = g; dp->coloursel_result.b = b; } -int dlg_coloursel_results(union control *ctrl, void *dlg, +int dlg_coloursel_results(union control *ctrl, dlgparam *dp, int *r, int *g, int *b) { - struct dlgparam *dp = (struct dlgparam *)dlg; if (dp->coloursel_result.ok) { *r = dp->coloursel_result.r; *g = dp->coloursel_result.g; @@ -2489,9 +2459,8 @@ int dlg_coloursel_results(union control *ctrl, void *dlg, return 0; } -void dlg_auto_set_fixed_pitch_flag(void *dlg) +void dlg_auto_set_fixed_pitch_flag(dlgparam *dp) { - struct dlgparam *dp = (struct dlgparam *)dlg; Conf *conf = (Conf *)dp->data; FontSpec *fs; int quality; @@ -2533,15 +2502,13 @@ void dlg_auto_set_fixed_pitch_flag(void *dlg) dp->fixed_pitch_fonts = FALSE; } -int dlg_get_fixed_pitch_flag(void *dlg) +int dlg_get_fixed_pitch_flag(dlgparam *dp) { - struct dlgparam *dp = (struct dlgparam *)dlg; return dp->fixed_pitch_fonts; } -void dlg_set_fixed_pitch_flag(void *dlg, int flag) +void dlg_set_fixed_pitch_flag(dlgparam *dp, int flag) { - struct dlgparam *dp = (struct dlgparam *)dlg; dp->fixed_pitch_fonts = flag; } diff --git a/windows/winstuff.h b/windows/winstuff.h index 1ecec333..e57bf0da 100644 --- a/windows/winstuff.h +++ b/windows/winstuff.h @@ -437,9 +437,9 @@ void fwdsetter(struct ctlpos *cp, int listid, char *stext, int sid, char *btext, int bid, char *r1text, int r1id, char *r2text, int r2id); -void dlg_auto_set_fixed_pitch_flag(void *dlg); -int dlg_get_fixed_pitch_flag(void *dlg); -void dlg_set_fixed_pitch_flag(void *dlg, int flag); +void dlg_auto_set_fixed_pitch_flag(dlgparam *dlg); +int dlg_get_fixed_pitch_flag(dlgparam *dlg); +void dlg_set_fixed_pitch_flag(dlgparam *dlg, int flag); #define MAX_SHORTCUTS_PER_CTRL 16 From 65b65bb8ef8e35cc700d0883d344a361f04d3927 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Thu, 13 Sep 2018 13:00:56 +0100 Subject: [PATCH 398/607] Expose the structure tag 'crcda_ctx'. This one isn't used in many places, but it's another 'void *' pointer that ought to come with an identifying structure tag. --- ssh.h | 7 ++++--- ssh1bpp.c | 2 +- sshcrcda.c | 8 +++----- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/ssh.h b/ssh.h index 2d285d23..1026a90b 100644 --- a/ssh.h +++ b/ssh.h @@ -322,9 +322,10 @@ unsigned long crc32_compute(const void *s, size_t len); unsigned long crc32_update(unsigned long crc_input, const void *s, size_t len); /* SSH CRC compensation attack detector */ -void *crcda_make_context(void); -void crcda_free_context(void *handle); -int detect_attack(void *handle, unsigned char *buf, uint32 len, +struct crcda_ctx; +struct crcda_ctx *crcda_make_context(void); +void crcda_free_context(struct crcda_ctx *ctx); +int detect_attack(struct crcda_ctx *ctx, unsigned char *buf, uint32 len, unsigned char *IV); /* diff --git a/ssh1bpp.c b/ssh1bpp.c index 7f5b72f6..5ace35fd 100644 --- a/ssh1bpp.c +++ b/ssh1bpp.c @@ -20,7 +20,7 @@ struct ssh1_bpp_state { const struct ssh_cipher *cipher; void *cipher_ctx; - void *crcda_ctx; + struct crcda_ctx *crcda_ctx; void *compctx, *decompctx; diff --git a/sshcrcda.c b/sshcrcda.c index 8d77cbb6..fe6598d3 100644 --- a/sshcrcda.c +++ b/sshcrcda.c @@ -55,7 +55,7 @@ struct crcda_ctx { uint32 n; }; -void *crcda_make_context(void) +struct crcda_ctx *crcda_make_context(void) { struct crcda_ctx *ret = snew(struct crcda_ctx); ret->h = NULL; @@ -63,9 +63,8 @@ void *crcda_make_context(void) return ret; } -void crcda_free_context(void *handle) +void crcda_free_context(struct crcda_ctx *ctx) { - struct crcda_ctx *ctx = (struct crcda_ctx *)handle; if (ctx) { sfree(ctx->h); ctx->h = NULL; @@ -102,9 +101,8 @@ static int check_crc(uchar *S, uchar *buf, uint32 len, uchar *IV) } /* Detect a crc32 compensation attack on a packet */ -int detect_attack(void *handle, uchar *buf, uint32 len, uchar *IV) +int detect_attack(struct crcda_ctx *ctx, uchar *buf, uint32 len, uchar *IV) { - struct crcda_ctx *ctx = (struct crcda_ctx *)handle; register uint32 i, j; uint32 l; register uchar *c; From 6c5cc49e276a7d0991da5a5a21540f38a8d0b0d6 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Thu, 13 Sep 2018 13:29:32 +0100 Subject: [PATCH 399/607] Turn SSH-1 ciphers into a classoid. The interchangeable system of SSH-1 ciphers previously followed the same pattern as the backends and the public-key algorithms, in that all the clients would maintain two separate pointers, one to the vtable and the other to the individual instance / context. Now I've merged them, just as I did with those other two, so that you only cart around a single pointer, which has a vtable pointer inside it and a type distinguishing it from an instance of any of the other interchangeable sets of algorithms. --- ssh.c | 7 ++-- ssh.h | 30 ++++++++++----- ssh1bpp.c | 18 ++++----- sshblowf.c | 54 +++++++++++++++++--------- sshbpp.h | 2 +- sshdes.c | 110 +++++++++++++++++++++++++++++++++-------------------- 6 files changed, 137 insertions(+), 84 deletions(-) diff --git a/ssh.c b/ssh.c index dd1d1c1f..3d4baf47 100644 --- a/ssh.c +++ b/ssh.c @@ -2914,10 +2914,9 @@ static void do_ssh1_login(void *vctx) sfree(s->rsabuf); { - const struct ssh_cipher *cipher = - (s->cipher_type == SSH_CIPHER_BLOWFISH ? &ssh_blowfish_ssh1 : - s->cipher_type == SSH_CIPHER_DES ? &ssh_des : - &ssh_3des); + const struct ssh1_cipheralg *cipher = + (s->cipher_type == SSH_CIPHER_BLOWFISH ? &ssh1_blowfish : + s->cipher_type == SSH_CIPHER_DES ? &ssh1_des : &ssh1_3des); ssh1_bpp_new_cipher(ssh->bpp, cipher, ssh->session_key); logeventf(ssh, "Initialised %s encryption", cipher->text_name); } diff --git a/ssh.h b/ssh.h index 1026a90b..c10d6fb1 100644 --- a/ssh.h +++ b/ssh.h @@ -420,17 +420,27 @@ void SHA384_Init(SHA384_State * s); void SHA384_Final(SHA384_State * s, unsigned char *output); void SHA384_Simple(const void *p, int len, unsigned char *output); -struct ssh_mac; -struct ssh_cipher { - void *(*make_context)(void); - void (*free_context)(void *); - void (*sesskey) (void *, const void *key); /* for SSH-1 */ - void (*encrypt) (void *, void *blk, int len); - void (*decrypt) (void *, void *blk, int len); +struct ssh2_macalg; + +struct ssh1_cipheralg; +typedef const struct ssh1_cipheralg *ssh1_cipher; + +struct ssh1_cipheralg { + ssh1_cipher *(*new)(void); + void (*free)(ssh1_cipher *); + void (*sesskey)(ssh1_cipher *, const void *key); + void (*encrypt)(ssh1_cipher *, void *blk, int len); + void (*decrypt)(ssh1_cipher *, void *blk, int len); int blksize; const char *text_name; }; +#define ssh1_cipher_new(alg) ((alg)->new()) +#define ssh1_cipher_free(ctx) ((*(ctx))->free(ctx)) +#define ssh1_cipher_sesskey(ctx, key) ((*(ctx))->sesskey(ctx, key)) +#define ssh1_cipher_encrypt(ctx, blk, len) ((*(ctx))->encrypt(ctx, blk, len)) +#define ssh1_cipher_decrypt(ctx, blk, len) ((*(ctx))->decrypt(ctx, blk, len)) + struct ssh2_cipher { void *(*make_context)(void); void (*free_context)(void *); @@ -576,9 +586,9 @@ struct ssh2_userkey { /* The maximum length of any hash algorithm used in kex. (bytes) */ #define SSH2_KEX_MAX_HASH_LEN (64) /* SHA-512 */ -extern const struct ssh_cipher ssh_3des; -extern const struct ssh_cipher ssh_des; -extern const struct ssh_cipher ssh_blowfish_ssh1; +extern const struct ssh1_cipheralg ssh1_3des; +extern const struct ssh1_cipheralg ssh1_des; +extern const struct ssh1_cipheralg ssh1_blowfish; extern const struct ssh2_ciphers ssh2_3des; extern const struct ssh2_ciphers ssh2_des; extern const struct ssh2_ciphers ssh2_aes; diff --git a/ssh1bpp.c b/ssh1bpp.c index 5ace35fd..627d55a5 100644 --- a/ssh1bpp.c +++ b/ssh1bpp.c @@ -17,8 +17,7 @@ struct ssh1_bpp_state { int chunk; PktIn *pktin; - const struct ssh_cipher *cipher; - void *cipher_ctx; + ssh1_cipher *cipher; struct crcda_ctx *crcda_ctx; @@ -51,7 +50,7 @@ static void ssh1_bpp_free(BinaryPacketProtocol *bpp) { struct ssh1_bpp_state *s = FROMFIELD(bpp, struct ssh1_bpp_state, bpp); if (s->cipher) - s->cipher->free_context(s->cipher_ctx); + ssh1_cipher_free(s->cipher); if (s->compctx) zlib_compress_cleanup(s->compctx); if (s->decompctx) @@ -64,7 +63,7 @@ static void ssh1_bpp_free(BinaryPacketProtocol *bpp) } void ssh1_bpp_new_cipher(BinaryPacketProtocol *bpp, - const struct ssh_cipher *cipher, + const struct ssh1_cipheralg *cipher, const void *session_key) { struct ssh1_bpp_state *s; @@ -73,10 +72,9 @@ void ssh1_bpp_new_cipher(BinaryPacketProtocol *bpp, assert(!s->cipher); - s->cipher = cipher; - if (s->cipher) { - s->cipher_ctx = cipher->make_context(); - cipher->sesskey(s->cipher_ctx, session_key); + if (cipher) { + s->cipher = ssh1_cipher_new(cipher); + ssh1_cipher_sesskey(s->cipher, session_key); assert(!s->crcda_ctx); s->crcda_ctx = crcda_make_context(); @@ -146,7 +144,7 @@ static void ssh1_bpp_handle_input(BinaryPacketProtocol *bpp) } if (s->cipher) - s->cipher->decrypt(s->cipher_ctx, s->data, s->biglen); + ssh1_cipher_decrypt(s->cipher, s->data, s->biglen); s->realcrc = crc32_compute(s->data, s->biglen - 4); s->gotcrc = GET_32BIT(s->data + s->biglen - 4); @@ -273,7 +271,7 @@ static void ssh1_bpp_format_packet(BinaryPacketProtocol *bpp, PktOut *pkt) PUT_32BIT(pkt->data + pktoffs, len); if (s->cipher) - s->cipher->encrypt(s->cipher_ctx, pkt->data + pktoffs + 4, biglen); + ssh1_cipher_encrypt(s->cipher, pkt->data + pktoffs + 4, biglen); bufchain_add(s->bpp.out_raw, pkt->data + pktoffs, biglen + 4); /* len(length+padding+type+data+CRC) */ diff --git a/sshblowf.c b/sshblowf.c index 24421059..764f3f65 100644 --- a/sshblowf.c +++ b/sshblowf.c @@ -561,15 +561,30 @@ void *blowfish_make_context(void) return snew(BlowfishContext); } -static void *blowfish_ssh1_make_context(void) +void blowfish_free_context(void *handle) { + sfree(handle); +} + +struct blowfish_ssh1_ctx { /* In SSH-1, need one key for each direction */ - return snewn(2, BlowfishContext); + BlowfishContext contexts[2]; + ssh1_cipher vt; +}; + +static ssh1_cipher *blowfish_ssh1_new(void) +{ + struct blowfish_ssh1_ctx *ctx = snew(struct blowfish_ssh1_ctx); + ctx->vt = &ssh1_blowfish; + return &ctx->vt; } -void blowfish_free_context(void *handle) +static void blowfish_ssh1_free(ssh1_cipher *cipher) { - sfree(handle); + struct blowfish_ssh1_ctx *ctx = + FROMFIELD(cipher, struct blowfish_ssh1_ctx, vt); + smemclr(ctx, sizeof(*ctx)); + sfree(ctx); } static void blowfish_key(void *handle, const void *key) @@ -592,25 +607,27 @@ static void blowfish_iv(void *handle, const void *viv) ctx->iv1 = GET_32BIT_MSB_FIRST(iv + 4); } -static void blowfish_sesskey(void *handle, const void *key) +static void blowfish_ssh1_sesskey(ssh1_cipher *cipher, const void *key) { - BlowfishContext *ctx = (BlowfishContext *)handle; - blowfish_setkey(ctx, key, SSH_SESSION_KEY_LENGTH); - ctx->iv0 = 0; - ctx->iv1 = 0; - ctx[1] = ctx[0]; /* structure copy */ + struct blowfish_ssh1_ctx *ctx = + FROMFIELD(cipher, struct blowfish_ssh1_ctx, vt); + blowfish_setkey(&ctx->contexts[0], key, SSH_SESSION_KEY_LENGTH); + ctx->contexts[0].iv0 = ctx->contexts[0].iv1 = 0; + ctx->contexts[1] = ctx->contexts[0]; /* structure copy */ } -static void blowfish_ssh1_encrypt_blk(void *handle, void *blk, int len) +static void blowfish_ssh1_encrypt_blk(ssh1_cipher *cipher, void *blk, int len) { - BlowfishContext *ctx = (BlowfishContext *)handle; - blowfish_lsb_encrypt_cbc(blk, len, ctx); + struct blowfish_ssh1_ctx *ctx = + FROMFIELD(cipher, struct blowfish_ssh1_ctx, vt); + blowfish_lsb_encrypt_cbc(blk, len, ctx->contexts); } -static void blowfish_ssh1_decrypt_blk(void *handle, void *blk, int len) +static void blowfish_ssh1_decrypt_blk(ssh1_cipher *cipher, void *blk, int len) { - BlowfishContext *ctx = (BlowfishContext *)handle; - blowfish_lsb_decrypt_cbc(blk, len, ctx+1); + struct blowfish_ssh1_ctx *ctx = + FROMFIELD(cipher, struct blowfish_ssh1_ctx, vt); + blowfish_lsb_decrypt_cbc(blk, len, ctx->contexts+1); } static void blowfish_ssh2_encrypt_blk(void *handle, void *blk, int len) @@ -631,8 +648,9 @@ static void blowfish_ssh2_sdctr(void *handle, void *blk, int len) blowfish_msb_sdctr(blk, len, ctx); } -const struct ssh_cipher ssh_blowfish_ssh1 = { - blowfish_ssh1_make_context, blowfish_free_context, blowfish_sesskey, +const struct ssh1_cipheralg ssh1_blowfish = { + blowfish_ssh1_new, blowfish_ssh1_free, + blowfish_ssh1_sesskey, blowfish_ssh1_encrypt_blk, blowfish_ssh1_decrypt_blk, 8, "Blowfish-128 CBC" }; diff --git a/sshbpp.h b/sshbpp.h index c1ac7a13..de11e69d 100644 --- a/sshbpp.h +++ b/sshbpp.h @@ -32,7 +32,7 @@ struct BinaryPacketProtocol { BinaryPacketProtocol *ssh1_bpp_new(void); void ssh1_bpp_new_cipher(BinaryPacketProtocol *bpp, - const struct ssh_cipher *cipher, + const struct ssh1_cipheralg *cipher, const void *session_key); void ssh1_bpp_start_compression(BinaryPacketProtocol *bpp); diff --git a/sshdes.c b/sshdes.c index 585deb7f..6cc1ce67 100644 --- a/sshdes.c +++ b/sshdes.c @@ -752,10 +752,23 @@ static void *des3_make_context(void) return snewn(3, DESContext); } -static void *des3_ssh1_make_context(void) +struct des3_ssh1_ctx { + /* 3 cipher context for each direction */ + DESContext contexts[6]; + ssh1_cipher vt; +}; + +struct des_ssh1_ctx { + /* 1 cipher context for each direction */ + DESContext contexts[2]; + ssh1_cipher vt; +}; + +static ssh1_cipher *des3_ssh1_new(void) { - /* Need 3 keys for each direction, in SSH-1 */ - return snewn(6, DESContext); + struct des3_ssh1_ctx *ctx = snew(struct des3_ssh1_ctx); + ctx->vt = &ssh1_3des; + return &ctx->vt; } static void *des_make_context(void) @@ -763,10 +776,25 @@ static void *des_make_context(void) return snew(DESContext); } -static void *des_ssh1_make_context(void) +static ssh1_cipher *des_ssh1_new(void) +{ + struct des_ssh1_ctx *ctx = snew(struct des_ssh1_ctx); + ctx->vt = &ssh1_des; + return &ctx->vt; +} + +static void des3_ssh1_free(ssh1_cipher *cipher) +{ + struct des3_ssh1_ctx *ctx = FROMFIELD(cipher, struct des3_ssh1_ctx, vt); + smemclr(ctx, sizeof(*ctx)); + sfree(ctx); +} + +static void des_ssh1_free(ssh1_cipher *cipher) { - /* Need one key for each direction, in SSH-1 */ - return snewn(2, DESContext); + struct des_ssh1_ctx *ctx = FROMFIELD(cipher, struct des_ssh1_ctx, vt); + smemclr(ctx, sizeof(*ctx)); + sfree(ctx); } static void des3_free_context(void *handle) /* used for both 3DES and DES */ @@ -802,23 +830,42 @@ static void des_key(void *handle, const void *vkey) GET_32BIT_MSB_FIRST(key + 4), &keys[0]); } -static void des3_sesskey(void *handle, const void *key) +static void des3_ssh1_sesskey(ssh1_cipher *cipher, const void *key) { - DESContext *keys = (DESContext *) handle; - des3_key(keys, key); - des3_key(keys+3, key); + struct des3_ssh1_ctx *ctx = FROMFIELD(cipher, struct des3_ssh1_ctx, vt); + des3_key(ctx->contexts, key); + des3_key(ctx->contexts+3, key); } -static void des3_encrypt_blk(void *handle, void *blk, int len) +static void des3_ssh1_encrypt_blk(ssh1_cipher *cipher, void *blk, int len) { - DESContext *keys = (DESContext *) handle; - des_3cbc_encrypt(blk, len, keys); + struct des_ssh1_ctx *ctx = FROMFIELD(cipher, struct des_ssh1_ctx, vt); + des_3cbc_encrypt(blk, len, ctx->contexts); } -static void des3_decrypt_blk(void *handle, void *blk, int len) +static void des3_ssh1_decrypt_blk(ssh1_cipher *cipher, void *blk, int len) { - DESContext *keys = (DESContext *) handle; - des_3cbc_decrypt(blk, len, keys+3); + struct des_ssh1_ctx *ctx = FROMFIELD(cipher, struct des_ssh1_ctx, vt); + des_3cbc_decrypt(blk, len, ctx->contexts+3); +} + +static void des_ssh1_sesskey(ssh1_cipher *cipher, const void *key) +{ + struct des_ssh1_ctx *ctx = FROMFIELD(cipher, struct des_ssh1_ctx, vt); + des_key(ctx->contexts, key); + des_key(ctx->contexts+1, key); +} + +static void des_ssh1_encrypt_blk(ssh1_cipher *cipher, void *blk, int len) +{ + struct des_ssh1_ctx *ctx = FROMFIELD(cipher, struct des_ssh1_ctx, vt); + des_cbc_encrypt(blk, len, ctx->contexts); +} + +static void des_ssh1_decrypt_blk(ssh1_cipher *cipher, void *blk, int len) +{ + struct des_ssh1_ctx *ctx = FROMFIELD(cipher, struct des_ssh1_ctx, vt); + des_cbc_decrypt(blk, len, ctx->contexts+1); } static void des3_ssh2_encrypt_blk(void *handle, void *blk, int len) @@ -1017,34 +1064,15 @@ const struct ssh2_ciphers ssh2_des = { des_list }; -const struct ssh_cipher ssh_3des = { - des3_ssh1_make_context, des3_free_context, des3_sesskey, - des3_encrypt_blk, des3_decrypt_blk, +const struct ssh1_cipheralg ssh1_3des = { + des3_ssh1_new, des3_ssh1_free, des3_ssh1_sesskey, + des3_ssh1_encrypt_blk, des3_ssh1_decrypt_blk, 8, "triple-DES inner-CBC" }; -static void des_sesskey(void *handle, const void *key) -{ - DESContext *keys = (DESContext *) handle; - des_key(keys, key); - des_key(keys+1, key); -} - -static void des_encrypt_blk(void *handle, void *blk, int len) -{ - DESContext *keys = (DESContext *) handle; - des_cbc_encrypt(blk, len, keys); -} - -static void des_decrypt_blk(void *handle, void *blk, int len) -{ - DESContext *keys = (DESContext *) handle; - des_cbc_decrypt(blk, len, keys+1); -} - -const struct ssh_cipher ssh_des = { - des_ssh1_make_context, des3_free_context, des_sesskey, - des_encrypt_blk, des_decrypt_blk, +const struct ssh1_cipheralg ssh1_des = { + des_ssh1_new, des_ssh1_free, des_ssh1_sesskey, + des_ssh1_encrypt_blk, des_ssh1_decrypt_blk, 8, "single-DES CBC" }; From 229af2b5bf6945395aa5719db609a4224bd75719 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Thu, 13 Sep 2018 14:43:04 +0100 Subject: [PATCH 400/607] Turn SSH-2 ciphers into a classoid. This is more or less the same job as the SSH-1 case, only more extensive, because we have a wider range of ciphers. I'm a bit disappointed about the AES case, in particular, because I feel as if it ought to have been possible to arrange to combine this layer of vtable dispatch with the subsidiary one that selects between hardware and software implementations of the underlying cipher. I may come back later and have another try at that, in fact. --- import.c | 2 +- ssh.c | 4 +- ssh.h | 60 +++++++++++------- ssh2bpp.c | 92 ++++++++++++++-------------- sshaes.c | 121 ++++++++++++++++++++++++------------ ssharcf.c | 44 ++++++++------ sshblowf.c | 104 +++++++++++++++++++------------ sshblowf.h | 4 +- sshbpp.h | 4 +- sshccp.c | 48 ++++++++------- sshdes.c | 176 +++++++++++++++++++++++++++++++++-------------------- sshmd5.c | 2 +- sshsh256.c | 2 +- sshsha.c | 2 +- 14 files changed, 402 insertions(+), 263 deletions(-) diff --git a/import.c b/import.c index e95883a0..98cf8010 100644 --- a/import.c +++ b/import.c @@ -549,7 +549,7 @@ struct ssh2_userkey *openssh_pem_read(const Filename *filename, des3_decrypt_pubkey_ossh(keybuf, key->iv, key->keyblob->u, key->keyblob->len); else { - void *ctx; + AESContext *ctx; assert(key->encryption == OP_E_AES); ctx = aes_make_context(); aes128_key(ctx, keybuf); diff --git a/ssh.c b/ssh.c index 3d4baf47..1ece7488 100644 --- a/ssh.c +++ b/ssh.c @@ -4850,7 +4850,7 @@ struct kexinit_algorithm { int warn; } hk; struct { - const struct ssh2_cipher *cipher; + const struct ssh2_cipheralg *cipher; int warn; } cipher; struct { @@ -5026,7 +5026,7 @@ static void do_ssh2_transport(void *vctx) const struct ssh_mac *const *maclist; int nmacs; struct { - const struct ssh2_cipher *cipher; + const struct ssh2_cipheralg *cipher; const struct ssh_mac *mac; int etm_mode; const struct ssh_compress *comp; diff --git a/ssh.h b/ssh.h index c10d6fb1..a856aa9e 100644 --- a/ssh.h +++ b/ssh.h @@ -355,6 +355,9 @@ Bignum ssh_ecdhkex_getkey(struct ec_key *key, Bignum *dss_gen_k(const char *id_string, Bignum modulus, Bignum private_key, unsigned char *digest, int digest_len); +struct ssh2_cipheralg; +typedef const struct ssh2_cipheralg *ssh2_cipher; + typedef struct { uint32 h[4]; } MD5_Core_State; @@ -371,7 +374,7 @@ void MD5Init(struct MD5Context *context); void MD5Final(unsigned char digest[16], struct MD5Context *context); void MD5Simple(void const *p, unsigned len, unsigned char output[16]); -void *hmacmd5_make_context(void *); +void *hmacmd5_make_context(ssh2_cipher *); void hmacmd5_free_context(void *handle); void hmacmd5_key(void *handle, void const *key, int len); void hmacmd5_do_hmac(void *handle, unsigned char const *blk, int len, @@ -441,16 +444,18 @@ struct ssh1_cipheralg { #define ssh1_cipher_encrypt(ctx, blk, len) ((*(ctx))->encrypt(ctx, blk, len)) #define ssh1_cipher_decrypt(ctx, blk, len) ((*(ctx))->decrypt(ctx, blk, len)) -struct ssh2_cipher { - void *(*make_context)(void); - void (*free_context)(void *); - void (*setiv) (void *, const void *iv); /* for SSH-2 */ - void (*setkey) (void *, const void *key);/* for SSH-2 */ - void (*encrypt) (void *, void *blk, int len); - void (*decrypt) (void *, void *blk, int len); +struct ssh2_cipheralg { + ssh2_cipher *(*new)(const struct ssh2_cipheralg *alg); + void (*free)(ssh2_cipher *); + void (*setiv)(ssh2_cipher *, const void *iv); + void (*setkey)(ssh2_cipher *, const void *key); + void (*encrypt)(ssh2_cipher *, void *blk, int len); + void (*decrypt)(ssh2_cipher *, void *blk, int len); /* Ignored unless SSH_CIPHER_SEPARATE_LENGTH flag set */ - void (*encrypt_length) (void *, void *blk, int len, unsigned long seq); - void (*decrypt_length) (void *, void *blk, int len, unsigned long seq); + void (*encrypt_length)(ssh2_cipher *, void *blk, int len, + unsigned long seq); + void (*decrypt_length)(ssh2_cipher *, void *blk, int len, + unsigned long seq); const char *name; int blksize; /* real_keybits is the number of bits of entropy genuinely used by @@ -474,14 +479,26 @@ struct ssh2_cipher { const struct ssh_mac *required_mac; }; +#define ssh2_cipher_new(alg) ((alg)->new(alg)) +#define ssh2_cipher_free(ctx) ((*(ctx))->free(ctx)) +#define ssh2_cipher_setiv(ctx, iv) ((*(ctx))->setiv(ctx, iv)) +#define ssh2_cipher_setkey(ctx, key) ((*(ctx))->setkey(ctx, key)) +#define ssh2_cipher_encrypt(ctx, blk, len) ((*(ctx))->encrypt(ctx, blk, len)) +#define ssh2_cipher_decrypt(ctx, blk, len) ((*(ctx))->decrypt(ctx, blk, len)) +#define ssh2_cipher_encrypt_length(ctx, blk, len, seq) \ + ((*(ctx))->encrypt_length(ctx, blk, len, seq)) +#define ssh2_cipher_decrypt_length(ctx, blk, len, seq) \ + ((*(ctx))->decrypt_length(ctx, blk, len, seq)) +#define ssh2_cipher_alg(ctx) (*(ctx)) + struct ssh2_ciphers { int nciphers; - const struct ssh2_cipher *const *list; + const struct ssh2_cipheralg *const *list; }; struct ssh_mac { /* Passes in the cipher context */ - void *(*make_context)(void *); + void *(*make_context)(ssh2_cipher *); void (*free_context)(void *); void (*setkey) (void *, const void *key); /* whole-packet operations */ @@ -618,15 +635,16 @@ extern const struct ssh_mac ssh_hmac_sha1_96; extern const struct ssh_mac ssh_hmac_sha1_96_buggy; extern const struct ssh_mac ssh_hmac_sha256; -void *aes_make_context(void); -void aes_free_context(void *handle); -void aes128_key(void *handle, const void *key); -void aes192_key(void *handle, const void *key); -void aes256_key(void *handle, const void *key); -void aes_iv(void *handle, const void *iv); -void aes_ssh2_encrypt_blk(void *handle, void *blk, int len); -void aes_ssh2_decrypt_blk(void *handle, void *blk, int len); -void aes_ssh2_sdctr(void *handle, void *blk, int len); +typedef struct AESContext AESContext; +AESContext *aes_make_context(void); +void aes_free_context(AESContext *ctx); +void aes128_key(AESContext *ctx, const void *key); +void aes192_key(AESContext *ctx, const void *key); +void aes256_key(AESContext *ctx, const void *key); +void aes_iv(AESContext *ctx, const void *iv); +void aes_ssh2_encrypt_blk(AESContext *ctx, void *blk, int len); +void aes_ssh2_decrypt_blk(AESContext *ctx, void *blk, int len); +void aes_ssh2_sdctr(AESContext *ctx, void *blk, int len); /* * PuTTY version number formatted as an SSH version string. diff --git a/ssh2bpp.c b/ssh2bpp.c index 007ab735..510e21a5 100644 --- a/ssh2bpp.c +++ b/ssh2bpp.c @@ -11,8 +11,7 @@ struct ssh2_bpp_direction { unsigned long sequence; - const struct ssh2_cipher *cipher; - void *cipher_ctx; + ssh2_cipher *cipher; const struct ssh_mac *mac; int etm_mode; void *mac_ctx; @@ -60,14 +59,14 @@ static void ssh2_bpp_free(BinaryPacketProtocol *bpp) { struct ssh2_bpp_state *s = FROMFIELD(bpp, struct ssh2_bpp_state, bpp); sfree(s->buf); - if (s->out.cipher_ctx) - s->out.cipher->free_context(s->out.cipher_ctx); + if (s->out.cipher) + ssh2_cipher_free(s->out.cipher); if (s->out.mac_ctx) s->out.mac->free_context(s->out.mac_ctx); if (s->out.comp_ctx) s->out.comp->compress_cleanup(s->out.comp_ctx); - if (s->in.cipher_ctx) - s->in.cipher->free_context(s->in.cipher_ctx); + if (s->in.cipher) + ssh2_cipher_free(s->in.cipher); if (s->in.mac_ctx) s->in.mac->free_context(s->in.mac_ctx); if (s->in.comp_ctx) @@ -79,7 +78,7 @@ static void ssh2_bpp_free(BinaryPacketProtocol *bpp) void ssh2_bpp_new_outgoing_crypto( BinaryPacketProtocol *bpp, - const struct ssh2_cipher *cipher, const void *ckey, const void *iv, + const struct ssh2_cipheralg *cipher, const void *ckey, const void *iv, const struct ssh_mac *mac, int etm_mode, const void *mac_key, const struct ssh_compress *compression) { @@ -87,23 +86,24 @@ void ssh2_bpp_new_outgoing_crypto( assert(bpp->vt == &ssh2_bpp_vtable); s = FROMFIELD(bpp, struct ssh2_bpp_state, bpp); - if (s->out.cipher_ctx) - s->out.cipher->free_context(s->out.cipher_ctx); + if (s->out.cipher) + ssh2_cipher_free(s->out.cipher); if (s->out.mac_ctx) s->out.mac->free_context(s->out.mac_ctx); if (s->out.comp_ctx) s->out.comp->compress_cleanup(s->out.comp_ctx); - s->out.cipher = cipher; if (cipher) { - s->out.cipher_ctx = cipher->make_context(); - cipher->setkey(s->out.cipher_ctx, ckey); - cipher->setiv(s->out.cipher_ctx, iv); + s->out.cipher = ssh2_cipher_new(cipher); + ssh2_cipher_setkey(s->out.cipher, ckey); + ssh2_cipher_setiv(s->out.cipher, iv); + } else { + s->out.cipher = NULL; } s->out.mac = mac; s->out.etm_mode = etm_mode; if (mac) { - s->out.mac_ctx = mac->make_context(s->out.cipher_ctx); + s->out.mac_ctx = mac->make_context(s->out.cipher); mac->setkey(s->out.mac_ctx, mac_key); } @@ -116,7 +116,7 @@ void ssh2_bpp_new_outgoing_crypto( void ssh2_bpp_new_incoming_crypto( BinaryPacketProtocol *bpp, - const struct ssh2_cipher *cipher, const void *ckey, const void *iv, + const struct ssh2_cipheralg *cipher, const void *ckey, const void *iv, const struct ssh_mac *mac, int etm_mode, const void *mac_key, const struct ssh_compress *compression) { @@ -124,23 +124,24 @@ void ssh2_bpp_new_incoming_crypto( assert(bpp->vt == &ssh2_bpp_vtable); s = FROMFIELD(bpp, struct ssh2_bpp_state, bpp); - if (s->in.cipher_ctx) - s->in.cipher->free_context(s->in.cipher_ctx); + if (s->in.cipher) + ssh2_cipher_free(s->in.cipher); if (s->in.mac_ctx) s->in.mac->free_context(s->in.mac_ctx); if (s->in.comp_ctx) s->in.comp->decompress_cleanup(s->in.comp_ctx); - s->in.cipher = cipher; if (cipher) { - s->in.cipher_ctx = cipher->make_context(); - cipher->setkey(s->in.cipher_ctx, ckey); - cipher->setiv(s->in.cipher_ctx, iv); + s->in.cipher = ssh2_cipher_new(cipher); + ssh2_cipher_setkey(s->in.cipher, ckey); + ssh2_cipher_setiv(s->in.cipher, iv); + } else { + s->in.cipher = NULL; } s->in.mac = mac; s->in.etm_mode = etm_mode; if (mac) { - s->in.mac_ctx = mac->make_context(s->in.cipher_ctx); + s->in.mac_ctx = mac->make_context(s->in.cipher); mac->setkey(s->in.mac_ctx, mac_key); } @@ -165,14 +166,15 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp) s->maxlen = 0; s->length = 0; if (s->in.cipher) - s->cipherblk = s->in.cipher->blksize; + s->cipherblk = ssh2_cipher_alg(s->in.cipher)->blksize; else s->cipherblk = 8; if (s->cipherblk < 8) s->cipherblk = 8; s->maclen = s->in.mac ? s->in.mac->len : 0; - if (s->in.cipher && (s->in.cipher->flags & SSH_CIPHER_IS_CBC) && + if (s->in.cipher && + (ssh2_cipher_alg(s->in.cipher)->flags & SSH_CIPHER_IS_CBC) && s->in.mac && !s->in.etm_mode) { /* * When dealing with a CBC-mode cipher, we want to avoid the @@ -219,9 +221,8 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp) s->cipherblk)); /* Decrypt one more block (a little further back in * the stream). */ - s->in.cipher->decrypt( - s->in.cipher_ctx, - s->buf + s->packetlen, s->cipherblk); + ssh2_cipher_decrypt(s->in.cipher, + s->buf + s->packetlen, s->cipherblk); /* Feed that block to the MAC. */ put_data(s->sc_mac_bs, @@ -265,13 +266,13 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp) s->bpp.in_raw, s->buf, 4)); /* Cipher supports length decryption, so do it */ - if (s->in.cipher && - (s->in.cipher->flags & SSH_CIPHER_SEPARATE_LENGTH)) { + if (s->in.cipher && (ssh2_cipher_alg(s->in.cipher)->flags & + SSH_CIPHER_SEPARATE_LENGTH)) { /* Keep the packet the same though, so the MAC passes */ unsigned char len[4]; memcpy(len, s->buf, 4); - s->in.cipher->decrypt_length( - s->in.cipher_ctx, len, 4, s->in.sequence); + ssh2_cipher_decrypt_length( + s->in.cipher, len, 4, s->in.sequence); s->len = toint(GET_32BIT(len)); } else { s->len = toint(GET_32BIT(s->buf)); @@ -321,8 +322,8 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp) /* Decrypt everything between the length field and the MAC. */ if (s->in.cipher) - s->in.cipher->decrypt( - s->in.cipher_ctx, s->data + 4, s->packetlen - 4); + ssh2_cipher_decrypt( + s->in.cipher, s->data + 4, s->packetlen - 4); } else { if (s->bufsize < s->cipherblk) { s->bufsize = s->cipherblk; @@ -337,8 +338,8 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp) s->bpp.in_raw, s->buf, s->cipherblk)); if (s->in.cipher) - s->in.cipher->decrypt( - s->in.cipher_ctx, s->buf, s->cipherblk); + ssh2_cipher_decrypt( + s->in.cipher, s->buf, s->cipherblk); /* * Now get the length figure. @@ -381,8 +382,8 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp) /* Decrypt everything _except_ the MAC. */ if (s->in.cipher) - s->in.cipher->decrypt( - s->in.cipher_ctx, + ssh2_cipher_decrypt( + s->in.cipher, s->data + s->cipherblk, s->packetlen - s->cipherblk); /* @@ -524,7 +525,7 @@ static void ssh2_bpp_format_packet_inner(struct ssh2_bpp_state *s, PktOut *pkt) pkt->downstream_id, pkt->additional_log_text); } - cipherblk = s->out.cipher ? s->out.cipher->blksize : 8; + cipherblk = s->out.cipher ? ssh2_cipher_alg(s->out.cipher)->blksize : 8; cipherblk = cipherblk < 8 ? 8 : cipherblk; /* or 8 if blksize < 8 */ if (s->out.comp && s->out.comp_ctx) { @@ -573,9 +574,9 @@ static void ssh2_bpp_format_packet_inner(struct ssh2_bpp_state *s, PktOut *pkt) /* Encrypt length if the scheme requires it */ if (s->out.cipher && - (s->out.cipher->flags & SSH_CIPHER_SEPARATE_LENGTH)) { - s->out.cipher->encrypt_length(s->out.cipher_ctx, pkt->data, 4, - s->out.sequence); + (ssh2_cipher_alg(s->out.cipher)->flags & SSH_CIPHER_SEPARATE_LENGTH)) { + ssh2_cipher_encrypt_length(s->out.cipher, pkt->data, 4, + s->out.sequence); } put_padding(pkt, maclen, 0); @@ -585,8 +586,8 @@ static void ssh2_bpp_format_packet_inner(struct ssh2_bpp_state *s, PktOut *pkt) * OpenSSH-defined encrypt-then-MAC protocol. */ if (s->out.cipher) - s->out.cipher->encrypt(s->out.cipher_ctx, - pkt->data + 4, origlen + padding - 4); + ssh2_cipher_encrypt(s->out.cipher, + pkt->data + 4, origlen + padding - 4); s->out.mac->generate(s->out.mac_ctx, pkt->data, origlen + padding, s->out.sequence); } else { @@ -598,8 +599,7 @@ static void ssh2_bpp_format_packet_inner(struct ssh2_bpp_state *s, PktOut *pkt) s->out.mac_ctx, pkt->data, origlen + padding, s->out.sequence); if (s->out.cipher) - s->out.cipher->encrypt(s->out.cipher_ctx, - pkt->data, origlen + padding); + ssh2_cipher_encrypt(s->out.cipher, pkt->data, origlen + padding); } s->out.sequence++; /* whether or not we MACed */ @@ -634,7 +634,7 @@ static void ssh2_bpp_format_packet(BinaryPacketProtocol *bpp, PktOut *pkt) int block, length; PktOut *ignore_pkt; - block = s->out.cipher ? s->out.cipher->blksize : 0; + block = s->out.cipher ? ssh2_cipher_alg(s->out.cipher)->blksize : 0; if (block < 8) block = 8; length = pkt->length; diff --git a/sshaes.c b/sshaes.c index 0b09a6a6..5259396f 100644 --- a/sshaes.c +++ b/sshaes.c @@ -970,38 +970,35 @@ static void aes_decrypt_cbc_sw(unsigned char *blk, int len, AESContext * ctx) memcpy(ctx->iv, iv, sizeof(iv)); } -void *aes_make_context(void) +AESContext *aes_make_context(void) { return snew(AESContext); } -void aes_free_context(void *handle) +void aes_free_context(AESContext *ctx) { - sfree(handle); + smemclr(ctx, sizeof(*ctx)); + sfree(ctx); } -void aes128_key(void *handle, const void *key) +void aes128_key(AESContext *ctx, const void *key) { - AESContext *ctx = (AESContext *)handle; aes_setup(ctx, key, 16); } -void aes192_key(void *handle, const void *key) +void aes192_key(AESContext *ctx, const void *key) { - AESContext *ctx = (AESContext *)handle; aes_setup(ctx, key, 24); } -void aes256_key(void *handle, const void *key) +void aes256_key(AESContext *ctx, const void *key) { - AESContext *ctx = (AESContext *)handle; aes_setup(ctx, key, 32); } -void aes_iv(void *handle, const void *viv) +void aes_iv(AESContext *ctx, const void *viv) { const unsigned char *iv = (const unsigned char *)viv; - AESContext *ctx = (AESContext *)handle; if (ctx->isNI) { memcpy(ctx->iv, iv, sizeof(ctx->iv)); } @@ -1012,21 +1009,18 @@ void aes_iv(void *handle, const void *viv) } } -void aes_ssh2_encrypt_blk(void *handle, void *blk, int len) +void aes_ssh2_encrypt_blk(AESContext *ctx, void *blk, int len) { - AESContext *ctx = (AESContext *)handle; aes_encrypt_cbc(blk, len, ctx); } -void aes_ssh2_decrypt_blk(void *handle, void *blk, int len) +void aes_ssh2_decrypt_blk(AESContext *ctx, void *blk, int len) { - AESContext *ctx = (AESContext *)handle; aes_decrypt_cbc(blk, len, ctx); } -void aes_ssh2_sdctr(void *handle, void *blk, int len) +void aes_ssh2_sdctr(AESContext *ctx, void *blk, int len) { - AESContext *ctx = (AESContext *)handle; aes_sdctr(blk, len, ctx); } @@ -1048,63 +1042,112 @@ void aes256_decrypt_pubkey(const void *key, void *blk, int len) smemclr(&ctx, sizeof(ctx)); } -static const struct ssh2_cipher ssh_aes128_ctr = { - aes_make_context, aes_free_context, aes_iv, aes128_key, - aes_ssh2_sdctr, aes_ssh2_sdctr, NULL, NULL, +struct aes_ssh2_ctx { + AESContext context; + ssh2_cipher vt; +}; + +ssh2_cipher *aes_ssh2_new(const struct ssh2_cipheralg *alg) +{ + struct aes_ssh2_ctx *ctx = snew(struct aes_ssh2_ctx); + ctx->vt = alg; + return &ctx->vt; +} + +static void aes_ssh2_free(ssh2_cipher *cipher) +{ + struct aes_ssh2_ctx *ctx = FROMFIELD(cipher, struct aes_ssh2_ctx, vt); + smemclr(ctx, sizeof(*ctx)); + sfree(ctx); +} + +static void aes_ssh2_setiv(ssh2_cipher *cipher, const void *iv) +{ + struct aes_ssh2_ctx *ctx = FROMFIELD(cipher, struct aes_ssh2_ctx, vt); + aes_iv(&ctx->context, iv); +} + +static void aes_ssh2_setkey(ssh2_cipher *cipher, const void *key) +{ + struct aes_ssh2_ctx *ctx = FROMFIELD(cipher, struct aes_ssh2_ctx, vt); + aes_setup(&ctx->context, key, ctx->vt->padded_keybytes); +} + +static void aes_ssh2_encrypt(ssh2_cipher *cipher, void *blk, int len) +{ + struct aes_ssh2_ctx *ctx = FROMFIELD(cipher, struct aes_ssh2_ctx, vt); + aes_encrypt_cbc(blk, len, &ctx->context); +} + +static void aes_ssh2_decrypt(ssh2_cipher *cipher, void *blk, int len) +{ + struct aes_ssh2_ctx *ctx = FROMFIELD(cipher, struct aes_ssh2_ctx, vt); + aes_decrypt_cbc(blk, len, &ctx->context); +} + +static void aes_ssh2_sdctr_method(ssh2_cipher *cipher, void *blk, int len) +{ + struct aes_ssh2_ctx *ctx = FROMFIELD(cipher, struct aes_ssh2_ctx, vt); + aes_sdctr(blk, len, &ctx->context); +} + +static const struct ssh2_cipheralg ssh_aes128_ctr = { + aes_ssh2_new, aes_ssh2_free, aes_ssh2_setiv, aes_ssh2_setkey, + aes_ssh2_sdctr_method, aes_ssh2_sdctr_method, NULL, NULL, "aes128-ctr", 16, 128, 16, 0, "AES-128 SDCTR", NULL }; -static const struct ssh2_cipher ssh_aes192_ctr = { - aes_make_context, aes_free_context, aes_iv, aes192_key, - aes_ssh2_sdctr, aes_ssh2_sdctr, NULL, NULL, +static const struct ssh2_cipheralg ssh_aes192_ctr = { + aes_ssh2_new, aes_ssh2_free, aes_ssh2_setiv, aes_ssh2_setkey, + aes_ssh2_sdctr_method, aes_ssh2_sdctr_method, NULL, NULL, "aes192-ctr", 16, 192, 24, 0, "AES-192 SDCTR", NULL }; -static const struct ssh2_cipher ssh_aes256_ctr = { - aes_make_context, aes_free_context, aes_iv, aes256_key, - aes_ssh2_sdctr, aes_ssh2_sdctr, NULL, NULL, +static const struct ssh2_cipheralg ssh_aes256_ctr = { + aes_ssh2_new, aes_ssh2_free, aes_ssh2_setiv, aes_ssh2_setkey, + aes_ssh2_sdctr_method, aes_ssh2_sdctr_method, NULL, NULL, "aes256-ctr", 16, 256, 32, 0, "AES-256 SDCTR", NULL }; -static const struct ssh2_cipher ssh_aes128 = { - aes_make_context, aes_free_context, aes_iv, aes128_key, - aes_ssh2_encrypt_blk, aes_ssh2_decrypt_blk, NULL, NULL, +static const struct ssh2_cipheralg ssh_aes128 = { + aes_ssh2_new, aes_ssh2_free, aes_ssh2_setiv, aes_ssh2_setkey, + aes_ssh2_encrypt, aes_ssh2_decrypt, NULL, NULL, "aes128-cbc", 16, 128, 16, SSH_CIPHER_IS_CBC, "AES-128 CBC", NULL }; -static const struct ssh2_cipher ssh_aes192 = { - aes_make_context, aes_free_context, aes_iv, aes192_key, - aes_ssh2_encrypt_blk, aes_ssh2_decrypt_blk, NULL, NULL, +static const struct ssh2_cipheralg ssh_aes192 = { + aes_ssh2_new, aes_ssh2_free, aes_ssh2_setiv, aes_ssh2_setkey, + aes_ssh2_encrypt, aes_ssh2_decrypt, NULL, NULL, "aes192-cbc", 16, 192, 24, SSH_CIPHER_IS_CBC, "AES-192 CBC", NULL }; -static const struct ssh2_cipher ssh_aes256 = { - aes_make_context, aes_free_context, aes_iv, aes256_key, - aes_ssh2_encrypt_blk, aes_ssh2_decrypt_blk, NULL, NULL, +static const struct ssh2_cipheralg ssh_aes256 = { + aes_ssh2_new, aes_ssh2_free, aes_ssh2_setiv, aes_ssh2_setkey, + aes_ssh2_encrypt, aes_ssh2_decrypt, NULL, NULL, "aes256-cbc", 16, 256, 32, SSH_CIPHER_IS_CBC, "AES-256 CBC", NULL }; -static const struct ssh2_cipher ssh_rijndael_lysator = { - aes_make_context, aes_free_context, aes_iv, aes256_key, - aes_ssh2_encrypt_blk, aes_ssh2_decrypt_blk, NULL, NULL, +static const struct ssh2_cipheralg ssh_rijndael_lysator = { + aes_ssh2_new, aes_ssh2_free, aes_ssh2_setiv, aes_ssh2_setkey, + aes_ssh2_encrypt, aes_ssh2_decrypt, NULL, NULL, "rijndael-cbc@lysator.liu.se", 16, 256, 32, SSH_CIPHER_IS_CBC, "AES-256 CBC", NULL }; -static const struct ssh2_cipher *const aes_list[] = { +static const struct ssh2_cipheralg *const aes_list[] = { &ssh_aes256_ctr, &ssh_aes256, &ssh_rijndael_lysator, diff --git a/ssharcf.c b/ssharcf.c index 336e4d06..3434459c 100644 --- a/ssharcf.c +++ b/ssharcf.c @@ -9,6 +9,7 @@ typedef struct { unsigned char i, j, s[256]; + ssh2_cipher vt; } ArcfourContext; static void arcfour_block(void *handle, void *vblk, int len) @@ -61,14 +62,18 @@ static void arcfour_setkey(ArcfourContext *ctx, unsigned char const *key, * to leak data about the key. */ -static void *arcfour_make_context(void) +static ssh2_cipher *arcfour_new(const struct ssh2_cipheralg *alg) { - return snew(ArcfourContext); + ArcfourContext *ctx = snew(ArcfourContext); + ctx->vt = alg; + return &ctx->vt; } -static void arcfour_free_context(void *handle) +static void arcfour_free(ssh2_cipher *cipher) { - sfree(handle); + ArcfourContext *ctx = FROMFIELD(cipher, ArcfourContext, vt); + smemclr(ctx, sizeof(*ctx)); + sfree(ctx); } static void arcfour_stir(ArcfourContext *ctx) @@ -80,42 +85,41 @@ static void arcfour_stir(ArcfourContext *ctx) sfree(junk); } -static void arcfour128_key(void *handle, const void *key) +static void arcfour_ssh2_setiv(ssh2_cipher *cipher, const void *key) { - ArcfourContext *ctx = (ArcfourContext *)handle; - arcfour_setkey(ctx, key, 16); - arcfour_stir(ctx); + /* As a pure stream cipher, Arcfour has no IV separate from the key */ } -static void arcfour256_key(void *handle, const void *key) +static void arcfour_ssh2_setkey(ssh2_cipher *cipher, const void *key) { - ArcfourContext *ctx = (ArcfourContext *)handle; - arcfour_setkey(ctx, key, 32); + ArcfourContext *ctx = FROMFIELD(cipher, ArcfourContext, vt); + arcfour_setkey(ctx, key, ctx->vt->padded_keybytes); arcfour_stir(ctx); } -static void arcfour_iv(void *handle, const void *iv) +static void arcfour_ssh2_block(ssh2_cipher *cipher, void *blk, int len) { - + ArcfourContext *ctx = FROMFIELD(cipher, ArcfourContext, vt); + arcfour_block(ctx, blk, len); } -const struct ssh2_cipher ssh_arcfour128_ssh2 = { - arcfour_make_context, arcfour_free_context, arcfour_iv, arcfour128_key, - arcfour_block, arcfour_block, NULL, NULL, +const struct ssh2_cipheralg ssh_arcfour128_ssh2 = { + arcfour_new, arcfour_free, arcfour_ssh2_setiv, arcfour_ssh2_setkey, + arcfour_ssh2_block, arcfour_ssh2_block, NULL, NULL, "arcfour128", 1, 128, 16, 0, "Arcfour-128", NULL }; -const struct ssh2_cipher ssh_arcfour256_ssh2 = { - arcfour_make_context, arcfour_free_context, arcfour_iv, arcfour256_key, - arcfour_block, arcfour_block, NULL, NULL, +const struct ssh2_cipheralg ssh_arcfour256_ssh2 = { + arcfour_new, arcfour_free, arcfour_ssh2_setiv, arcfour_ssh2_setkey, + arcfour_ssh2_block, arcfour_ssh2_block, NULL, NULL, "arcfour256", 1, 256, 32, 0, "Arcfour-256", NULL }; -static const struct ssh2_cipher *const arcfour_list[] = { +static const struct ssh2_cipheralg *const arcfour_list[] = { &ssh_arcfour256_ssh2, &ssh_arcfour128_ssh2, }; diff --git a/sshblowf.c b/sshblowf.c index 764f3f65..f5460518 100644 --- a/sshblowf.c +++ b/sshblowf.c @@ -554,16 +554,23 @@ static void blowfish_setkey(BlowfishContext *ctx, /* -- Interface with PuTTY -- */ -#define SSH_SESSION_KEY_LENGTH 32 +#define SSH1_SESSION_KEY_LENGTH 32 -void *blowfish_make_context(void) +BlowfishContext *blowfish_make_context(void) { return snew(BlowfishContext); } -void blowfish_free_context(void *handle) +void blowfish_free_context(BlowfishContext *ctx) { - sfree(handle); + sfree(ctx); +} + +static void blowfish_iv(BlowfishContext *ctx, const void *viv) +{ + const unsigned char *iv = (const unsigned char *)viv; + ctx->iv0 = GET_32BIT_MSB_FIRST(iv); + ctx->iv1 = GET_32BIT_MSB_FIRST(iv + 4); } struct blowfish_ssh1_ctx { @@ -587,31 +594,11 @@ static void blowfish_ssh1_free(ssh1_cipher *cipher) sfree(ctx); } -static void blowfish_key(void *handle, const void *key) -{ - BlowfishContext *ctx = (BlowfishContext *)handle; - blowfish_setkey(ctx, key, 16); -} - -static void blowfish256_key(void *handle, const void *key) -{ - BlowfishContext *ctx = (BlowfishContext *)handle; - blowfish_setkey(ctx, key, 32); -} - -static void blowfish_iv(void *handle, const void *viv) -{ - const unsigned char *iv = (const unsigned char *)viv; - BlowfishContext *ctx = (BlowfishContext *)handle; - ctx->iv0 = GET_32BIT_MSB_FIRST(iv); - ctx->iv1 = GET_32BIT_MSB_FIRST(iv + 4); -} - static void blowfish_ssh1_sesskey(ssh1_cipher *cipher, const void *key) { struct blowfish_ssh1_ctx *ctx = FROMFIELD(cipher, struct blowfish_ssh1_ctx, vt); - blowfish_setkey(&ctx->contexts[0], key, SSH_SESSION_KEY_LENGTH); + blowfish_setkey(&ctx->contexts[0], key, SSH1_SESSION_KEY_LENGTH); ctx->contexts[0].iv0 = ctx->contexts[0].iv1 = 0; ctx->contexts[1] = ctx->contexts[0]; /* structure copy */ } @@ -630,22 +617,59 @@ static void blowfish_ssh1_decrypt_blk(ssh1_cipher *cipher, void *blk, int len) blowfish_lsb_decrypt_cbc(blk, len, ctx->contexts+1); } -static void blowfish_ssh2_encrypt_blk(void *handle, void *blk, int len) +struct blowfish_ssh2_ctx { + BlowfishContext context; + ssh2_cipher vt; +}; + +static ssh2_cipher *blowfish_ssh2_new(const struct ssh2_cipheralg *alg) +{ + struct blowfish_ssh2_ctx *ctx = snew(struct blowfish_ssh2_ctx); + ctx->vt = alg; + return &ctx->vt; +} + +static void blowfish_ssh2_free(ssh2_cipher *cipher) +{ + struct blowfish_ssh2_ctx *ctx = + FROMFIELD(cipher, struct blowfish_ssh2_ctx, vt); + smemclr(ctx, sizeof(*ctx)); + sfree(ctx); +} + +static void blowfish_ssh2_setiv(ssh2_cipher *cipher, const void *iv) +{ + struct blowfish_ssh2_ctx *ctx = + FROMFIELD(cipher, struct blowfish_ssh2_ctx, vt); + blowfish_iv(&ctx->context, iv); +} + +static void blowfish_ssh2_setkey(ssh2_cipher *cipher, const void *key) +{ + struct blowfish_ssh2_ctx *ctx = + FROMFIELD(cipher, struct blowfish_ssh2_ctx, vt); + blowfish_setkey(&ctx->context, key, ctx->vt->padded_keybytes); +} + +static void blowfish_ssh2_encrypt_blk(ssh2_cipher *cipher, void *blk, int len) { - BlowfishContext *ctx = (BlowfishContext *)handle; - blowfish_msb_encrypt_cbc(blk, len, ctx); + struct blowfish_ssh2_ctx *ctx = + FROMFIELD(cipher, struct blowfish_ssh2_ctx, vt); + blowfish_msb_encrypt_cbc(blk, len, &ctx->context); } -static void blowfish_ssh2_decrypt_blk(void *handle, void *blk, int len) +static void blowfish_ssh2_decrypt_blk(ssh2_cipher *cipher, void *blk, int len) { - BlowfishContext *ctx = (BlowfishContext *)handle; - blowfish_msb_decrypt_cbc(blk, len, ctx); + struct blowfish_ssh2_ctx *ctx = + FROMFIELD(cipher, struct blowfish_ssh2_ctx, vt); + blowfish_msb_decrypt_cbc(blk, len, &ctx->context); } -static void blowfish_ssh2_sdctr(void *handle, void *blk, int len) +static void blowfish_ssh2_sdctr(ssh2_cipher *cipher, void *blk, int len) { - BlowfishContext *ctx = (BlowfishContext *)handle; - blowfish_msb_sdctr(blk, len, ctx); + struct blowfish_ssh2_ctx *ctx = + FROMFIELD(cipher, struct blowfish_ssh2_ctx, vt); + blowfish_msb_sdctr(blk, len, &ctx->context); } const struct ssh1_cipheralg ssh1_blowfish = { @@ -655,23 +679,25 @@ const struct ssh1_cipheralg ssh1_blowfish = { 8, "Blowfish-128 CBC" }; -static const struct ssh2_cipher ssh_blowfish_ssh2 = { - blowfish_make_context, blowfish_free_context, blowfish_iv, blowfish_key, +static const struct ssh2_cipheralg ssh_blowfish_ssh2 = { + blowfish_ssh2_new, blowfish_ssh2_free, + blowfish_ssh2_setiv, blowfish_ssh2_setkey, blowfish_ssh2_encrypt_blk, blowfish_ssh2_decrypt_blk, NULL, NULL, "blowfish-cbc", 8, 128, 16, SSH_CIPHER_IS_CBC, "Blowfish-128 CBC", NULL }; -static const struct ssh2_cipher ssh_blowfish_ssh2_ctr = { - blowfish_make_context, blowfish_free_context, blowfish_iv, blowfish256_key, +static const struct ssh2_cipheralg ssh_blowfish_ssh2_ctr = { + blowfish_ssh2_new, blowfish_ssh2_free, + blowfish_ssh2_setiv, blowfish_ssh2_setkey, blowfish_ssh2_sdctr, blowfish_ssh2_sdctr, NULL, NULL, "blowfish-ctr", 8, 256, 32, 0, "Blowfish-256 SDCTR", NULL }; -static const struct ssh2_cipher *const blowfish_list[] = { +static const struct ssh2_cipheralg *const blowfish_list[] = { &ssh_blowfish_ssh2_ctr, &ssh_blowfish_ssh2 }; diff --git a/sshblowf.h b/sshblowf.h index e2364521..a9efe3da 100644 --- a/sshblowf.h +++ b/sshblowf.h @@ -5,8 +5,8 @@ typedef struct BlowfishContext BlowfishContext; -void *blowfish_make_context(void); -void blowfish_free_context(void *handle); +BlowfishContext *blowfish_make_context(void); +void blowfish_free_context(BlowfishContext *ctx); void blowfish_initkey(BlowfishContext *ctx); void blowfish_expandkey(BlowfishContext *ctx, const void *key, short keybytes, diff --git a/sshbpp.h b/sshbpp.h index de11e69d..41683410 100644 --- a/sshbpp.h +++ b/sshbpp.h @@ -39,12 +39,12 @@ void ssh1_bpp_start_compression(BinaryPacketProtocol *bpp); BinaryPacketProtocol *ssh2_bpp_new(void); void ssh2_bpp_new_outgoing_crypto( BinaryPacketProtocol *bpp, - const struct ssh2_cipher *cipher, const void *ckey, const void *iv, + const struct ssh2_cipheralg *cipher, const void *ckey, const void *iv, const struct ssh_mac *mac, int etm_mode, const void *mac_key, const struct ssh_compress *compression); void ssh2_bpp_new_incoming_crypto( BinaryPacketProtocol *bpp, - const struct ssh2_cipher *cipher, const void *ckey, const void *iv, + const struct ssh2_cipheralg *cipher, const void *ckey, const void *iv, const struct ssh_mac *mac, int etm_mode, const void *mac_key, const struct ssh_compress *compression); diff --git a/sshccp.c b/sshccp.c index 04f1cc16..9919ced2 100644 --- a/sshccp.c +++ b/sshccp.c @@ -20,7 +20,7 @@ * This has an intricate link between the cipher and the MAC. The * keying of both is done in by the cipher and setting of the IV is * done by the MAC. One cannot operate without the other. The - * configuration of the ssh2_cipher structure ensures that the MAC is + * configuration of the ssh2_cipheralg structure ensures that the MAC is * set (and others ignored) if this cipher is chosen. * * This cipher also encrypts the length using a different @@ -866,11 +866,12 @@ struct ccp_context { struct poly1305 mac; BinarySink_IMPLEMENTATION; + ssh2_cipher vt; }; -static void *poly_make_context(void *ctx) +static void *poly_make_context(ssh2_cipher *cipher) { - return ctx; + return FROMFIELD(cipher, struct ccp_context, vt); } static void poly_free_context(void *ctx) @@ -987,48 +988,49 @@ static const struct ssh_mac ssh2_poly1305 = { 16, 0, "Poly1305" }; -static void *ccp_make_context(void) +static ssh2_cipher *ccp_new(const struct ssh2_cipheralg *alg) { struct ccp_context *ctx = snew(struct ccp_context); BinarySink_INIT(ctx, poly_BinarySink_write); poly1305_init(&ctx->mac); - return ctx; + ctx->vt = alg; + return &ctx->vt; } -static void ccp_free_context(void *vctx) +static void ccp_free(ssh2_cipher *cipher) { - struct ccp_context *ctx = (struct ccp_context *)vctx; + struct ccp_context *ctx = FROMFIELD(cipher, struct ccp_context, vt); smemclr(&ctx->a_cipher, sizeof(ctx->a_cipher)); smemclr(&ctx->b_cipher, sizeof(ctx->b_cipher)); smemclr(&ctx->mac, sizeof(ctx->mac)); sfree(ctx); } -static void ccp_iv(void *vctx, const void *iv) +static void ccp_iv(ssh2_cipher *cipher, const void *iv) { - /* struct ccp_context *ctx = (struct ccp_context *)vctx; */ + /* struct ccp_context *ctx = FROMFIELD(cipher, struct ccp_context, vt); */ /* IV is set based on the sequence number */ } -static void ccp_key(void *vctx, const void *vkey) +static void ccp_key(ssh2_cipher *cipher, const void *vkey) { const unsigned char *key = (const unsigned char *)vkey; - struct ccp_context *ctx = (struct ccp_context *)vctx; + struct ccp_context *ctx = FROMFIELD(cipher, struct ccp_context, vt); /* Initialise the a_cipher (for decrypting lengths) with the first 256 bits */ chacha20_key(&ctx->a_cipher, key + 32); /* Initialise the b_cipher (for content and MAC) with the second 256 bits */ chacha20_key(&ctx->b_cipher, key); } -static void ccp_encrypt(void *vctx, void *blk, int len) +static void ccp_encrypt(ssh2_cipher *cipher, void *blk, int len) { - struct ccp_context *ctx = (struct ccp_context *)vctx; + struct ccp_context *ctx = FROMFIELD(cipher, struct ccp_context, vt); chacha20_encrypt(&ctx->b_cipher, blk, len); } -static void ccp_decrypt(void *vctx, void *blk, int len) +static void ccp_decrypt(ssh2_cipher *cipher, void *blk, int len) { - struct ccp_context *ctx = (struct ccp_context *)vctx; + struct ccp_context *ctx = FROMFIELD(cipher, struct ccp_context, vt); chacha20_decrypt(&ctx->b_cipher, blk, len); } @@ -1049,26 +1051,26 @@ static void ccp_length_op(struct ccp_context *ctx, void *blk, int len, smemclr(iv, sizeof(iv)); } -static void ccp_encrypt_length(void *vctx, void *blk, int len, +static void ccp_encrypt_length(ssh2_cipher *cipher, void *blk, int len, unsigned long seq) { - struct ccp_context *ctx = (struct ccp_context *)vctx; + struct ccp_context *ctx = FROMFIELD(cipher, struct ccp_context, vt); ccp_length_op(ctx, blk, len, seq); chacha20_encrypt(&ctx->a_cipher, blk, len); } -static void ccp_decrypt_length(void *vctx, void *blk, int len, +static void ccp_decrypt_length(ssh2_cipher *cipher, void *blk, int len, unsigned long seq) { - struct ccp_context *ctx = (struct ccp_context *)vctx; + struct ccp_context *ctx = FROMFIELD(cipher, struct ccp_context, vt); ccp_length_op(ctx, blk, len, seq); chacha20_decrypt(&ctx->a_cipher, blk, len); } -static const struct ssh2_cipher ssh2_chacha20_poly1305 = { +static const struct ssh2_cipheralg ssh2_chacha20_poly1305 = { - ccp_make_context, - ccp_free_context, + ccp_new, + ccp_free, ccp_iv, ccp_key, ccp_encrypt, @@ -1082,7 +1084,7 @@ static const struct ssh2_cipher ssh2_chacha20_poly1305 = { &ssh2_poly1305 }; -static const struct ssh2_cipher *const ccp_list[] = { +static const struct ssh2_cipheralg *const ccp_list[] = { &ssh2_chacha20_poly1305 }; diff --git a/sshdes.c b/sshdes.c index 6cc1ce67..c3afe3eb 100644 --- a/sshdes.c +++ b/sshdes.c @@ -747,9 +747,29 @@ static void des_sdctr3(unsigned char *blk, scheds->iv1 = iv1; } -static void *des3_make_context(void) +static void des3_key(DESContext *contexts, const void *vkey) { - return snewn(3, DESContext); + const unsigned char *key = (const unsigned char *)vkey; + des_key_setup(GET_32BIT_MSB_FIRST(key), + GET_32BIT_MSB_FIRST(key + 4), &contexts[0]); + des_key_setup(GET_32BIT_MSB_FIRST(key + 8), + GET_32BIT_MSB_FIRST(key + 12), &contexts[1]); + des_key_setup(GET_32BIT_MSB_FIRST(key + 16), + GET_32BIT_MSB_FIRST(key + 20), &contexts[2]); +} + +static void des_iv(DESContext *context, const void *viv) +{ + const unsigned char *iv = (const unsigned char *)viv; + context->iv0 = GET_32BIT_MSB_FIRST(iv); + context->iv1 = GET_32BIT_MSB_FIRST(iv + 4); +} + +static void des_key(DESContext *context, const void *vkey) +{ + const unsigned char *key = (const unsigned char *)vkey; + des_key_setup(GET_32BIT_MSB_FIRST(key), + GET_32BIT_MSB_FIRST(key + 4), context); } struct des3_ssh1_ctx { @@ -771,11 +791,6 @@ static ssh1_cipher *des3_ssh1_new(void) return &ctx->vt; } -static void *des_make_context(void) -{ - return snew(DESContext); -} - static ssh1_cipher *des_ssh1_new(void) { struct des_ssh1_ctx *ctx = snew(struct des_ssh1_ctx); @@ -797,39 +812,6 @@ static void des_ssh1_free(ssh1_cipher *cipher) sfree(ctx); } -static void des3_free_context(void *handle) /* used for both 3DES and DES */ -{ - sfree(handle); -} - -static void des3_key(void *handle, const void *vkey) -{ - const unsigned char *key = (const unsigned char *)vkey; - DESContext *keys = (DESContext *) handle; - des_key_setup(GET_32BIT_MSB_FIRST(key), - GET_32BIT_MSB_FIRST(key + 4), &keys[0]); - des_key_setup(GET_32BIT_MSB_FIRST(key + 8), - GET_32BIT_MSB_FIRST(key + 12), &keys[1]); - des_key_setup(GET_32BIT_MSB_FIRST(key + 16), - GET_32BIT_MSB_FIRST(key + 20), &keys[2]); -} - -static void des3_iv(void *handle, const void *viv) -{ - const unsigned char *iv = (const unsigned char *)viv; - DESContext *keys = (DESContext *) handle; - keys[0].iv0 = GET_32BIT_MSB_FIRST(iv); - keys[0].iv1 = GET_32BIT_MSB_FIRST(iv + 4); -} - -static void des_key(void *handle, const void *vkey) -{ - const unsigned char *key = (const unsigned char *)vkey; - DESContext *keys = (DESContext *) handle; - des_key_setup(GET_32BIT_MSB_FIRST(key), - GET_32BIT_MSB_FIRST(key + 4), &keys[0]); -} - static void des3_ssh1_sesskey(ssh1_cipher *cipher, const void *key) { struct des3_ssh1_ctx *ctx = FROMFIELD(cipher, struct des3_ssh1_ctx, vt); @@ -868,34 +850,98 @@ static void des_ssh1_decrypt_blk(ssh1_cipher *cipher, void *blk, int len) des_cbc_decrypt(blk, len, ctx->contexts+1); } -static void des3_ssh2_encrypt_blk(void *handle, void *blk, int len) +struct des3_ssh2_ctx { + DESContext contexts[3]; + ssh2_cipher vt; +}; + +struct des_ssh2_ctx { + DESContext context; + ssh2_cipher vt; +}; + +static ssh2_cipher *des3_ssh2_new(const struct ssh2_cipheralg *alg) +{ + struct des3_ssh2_ctx *ctx = snew(struct des3_ssh2_ctx); + ctx->vt = alg; + return &ctx->vt; +} + +static ssh2_cipher *des_ssh2_new(const struct ssh2_cipheralg *alg) +{ + struct des_ssh2_ctx *ctx = snew(struct des_ssh2_ctx); + ctx->vt = alg; + return &ctx->vt; +} + +static void des3_ssh2_free(ssh2_cipher *cipher) +{ + struct des3_ssh2_ctx *ctx = FROMFIELD(cipher, struct des3_ssh2_ctx, vt); + smemclr(ctx, sizeof(*ctx)); + sfree(ctx); +} + +static void des_ssh2_free(ssh2_cipher *cipher) +{ + struct des_ssh2_ctx *ctx = FROMFIELD(cipher, struct des_ssh2_ctx, vt); + smemclr(ctx, sizeof(*ctx)); + sfree(ctx); +} + +static void des3_ssh2_setiv(ssh2_cipher *cipher, const void *iv) +{ + struct des3_ssh2_ctx *ctx = FROMFIELD(cipher, struct des3_ssh2_ctx, vt); + des_iv(&ctx->contexts[0], iv); + /* SSH-2 treats triple-DES as a single block cipher to wrap in + * CBC, so there's only one IV required, not three */ +} + +static void des3_ssh2_setkey(ssh2_cipher *cipher, const void *key) +{ + struct des3_ssh2_ctx *ctx = FROMFIELD(cipher, struct des3_ssh2_ctx, vt); + des3_key(ctx->contexts, key); +} + +static void des_ssh2_setiv(ssh2_cipher *cipher, const void *iv) +{ + struct des_ssh2_ctx *ctx = FROMFIELD(cipher, struct des_ssh2_ctx, vt); + des_iv(&ctx->context, iv); +} + +static void des_ssh2_setkey(ssh2_cipher *cipher, const void *key) +{ + struct des_ssh2_ctx *ctx = FROMFIELD(cipher, struct des_ssh2_ctx, vt); + des_key(&ctx->context, key); +} + +static void des3_ssh2_encrypt_blk(ssh2_cipher *cipher, void *blk, int len) { - DESContext *keys = (DESContext *) handle; - des_cbc3_encrypt(blk, len, keys); + struct des3_ssh2_ctx *ctx = FROMFIELD(cipher, struct des3_ssh2_ctx, vt); + des_cbc3_encrypt(blk, len, ctx->contexts); } -static void des3_ssh2_decrypt_blk(void *handle, void *blk, int len) +static void des3_ssh2_decrypt_blk(ssh2_cipher *cipher, void *blk, int len) { - DESContext *keys = (DESContext *) handle; - des_cbc3_decrypt(blk, len, keys); + struct des3_ssh2_ctx *ctx = FROMFIELD(cipher, struct des3_ssh2_ctx, vt); + des_cbc3_decrypt(blk, len, ctx->contexts); } -static void des3_ssh2_sdctr(void *handle, void *blk, int len) +static void des3_ssh2_sdctr(ssh2_cipher *cipher, void *blk, int len) { - DESContext *keys = (DESContext *) handle; - des_sdctr3(blk, len, keys); + struct des3_ssh2_ctx *ctx = FROMFIELD(cipher, struct des3_ssh2_ctx, vt); + des_sdctr3(blk, len, ctx->contexts); } -static void des_ssh2_encrypt_blk(void *handle, void *blk, int len) +static void des_ssh2_encrypt_blk(ssh2_cipher *cipher, void *blk, int len) { - DESContext *keys = (DESContext *) handle; - des_cbc_encrypt(blk, len, keys); + struct des_ssh2_ctx *ctx = FROMFIELD(cipher, struct des_ssh2_ctx, vt); + des_cbc_encrypt(blk, len, &ctx->context); } -static void des_ssh2_decrypt_blk(void *handle, void *blk, int len) +static void des_ssh2_decrypt_blk(ssh2_cipher *cipher, void *blk, int len) { - DESContext *keys = (DESContext *) handle; - des_cbc_decrypt(blk, len, keys); + struct des_ssh2_ctx *ctx = FROMFIELD(cipher, struct des_ssh2_ctx, vt); + des_cbc_decrypt(blk, len, &ctx->context); } void des3_decrypt_pubkey(const void *vkey, void *vblk, int len) @@ -1004,16 +1050,16 @@ void des_decrypt_xdmauth(const void *keydata, void *blk, int len) des_cbc_decrypt(blk, len, &dc); } -static const struct ssh2_cipher ssh_3des_ssh2 = { - des3_make_context, des3_free_context, des3_iv, des3_key, +static const struct ssh2_cipheralg ssh_3des_ssh2 = { + des3_ssh2_new, des3_ssh2_free, des3_ssh2_setiv, des3_ssh2_setkey, des3_ssh2_encrypt_blk, des3_ssh2_decrypt_blk, NULL, NULL, "3des-cbc", 8, 168, 24, SSH_CIPHER_IS_CBC, "triple-DES CBC", NULL }; -static const struct ssh2_cipher ssh_3des_ssh2_ctr = { - des3_make_context, des3_free_context, des3_iv, des3_key, +static const struct ssh2_cipheralg ssh_3des_ssh2_ctr = { + des3_ssh2_new, des3_ssh2_free, des3_ssh2_setiv, des3_ssh2_setkey, des3_ssh2_sdctr, des3_ssh2_sdctr, NULL, NULL, "3des-ctr", 8, 168, 24, 0, "triple-DES SDCTR", @@ -1028,23 +1074,23 @@ static const struct ssh2_cipher ssh_3des_ssh2_ctr = { * apparently aren't the only people to do so, so we sigh * and implement it anyway. */ -static const struct ssh2_cipher ssh_des_ssh2 = { - des_make_context, des3_free_context, des3_iv, des_key, +static const struct ssh2_cipheralg ssh_des_ssh2 = { + des_ssh2_new, des_ssh2_free, des_ssh2_setiv, des_ssh2_setkey, des_ssh2_encrypt_blk, des_ssh2_decrypt_blk, NULL, NULL, "des-cbc", 8, 56, 8, SSH_CIPHER_IS_CBC, "single-DES CBC", NULL }; -static const struct ssh2_cipher ssh_des_sshcom_ssh2 = { - des_make_context, des3_free_context, des3_iv, des_key, +static const struct ssh2_cipheralg ssh_des_sshcom_ssh2 = { + des_ssh2_new, des_ssh2_free, des_ssh2_setiv, des_ssh2_setkey, des_ssh2_encrypt_blk, des_ssh2_decrypt_blk, NULL, NULL, "des-cbc@ssh.com", 8, 56, 8, SSH_CIPHER_IS_CBC, "single-DES CBC", NULL }; -static const struct ssh2_cipher *const des3_list[] = { +static const struct ssh2_cipheralg *const des3_list[] = { &ssh_3des_ssh2_ctr, &ssh_3des_ssh2 }; @@ -1054,7 +1100,7 @@ const struct ssh2_ciphers ssh2_3des = { des3_list }; -static const struct ssh2_cipher *const des_list[] = { +static const struct ssh2_cipheralg *const des_list[] = { &ssh_des_ssh2, &ssh_des_sshcom_ssh2 }; diff --git a/sshmd5.c b/sshmd5.c index 05f00d0b..be3b96cf 100644 --- a/sshmd5.c +++ b/sshmd5.c @@ -228,7 +228,7 @@ void MD5Simple(void const *p, unsigned len, unsigned char output[16]) * useful elsewhere (SOCKS5 CHAP authentication uses HMAC-MD5). */ -void *hmacmd5_make_context(void *cipher_ctx) +void *hmacmd5_make_context(ssh2_cipher *cipher) { return snewn(3, struct MD5Context); } diff --git a/sshsh256.c b/sshsh256.c index 66752326..51788679 100644 --- a/sshsh256.c +++ b/sshsh256.c @@ -256,7 +256,7 @@ const struct ssh_hash ssh_sha256 = { * HMAC wrapper on it. */ -static void *sha256_make_context(void *cipher_ctx) +static void *sha256_make_context(ssh2_cipher *cipher) { return snewn(3, SHA256_State); } diff --git a/sshsha.c b/sshsha.c index 4b9d002f..e2f2a860 100644 --- a/sshsha.c +++ b/sshsha.c @@ -283,7 +283,7 @@ const struct ssh_hash ssh_sha1 = { * HMAC wrapper on it. */ -static void *sha1_make_context(void *cipher_ctx) +static void *sha1_make_context(ssh2_cipher *cipher) { return snewn(3, SHA_State); } From 853bd8b28410d0469596d0b594e5199fbb3b3b8f Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Thu, 13 Sep 2018 16:15:17 +0100 Subject: [PATCH 401/607] Turn SSH-2 MACs into a classoid. This piece of tidying-up has come out particularly well in terms of saving tedious repetition and boilerplate. I've managed to remove three pointless methods from every MAC implementation by means of writing them once centrally in terms of the implementation-specific methods; another method (hmacmd5_sink) vanished because I was able to make the interface type 'ssh2_mac' be directly usable as a BinarySink by way of a new delegation system; and because all the method implementations can now find their own vtable, I was even able to merge a lot of keying and output functions that had previously differed only in length parameters by having them look up the lengths in whatever vtable they were passed. --- Recipe | 1 + cproxy.c | 4 +- marshal.h | 11 ++++ ssh.c | 10 ++-- ssh.h | 61 +++++++++++++-------- ssh2bpp.c | 75 ++++++++++++------------- sshbpp.h | 4 +- sshccp.c | 95 +++++++++----------------------- sshmac.c | 42 ++++++++++++++ sshmd5.c | 129 +++++++++++++++++-------------------------- sshsh256.c | 99 ++++++++++++--------------------- sshsha.c | 158 ++++++++++++++++------------------------------------- 12 files changed, 293 insertions(+), 396 deletions(-) create mode 100644 sshmac.c diff --git a/Recipe b/Recipe index 5af98117..b735ac47 100644 --- a/Recipe +++ b/Recipe @@ -255,6 +255,7 @@ SSH = ssh ssh1bpp ssh2bpp ssh2bpp-bare ssh1censor ssh2censor + sshdh sshcrcda sshpubk sshzlib sshdss x11fwd portfwd + sshaes sshccp sshsh256 sshsh512 sshbn wildcard pinger ssharcf + sshgssc pgssapi sshshare sshecc aqsync marshal nullplug agentf + + sshmac WINSSH = SSH winnoise wincapi winpgntc wingss winshare winnps winnpc + winhsock errsock UXSSH = SSH uxnoise uxagentc uxgss uxshare diff --git a/cproxy.c b/cproxy.c index 142c2a17..5d5439fa 100644 --- a/cproxy.c +++ b/cproxy.c @@ -19,10 +19,10 @@ static void hmacmd5_chap(const unsigned char *challenge, int challen, const char *passwd, unsigned char *response) { - void *hmacmd5_ctx; + struct hmacmd5_context *hmacmd5_ctx; int pwlen; - hmacmd5_ctx = hmacmd5_make_context(NULL); + hmacmd5_ctx = hmacmd5_make_context(); pwlen = strlen(passwd); if (pwlen>64) { diff --git a/marshal.h b/marshal.h index 2aa0301a..631e2465 100644 --- a/marshal.h +++ b/marshal.h @@ -25,6 +25,17 @@ struct BinarySink { ((obj)->binarysink_->write = (writefn), \ (obj)->binarysink_->binarysink_ = (obj)->binarysink_) +/* + * To define a larger structure type as a valid BinarySink in such a + * way that it will delegate the write method to some other object, + * put 'BinarySink_DELEGATE_IMPLEMENTATION' in its declaration, and + * when an instance is set up, use 'BinarySink_DELEGATE_INIT' to point + * at the object it wants to delegate to. + */ +#define BinarySink_DELEGATE_IMPLEMENTATION BinarySink *binarysink_ +#define BinarySink_DELEGATE_INIT(obj, othersink) \ + ((obj)->binarysink_ = BinarySink_UPCAST(othersink)) + /* * The implementing type's write function will want to downcast its * 'BinarySink *' parameter back to the more specific type. Also, diff --git a/ssh.c b/ssh.c index 1ece7488..814d28b7 100644 --- a/ssh.c +++ b/ssh.c @@ -328,10 +328,10 @@ const static struct ssh_signkey_with_user_pref_id hostkey_algs[] = { { &ssh_rsa, HK_RSA }, }; -const static struct ssh_mac *const macs[] = { +const static struct ssh2_macalg *const macs[] = { &ssh_hmac_sha256, &ssh_hmac_sha1, &ssh_hmac_sha1_96, &ssh_hmac_md5 }; -const static struct ssh_mac *const buggymacs[] = { +const static struct ssh2_macalg *const buggymacs[] = { &ssh_hmac_sha1_buggy, &ssh_hmac_sha1_96_buggy, &ssh_hmac_md5 }; @@ -4854,7 +4854,7 @@ struct kexinit_algorithm { int warn; } cipher; struct { - const struct ssh_mac *mac; + const struct ssh2_macalg *mac; int etm; } mac; const struct ssh_compress *comp; @@ -5023,11 +5023,11 @@ static void do_ssh2_transport(void *vctx) void *our_kexinit; int our_kexinitlen; int kex_init_value, kex_reply_value; - const struct ssh_mac *const *maclist; + const struct ssh2_macalg *const *maclist; int nmacs; struct { const struct ssh2_cipheralg *cipher; - const struct ssh_mac *mac; + const struct ssh2_macalg *mac; int etm_mode; const struct ssh_compress *comp; } in, out; diff --git a/ssh.h b/ssh.h index a856aa9e..6b768a8a 100644 --- a/ssh.h +++ b/ssh.h @@ -374,11 +374,12 @@ void MD5Init(struct MD5Context *context); void MD5Final(unsigned char digest[16], struct MD5Context *context); void MD5Simple(void const *p, unsigned len, unsigned char output[16]); -void *hmacmd5_make_context(ssh2_cipher *); -void hmacmd5_free_context(void *handle); -void hmacmd5_key(void *handle, void const *key, int len); -void hmacmd5_do_hmac(void *handle, unsigned char const *blk, int len, - unsigned char *hmac); +struct hmacmd5_context; +struct hmacmd5_context *hmacmd5_make_context(void); +void hmacmd5_free_context(struct hmacmd5_context *ctx); +void hmacmd5_key(struct hmacmd5_context *ctx, void const *key, int len); +void hmacmd5_do_hmac(struct hmacmd5_context *ctx, + unsigned char const *blk, int len, unsigned char *hmac); int supports_sha_ni(void); @@ -476,7 +477,7 @@ struct ssh2_cipheralg { #define SSH_CIPHER_SEPARATE_LENGTH 2 const char *text_name; /* If set, this takes priority over other MAC. */ - const struct ssh_mac *required_mac; + const struct ssh2_macalg *required_mac; }; #define ssh2_cipher_new(alg) ((alg)->new(alg)) @@ -496,24 +497,36 @@ struct ssh2_ciphers { const struct ssh2_cipheralg *const *list; }; -struct ssh_mac { +struct ssh2_macalg; +typedef struct ssh2_mac { + const struct ssh2_macalg *vt; + BinarySink_DELEGATE_IMPLEMENTATION; +} ssh2_mac; + +struct ssh2_macalg { /* Passes in the cipher context */ - void *(*make_context)(ssh2_cipher *); - void (*free_context)(void *); - void (*setkey) (void *, const void *key); - /* whole-packet operations */ - void (*generate) (void *, void *blk, int len, unsigned long seq); - int (*verify) (void *, const void *blk, int len, unsigned long seq); - /* partial-packet operations */ - void (*start) (void *); - BinarySink *(*sink) (void *); - void (*genresult) (void *, unsigned char *); - int (*verresult) (void *, unsigned char const *); + ssh2_mac *(*new)(const struct ssh2_macalg *alg, ssh2_cipher *cipher); + void (*free)(ssh2_mac *); + void (*setkey)(ssh2_mac *, const void *key); + void (*start)(ssh2_mac *); + void (*genresult)(ssh2_mac *, unsigned char *); const char *name, *etm_name; int len, keylen; const char *text_name; }; +#define ssh2_mac_new(alg, cipher) ((alg)->new(alg, cipher)) +#define ssh2_mac_free(ctx) ((ctx)->vt->free(ctx)) +#define ssh2_mac_setkey(ctx, key) ((ctx)->vt->free(ctx, key)) +#define ssh2_mac_start(ctx) ((ctx)->vt->start(ctx)) +#define ssh2_mac_genresult(ctx, out) ((ctx)->vt->genresult(ctx, out)) +#define ssh2_mac_alg(ctx) ((ctx)->vt) + +/* Centralised 'methods' for ssh2_mac, defined in sshmac.c */ +int ssh2_mac_verresult(ssh2_mac *, const void *); +void ssh2_mac_generate(ssh2_mac *, void *, int, unsigned long seq); +int ssh2_mac_verify(ssh2_mac *, const void *, int, unsigned long seq); + struct ssh_hash { void *(*init)(void); /* also allocates context */ void *(*copy)(const void *); @@ -628,12 +641,12 @@ extern const ssh_keyalg ssh_ecdsa_ed25519; extern const ssh_keyalg ssh_ecdsa_nistp256; extern const ssh_keyalg ssh_ecdsa_nistp384; extern const ssh_keyalg ssh_ecdsa_nistp521; -extern const struct ssh_mac ssh_hmac_md5; -extern const struct ssh_mac ssh_hmac_sha1; -extern const struct ssh_mac ssh_hmac_sha1_buggy; -extern const struct ssh_mac ssh_hmac_sha1_96; -extern const struct ssh_mac ssh_hmac_sha1_96_buggy; -extern const struct ssh_mac ssh_hmac_sha256; +extern const struct ssh2_macalg ssh_hmac_md5; +extern const struct ssh2_macalg ssh_hmac_sha1; +extern const struct ssh2_macalg ssh_hmac_sha1_buggy; +extern const struct ssh2_macalg ssh_hmac_sha1_96; +extern const struct ssh2_macalg ssh_hmac_sha1_96_buggy; +extern const struct ssh2_macalg ssh_hmac_sha256; typedef struct AESContext AESContext; AESContext *aes_make_context(void); diff --git a/ssh2bpp.c b/ssh2bpp.c index 510e21a5..ff957b05 100644 --- a/ssh2bpp.c +++ b/ssh2bpp.c @@ -12,9 +12,8 @@ struct ssh2_bpp_direction { unsigned long sequence; ssh2_cipher *cipher; - const struct ssh_mac *mac; + ssh2_mac *mac; int etm_mode; - void *mac_ctx; const struct ssh_compress *comp; void *comp_ctx; }; @@ -27,7 +26,6 @@ struct ssh2_bpp_state { unsigned char *data; unsigned cipherblk; PktIn *pktin; - BinarySink *sc_mac_bs; struct ssh2_bpp_direction in, out; int pending_newkeys; @@ -61,14 +59,14 @@ static void ssh2_bpp_free(BinaryPacketProtocol *bpp) sfree(s->buf); if (s->out.cipher) ssh2_cipher_free(s->out.cipher); - if (s->out.mac_ctx) - s->out.mac->free_context(s->out.mac_ctx); + if (s->out.mac) + ssh2_mac_free(s->out.mac); if (s->out.comp_ctx) s->out.comp->compress_cleanup(s->out.comp_ctx); if (s->in.cipher) ssh2_cipher_free(s->in.cipher); - if (s->in.mac_ctx) - s->in.mac->free_context(s->in.mac_ctx); + if (s->in.mac) + ssh2_mac_free(s->in.mac); if (s->in.comp_ctx) s->in.comp->decompress_cleanup(s->in.comp_ctx); if (s->pktin) @@ -79,7 +77,7 @@ static void ssh2_bpp_free(BinaryPacketProtocol *bpp) void ssh2_bpp_new_outgoing_crypto( BinaryPacketProtocol *bpp, const struct ssh2_cipheralg *cipher, const void *ckey, const void *iv, - const struct ssh_mac *mac, int etm_mode, const void *mac_key, + const struct ssh2_macalg *mac, int etm_mode, const void *mac_key, const struct ssh_compress *compression) { struct ssh2_bpp_state *s; @@ -88,8 +86,8 @@ void ssh2_bpp_new_outgoing_crypto( if (s->out.cipher) ssh2_cipher_free(s->out.cipher); - if (s->out.mac_ctx) - s->out.mac->free_context(s->out.mac_ctx); + if (s->out.mac) + ssh2_mac_free(s->out.mac); if (s->out.comp_ctx) s->out.comp->compress_cleanup(s->out.comp_ctx); @@ -100,11 +98,12 @@ void ssh2_bpp_new_outgoing_crypto( } else { s->out.cipher = NULL; } - s->out.mac = mac; s->out.etm_mode = etm_mode; if (mac) { - s->out.mac_ctx = mac->make_context(s->out.cipher); - mac->setkey(s->out.mac_ctx, mac_key); + s->out.mac = ssh2_mac_new(mac, s->out.cipher); + mac->setkey(s->out.mac, mac_key); + } else { + s->out.mac = NULL; } s->out.comp = compression; @@ -117,7 +116,7 @@ void ssh2_bpp_new_outgoing_crypto( void ssh2_bpp_new_incoming_crypto( BinaryPacketProtocol *bpp, const struct ssh2_cipheralg *cipher, const void *ckey, const void *iv, - const struct ssh_mac *mac, int etm_mode, const void *mac_key, + const struct ssh2_macalg *mac, int etm_mode, const void *mac_key, const struct ssh_compress *compression) { struct ssh2_bpp_state *s; @@ -126,8 +125,8 @@ void ssh2_bpp_new_incoming_crypto( if (s->in.cipher) ssh2_cipher_free(s->in.cipher); - if (s->in.mac_ctx) - s->in.mac->free_context(s->in.mac_ctx); + if (s->in.mac) + ssh2_mac_free(s->in.mac); if (s->in.comp_ctx) s->in.comp->decompress_cleanup(s->in.comp_ctx); @@ -138,11 +137,12 @@ void ssh2_bpp_new_incoming_crypto( } else { s->in.cipher = NULL; } - s->in.mac = mac; s->in.etm_mode = etm_mode; if (mac) { - s->in.mac_ctx = mac->make_context(s->in.cipher); - mac->setkey(s->in.mac_ctx, mac_key); + s->in.mac = ssh2_mac_new(mac, s->in.cipher); + mac->setkey(s->in.mac, mac_key); + } else { + s->in.mac = NULL; } s->in.comp = compression; @@ -171,7 +171,7 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp) s->cipherblk = 8; if (s->cipherblk < 8) s->cipherblk = 8; - s->maclen = s->in.mac ? s->in.mac->len : 0; + s->maclen = s->in.mac ? ssh2_mac_alg(s->in.mac)->len : 0; if (s->in.cipher && (ssh2_cipher_alg(s->in.cipher)->flags & SSH_CIPHER_IS_CBC) && @@ -208,9 +208,8 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp) s->bpp.in_raw, s->buf, s->maclen)); s->packetlen = 0; - s->in.mac->start(s->in.mac_ctx); - s->sc_mac_bs = s->in.mac->sink(s->in.mac_ctx); - put_uint32(s->sc_mac_bs, s->in.sequence); + ssh2_mac_start(s->in.mac); + put_uint32(s->in.mac, s->in.sequence); for (;;) { /* Once around this loop per cipher block. */ /* Read another cipher-block's worth, and tack it on to @@ -225,13 +224,12 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp) s->buf + s->packetlen, s->cipherblk); /* Feed that block to the MAC. */ - put_data(s->sc_mac_bs, + put_data(s->in.mac, s->buf + s->packetlen, s->cipherblk); s->packetlen += s->cipherblk; /* See if that gives us a valid packet. */ - if (s->in.mac->verresult( - s->in.mac_ctx, s->buf + s->packetlen) && + if (ssh2_mac_verresult(s->in.mac, s->buf + s->packetlen) && ((s->len = toint(GET_32BIT(s->buf))) == s->packetlen-4)) break; @@ -314,8 +312,8 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp) /* * Check the MAC. */ - if (s->in.mac && !s->in.mac->verify( - s->in.mac_ctx, s->data, s->len + 4, s->in.sequence)) { + if (s->in.mac && !ssh2_mac_verify( + s->in.mac, s->data, s->len + 4, s->in.sequence)) { s->bpp.error = dupprintf("Incorrect MAC received on packet"); crStopV; } @@ -389,8 +387,8 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp) /* * Check the MAC. */ - if (s->in.mac && !s->in.mac->verify( - s->in.mac_ctx, s->data, s->len + 4, s->in.sequence)) { + if (s->in.mac && !ssh2_mac_verify( + s->in.mac, s->data, s->len + 4, s->in.sequence)) { s->bpp.error = dupprintf("Incorrect MAC received on packet"); crStopV; } @@ -542,7 +540,7 @@ static void ssh2_bpp_format_packet_inner(struct ssh2_bpp_state *s, PktOut *pkt) * make the overall packet length come to pkt->minlen. */ if (s->out.mac) - minlen -= s->out.mac->len; + minlen -= ssh2_mac_alg(s->out.mac)->len; minlen -= 8; /* length field + min padding */ } @@ -565,7 +563,7 @@ static void ssh2_bpp_format_packet_inner(struct ssh2_bpp_state *s, PktOut *pkt) (cipherblk - (pkt->length - unencrypted_prefix + padding) % cipherblk) % cipherblk; assert(padding <= 255); - maclen = s->out.mac ? s->out.mac->len : 0; + maclen = s->out.mac ? ssh2_mac_alg(s->out.mac)->len : 0; origlen = pkt->length; for (i = 0; i < padding; i++) put_byte(pkt, random_byte()); @@ -588,16 +586,15 @@ static void ssh2_bpp_format_packet_inner(struct ssh2_bpp_state *s, PktOut *pkt) if (s->out.cipher) ssh2_cipher_encrypt(s->out.cipher, pkt->data + 4, origlen + padding - 4); - s->out.mac->generate(s->out.mac_ctx, pkt->data, origlen + padding, - s->out.sequence); + ssh2_mac_generate(s->out.mac, pkt->data, origlen + padding, + s->out.sequence); } else { /* * SSH-2 standard protocol. */ if (s->out.mac) - s->out.mac->generate( - s->out.mac_ctx, pkt->data, origlen + padding, - s->out.sequence); + ssh2_mac_generate(s->out.mac, pkt->data, origlen + padding, + s->out.sequence); if (s->out.cipher) ssh2_cipher_encrypt(s->out.cipher, pkt->data, origlen + padding); } @@ -642,7 +639,7 @@ static void ssh2_bpp_format_packet(BinaryPacketProtocol *bpp, PktOut *pkt) length += block-1; length -= (length % block); if (s->out.mac) - length += s->out.mac->len; + length += ssh2_mac_alg(s->out.mac)->len; if (length < pkt->minlen) { /* @@ -655,7 +652,7 @@ static void ssh2_bpp_format_packet(BinaryPacketProtocol *bpp, PktOut *pkt) * contained string. */ if (s->out.mac) - length -= s->out.mac->len; + length -= ssh2_mac_alg(s->out.mac)->len; length -= 8; /* length field + min padding */ length -= 5; /* type code + string length prefix */ diff --git a/sshbpp.h b/sshbpp.h index 41683410..f7e2fe2c 100644 --- a/sshbpp.h +++ b/sshbpp.h @@ -40,12 +40,12 @@ BinaryPacketProtocol *ssh2_bpp_new(void); void ssh2_bpp_new_outgoing_crypto( BinaryPacketProtocol *bpp, const struct ssh2_cipheralg *cipher, const void *ckey, const void *iv, - const struct ssh_mac *mac, int etm_mode, const void *mac_key, + const struct ssh2_macalg *mac, int etm_mode, const void *mac_key, const struct ssh_compress *compression); void ssh2_bpp_new_incoming_crypto( BinaryPacketProtocol *bpp, const struct ssh2_cipheralg *cipher, const void *ckey, const void *iv, - const struct ssh_mac *mac, int etm_mode, const void *mac_key, + const struct ssh2_macalg *mac, int etm_mode, const void *mac_key, const struct ssh_compress *compression); BinaryPacketProtocol *ssh2_bare_bpp_new(void); diff --git a/sshccp.c b/sshccp.c index 9919ced2..dfcb02c8 100644 --- a/sshccp.c +++ b/sshccp.c @@ -866,27 +866,32 @@ struct ccp_context { struct poly1305 mac; BinarySink_IMPLEMENTATION; - ssh2_cipher vt; + ssh2_cipher cvt; + ssh2_mac mac_if; }; -static void *poly_make_context(ssh2_cipher *cipher) +static ssh2_mac *poly_ssh2_new( + const struct ssh2_macalg *alg, ssh2_cipher *cipher) { - return FROMFIELD(cipher, struct ccp_context, vt); + struct ccp_context *ctx = FROMFIELD(cipher, struct ccp_context, cvt); + ctx->mac_if.vt = alg; + BinarySink_DELEGATE_INIT(&ctx->mac_if, ctx); + return &ctx->mac_if; } -static void poly_free_context(void *ctx) +static void poly_ssh2_free(ssh2_mac *mac) { /* Not allocated, just forwarded, no need to free */ } -static void poly_setkey(void *ctx, const void *key) +static void poly_setkey(ssh2_mac *mac, const void *key) { /* Uses the same context as ChaCha20, so ignore */ } -static void poly_start(void *handle) +static void poly_start(ssh2_mac *mac) { - struct ccp_context *ctx = (struct ccp_context *)handle; + struct ccp_context *ctx = FROMFIELD(mac, struct ccp_context, mac_if); ctx->mac_initialised = 0; memset(ctx->mac_iv, 0, 8); @@ -926,63 +931,15 @@ static void poly_BinarySink_write(BinarySink *bs, const void *blkv, size_t len) } } -static BinarySink *poly_sink(void *handle) +static void poly_genresult(ssh2_mac *mac, unsigned char *blk) { - struct ccp_context *ctx = (struct ccp_context *)handle; - return BinarySink_UPCAST(ctx); -} - -static void poly_genresult(void *handle, unsigned char *blk) -{ - struct ccp_context *ctx = (struct ccp_context *)handle; + struct ccp_context *ctx = FROMFIELD(mac, struct ccp_context, mac_if); poly1305_finalise(&ctx->mac, blk); } -static int poly_verresult(void *handle, unsigned char const *blk) -{ - struct ccp_context *ctx = (struct ccp_context *)handle; - int res; - unsigned char mac[16]; - poly1305_finalise(&ctx->mac, mac); - res = smemeq(blk, mac, 16); - return res; -} - -/* The generic poly operation used before generate and verify */ -static void poly_op(void *handle, const unsigned char *blk, int len, - unsigned long seq) -{ - struct ccp_context *ctx = (struct ccp_context *)handle; - poly_start(ctx); - /* the data receiver expects the first 4 bytes to be the IV */ - put_uint32(ctx, seq); - put_data(ctx, blk, len); -} - -static void poly_generate(void *handle, void *vblk, int len, unsigned long seq) -{ - unsigned char *blk = (unsigned char *)vblk; - poly_op(handle, blk, len, seq); - poly_genresult(handle, blk+len); -} - -static int poly_verify(void *handle, const void *vblk, int len, - unsigned long seq) -{ - const unsigned char *blk = (const unsigned char *)vblk; - poly_op(handle, blk, len, seq); - return poly_verresult(handle, blk+len); -} - -static const struct ssh_mac ssh2_poly1305 = { - poly_make_context, poly_free_context, - poly_setkey, - - /* whole-packet operations */ - poly_generate, poly_verify, - - /* partial-packet operations */ - poly_start, poly_sink, poly_genresult, poly_verresult, +static const struct ssh2_macalg ssh2_poly1305 = { + poly_ssh2_new, poly_ssh2_free, poly_setkey, + poly_start, poly_genresult, "", "", /* Not selectable individually, just part of ChaCha20-Poly1305 */ 16, 0, "Poly1305" @@ -993,13 +950,13 @@ static ssh2_cipher *ccp_new(const struct ssh2_cipheralg *alg) struct ccp_context *ctx = snew(struct ccp_context); BinarySink_INIT(ctx, poly_BinarySink_write); poly1305_init(&ctx->mac); - ctx->vt = alg; - return &ctx->vt; + ctx->cvt = alg; + return &ctx->cvt; } static void ccp_free(ssh2_cipher *cipher) { - struct ccp_context *ctx = FROMFIELD(cipher, struct ccp_context, vt); + struct ccp_context *ctx = FROMFIELD(cipher, struct ccp_context, cvt); smemclr(&ctx->a_cipher, sizeof(ctx->a_cipher)); smemclr(&ctx->b_cipher, sizeof(ctx->b_cipher)); smemclr(&ctx->mac, sizeof(ctx->mac)); @@ -1008,14 +965,14 @@ static void ccp_free(ssh2_cipher *cipher) static void ccp_iv(ssh2_cipher *cipher, const void *iv) { - /* struct ccp_context *ctx = FROMFIELD(cipher, struct ccp_context, vt); */ + /* struct ccp_context *ctx = FROMFIELD(cipher, struct ccp_context, cvt); */ /* IV is set based on the sequence number */ } static void ccp_key(ssh2_cipher *cipher, const void *vkey) { const unsigned char *key = (const unsigned char *)vkey; - struct ccp_context *ctx = FROMFIELD(cipher, struct ccp_context, vt); + struct ccp_context *ctx = FROMFIELD(cipher, struct ccp_context, cvt); /* Initialise the a_cipher (for decrypting lengths) with the first 256 bits */ chacha20_key(&ctx->a_cipher, key + 32); /* Initialise the b_cipher (for content and MAC) with the second 256 bits */ @@ -1024,13 +981,13 @@ static void ccp_key(ssh2_cipher *cipher, const void *vkey) static void ccp_encrypt(ssh2_cipher *cipher, void *blk, int len) { - struct ccp_context *ctx = FROMFIELD(cipher, struct ccp_context, vt); + struct ccp_context *ctx = FROMFIELD(cipher, struct ccp_context, cvt); chacha20_encrypt(&ctx->b_cipher, blk, len); } static void ccp_decrypt(ssh2_cipher *cipher, void *blk, int len) { - struct ccp_context *ctx = FROMFIELD(cipher, struct ccp_context, vt); + struct ccp_context *ctx = FROMFIELD(cipher, struct ccp_context, cvt); chacha20_decrypt(&ctx->b_cipher, blk, len); } @@ -1054,7 +1011,7 @@ static void ccp_length_op(struct ccp_context *ctx, void *blk, int len, static void ccp_encrypt_length(ssh2_cipher *cipher, void *blk, int len, unsigned long seq) { - struct ccp_context *ctx = FROMFIELD(cipher, struct ccp_context, vt); + struct ccp_context *ctx = FROMFIELD(cipher, struct ccp_context, cvt); ccp_length_op(ctx, blk, len, seq); chacha20_encrypt(&ctx->a_cipher, blk, len); } @@ -1062,7 +1019,7 @@ static void ccp_encrypt_length(ssh2_cipher *cipher, void *blk, int len, static void ccp_decrypt_length(ssh2_cipher *cipher, void *blk, int len, unsigned long seq) { - struct ccp_context *ctx = FROMFIELD(cipher, struct ccp_context, vt); + struct ccp_context *ctx = FROMFIELD(cipher, struct ccp_context, cvt); ccp_length_op(ctx, blk, len, seq); chacha20_decrypt(&ctx->a_cipher, blk, len); } diff --git a/sshmac.c b/sshmac.c new file mode 100644 index 00000000..e3b74b38 --- /dev/null +++ b/sshmac.c @@ -0,0 +1,42 @@ +/* + * Centralised parts of the SSH-2 MAC API, which don't need to vary + * with the MAC implementation. + */ + +#include + +#include "ssh.h" + +int ssh2_mac_verresult(ssh2_mac *mac, const void *candidate) +{ + unsigned char correct[64]; /* at least as big as all known MACs */ + int toret; + + assert(mac->vt->len <= sizeof(correct)); + ssh2_mac_genresult(mac, correct); + toret = smemeq(correct, candidate, mac->vt->len); + + smemclr(correct, sizeof(correct)); + + return toret; +} + +static void ssh2_mac_prepare(ssh2_mac *mac, const void *blk, int len, + unsigned long seq) +{ + ssh2_mac_start(mac); + put_uint32(mac, seq); + put_data(mac, blk, len); +} + +void ssh2_mac_generate(ssh2_mac *mac, void *blk, int len, unsigned long seq) +{ + ssh2_mac_prepare(mac, blk, len, seq); + return ssh2_mac_genresult(mac, (unsigned char *)blk + len); +} + +int ssh2_mac_verify(ssh2_mac *mac, const void *blk, int len, unsigned long seq) +{ + ssh2_mac_prepare(mac, blk, len, seq); + return ssh2_mac_verresult(mac, (const unsigned char *)blk + len); +} diff --git a/sshmd5.c b/sshmd5.c index be3b96cf..87a224d9 100644 --- a/sshmd5.c +++ b/sshmd5.c @@ -228,20 +228,40 @@ void MD5Simple(void const *p, unsigned len, unsigned char output[16]) * useful elsewhere (SOCKS5 CHAP authentication uses HMAC-MD5). */ -void *hmacmd5_make_context(ssh2_cipher *cipher) +struct hmacmd5_context { + struct MD5Context md5[3]; + ssh2_mac mac; +}; + +struct hmacmd5_context *hmacmd5_make_context(void) +{ + struct hmacmd5_context *ctx = snew(struct hmacmd5_context); + BinarySink_DELEGATE_INIT(&ctx->mac, &ctx->md5[2]); + return ctx; +} + +static ssh2_mac *hmacmd5_ssh2_new(const struct ssh2_macalg *alg, + ssh2_cipher *cipher) +{ + struct hmacmd5_context *ctx = hmacmd5_make_context(); + ctx->mac.vt = alg; + return &ctx->mac; +} + +void hmacmd5_free_context(struct hmacmd5_context *ctx) { - return snewn(3, struct MD5Context); + smemclr(ctx, sizeof(*ctx)); + sfree(ctx); } -void hmacmd5_free_context(void *handle) +static void hmacmd5_ssh2_free(ssh2_mac *mac) { - smemclr(handle, 3*sizeof(struct MD5Context)); - sfree(handle); + struct hmacmd5_context *ctx = FROMFIELD(mac, struct hmacmd5_context, mac); + hmacmd5_free_context(ctx); } -void hmacmd5_key(void *handle, void const *keyv, int len) +void hmacmd5_key(struct hmacmd5_context *ctx, void const *keyv, int len) { - struct MD5Context *keys = (struct MD5Context *)handle; unsigned char foo[64]; unsigned char const *key = (unsigned char const *)keyv; int i; @@ -249,106 +269,59 @@ void hmacmd5_key(void *handle, void const *keyv, int len) memset(foo, 0x36, 64); for (i = 0; i < len && i < 64; i++) foo[i] ^= key[i]; - MD5Init(&keys[0]); - put_data(&keys[0], foo, 64); + MD5Init(&ctx->md5[0]); + put_data(&ctx->md5[0], foo, 64); memset(foo, 0x5C, 64); for (i = 0; i < len && i < 64; i++) foo[i] ^= key[i]; - MD5Init(&keys[1]); - put_data(&keys[1], foo, 64); + MD5Init(&ctx->md5[1]); + put_data(&ctx->md5[1], foo, 64); smemclr(foo, 64); /* burn the evidence */ } -static void hmacmd5_key_16(void *handle, const void *key) +static void hmacmd5_ssh2_setkey(ssh2_mac *mac, const void *key) { - hmacmd5_key(handle, key, 16); + struct hmacmd5_context *ctx = FROMFIELD(mac, struct hmacmd5_context, mac); + hmacmd5_key(ctx, key, ctx->mac.vt->keylen); } -static void hmacmd5_start(void *handle) +static void hmacmd5_start(ssh2_mac *mac) { - struct MD5Context *keys = (struct MD5Context *)handle; - - keys[2] = keys[0]; /* structure copy */ - BinarySink_COPIED(&keys[2]); -} + struct hmacmd5_context *ctx = FROMFIELD(mac, struct hmacmd5_context, mac); -static BinarySink *hmacmd5_sink(void *handle) -{ - struct MD5Context *keys = (struct MD5Context *)handle; - return BinarySink_UPCAST(&keys[2]); + ctx->md5[2] = ctx->md5[0]; /* structure copy */ + BinarySink_COPIED(&ctx->md5[2]); } -static void hmacmd5_genresult(void *handle, unsigned char *hmac) +static void hmacmd5_genresult(ssh2_mac *mac, unsigned char *hmac) { - struct MD5Context *keys = (struct MD5Context *)handle; + struct hmacmd5_context *ctx = FROMFIELD(mac, struct hmacmd5_context, mac); struct MD5Context s; unsigned char intermediate[16]; - s = keys[2]; /* structure copy */ + s = ctx->md5[2]; /* structure copy */ BinarySink_COPIED(&s); MD5Final(intermediate, &s); - s = keys[1]; /* structure copy */ + s = ctx->md5[1]; /* structure copy */ BinarySink_COPIED(&s); put_data(&s, intermediate, 16); MD5Final(hmac, &s); + smemclr(intermediate, sizeof(intermediate)); } -static int hmacmd5_verresult(void *handle, unsigned char const *hmac) -{ - unsigned char correct[16]; - hmacmd5_genresult(handle, correct); - return smemeq(correct, hmac, 16); -} - -static void hmacmd5_do_hmac_internal(void *handle, - unsigned char const *blk, int len, - unsigned char const *blk2, int len2, - unsigned char *hmac) -{ - BinarySink *bs = hmacmd5_sink(handle); - hmacmd5_start(handle); - put_data(bs, blk, len); - if (blk2) put_data(bs, blk2, len2); - hmacmd5_genresult(handle, hmac); -} - -void hmacmd5_do_hmac(void *handle, unsigned char const *blk, int len, - unsigned char *hmac) -{ - hmacmd5_do_hmac_internal(handle, blk, len, NULL, 0, hmac); -} - -static void hmacmd5_do_hmac_ssh(void *handle, unsigned char const *blk, int len, - unsigned long seq, unsigned char *hmac) -{ - unsigned char seqbuf[16]; - - PUT_32BIT_MSB_FIRST(seqbuf, seq); - hmacmd5_do_hmac_internal(handle, seqbuf, 4, blk, len, hmac); -} - -static void hmacmd5_generate(void *handle, void *vblk, int len, - unsigned long seq) -{ - unsigned char *blk = (unsigned char *)vblk; - hmacmd5_do_hmac_ssh(handle, blk, len, seq, blk + len); -} - -static int hmacmd5_verify(void *handle, const void *vblk, int len, - unsigned long seq) +void hmacmd5_do_hmac(struct hmacmd5_context *ctx, + unsigned char const *blk, int len, unsigned char *hmac) { - const unsigned char *blk = (const unsigned char *)vblk; - unsigned char correct[16]; - hmacmd5_do_hmac_ssh(handle, blk, len, seq, correct); - return smemeq(correct, blk + len, 16); + ssh2_mac_start(&ctx->mac); + put_data(&ctx->mac, blk, len); + return ssh2_mac_genresult(&ctx->mac, hmac); } -const struct ssh_mac ssh_hmac_md5 = { - hmacmd5_make_context, hmacmd5_free_context, hmacmd5_key_16, - hmacmd5_generate, hmacmd5_verify, - hmacmd5_start, hmacmd5_sink, hmacmd5_genresult, hmacmd5_verresult, +const struct ssh2_macalg ssh_hmac_md5 = { + hmacmd5_ssh2_new, hmacmd5_ssh2_free, hmacmd5_ssh2_setkey, + hmacmd5_start, hmacmd5_genresult, "hmac-md5", "hmac-md5-etm@openssh.com", 16, 16, "HMAC-MD5" diff --git a/sshsh256.c b/sshsh256.c index 51788679..e4b14fd7 100644 --- a/sshsh256.c +++ b/sshsh256.c @@ -256,111 +256,80 @@ const struct ssh_hash ssh_sha256 = { * HMAC wrapper on it. */ -static void *sha256_make_context(ssh2_cipher *cipher) +struct hmacsha256 { + SHA256_State sha[3]; + ssh2_mac mac; +}; + +static ssh2_mac *hmacsha256_new( + const struct ssh2_macalg *alg, ssh2_cipher *cipher) { - return snewn(3, SHA256_State); + struct hmacsha256 *ctx = snew(struct hmacsha256); + ctx->mac.vt = alg; + BinarySink_DELEGATE_INIT(&ctx->mac, &ctx->sha[2]); + return &ctx->mac; } -static void sha256_free_context(void *handle) +static void hmacsha256_free(ssh2_mac *mac) { - smemclr(handle, 3 * sizeof(SHA256_State)); - sfree(handle); + struct hmacsha256 *ctx = FROMFIELD(mac, struct hmacsha256, mac); + smemclr(ctx, sizeof(*ctx)); + sfree(ctx); } -static void sha256_key_internal(void *handle, +static void sha256_key_internal(struct hmacsha256 *ctx, const unsigned char *key, int len) { - SHA256_State *keys = (SHA256_State *)handle; unsigned char foo[64]; int i; memset(foo, 0x36, 64); for (i = 0; i < len && i < 64; i++) foo[i] ^= key[i]; - SHA256_Init(&keys[0]); - put_data(&keys[0], foo, 64); + SHA256_Init(&ctx->sha[0]); + put_data(&ctx->sha[0], foo, 64); memset(foo, 0x5C, 64); for (i = 0; i < len && i < 64; i++) foo[i] ^= key[i]; - SHA256_Init(&keys[1]); - put_data(&keys[1], foo, 64); + SHA256_Init(&ctx->sha[1]); + put_data(&ctx->sha[1], foo, 64); smemclr(foo, 64); /* burn the evidence */ } -static void sha256_key(void *handle, const void *key) +static void hmacsha256_key(ssh2_mac *mac, const void *key) { - sha256_key_internal(handle, key, 32); + struct hmacsha256 *ctx = FROMFIELD(mac, struct hmacsha256, mac); + sha256_key_internal(ctx, key, ctx->mac.vt->keylen); } -static void hmacsha256_start(void *handle) +static void hmacsha256_start(ssh2_mac *mac) { - SHA256_State *keys = (SHA256_State *)handle; + struct hmacsha256 *ctx = FROMFIELD(mac, struct hmacsha256, mac); - keys[2] = keys[0]; /* structure copy */ - BinarySink_COPIED(&keys[2]); -} - -static BinarySink *hmacsha256_sink(void *handle) -{ - SHA256_State *keys = (SHA256_State *)handle; - return BinarySink_UPCAST(&keys[2]); + ctx->sha[2] = ctx->sha[0]; /* structure copy */ + BinarySink_COPIED(&ctx->sha[2]); } -static void hmacsha256_genresult(void *handle, unsigned char *hmac) +static void hmacsha256_genresult(ssh2_mac *mac, unsigned char *hmac) { - SHA256_State *keys = (SHA256_State *)handle; + struct hmacsha256 *ctx = FROMFIELD(mac, struct hmacsha256, mac); SHA256_State s; unsigned char intermediate[32]; - s = keys[2]; /* structure copy */ + s = ctx->sha[2]; /* structure copy */ BinarySink_COPIED(&s); SHA256_Final(&s, intermediate); - s = keys[1]; /* structure copy */ + s = ctx->sha[1]; /* structure copy */ BinarySink_COPIED(&s); put_data(&s, intermediate, 32); SHA256_Final(&s, hmac); } -static void sha256_do_hmac(void *handle, const unsigned char *blk, int len, - unsigned long seq, unsigned char *hmac) -{ - BinarySink *bs = hmacsha256_sink(handle); - hmacsha256_start(handle); - put_uint32(bs, seq); - put_data(bs, blk, len); - hmacsha256_genresult(handle, hmac); -} - -static void sha256_generate(void *handle, void *vblk, int len, - unsigned long seq) -{ - unsigned char *blk = (unsigned char *)vblk; - sha256_do_hmac(handle, blk, len, seq, blk + len); -} - -static int hmacsha256_verresult(void *handle, unsigned char const *hmac) -{ - unsigned char correct[32]; - hmacsha256_genresult(handle, correct); - return smemeq(correct, hmac, 32); -} - -static int sha256_verify(void *handle, const void *vblk, int len, - unsigned long seq) -{ - const unsigned char *blk = (const unsigned char *)vblk; - unsigned char correct[32]; - sha256_do_hmac(handle, blk, len, seq, correct); - return smemeq(correct, blk + len, 32); -} - -const struct ssh_mac ssh_hmac_sha256 = { - sha256_make_context, sha256_free_context, sha256_key, - sha256_generate, sha256_verify, - hmacsha256_start, hmacsha256_sink, - hmacsha256_genresult, hmacsha256_verresult, +const struct ssh2_macalg ssh_hmac_sha256 = { + hmacsha256_new, hmacsha256_free, hmacsha256_key, + hmacsha256_start, hmacsha256_genresult, "hmac-sha2-256", "hmac-sha2-256-etm@openssh.com", 32, 32, "HMAC-SHA-256" diff --git a/sshsha.c b/sshsha.c index e2f2a860..310241a4 100644 --- a/sshsha.c +++ b/sshsha.c @@ -283,20 +283,30 @@ const struct ssh_hash ssh_sha1 = { * HMAC wrapper on it. */ -static void *sha1_make_context(ssh2_cipher *cipher) +struct hmacsha1 { + SHA_State sha[3]; + ssh2_mac mac; +}; + +static ssh2_mac *hmacsha1_new( + const struct ssh2_macalg *alg, ssh2_cipher *cipher) { - return snewn(3, SHA_State); + struct hmacsha1 *ctx = snew(struct hmacsha1); + ctx->mac.vt = alg; + BinarySink_DELEGATE_INIT(&ctx->mac, &ctx->sha[2]); + return &ctx->mac; } -static void sha1_free_context(void *handle) +static void hmacsha1_free(ssh2_mac *mac) { - smemclr(handle, 3 * sizeof(SHA_State)); - sfree(handle); + struct hmacsha1 *ctx = FROMFIELD(mac, struct hmacsha1, mac); + smemclr(ctx, sizeof(*ctx)); + sfree(ctx); } -static void sha1_key_internal(void *handle, const unsigned char *key, int len) +static void sha1_key_internal(SHA_State *keys, + const unsigned char *key, int len) { - SHA_State *keys = (SHA_State *)handle; unsigned char foo[64]; int i; @@ -315,108 +325,38 @@ static void sha1_key_internal(void *handle, const unsigned char *key, int len) smemclr(foo, 64); /* burn the evidence */ } -static void sha1_key(void *handle, const void *key) -{ - sha1_key_internal(handle, key, 20); -} - -static void sha1_key_buggy(void *handle, const void *key) +static void hmacsha1_key(ssh2_mac *mac, const void *key) { - sha1_key_internal(handle, key, 16); + struct hmacsha1 *ctx = FROMFIELD(mac, struct hmacsha1, mac); + /* Reading the key length out of the ssh2_macalg structure means + * this same method can be used for the _buggy variants which use + * a shorter key */ + sha1_key_internal(ctx->sha, key, ctx->mac.vt->keylen); } -static void hmacsha1_start(void *handle) +static void hmacsha1_start(ssh2_mac *mac) { - SHA_State *keys = (SHA_State *)handle; + struct hmacsha1 *ctx = FROMFIELD(mac, struct hmacsha1, mac); - keys[2] = keys[0]; /* structure copy */ - BinarySink_COPIED(&keys[2]); + ctx->sha[2] = ctx->sha[0]; /* structure copy */ + BinarySink_COPIED(&ctx->sha[2]); } -static BinarySink *hmacsha1_sink(void *handle) +static void hmacsha1_genresult(ssh2_mac *mac, unsigned char *hmac) { - SHA_State *keys = (SHA_State *)handle; - return BinarySink_UPCAST(&keys[2]); -} - -static void hmacsha1_genresult(void *handle, unsigned char *hmac) -{ - SHA_State *keys = (SHA_State *)handle; + struct hmacsha1 *ctx = FROMFIELD(mac, struct hmacsha1, mac); SHA_State s; unsigned char intermediate[20]; - s = keys[2]; /* structure copy */ + s = ctx->sha[2]; /* structure copy */ BinarySink_COPIED(&s); SHA_Final(&s, intermediate); - s = keys[1]; /* structure copy */ + s = ctx->sha[1]; /* structure copy */ BinarySink_COPIED(&s); put_data(&s, intermediate, 20); - SHA_Final(&s, hmac); -} - -static void sha1_do_hmac(void *handle, const unsigned char *blk, int len, - unsigned long seq, unsigned char *hmac) -{ - BinarySink *bs = hmacsha1_sink(handle); - hmacsha1_start(handle); - put_uint32(bs, seq); - put_data(bs, blk, len); - hmacsha1_genresult(handle, hmac); -} - -static void sha1_generate(void *handle, void *vblk, int len, - unsigned long seq) -{ - unsigned char *blk = (unsigned char *)vblk; - sha1_do_hmac(handle, blk, len, seq, blk + len); -} - -static int hmacsha1_verresult(void *handle, unsigned char const *hmac) -{ - unsigned char correct[20]; - hmacsha1_genresult(handle, correct); - return smemeq(correct, hmac, 20); -} - -static int sha1_verify(void *handle, const void *vblk, int len, - unsigned long seq) -{ - const unsigned char *blk = (const unsigned char *)vblk; - unsigned char correct[20]; - sha1_do_hmac(handle, blk, len, seq, correct); - return smemeq(correct, blk + len, 20); -} - -static void hmacsha1_96_genresult(void *handle, unsigned char *hmac) -{ - unsigned char full[20]; - hmacsha1_genresult(handle, full); - memcpy(hmac, full, 12); -} - -static void sha1_96_generate(void *handle, void *vblk, int len, - unsigned long seq) -{ - unsigned char *blk = (unsigned char *)vblk; - unsigned char full[20]; - sha1_do_hmac(handle, blk, len, seq, full); - memcpy(blk + len, full, 12); -} - -static int hmacsha1_96_verresult(void *handle, unsigned char const *hmac) -{ - unsigned char correct[20]; - hmacsha1_genresult(handle, correct); - return smemeq(correct, hmac, 12); -} - -static int sha1_96_verify(void *handle, const void *vblk, int len, - unsigned long seq) -{ - const unsigned char *blk = (const unsigned char *)vblk; - unsigned char correct[20]; - sha1_do_hmac(handle, blk, len, seq, correct); - return smemeq(correct, blk + len, 12); + SHA_Final(&s, intermediate); + memcpy(hmac, intermediate, ctx->mac.vt->len); + smemclr(intermediate, sizeof(intermediate)); } void hmac_sha1_simple(void *key, int keylen, void *data, int datalen, @@ -432,39 +372,33 @@ void hmac_sha1_simple(void *key, int keylen, void *data, int datalen, SHA_Final(&states[1], output); } -const struct ssh_mac ssh_hmac_sha1 = { - sha1_make_context, sha1_free_context, sha1_key, - sha1_generate, sha1_verify, - hmacsha1_start, hmacsha1_sink, hmacsha1_genresult, hmacsha1_verresult, +const struct ssh2_macalg ssh_hmac_sha1 = { + hmacsha1_new, hmacsha1_free, hmacsha1_key, + hmacsha1_start, hmacsha1_genresult, "hmac-sha1", "hmac-sha1-etm@openssh.com", 20, 20, "HMAC-SHA1" }; -const struct ssh_mac ssh_hmac_sha1_96 = { - sha1_make_context, sha1_free_context, sha1_key, - sha1_96_generate, sha1_96_verify, - hmacsha1_start, hmacsha1_sink, - hmacsha1_96_genresult, hmacsha1_96_verresult, +const struct ssh2_macalg ssh_hmac_sha1_96 = { + hmacsha1_new, hmacsha1_free, hmacsha1_key, + hmacsha1_start, hmacsha1_genresult, "hmac-sha1-96", "hmac-sha1-96-etm@openssh.com", 12, 20, "HMAC-SHA1-96" }; -const struct ssh_mac ssh_hmac_sha1_buggy = { - sha1_make_context, sha1_free_context, sha1_key_buggy, - sha1_generate, sha1_verify, - hmacsha1_start, hmacsha1_sink, hmacsha1_genresult, hmacsha1_verresult, +const struct ssh2_macalg ssh_hmac_sha1_buggy = { + hmacsha1_new, hmacsha1_free, hmacsha1_key, + hmacsha1_start, hmacsha1_genresult, "hmac-sha1", NULL, 20, 16, "bug-compatible HMAC-SHA1" }; -const struct ssh_mac ssh_hmac_sha1_96_buggy = { - sha1_make_context, sha1_free_context, sha1_key_buggy, - sha1_96_generate, sha1_96_verify, - hmacsha1_start, hmacsha1_sink, - hmacsha1_96_genresult, hmacsha1_96_verresult, +const struct ssh2_macalg ssh_hmac_sha1_96_buggy = { + hmacsha1_new, hmacsha1_free, hmacsha1_key, + hmacsha1_start, hmacsha1_genresult, "hmac-sha1-96", NULL, 12, 16, "bug-compatible HMAC-SHA1-96" From 4f9a90fc1adae90166d258ba17af6aa44e0d32c2 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Thu, 13 Sep 2018 16:41:46 +0100 Subject: [PATCH 402/607] Turn SSH hashes into a classoid. The new version of ssh_hash has the same nice property as ssh2_mac, that I can make the generic interface object type function directly as a BinarySink so that clients don't have to call h->sink() and worry about the separate sink object they get back from that. --- ssh.c | 99 ++++++++++++++++++++++++++---------------------------- ssh.h | 37 +++++++++++++------- sshecc.c | 18 +++++----- sshrsa.c | 22 ++++++------ sshsh256.c | 60 ++++++++++++++++----------------- sshsh512.c | 87 +++++++++++++++++++++++------------------------ sshsha.c | 59 ++++++++++++++++---------------- 7 files changed, 194 insertions(+), 188 deletions(-) diff --git a/ssh.c b/ssh.c index 814d28b7..ab6d6fbe 100644 --- a/ssh.c +++ b/ssh.c @@ -668,8 +668,7 @@ enum RekeyClass { struct ssh_tag { char *v_c, *v_s; - void *exhash; - BinarySink *exhash_bs; + ssh_hash *exhash; Socket s; @@ -4780,11 +4779,10 @@ static void add_to_commasep(strbuf *buf, const char *data) static void ssh2_mkkey(Ssh ssh, strbuf *out, Bignum K, unsigned char *H, char chr, int keylen) { - const struct ssh_hash *h = ssh->kex->hash; + const struct ssh_hashalg *h = ssh->kex->hash; int keylen_padded; unsigned char *key; - void *s, *s2; - BinarySink *bs; + ssh_hash *s, *s2; if (keylen == 0) return; @@ -4805,32 +4803,30 @@ static void ssh2_mkkey(Ssh ssh, strbuf *out, Bignum K, unsigned char *H, key = strbuf_append(out, keylen_padded); /* First hlen bytes. */ - s = h->init(); - bs = h->sink(s); + s = ssh_hash_new(h); if (!(ssh->remote_bugs & BUG_SSH2_DERIVEKEY)) - put_mp_ssh2(bs, K); - put_data(bs, H, h->hlen); - put_byte(bs, chr); - put_data(bs, ssh->v2_session_id, ssh->v2_session_id_len); - h->final(s, key); + put_mp_ssh2(s, K); + put_data(s, H, h->hlen); + put_byte(s, chr); + put_data(s, ssh->v2_session_id, ssh->v2_session_id_len); + ssh_hash_final(s, key); /* Subsequent blocks of hlen bytes. */ if (keylen_padded > h->hlen) { int offset; - s = h->init(); - bs = h->sink(s); + s = ssh_hash_new(h); if (!(ssh->remote_bugs & BUG_SSH2_DERIVEKEY)) - put_mp_ssh2(bs, K); - put_data(bs, H, h->hlen); + put_mp_ssh2(s, K); + put_data(s, H, h->hlen); for (offset = h->hlen; offset < keylen_padded; offset += h->hlen) { - put_data(bs, key + offset - h->hlen, h->hlen); - s2 = h->copy(s); - h->final(s2, key + offset); + put_data(s, key + offset - h->hlen, h->hlen); + s2 = ssh_hash_copy(s); + ssh_hash_final(s2, key + offset); } - h->free(s); + ssh_hash_free(s); } } @@ -5600,14 +5596,13 @@ static void do_ssh2_transport(void *vctx) get_string(pktin); /* server->client language */ s->ignorepkt = get_bool(pktin) && !s->guessok; - ssh->exhash = ssh->kex->hash->init(); - ssh->exhash_bs = ssh->kex->hash->sink(ssh->exhash); - put_stringz(ssh->exhash_bs, ssh->v_c); - put_stringz(ssh->exhash_bs, ssh->v_s); - put_string(ssh->exhash_bs, s->our_kexinit, s->our_kexinitlen); + ssh->exhash = ssh_hash_new(ssh->kex->hash); + put_stringz(ssh->exhash, ssh->v_c); + put_stringz(ssh->exhash, ssh->v_s); + put_string(ssh->exhash, s->our_kexinit, s->our_kexinitlen); sfree(s->our_kexinit); /* Include the type byte in the hash of server's KEXINIT */ - put_string(ssh->exhash_bs, + put_string(ssh->exhash, (const char *)BinarySource_UPCAST(pktin)->data - 1, BinarySource_UPCAST(pktin)->len + 1); @@ -5844,18 +5839,18 @@ static void do_ssh2_transport(void *vctx) * involve user interaction. */ set_busy_status(ssh->frontend, BUSY_NOT); - put_stringpl(ssh->exhash_bs, s->hostkeydata); + put_stringpl(ssh->exhash, s->hostkeydata); if (dh_is_gex(ssh->kex)) { if (!(ssh->remote_bugs & BUG_SSH2_OLDGEX)) - put_uint32(ssh->exhash_bs, DH_MIN_SIZE); - put_uint32(ssh->exhash_bs, s->pbits); + put_uint32(ssh->exhash, DH_MIN_SIZE); + put_uint32(ssh->exhash, s->pbits); if (!(ssh->remote_bugs & BUG_SSH2_OLDGEX)) - put_uint32(ssh->exhash_bs, DH_MAX_SIZE); - put_mp_ssh2(ssh->exhash_bs, s->p); - put_mp_ssh2(ssh->exhash_bs, s->g); + put_uint32(ssh->exhash, DH_MAX_SIZE); + put_mp_ssh2(ssh->exhash, s->p); + put_mp_ssh2(ssh->exhash, s->g); } - put_mp_ssh2(ssh->exhash_bs, s->e); - put_mp_ssh2(ssh->exhash_bs, s->f); + put_mp_ssh2(ssh->exhash, s->e); + put_mp_ssh2(ssh->exhash, s->f); dh_cleanup(ssh->kex_ctx); freebn(s->f); @@ -5893,19 +5888,19 @@ static void do_ssh2_transport(void *vctx) } s->hostkeydata = get_string(pktin); - put_stringpl(ssh->exhash_bs, s->hostkeydata); + put_stringpl(ssh->exhash, s->hostkeydata); s->hkey = ssh_key_new_pub(ssh->hostkey_alg, s->hostkeydata); { strbuf *pubpoint = strbuf_new(); ssh_ecdhkex_getpublic(s->eckey, BinarySink_UPCAST(pubpoint)); - put_string(ssh->exhash_bs, pubpoint->u, pubpoint->len); + put_string(ssh->exhash, pubpoint->u, pubpoint->len); strbuf_free(pubpoint); } { ptrlen keydata = get_string(pktin); - put_stringpl(ssh->exhash_bs, keydata); + put_stringpl(ssh->exhash, keydata); s->K = ssh_ecdhkex_getkey(s->eckey, keydata.ptr, keydata.len); if (!get_err(pktin) && !s->K) { ssh_ecdhkex_freekey(s->eckey); @@ -6100,7 +6095,7 @@ static void do_ssh2_transport(void *vctx) if (ssh->hostkey_alg) { s->hkey = ssh_key_new_pub(ssh->hostkey_alg, s->hostkeydata); - put_string(ssh->exhash_bs, + put_string(ssh->exhash, s->hostkeydata.ptr, s->hostkeydata.len); } /* @@ -6149,18 +6144,18 @@ static void do_ssh2_transport(void *vctx) set_busy_status(ssh->frontend, BUSY_NOT); if (!s->hkey) - put_stringz(ssh->exhash_bs, ""); + put_stringz(ssh->exhash, ""); if (dh_is_gex(ssh->kex)) { /* min, preferred, max */ - put_uint32(ssh->exhash_bs, s->pbits); - put_uint32(ssh->exhash_bs, s->pbits); - put_uint32(ssh->exhash_bs, s->pbits * 2); + put_uint32(ssh->exhash, s->pbits); + put_uint32(ssh->exhash, s->pbits); + put_uint32(ssh->exhash, s->pbits * 2); - put_mp_ssh2(ssh->exhash_bs, s->p); - put_mp_ssh2(ssh->exhash_bs, s->g); + put_mp_ssh2(ssh->exhash, s->p); + put_mp_ssh2(ssh->exhash, s->g); } - put_mp_ssh2(ssh->exhash_bs, s->e); - put_mp_ssh2(ssh->exhash_bs, s->f); + put_mp_ssh2(ssh->exhash, s->e); + put_mp_ssh2(ssh->exhash, s->f); /* * MIC verification is done below, after we compute the hash @@ -6192,7 +6187,7 @@ static void do_ssh2_transport(void *vctx) } s->hostkeydata = get_string(pktin); - put_stringpl(ssh->exhash_bs, s->hostkeydata); + put_stringpl(ssh->exhash, s->hostkeydata); s->hkey = ssh_key_new_pub(ssh->hostkey_alg, s->hostkeydata); rsakeydata = get_string(pktin); @@ -6203,7 +6198,7 @@ static void do_ssh2_transport(void *vctx) crStopV; } - put_stringpl(ssh->exhash_bs, rsakeydata); + put_stringpl(ssh->exhash, rsakeydata); /* * Next, set up a shared secret K, of precisely KLEN - @@ -6249,7 +6244,7 @@ static void do_ssh2_transport(void *vctx) put_string(s->pktout, outstr, outstrlen); ssh_pkt_write(ssh, s->pktout); - put_string(ssh->exhash_bs, outstr, outstrlen); + put_string(ssh->exhash, outstr, outstrlen); strbuf_free(buf); sfree(outstr); @@ -6270,9 +6265,9 @@ static void do_ssh2_transport(void *vctx) } } - put_mp_ssh2(ssh->exhash_bs, s->K); - assert(ssh->kex->hash->hlen <= sizeof(s->exchange_hash)); - ssh->kex->hash->final(ssh->exhash, s->exchange_hash); + put_mp_ssh2(ssh->exhash, s->K); + assert(ssh_hash_alg(ssh->exhash)->hlen <= sizeof(s->exchange_hash)); + ssh_hash_final(ssh->exhash, s->exchange_hash); #ifndef NO_GSSAPI if (ssh->kex->main_type == KEXTYPE_GSS) { diff --git a/ssh.h b/ssh.h index 6b768a8a..ff4305b0 100644 --- a/ssh.h +++ b/ssh.h @@ -331,11 +331,12 @@ int detect_attack(struct crcda_ctx *ctx, unsigned char *buf, uint32 len, /* * SSH2 RSA key exchange functions */ -struct ssh_hash; +struct ssh_hashalg; struct RSAKey *ssh_rsakex_newkey(const void *data, int len); void ssh_rsakex_freekey(struct RSAKey *key); int ssh_rsakex_klen(struct RSAKey *key); -void ssh_rsakex_encrypt(const struct ssh_hash *h, unsigned char *in, int inlen, +void ssh_rsakex_encrypt(const struct ssh_hashalg *h, + unsigned char *in, int inlen, unsigned char *out, int outlen, struct RSAKey *key); /* @@ -527,20 +528,30 @@ int ssh2_mac_verresult(ssh2_mac *, const void *); void ssh2_mac_generate(ssh2_mac *, void *, int, unsigned long seq); int ssh2_mac_verify(ssh2_mac *, const void *, int, unsigned long seq); -struct ssh_hash { - void *(*init)(void); /* also allocates context */ - void *(*copy)(const void *); - BinarySink *(*sink) (void *); - void (*final)(void *, unsigned char *); /* also frees context */ - void (*free)(void *); +typedef struct ssh_hash { + const struct ssh_hashalg *vt; + BinarySink_DELEGATE_IMPLEMENTATION; +} ssh_hash; + +struct ssh_hashalg { + ssh_hash *(*new)(const struct ssh_hashalg *alg); + ssh_hash *(*copy)(ssh_hash *); + void (*final)(ssh_hash *, unsigned char *); /* ALSO FREES THE ssh_hash! */ + void (*free)(ssh_hash *); int hlen; /* output length in bytes */ const char *text_name; }; +#define ssh_hash_new(alg) ((alg)->new(alg)) +#define ssh_hash_copy(ctx) ((ctx)->vt->copy(ctx)) +#define ssh_hash_final(ctx, out) ((ctx)->vt->final(ctx, out)) +#define ssh_hash_free(ctx) ((ctx)->vt->free(ctx)) +#define ssh_hash_alg(ctx) ((ctx)->vt) + struct ssh_kex { const char *name, *groupname; enum { KEXTYPE_DH, KEXTYPE_RSA, KEXTYPE_ECDH, KEXTYPE_GSS } main_type; - const struct ssh_hash *hash; + const struct ssh_hashalg *hash; const void *extra; /* private to the kex methods */ }; @@ -625,10 +636,10 @@ extern const struct ssh2_ciphers ssh2_aes; extern const struct ssh2_ciphers ssh2_blowfish; extern const struct ssh2_ciphers ssh2_arcfour; extern const struct ssh2_ciphers ssh2_ccp; -extern const struct ssh_hash ssh_sha1; -extern const struct ssh_hash ssh_sha256; -extern const struct ssh_hash ssh_sha384; -extern const struct ssh_hash ssh_sha512; +extern const struct ssh_hashalg ssh_sha1; +extern const struct ssh_hashalg ssh_sha256; +extern const struct ssh_hashalg ssh_sha384; +extern const struct ssh_hashalg ssh_sha512; extern const struct ssh_kexes ssh_diffiehellman_group1; extern const struct ssh_kexes ssh_diffiehellman_group14; extern const struct ssh_kexes ssh_diffiehellman_gex; diff --git a/sshecc.c b/sshecc.c index ce663bfb..34d0e948 100644 --- a/sshecc.c +++ b/sshecc.c @@ -1688,7 +1688,7 @@ static int BinarySource_get_point(BinarySource *src, struct ec_point *point) struct ecsign_extra { struct ec_curve *(*curve)(void); - const struct ssh_hash *hash; + const struct ssh_hashalg *hash; /* These fields are used by the OpenSSH PEM format importer/exporter */ const unsigned char *oid; @@ -2227,7 +2227,7 @@ static int ecdsa_verify(ssh_key *key, ptrlen sig, ptrlen data) Bignum r, s; unsigned char digest[512 / 8]; int digestLen; - void *hashctx; + ssh_hash *hashctx; BinarySource_BARE_INIT(src, sigstr.ptr, sigstr.len); @@ -2241,9 +2241,9 @@ static int ecdsa_verify(ssh_key *key, ptrlen sig, ptrlen data) digestLen = extra->hash->hlen; assert(digestLen <= sizeof(digest)); - hashctx = extra->hash->init(); - put_data(extra->hash->sink(hashctx), data.ptr, data.len); - extra->hash->final(hashctx, digest); + hashctx = ssh_hash_new(extra->hash); + put_data(hashctx, data.ptr, data.len); + ssh_hash_final(hashctx, digest); /* Verify the signature */ ret = _ecdsa_verify(&ec->publicKey, digest, digestLen, r, s); @@ -2363,14 +2363,14 @@ static void ecdsa_sign(ssh_key *key, const void *data, int datalen, put_byte(bs, bignum_byte(s, i)); freebn(s); } else { - void *hashctx; + ssh_hash *hashctx; strbuf *substr; digestLen = extra->hash->hlen; assert(digestLen <= sizeof(digest)); - hashctx = extra->hash->init(); - put_data(extra->hash->sink(hashctx), data, datalen); - extra->hash->final(hashctx, digest); + hashctx = ssh_hash_new(extra->hash); + put_data(hashctx, data, datalen); + ssh_hash_final(hashctx, digest); /* Do the signature */ _ecdsa_sign(ec->privateKey, ec->publicKey.curve, digest, digestLen, &r, &s); diff --git a/sshrsa.c b/sshrsa.c index f66af550..c2bc4bfb 100644 --- a/sshrsa.c +++ b/sshrsa.c @@ -783,7 +783,7 @@ int ssh_rsakex_klen(struct RSAKey *rsa) return bignum_bitcount(rsa->modulus); } -static void oaep_mask(const struct ssh_hash *h, void *seed, int seedlen, +static void oaep_mask(const struct ssh_hashalg *h, void *seed, int seedlen, void *vdata, int datalen) { unsigned char *data = (unsigned char *)vdata; @@ -791,16 +791,14 @@ static void oaep_mask(const struct ssh_hash *h, void *seed, int seedlen, while (datalen > 0) { int i, max = (datalen > h->hlen ? h->hlen : datalen); - void *s; - BinarySink *bs; + ssh_hash *s; unsigned char hash[SSH2_KEX_MAX_HASH_LEN]; assert(h->hlen <= SSH2_KEX_MAX_HASH_LEN); - s = h->init(); - bs = h->sink(s); - put_data(bs, seed, seedlen); - put_uint32(bs, count); - h->final(s, hash); + s = ssh_hash_new(h); + put_data(s, seed, seedlen); + put_uint32(s, count); + ssh_hash_final(s, hash); count++; for (i = 0; i < max; i++) @@ -811,7 +809,8 @@ static void oaep_mask(const struct ssh_hash *h, void *seed, int seedlen, } } -void ssh_rsakex_encrypt(const struct ssh_hash *h, unsigned char *in, int inlen, +void ssh_rsakex_encrypt(const struct ssh_hashalg *h, + unsigned char *in, int inlen, unsigned char *out, int outlen, struct RSAKey *rsa) { Bignum b1, b2; @@ -866,7 +865,10 @@ void ssh_rsakex_encrypt(const struct ssh_hash *h, unsigned char *in, int inlen, out[i + 1] = random_byte(); /* At position 1+HLEN, the data block DB, consisting of: */ /* The hash of the label (we only support an empty label here) */ - h->final(h->init(), out + HLEN + 1); + { + ssh_hash *s = ssh_hash_new(h); + ssh_hash_final(s, out + HLEN + 1); + } /* A bunch of zero octets */ memset(out + 2*HLEN + 1, 0, outlen - (2*HLEN + 1)); /* A single 1 octet, followed by the input message data. */ diff --git a/sshsh256.c b/sshsh256.c index e4b14fd7..75a04495 100644 --- a/sshsh256.c +++ b/sshsh256.c @@ -204,51 +204,51 @@ void SHA256_Simple(const void *p, int len, unsigned char *output) { * Thin abstraction for things where hashes are pluggable. */ -static void *sha256_init(void) -{ - SHA256_State *s; +struct sha256_hash { + SHA256_State state; + ssh_hash hash; +}; - s = snew(SHA256_State); - SHA256_Init(s); - return s; +static ssh_hash *sha256_new(const struct ssh_hashalg *alg) +{ + struct sha256_hash *h = snew(struct sha256_hash); + SHA256_Init(&h->state); + h->hash.vt = alg; + BinarySink_DELEGATE_INIT(&h->hash, &h->state); + return &h->hash; } -static void *sha256_copy(const void *vold) +static ssh_hash *sha256_copy(ssh_hash *hashold) { - const SHA256_State *old = (const SHA256_State *)vold; - SHA256_State *s; + struct sha256_hash *hold, *hnew; + ssh_hash *hashnew = sha256_new(hashold->vt); - s = snew(SHA256_State); - *s = *old; - BinarySink_COPIED(s); - return s; -} + hold = FROMFIELD(hashold, struct sha256_hash, hash); + hnew = FROMFIELD(hashnew, struct sha256_hash, hash); -static void sha256_free(void *handle) -{ - SHA256_State *s = handle; + hnew->state = hold->state; + BinarySink_COPIED(&hnew->state); - smemclr(s, sizeof(*s)); - sfree(s); + return hashnew; } -static BinarySink *sha256_sink(void *handle) +static void sha256_free(ssh_hash *hash) { - SHA256_State *s = handle; - return BinarySink_UPCAST(s); + struct sha256_hash *h = FROMFIELD(hash, struct sha256_hash, hash); + + smemclr(h, sizeof(*h)); + sfree(h); } -static void sha256_final(void *handle, unsigned char *output) +static void sha256_final(ssh_hash *hash, unsigned char *output) { - SHA256_State *s = handle; - - SHA256_Final(s, output); - sha256_free(s); + struct sha256_hash *h = FROMFIELD(hash, struct sha256_hash, hash); + SHA256_Final(&h->state, output); + sha256_free(hash); } -const struct ssh_hash ssh_sha256 = { - sha256_init, sha256_copy, sha256_sink, sha256_final, sha256_free, - 32, "SHA-256" +const struct ssh_hashalg ssh_sha256 = { + sha256_new, sha256_copy, sha256_final, sha256_free, 32, "SHA-256" }; /* ---------------------------------------------------------------------- diff --git a/sshsh512.c b/sshsh512.c index e16e8c9f..85df1f29 100644 --- a/sshsh512.c +++ b/sshsh512.c @@ -327,74 +327,71 @@ void SHA384_Simple(const void *p, int len, unsigned char *output) { * Thin abstraction for things where hashes are pluggable. */ -static void *sha512_init(void) -{ - SHA512_State *s; +struct sha512_hash { + SHA512_State state; + ssh_hash hash; +}; - s = snew(SHA512_State); - SHA512_Init(s); - return s; +static ssh_hash *sha512_new(const struct ssh_hashalg *alg) +{ + struct sha512_hash *h = snew(struct sha512_hash); + SHA512_Init(&h->state); + h->hash.vt = alg; + BinarySink_DELEGATE_INIT(&h->hash, &h->state); + return &h->hash; } -static void *sha512_copy(const void *vold) +static ssh_hash *sha512_copy(ssh_hash *hashold) { - const SHA512_State *old = (const SHA512_State *)vold; - SHA512_State *s; + struct sha512_hash *hold, *hnew; + ssh_hash *hashnew = sha512_new(hashold->vt); - s = snew(SHA512_State); - *s = *old; - BinarySink_COPIED(s); - return s; -} + hold = FROMFIELD(hashold, struct sha512_hash, hash); + hnew = FROMFIELD(hashnew, struct sha512_hash, hash); -static void sha512_free(void *handle) -{ - SHA512_State *s = handle; + hnew->state = hold->state; + BinarySink_COPIED(&hnew->state); - smemclr(s, sizeof(*s)); - sfree(s); + return hashnew; } -static BinarySink *sha512_sink(void *handle) +static void sha512_free(ssh_hash *hash) { - SHA512_State *s = handle; - return BinarySink_UPCAST(s); + struct sha512_hash *h = FROMFIELD(hash, struct sha512_hash, hash); + + smemclr(h, sizeof(*h)); + sfree(h); } -static void sha512_final(void *handle, unsigned char *output) +static void sha512_final(ssh_hash *hash, unsigned char *output) { - SHA512_State *s = handle; - - SHA512_Final(s, output); - sha512_free(s); + struct sha512_hash *h = FROMFIELD(hash, struct sha512_hash, hash); + SHA512_Final(&h->state, output); + sha512_free(hash); } -const struct ssh_hash ssh_sha512 = { - sha512_init, sha512_copy, sha512_sink, sha512_final, sha512_free, - 64, "SHA-512" +const struct ssh_hashalg ssh_sha512 = { + sha512_new, sha512_copy, sha512_final, sha512_free, 64, "SHA-512" }; -static void *sha384_init(void) +static ssh_hash *sha384_new(const struct ssh_hashalg *alg) { - SHA512_State *s; - - s = snew(SHA512_State); - SHA384_Init(s); - return s; + struct sha512_hash *h = snew(struct sha512_hash); + SHA384_Init(&h->state); + h->hash.vt = alg; + BinarySink_DELEGATE_INIT(&h->hash, &h->state); + return &h->hash; } -static void sha384_final(void *handle, unsigned char *output) +static void sha384_final(ssh_hash *hash, unsigned char *output) { - SHA512_State *s = handle; - - SHA384_Final(s, output); - smemclr(s, sizeof(*s)); - sfree(s); + struct sha512_hash *h = FROMFIELD(hash, struct sha512_hash, hash); + SHA384_Final(&h->state, output); + sha512_free(hash); } -const struct ssh_hash ssh_sha384 = { - sha384_init, sha512_copy, sha512_sink, sha384_final, sha512_free, - 48, "SHA-384" +const struct ssh_hashalg ssh_sha384 = { + sha384_new, sha512_copy, sha384_final, sha512_free, 48, "SHA-384" }; #ifdef TEST diff --git a/sshsha.c b/sshsha.c index 310241a4..f93c2a1f 100644 --- a/sshsha.c +++ b/sshsha.c @@ -232,50 +232,51 @@ void SHA_Simple(const void *p, int len, unsigned char *output) * Thin abstraction for things where hashes are pluggable. */ -static void *sha1_init(void) -{ - SHA_State *s; +struct sha1_hash { + SHA_State state; + ssh_hash hash; +}; - s = snew(SHA_State); - SHA_Init(s); - return s; +static ssh_hash *sha1_new(const struct ssh_hashalg *alg) +{ + struct sha1_hash *h = snew(struct sha1_hash); + SHA_Init(&h->state); + h->hash.vt = alg; + BinarySink_DELEGATE_INIT(&h->hash, &h->state); + return &h->hash; } -static void *sha1_copy(const void *vold) +static ssh_hash *sha1_copy(ssh_hash *hashold) { - const SHA_State *old = (const SHA_State *)vold; - SHA_State *s; + struct sha1_hash *hold, *hnew; + ssh_hash *hashnew = sha1_new(hashold->vt); - s = snew(SHA_State); - *s = *old; - BinarySink_COPIED(s); - return s; -} + hold = FROMFIELD(hashold, struct sha1_hash, hash); + hnew = FROMFIELD(hashnew, struct sha1_hash, hash); -static void sha1_free(void *handle) -{ - SHA_State *s = handle; + hnew->state = hold->state; + BinarySink_COPIED(&hnew->state); - smemclr(s, sizeof(*s)); - sfree(s); + return hashnew; } -static BinarySink *sha1_sink(void *handle) +static void sha1_free(ssh_hash *hash) { - SHA_State *s = handle; - return BinarySink_UPCAST(s); + struct sha1_hash *h = FROMFIELD(hash, struct sha1_hash, hash); + + smemclr(h, sizeof(*h)); + sfree(h); } -static void sha1_final(void *handle, unsigned char *output) +static void sha1_final(ssh_hash *hash, unsigned char *output) { - SHA_State *s = handle; - - SHA_Final(s, output); - sha1_free(s); + struct sha1_hash *h = FROMFIELD(hash, struct sha1_hash, hash); + SHA_Final(&h->state, output); + sha1_free(hash); } -const struct ssh_hash ssh_sha1 = { - sha1_init, sha1_copy, sha1_sink, sha1_final, sha1_free, 20, "SHA-1" +const struct ssh_hashalg ssh_sha1 = { + sha1_new, sha1_copy, sha1_final, sha1_free, 20, "SHA-1" }; /* ---------------------------------------------------------------------- From 9738e042f90942ef782381f747d21709f3b37c62 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Thu, 13 Sep 2018 16:43:30 +0100 Subject: [PATCH 403/607] Clean up a couple of consts and char pointers. hmacmd5_do_hmac and hmac_sha1_simple should be consistently referring to input memory blocks as 'const void *', but one had pointlessly typed the pointer as 'const unsigned char *' and the other had missed out the consts. --- ssh.h | 5 +++-- sshmd5.c | 2 +- sshsha.c | 3 ++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/ssh.h b/ssh.h index ff4305b0..0b2d78ec 100644 --- a/ssh.h +++ b/ssh.h @@ -380,7 +380,7 @@ struct hmacmd5_context *hmacmd5_make_context(void); void hmacmd5_free_context(struct hmacmd5_context *ctx); void hmacmd5_key(struct hmacmd5_context *ctx, void const *key, int len); void hmacmd5_do_hmac(struct hmacmd5_context *ctx, - unsigned char const *blk, int len, unsigned char *hmac); + const void *blk, int len, unsigned char *hmac); int supports_sha_ni(void); @@ -396,7 +396,8 @@ void SHA_Init(SHA_State * s); void SHA_Final(SHA_State * s, unsigned char *output); void SHA_Simple(const void *p, int len, unsigned char *output); -void hmac_sha1_simple(void *key, int keylen, void *data, int datalen, +void hmac_sha1_simple(const void *key, int keylen, + const void *data, int datalen, unsigned char *output); typedef struct SHA256_State { uint32 h[8]; diff --git a/sshmd5.c b/sshmd5.c index 87a224d9..35a21df4 100644 --- a/sshmd5.c +++ b/sshmd5.c @@ -312,7 +312,7 @@ static void hmacmd5_genresult(ssh2_mac *mac, unsigned char *hmac) } void hmacmd5_do_hmac(struct hmacmd5_context *ctx, - unsigned char const *blk, int len, unsigned char *hmac) + const void *blk, int len, unsigned char *hmac) { ssh2_mac_start(&ctx->mac); put_data(&ctx->mac, blk, len); diff --git a/sshsha.c b/sshsha.c index f93c2a1f..282e98a3 100644 --- a/sshsha.c +++ b/sshsha.c @@ -360,7 +360,8 @@ static void hmacsha1_genresult(ssh2_mac *mac, unsigned char *hmac) smemclr(intermediate, sizeof(intermediate)); } -void hmac_sha1_simple(void *key, int keylen, void *data, int datalen, +void hmac_sha1_simple(const void *key, int keylen, + const void *data, int datalen, unsigned char *output) { SHA_State states[2]; unsigned char intermediate[20]; From 7efa4a53051e6ee43d30ee1573f55cb0d2797769 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Fri, 14 Sep 2018 08:30:09 +0100 Subject: [PATCH 404/607] Clean up a 'void *' in a unix.h typedef. 'struct draw_ctx' has a structure tag inside gtkwin.c, so as per this week's standard practice, let's expose the tag elsewhere so that pointers declared that way can't be confused with anything else. --- fuzzterm.c | 6 +----- unix/gtkwin.c | 16 ++++++---------- unix/unix.h | 2 +- 3 files changed, 8 insertions(+), 16 deletions(-) diff --git a/fuzzterm.c b/fuzzterm.c index fda9f6c8..fb68482c 100644 --- a/fuzzterm.c +++ b/fuzzterm.c @@ -73,11 +73,7 @@ void set_sbar(Frontend *frontend, int a, int b, int c) { } void ldisc_send(Ldisc *ldisc, const void *buf, int len, int interactive) {} void ldisc_echoedit_update(Ldisc *ldisc) {} -Context get_ctx(Frontend *frontend) { - static char x; - - return &x; -} +Context get_ctx(Frontend *frontend) { return NULL; } void free_ctx(Context ctx) { } void palette_set(Frontend *frontend, int a, int b, int c, int d) { } void palette_reset(Frontend *frontend) { } diff --git a/unix/gtkwin.c b/unix/gtkwin.c index aebeff8f..46b62782 100644 --- a/unix/gtkwin.c +++ b/unix/gtkwin.c @@ -3481,9 +3481,8 @@ Context get_ctx(Frontend *inst) return dctx; } -void free_ctx(Context ctx) +void free_ctx(Context dctx) { - struct draw_ctx *dctx = (struct draw_ctx *)ctx; /* Frontend *inst = dctx->inst; */ #ifdef DRAW_TEXT_GDK if (dctx->uctx.type == DRAWTYPE_GDK) { @@ -3796,10 +3795,9 @@ static void draw_backing_rect(Frontend *inst) * * We are allowed to fiddle with the contents of `text'. */ -void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, +void do_text_internal(Context dctx, int x, int y, wchar_t *text, int len, unsigned long attr, int lattr, truecolour truecolour) { - struct draw_ctx *dctx = (struct draw_ctx *)ctx; Frontend *inst = dctx->inst; int ncombining; int nfg, nbg, t, fontid, shadow, rlen, widefactor, bold; @@ -3953,14 +3951,13 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, } } -void do_text(Context ctx, int x, int y, wchar_t *text, int len, +void do_text(Context dctx, int x, int y, wchar_t *text, int len, unsigned long attr, int lattr, truecolour truecolour) { - struct draw_ctx *dctx = (struct draw_ctx *)ctx; Frontend *inst = dctx->inst; int widefactor; - do_text_internal(ctx, x, y, text, len, attr, lattr, truecolour); + do_text_internal(dctx, x, y, text, len, attr, lattr, truecolour); if (attr & ATTR_WIDE) { widefactor = 2; @@ -3983,10 +3980,9 @@ void do_text(Context ctx, int x, int y, wchar_t *text, int len, len*widefactor*inst->font_width, inst->font_height); } -void do_cursor(Context ctx, int x, int y, wchar_t *text, int len, +void do_cursor(Context dctx, int x, int y, wchar_t *text, int len, unsigned long attr, int lattr, truecolour truecolour) { - struct draw_ctx *dctx = (struct draw_ctx *)ctx; Frontend *inst = dctx->inst; int active, passive, widefactor; @@ -4001,7 +3997,7 @@ void do_cursor(Context ctx, int x, int y, wchar_t *text, int len, active = 1; } else active = 0; - do_text_internal(ctx, x, y, text, len, attr, lattr, truecolour); + do_text_internal(dctx, x, y, text, len, attr, lattr, truecolour); if (attr & TATTR_COMBINING) len = 1; diff --git a/unix/unix.h b/unix/unix.h index 3dd2864a..9a93a059 100644 --- a/unix/unix.h +++ b/unix/unix.h @@ -65,7 +65,7 @@ struct FontSpec { }; struct FontSpec *fontspec_new(const char *name); -typedef void *Context; /* FIXME: probably needs changing */ +typedef struct draw_ctx *Context; extern const struct Backend_vtable pty_backend; From 733fcca2cdf7e4719d4d298cf980537eca2580d8 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Fri, 14 Sep 2018 08:45:42 +0100 Subject: [PATCH 405/607] Invent structure tags for the storage.h abstractions. Most of these were 'void *' because they weren't even reliably a structure type underneath - the per-OS storage systems would directly cast read/write/enum settings handles to and from random things like FILE *, Unix DIR *, or Windows HKEY. So I've wrapped them in tiny structs for the sake of having a sensible structure tag visible elsewhere in the code. --- defs.h | 4 ++ putty.h | 4 +- settings.c | 10 ++--- storage.h | 32 ++++++++------- unix/uxstore.c | 98 ++++++++++++++++++++++++++-------------------- windows/winjump.c | 3 +- windows/winstore.c | 77 +++++++++++++++++++++--------------- 7 files changed, 131 insertions(+), 97 deletions(-) diff --git a/defs.h b/defs.h index 1bc8f9b8..ba61708b 100644 --- a/defs.h +++ b/defs.h @@ -61,6 +61,10 @@ typedef struct share_channel share_channel; typedef struct dlgparam dlgparam; +typedef struct settings_w settings_w; +typedef struct settings_r settings_r; +typedef struct settings_e settings_e; + /* Note indirection: for historical reasons (it used to be closer to * the OS socket type), the type that most code uses for a socket is * 'Socket', not 'Socket *'. So an implementation of Socket or Plug diff --git a/putty.h b/putty.h index 7b1f90e4..dd43e8c4 100644 --- a/putty.h +++ b/putty.h @@ -1074,9 +1074,9 @@ const struct Backend_vtable *backend_vt_from_name(const char *name); const struct Backend_vtable *backend_vt_from_proto(int proto); char *get_remote_username(Conf *conf); /* dynamically allocated */ char *save_settings(const char *section, Conf *conf); -void save_open_settings(void *sesskey, Conf *conf); +void save_open_settings(settings_w *sesskey, Conf *conf); void load_settings(const char *section, Conf *conf); -void load_open_settings(void *sesskey, Conf *conf); +void load_open_settings(settings_r *sesskey, Conf *conf); void get_sesslist(struct sesslist *, int allocate); void do_defaults(const char *, Conf *); void registry_cleanup(void); diff --git a/settings.c b/settings.c index ecdb3a4b..ab735488 100644 --- a/settings.c +++ b/settings.c @@ -502,7 +502,7 @@ static void read_clip_setting(void *handle, const char *savekey, char *save_settings(const char *section, Conf *conf) { - void *sesskey; + struct settings_w *sesskey; char *errmsg; sesskey = open_settings_w(section, &errmsg); @@ -513,7 +513,7 @@ char *save_settings(const char *section, Conf *conf) return NULL; } -void save_open_settings(void *sesskey, Conf *conf) +void save_open_settings(settings_w *sesskey, Conf *conf) { int i; const char *p; @@ -760,7 +760,7 @@ void save_open_settings(void *sesskey, Conf *conf) void load_settings(const char *section, Conf *conf) { - void *sesskey; + settings_r *sesskey; sesskey = open_settings_r(section); load_open_settings(sesskey, conf); @@ -770,7 +770,7 @@ void load_settings(const char *section, Conf *conf) add_session_to_jumplist(section); } -void load_open_settings(void *sesskey, Conf *conf) +void load_open_settings(settings_r *sesskey, Conf *conf) { int i; char *prot; @@ -1242,7 +1242,7 @@ void get_sesslist(struct sesslist *list, int allocate) char otherbuf[2048]; int buflen, bufsize, i; char *p, *ret; - void *handle; + settings_e *handle; if (allocate) { diff --git a/storage.h b/storage.h index 8e07ef0c..6186e91d 100644 --- a/storage.h +++ b/storage.h @@ -28,12 +28,14 @@ * * Any returned error message must be freed after use. */ -void *open_settings_w(const char *sessionname, char **errmsg); -void write_setting_s(void *handle, const char *key, const char *value); -void write_setting_i(void *handle, const char *key, int value); -void write_setting_filename(void *handle, const char *key, Filename *value); -void write_setting_fontspec(void *handle, const char *key, FontSpec *font); -void close_settings_w(void *handle); +settings_w *open_settings_w(const char *sessionname, char **errmsg); +void write_setting_s(settings_w *handle, const char *key, const char *value); +void write_setting_i(settings_w *handle, const char *key, int value); +void write_setting_filename(settings_w *handle, + const char *key, Filename *value); +void write_setting_fontspec(settings_w *handle, + const char *key, FontSpec *font); +void close_settings_w(settings_w *handle); /* * Read a saved session. The caller is expected to call @@ -51,12 +53,12 @@ void close_settings_w(void *handle); * should invent a sensible default. If an integer setting is not * present, read_setting_i() returns its provided default. */ -void *open_settings_r(const char *sessionname); -char *read_setting_s(void *handle, const char *key); -int read_setting_i(void *handle, const char *key, int defvalue); -Filename *read_setting_filename(void *handle, const char *key); -FontSpec *read_setting_fontspec(void *handle, const char *key); -void close_settings_r(void *handle); +settings_r *open_settings_r(const char *sessionname); +char *read_setting_s(settings_r *handle, const char *key); +int read_setting_i(settings_r *handle, const char *key, int defvalue); +Filename *read_setting_filename(settings_r *handle, const char *key); +FontSpec *read_setting_fontspec(settings_r *handle, const char *key); +void close_settings_r(settings_r *handle); /* * Delete a whole saved session. @@ -66,9 +68,9 @@ void del_settings(const char *sessionname); /* * Enumerate all saved sessions. */ -void *enum_settings_start(void); -char *enum_settings_next(void *handle, char *buffer, int buflen); -void enum_settings_finish(void *handle); +settings_e *enum_settings_start(void); +char *enum_settings_next(settings_e *handle, char *buffer, int buflen); +void enum_settings_finish(settings_e *handle); /* ---------------------------------------------------------------------- * Functions to access PuTTY's host key database. diff --git a/unix/uxstore.c b/unix/uxstore.c index 15801785..54a20b8a 100644 --- a/unix/uxstore.c +++ b/unix/uxstore.c @@ -218,7 +218,11 @@ static char *make_filename(int index, const char *subname) return ret; } -void *open_settings_w(const char *sessionname, char **errmsg) +struct settings_w { + FILE *fp; +}; + +settings_w *open_settings_w(const char *sessionname, char **errmsg) { char *filename, *err; FILE *fp; @@ -256,25 +260,26 @@ void *open_settings_w(const char *sessionname, char **errmsg) return NULL; /* can't open */ } sfree(filename); - return fp; + + settings_w *toret = snew(settings_w); + toret->fp = fp; + return toret; } -void write_setting_s(void *handle, const char *key, const char *value) +void write_setting_s(settings_w *handle, const char *key, const char *value) { - FILE *fp = (FILE *)handle; - fprintf(fp, "%s=%s\n", key, value); + fprintf(handle->fp, "%s=%s\n", key, value); } -void write_setting_i(void *handle, const char *key, int value) +void write_setting_i(settings_w *handle, const char *key, int value) { - FILE *fp = (FILE *)handle; - fprintf(fp, "%s=%d\n", key, value); + fprintf(handle->fp, "%s=%d\n", key, value); } -void close_settings_w(void *handle) +void close_settings_w(settings_w *handle) { - FILE *fp = (FILE *)handle; - fclose(fp); + fclose(handle->fp); + sfree(handle); } /* @@ -347,12 +352,16 @@ const char *get_setting(const char *key) return x_get_default(key); } -void *open_settings_r(const char *sessionname) +struct settings_r { + tree234 *t; +}; + +settings_r *open_settings_r(const char *sessionname) { char *filename; FILE *fp; char *line; - tree234 *ret; + settings_r *toret; filename = make_filename(INDEX_SESSION, sessionname); fp = fopen(filename, "r"); @@ -360,7 +369,8 @@ void *open_settings_r(const char *sessionname) if (!fp) return NULL; /* can't open */ - ret = newtree234(keycmp); + toret = snew(settings_r); + toret->t = newtree234(keycmp); while ( (line = fgetline(fp)) ) { char *value = strchr(line, '='); @@ -376,25 +386,24 @@ void *open_settings_r(const char *sessionname) kv = snew(struct skeyval); kv->key = dupstr(line); kv->value = dupstr(value); - add234(ret, kv); + add234(toret->t, kv); sfree(line); } fclose(fp); - return ret; + return toret; } -char *read_setting_s(void *handle, const char *key) +char *read_setting_s(settings_r *handle, const char *key) { - tree234 *tree = (tree234 *)handle; const char *val; struct skeyval tmp, *kv; tmp.key = key; - if (tree != NULL && - (kv = find234(tree, &tmp, NULL)) != NULL) { + if (handle != NULL && + (kv = find234(handle->t, &tmp, NULL)) != NULL) { val = kv->value; assert(val != NULL); } else @@ -406,15 +415,14 @@ char *read_setting_s(void *handle, const char *key) return dupstr(val); } -int read_setting_i(void *handle, const char *key, int defvalue) +int read_setting_i(settings_r *handle, const char *key, int defvalue) { - tree234 *tree = (tree234 *)handle; const char *val; struct skeyval tmp, *kv; tmp.key = key; - if (tree != NULL && - (kv = find234(tree, &tmp, NULL)) != NULL) { + if (handle != NULL && + (kv = find234(handle->t, &tmp, NULL)) != NULL) { val = kv->value; assert(val != NULL); } else @@ -426,7 +434,7 @@ int read_setting_i(void *handle, const char *key, int defvalue) return atoi(val); } -FontSpec *read_setting_fontspec(void *handle, const char *name) +FontSpec *read_setting_fontspec(settings_r *handle, const char *name) { /* * In GTK1-only PuTTY, we used to store font names simply as a @@ -464,7 +472,7 @@ FontSpec *read_setting_fontspec(void *handle, const char *name) return NULL; } } -Filename *read_setting_filename(void *handle, const char *name) +Filename *read_setting_filename(settings_r *handle, const char *name) { char *tmp = read_setting_s(handle, name); if (tmp) { @@ -475,7 +483,7 @@ Filename *read_setting_filename(void *handle, const char *name) return NULL; } -void write_setting_fontspec(void *handle, const char *name, FontSpec *fs) +void write_setting_fontspec(settings_w *handle, const char *name, FontSpec *fs) { /* * read_setting_fontspec had to handle two cases, but when @@ -486,27 +494,28 @@ void write_setting_fontspec(void *handle, const char *name, FontSpec *fs) write_setting_s(handle, suffname, fs->name); sfree(suffname); } -void write_setting_filename(void *handle, const char *name, Filename *result) +void write_setting_filename(settings_w *handle, + const char *name, Filename *result) { write_setting_s(handle, name, result->path); } -void close_settings_r(void *handle) +void close_settings_r(settings_r *handle) { - tree234 *tree = (tree234 *)handle; struct skeyval *kv; - if (!tree) + if (!handle) return; - while ( (kv = index234(tree, 0)) != NULL) { - del234(tree, kv); + while ( (kv = index234(handle->t, 0)) != NULL) { + del234(handle->t, kv); sfree((char *)kv->key); sfree((char *)kv->value); sfree(kv); } - freetree234(tree); + freetree234(handle->t); + sfree(handle); } void del_settings(const char *sessionname) @@ -517,7 +526,11 @@ void del_settings(const char *sessionname) sfree(filename); } -void *enum_settings_start(void) +struct settings_e { + DIR *dp; +}; + +settings_e *enum_settings_start(void) { DIR *dp; char *filename; @@ -526,12 +539,13 @@ void *enum_settings_start(void) dp = opendir(filename); sfree(filename); - return dp; + settings_e *toret = snew(settings_e); + toret->dp = dp; + return toret; } -char *enum_settings_next(void *handle, char *buffer, int buflen) +char *enum_settings_next(settings_e *handle, char *buffer, int buflen) { - DIR *dp = (DIR *)handle; struct dirent *de; struct stat st; char *fullpath; @@ -541,7 +555,7 @@ char *enum_settings_next(void *handle, char *buffer, int buflen) fullpath = make_filename(INDEX_SESSIONDIR, NULL); maxlen = len = strlen(fullpath); - while ( (de = readdir(dp)) != NULL ) { + while ( (de = readdir(handle->dp)) != NULL ) { thislen = len + 1 + strlen(de->d_name); if (maxlen < thislen) { maxlen = thislen; @@ -566,10 +580,10 @@ char *enum_settings_next(void *handle, char *buffer, int buflen) return NULL; } -void enum_settings_finish(void *handle) +void enum_settings_finish(settings_e *handle) { - DIR *dp = (DIR *)handle; - closedir(dp); + closedir(handle->dp); + sfree(handle); } /* diff --git a/windows/winjump.c b/windows/winjump.c index 7e7b34e8..e42ba275 100644 --- a/windows/winjump.c +++ b/windows/winjump.c @@ -383,7 +383,6 @@ static IShellLink *make_shell_link(const char *appname, { IShellLink *ret; char *app_path, *param_string, *desc_string; - void *psettings_tmp; IPropertyStore *pPS; PROPVARIANT pv; @@ -409,7 +408,7 @@ static IShellLink *make_shell_link(const char *appname, /* Check if this is a valid session, otherwise don't add. */ if (sessionname) { - psettings_tmp = open_settings_r(sessionname); + settings_r *psettings_tmp = open_settings_r(sessionname); if (!psettings_tmp) { sfree(app_path); return NULL; diff --git a/windows/winstore.c b/windows/winstore.c index 26cbf634..7c4be074 100644 --- a/windows/winstore.c +++ b/windows/winstore.c @@ -74,7 +74,11 @@ static void unmungestr(const char *in, char *out, int outlen) return; } -void *open_settings_w(const char *sessionname, char **errmsg) +struct settings_w { + HKEY sesskey; +}; + +settings_w *open_settings_w(const char *sessionname, char **errmsg) { HKEY subkey1, sesskey; int ret; @@ -104,29 +108,37 @@ void *open_settings_w(const char *sessionname, char **errmsg) return NULL; } sfree(p); - return (void *) sesskey; + + settings_w *toret = snew(settings_w); + toret->sesskey = sesskey; + return toret; } -void write_setting_s(void *handle, const char *key, const char *value) +void write_setting_s(settings_w *handle, const char *key, const char *value) { if (handle) - RegSetValueEx((HKEY) handle, key, 0, REG_SZ, (CONST BYTE *)value, + RegSetValueEx(handle->sesskey, key, 0, REG_SZ, (CONST BYTE *)value, 1 + strlen(value)); } -void write_setting_i(void *handle, const char *key, int value) +void write_setting_i(settings_w *handle, const char *key, int value) { if (handle) - RegSetValueEx((HKEY) handle, key, 0, REG_DWORD, + RegSetValueEx(handle->sesskey, key, 0, REG_DWORD, (CONST BYTE *) &value, sizeof(value)); } -void close_settings_w(void *handle) +void close_settings_w(settings_w *handle) { - RegCloseKey((HKEY) handle); + RegCloseKey(handle->sesskey); + sfree(handle); } -void *open_settings_r(const char *sessionname) +struct settings_r { + HKEY sesskey; +}; + +settings_r *open_settings_r(const char *sessionname) { HKEY subkey1, sesskey; char *p; @@ -148,10 +160,12 @@ void *open_settings_r(const char *sessionname) sfree(p); - return (void *) sesskey; + settings_r *toret = snew(settings_r); + toret->sesskey = sesskey; + return toret; } -char *read_setting_s(void *handle, const char *key) +char *read_setting_s(settings_r *handle, const char *key) { DWORD type, allocsize, size; char *ret; @@ -160,14 +174,14 @@ char *read_setting_s(void *handle, const char *key) return NULL; /* Find out the type and size of the data. */ - if (RegQueryValueEx((HKEY) handle, key, 0, + if (RegQueryValueEx(handle->sesskey, key, 0, &type, NULL, &size) != ERROR_SUCCESS || type != REG_SZ) return NULL; allocsize = size+1; /* allow for an extra NUL if needed */ ret = snewn(allocsize, char); - if (RegQueryValueEx((HKEY) handle, key, 0, + if (RegQueryValueEx(handle->sesskey, key, 0, &type, (BYTE *)ret, &size) != ERROR_SUCCESS || type != REG_SZ) { sfree(ret); @@ -180,13 +194,13 @@ char *read_setting_s(void *handle, const char *key) return ret; } -int read_setting_i(void *handle, const char *key, int defvalue) +int read_setting_i(settings_r *handle, const char *key, int defvalue) { DWORD type, val, size; size = sizeof(val); if (!handle || - RegQueryValueEx((HKEY) handle, key, 0, &type, + RegQueryValueEx(handle->sesskey, key, 0, &type, (BYTE *) &val, &size) != ERROR_SUCCESS || size != sizeof(val) || type != REG_DWORD) return defvalue; @@ -194,7 +208,7 @@ int read_setting_i(void *handle, const char *key, int defvalue) return val; } -FontSpec *read_setting_fontspec(void *handle, const char *name) +FontSpec *read_setting_fontspec(settings_r *handle, const char *name) { char *settingname; char *fontname; @@ -234,7 +248,8 @@ FontSpec *read_setting_fontspec(void *handle, const char *name) return ret; } -void write_setting_fontspec(void *handle, const char *name, FontSpec *font) +void write_setting_fontspec(settings_w *handle, + const char *name, FontSpec *font) { char *settingname; @@ -250,7 +265,7 @@ void write_setting_fontspec(void *handle, const char *name, FontSpec *font) sfree(settingname); } -Filename *read_setting_filename(void *handle, const char *name) +Filename *read_setting_filename(settings_r *handle, const char *name) { char *tmp = read_setting_s(handle, name); if (tmp) { @@ -261,14 +276,16 @@ Filename *read_setting_filename(void *handle, const char *name) return NULL; } -void write_setting_filename(void *handle, const char *name, Filename *result) +void write_setting_filename(settings_w *handle, + const char *name, Filename *result) { write_setting_s(handle, name, result->path); } -void close_settings_r(void *handle) +void close_settings_r(settings_r *handle) { - RegCloseKey((HKEY) handle); + RegCloseKey(handle->sesskey); + sfree(handle); } void del_settings(const char *sessionname) @@ -289,20 +306,20 @@ void del_settings(const char *sessionname) remove_session_from_jumplist(sessionname); } -struct enumsettings { +struct settings_e { HKEY key; int i; }; -void *enum_settings_start(void) +settings_e *enum_settings_start(void) { - struct enumsettings *ret; + settings_e *ret; HKEY key; if (RegOpenKey(HKEY_CURRENT_USER, puttystr, &key) != ERROR_SUCCESS) return NULL; - ret = snew(struct enumsettings); + ret = snew(settings_e); if (ret) { ret->key = key; ret->i = 0; @@ -311,9 +328,8 @@ void *enum_settings_start(void) return ret; } -char *enum_settings_next(void *handle, char *buffer, int buflen) +char *enum_settings_next(settings_e *e, char *buffer, int buflen) { - struct enumsettings *e = (struct enumsettings *) handle; char *otherbuf; otherbuf = snewn(3 * buflen, char); if (RegEnumKey(e->key, e->i++, otherbuf, 3 * buflen) == ERROR_SUCCESS) { @@ -326,9 +342,8 @@ char *enum_settings_next(void *handle, char *buffer, int buflen) } } -void enum_settings_finish(void *handle) +void enum_settings_finish(settings_e *e) { - struct enumsettings *e = (struct enumsettings *) handle; RegCloseKey(e->key); sfree(e); } @@ -656,7 +671,7 @@ static int transform_jumplist_registry (const char *add, const char *rem, char **out) { int ret; - HKEY pjumplist_key, psettings_tmp; + HKEY pjumplist_key; DWORD type; DWORD value_length; char *old_value, *new_value; @@ -741,7 +756,7 @@ static int transform_jumplist_registry while (*piterator_old != '\0') { if (!rem || strcmp(piterator_old, rem) != 0) { /* Check if this is a valid session, otherwise don't add. */ - psettings_tmp = open_settings_r(piterator_old); + settings_r *psettings_tmp = open_settings_r(piterator_old); if (psettings_tmp != NULL) { close_settings_r(psettings_tmp); strcpy(piterator_new, piterator_old); From 03fb4423af303637029ad1318884a207d6aa66da Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Fri, 14 Sep 2018 08:48:54 +0100 Subject: [PATCH 406/607] Expose the 'dh_ctx' struct tag used for Diffie-Hellman. --- ssh.c | 32 ++++++++++++++++---------------- ssh.h | 13 +++++++------ sshdh.c | 16 ++++++---------- 3 files changed, 29 insertions(+), 32 deletions(-) diff --git a/ssh.c b/ssh.c index ab6d6fbe..f4061894 100644 --- a/ssh.c +++ b/ssh.c @@ -691,7 +691,7 @@ struct ssh_tag { int v2_session_id_len; int v2_cbc_ignore_workaround; int v2_out_cipherblksize; - void *kex_ctx; + struct dh_ctx *dh_ctx; int bare_connection; int attempting_connshare; @@ -5787,12 +5787,12 @@ static void do_ssh2_transport(void *vctx) bombout(("unable to read mp-ints from incoming group packet")); crStopV; } - ssh->kex_ctx = dh_setup_gex(s->p, s->g); + ssh->dh_ctx = dh_setup_gex(s->p, s->g); s->kex_init_value = SSH2_MSG_KEX_DH_GEX_INIT; s->kex_reply_value = SSH2_MSG_KEX_DH_GEX_REPLY; } else { ssh->pls.kctx = SSH2_PKTCTX_DHGROUP; - ssh->kex_ctx = dh_setup_group(ssh->kex); + ssh->dh_ctx = dh_setup_group(ssh->kex); s->kex_init_value = SSH2_MSG_KEXDH_INIT; s->kex_reply_value = SSH2_MSG_KEXDH_REPLY; logeventf(ssh, "Using Diffie-Hellman with standard group \"%s\"", @@ -5805,7 +5805,7 @@ static void do_ssh2_transport(void *vctx) * Now generate and send e for Diffie-Hellman. */ set_busy_status(ssh->frontend, BUSY_CPU); /* this can take a while */ - s->e = dh_create_e(ssh->kex_ctx, s->nbits * 2); + s->e = dh_create_e(ssh->dh_ctx, s->nbits * 2); s->pktout = ssh_bpp_new_pktout(ssh->bpp, s->kex_init_value); put_mp_ssh2(s->pktout, s->e); ssh_pkt_write(ssh, s->pktout); @@ -5827,13 +5827,13 @@ static void do_ssh2_transport(void *vctx) } { - const char *err = dh_validate_f(ssh->kex_ctx, s->f); + const char *err = dh_validate_f(ssh->dh_ctx, s->f); if (err) { bombout(("key exchange reply failed validation: %s", err)); crStopV; } } - s->K = dh_find_K(ssh->kex_ctx, s->f); + s->K = dh_find_K(ssh->dh_ctx, s->f); /* We assume everything from now on will be quick, and it might * involve user interaction. */ @@ -5852,7 +5852,7 @@ static void do_ssh2_transport(void *vctx) put_mp_ssh2(ssh->exhash, s->e); put_mp_ssh2(ssh->exhash, s->f); - dh_cleanup(ssh->kex_ctx); + dh_cleanup(ssh->dh_ctx); freebn(s->f); if (dh_is_gex(ssh->kex)) { freebn(s->g); @@ -5972,9 +5972,9 @@ static void do_ssh2_transport(void *vctx) bombout(("unable to read mp-ints from incoming group packet")); crStopV; } - ssh->kex_ctx = dh_setup_gex(s->p, s->g); + ssh->dh_ctx = dh_setup_gex(s->p, s->g); } else { - ssh->kex_ctx = dh_setup_group(ssh->kex); + ssh->dh_ctx = dh_setup_group(ssh->kex); logeventf(ssh, "Using GSSAPI (with Kerberos V5) Diffie-Hellman with standard group \"%s\"", ssh->kex->groupname); } @@ -5983,7 +5983,7 @@ static void do_ssh2_transport(void *vctx) ssh->kex->hash->text_name); /* Now generate e for Diffie-Hellman. */ set_busy_status(ssh->frontend, BUSY_CPU); /* this can take a while */ - s->e = dh_create_e(ssh->kex_ctx, s->nbits * 2); + s->e = dh_create_e(ssh->dh_ctx, s->nbits * 2); if (ssh->gsslib->gsslogmsg) logevent(ssh->gsslib->gsslogmsg); @@ -6137,7 +6137,7 @@ static void do_ssh2_transport(void *vctx) s->gss_stat == SSH_GSS_S_CONTINUE_NEEDED || !s->complete_rcvd); - s->K = dh_find_K(ssh->kex_ctx, s->f); + s->K = dh_find_K(ssh->dh_ctx, s->f); /* We assume everything from now on will be quick, and it might * involve user interaction. */ @@ -6162,7 +6162,7 @@ static void do_ssh2_transport(void *vctx) * used as the MIC input. */ - dh_cleanup(ssh->kex_ctx); + dh_cleanup(ssh->dh_ctx); freebn(s->f); if (dh_is_gex(ssh->kex)) { freebn(s->g); @@ -6313,7 +6313,7 @@ static void do_ssh2_transport(void *vctx) } #endif - ssh->kex_ctx = NULL; + ssh->dh_ctx = NULL; #if 0 debug(("Exchange hash is:\n")); @@ -10554,7 +10554,7 @@ static const char *ssh_init(Frontend *frontend, Backend **backend_handle, ssh->version = 0; /* when not ready yet */ ssh->s = NULL; ssh->kex = NULL; - ssh->kex_ctx = NULL; + ssh->dh_ctx = NULL; ssh->hostkey_alg = NULL; ssh->hostkey_str = NULL; ssh->exitcode = -1; @@ -10711,8 +10711,8 @@ static void ssh_free(Backend *be) struct X11FakeAuth *auth; int need_random_unref; - if (ssh->kex_ctx) - dh_cleanup(ssh->kex_ctx); + if (ssh->dh_ctx) + dh_cleanup(ssh->dh_ctx); sfree(ssh->savedhost); while (ssh->queuelen-- > 0) diff --git a/ssh.h b/ssh.h index 0b2d78ec..377c0568 100644 --- a/ssh.h +++ b/ssh.h @@ -874,12 +874,13 @@ void diagbn(char *prefix, Bignum md); #endif int dh_is_gex(const struct ssh_kex *kex); -void *dh_setup_group(const struct ssh_kex *kex); -void *dh_setup_gex(Bignum pval, Bignum gval); -void dh_cleanup(void *); -Bignum dh_create_e(void *, int nbits); -const char *dh_validate_f(void *handle, Bignum f); -Bignum dh_find_K(void *, Bignum f); +struct dh_ctx; +struct dh_ctx *dh_setup_group(const struct ssh_kex *kex); +struct dh_ctx *dh_setup_gex(Bignum pval, Bignum gval); +void dh_cleanup(struct dh_ctx *); +Bignum dh_create_e(struct dh_ctx *, int nbits); +const char *dh_validate_f(struct dh_ctx *, Bignum f); +Bignum dh_find_K(struct dh_ctx *, Bignum f); int rsa_ssh1_encrypted(const Filename *filename, char **comment); int rsa_ssh1_loadpub(const Filename *filename, BinarySink *bs, diff --git a/sshdh.c b/sshdh.c index 1c27b021..c18da320 100644 --- a/sshdh.c +++ b/sshdh.c @@ -187,7 +187,7 @@ int dh_is_gex(const struct ssh_kex *kex) /* * Initialise DH for a standard group. */ -void *dh_setup_group(const struct ssh_kex *kex) +struct dh_ctx *dh_setup_group(const struct ssh_kex *kex) { const struct dh_extra *extra = (const struct dh_extra *)kex->extra; struct dh_ctx *ctx = snew(struct dh_ctx); @@ -200,7 +200,7 @@ void *dh_setup_group(const struct ssh_kex *kex) /* * Initialise DH for a server-supplied group. */ -void *dh_setup_gex(Bignum pval, Bignum gval) +struct dh_ctx *dh_setup_gex(Bignum pval, Bignum gval) { struct dh_ctx *ctx = snew(struct dh_ctx); ctx->p = copybn(pval); @@ -212,9 +212,8 @@ void *dh_setup_gex(Bignum pval, Bignum gval) /* * Clean up and free a context. */ -void dh_cleanup(void *handle) +void dh_cleanup(struct dh_ctx *ctx) { - struct dh_ctx *ctx = (struct dh_ctx *)handle; freebn(ctx->x); freebn(ctx->e); freebn(ctx->p); @@ -239,9 +238,8 @@ void dh_cleanup(void *handle) * Advances in Cryptology: Proceedings of Eurocrypt '96 * Springer-Verlag, May 1996. */ -Bignum dh_create_e(void *handle, int nbits) +Bignum dh_create_e(struct dh_ctx *ctx, int nbits) { - struct dh_ctx *ctx = (struct dh_ctx *)handle; int i; int nbytes; @@ -295,9 +293,8 @@ Bignum dh_create_e(void *handle, int nbits) * they lead to obviously weak keys that even a passive eavesdropper * can figure out.) */ -const char *dh_validate_f(void *handle, Bignum f) +const char *dh_validate_f(struct dh_ctx *ctx, Bignum f) { - struct dh_ctx *ctx = (struct dh_ctx *)handle; if (bignum_cmp(f, One) <= 0) { return "f value received is too small"; } else { @@ -313,9 +310,8 @@ const char *dh_validate_f(void *handle, Bignum f) /* * DH stage 2: given a number f, compute K = f^x mod p. */ -Bignum dh_find_K(void *handle, Bignum f) +Bignum dh_find_K(struct dh_ctx *ctx, Bignum f) { - struct dh_ctx *ctx = (struct dh_ctx *)handle; Bignum ret; ret = modpow(f, ctx->x, ctx->p); return ret; From d437e5402ead209315c38cd9daff8cce8b4d7966 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Fri, 14 Sep 2018 09:16:41 +0100 Subject: [PATCH 407/607] Make ssh_compress into a pair of linked classoids. This was mildly fiddly because there's a single vtable structure that implements two distinct interface types, one for compression and one for decompression - and I have actually confused them before now (commit d4304f1b7), so I think it's important to make them actually be separate types! --- ssh.c | 32 +++++++++++++++++---------- ssh.h | 50 ++++++++++++++++++++++-------------------- ssh1bpp.c | 21 +++++++++--------- ssh2bpp.c | 57 ++++++++++++++++++++++++------------------------ sshbpp.h | 4 ++-- sshzlib.c | 65 +++++++++++++++++++++++++++++++++++-------------------- 6 files changed, 130 insertions(+), 99 deletions(-) diff --git a/ssh.c b/ssh.c index f4061894..29f25466 100644 --- a/ssh.c +++ b/ssh.c @@ -335,31 +335,39 @@ const static struct ssh2_macalg *const buggymacs[] = { &ssh_hmac_sha1_buggy, &ssh_hmac_sha1_96_buggy, &ssh_hmac_md5 }; -static void *ssh_comp_none_init(void) +static ssh_compressor *ssh_comp_none_init(void) { return NULL; } -static void ssh_comp_none_cleanup(void *handle) +static void ssh_comp_none_cleanup(ssh_compressor *handle) { } -static void ssh_comp_none_block(void *handle, unsigned char *block, int len, +static ssh_decompressor *ssh_decomp_none_init(void) +{ + return NULL; +} +static void ssh_decomp_none_cleanup(ssh_decompressor *handle) +{ +} +static void ssh_comp_none_block(ssh_compressor *handle, + unsigned char *block, int len, unsigned char **outblock, int *outlen, int minlen) { } -static int ssh_decomp_none_block(void *handle, unsigned char *block, int len, +static int ssh_decomp_none_block(ssh_decompressor *handle, + unsigned char *block, int len, unsigned char **outblock, int *outlen) { return 0; } -const static struct ssh_compress ssh_comp_none = { +const static struct ssh_compression_alg ssh_comp_none = { "none", NULL, ssh_comp_none_init, ssh_comp_none_cleanup, ssh_comp_none_block, - ssh_comp_none_init, ssh_comp_none_cleanup, ssh_decomp_none_block, + ssh_decomp_none_init, ssh_decomp_none_cleanup, ssh_decomp_none_block, NULL }; -extern const struct ssh_compress ssh_zlib; -const static struct ssh_compress *const compressions[] = { +const static struct ssh_compression_alg *const compressions[] = { &ssh_zlib, &ssh_comp_none }; @@ -4853,7 +4861,7 @@ struct kexinit_algorithm { const struct ssh2_macalg *mac; int etm; } mac; - const struct ssh_compress *comp; + const struct ssh_compression_alg *comp; } u; }; @@ -5025,7 +5033,7 @@ static void do_ssh2_transport(void *vctx) const struct ssh2_cipheralg *cipher; const struct ssh2_macalg *mac; int etm_mode; - const struct ssh_compress *comp; + const struct ssh_compression_alg *comp; } in, out; ptrlen hostkeydata, sigdata; char *keystr, *fingerprint; @@ -5042,7 +5050,7 @@ static void do_ssh2_transport(void *vctx) int preferred_hk[HK_MAX]; int n_preferred_ciphers; const struct ssh2_ciphers *preferred_ciphers[CIPHER_MAX]; - const struct ssh_compress *preferred_comp; + const struct ssh_compression_alg *preferred_comp; int userauth_succeeded; /* for delayed compression */ int pending_compression; int got_session_id; @@ -5413,7 +5421,7 @@ static void do_ssh2_transport(void *vctx) alg->u.comp = s->preferred_comp; } for (i = 0; i < lenof(compressions); i++) { - const struct ssh_compress *c = compressions[i]; + const struct ssh_compression_alg *c = compressions[i]; alg = ssh2_kexinit_addalg(s->kexlists[j], c->name); alg->u.comp = c; if (s->userauth_succeeded && c->delayed_name) { diff --git a/ssh.h b/ssh.h index 377c0568..7f038b9c 100644 --- a/ssh.h +++ b/ssh.h @@ -603,23 +603,39 @@ struct ssh_keyalg { #define ssh_key_ssh_id(key) ((*(key))->ssh_id) #define ssh_key_cache_id(key) ((*(key))->cache_id) -struct ssh_compress { +typedef struct ssh_compressor { + const struct ssh_compression_alg *vt; +} ssh_compressor; +typedef struct ssh_decompressor { + const struct ssh_compression_alg *vt; +} ssh_decompressor; + +struct ssh_compression_alg { const char *name; /* For zlib@openssh.com: if non-NULL, this name will be considered once * userauth has completed successfully. */ const char *delayed_name; - void *(*compress_init) (void); - void (*compress_cleanup) (void *); - void (*compress) (void *, unsigned char *block, int len, - unsigned char **outblock, int *outlen, - int minlen); - void *(*decompress_init) (void); - void (*decompress_cleanup) (void *); - int (*decompress) (void *, unsigned char *block, int len, - unsigned char **outblock, int *outlen); + ssh_compressor *(*compress_new)(void); + void (*compress_free)(ssh_compressor *); + void (*compress)(ssh_compressor *, unsigned char *block, int len, + unsigned char **outblock, int *outlen, + int minlen); + ssh_decompressor *(*decompress_new)(void); + void (*decompress_free)(ssh_decompressor *); + int (*decompress)(ssh_decompressor *, unsigned char *block, int len, + unsigned char **outblock, int *outlen); const char *text_name; }; +#define ssh_compressor_new(alg) ((alg)->compress_new()) +#define ssh_compressor_free(comp) ((comp)->vt->compress_free(comp)) +#define ssh_compressor_compress(comp, in, inlen, out, outlen, minlen) \ + ((comp)->vt->compress(comp, in, inlen, out, outlen, minlen)) +#define ssh_decompressor_new(alg) ((alg)->decompress_new()) +#define ssh_decompressor_free(comp) ((comp)->vt->decompress_free(comp)) +#define ssh_decompressor_decompress(comp, in, inlen, out, outlen) \ + ((comp)->vt->decompress(comp, in, inlen, out, outlen)) + struct ssh2_userkey { ssh_key *key; /* the key itself */ char *comment; /* the key comment */ @@ -659,6 +675,7 @@ extern const struct ssh2_macalg ssh_hmac_sha1_buggy; extern const struct ssh2_macalg ssh_hmac_sha1_96; extern const struct ssh2_macalg ssh_hmac_sha1_96_buggy; extern const struct ssh2_macalg ssh_hmac_sha256; +extern const struct ssh_compression_alg ssh_zlib; typedef struct AESContext AESContext; AESContext *aes_make_context(void); @@ -1017,19 +1034,6 @@ Bignum primegen(int bits, int modulus, int residue, Bignum factor, int phase, progfn_t pfn, void *pfnparam, unsigned firstbits); void invent_firstbits(unsigned *one, unsigned *two); - -/* - * zlib compression. - */ -void *zlib_compress_init(void); -void zlib_compress_cleanup(void *); -void *zlib_decompress_init(void); -void zlib_decompress_cleanup(void *); -void zlib_compress_block(void *, unsigned char *block, int len, - unsigned char **outblock, int *outlen, int minlen); -int zlib_decompress_block(void *, unsigned char *block, int len, - unsigned char **outblock, int *outlen); - /* * Connection-sharing API provided by platforms. This function must * either: diff --git a/ssh1bpp.c b/ssh1bpp.c index 627d55a5..a1fd78c9 100644 --- a/ssh1bpp.c +++ b/ssh1bpp.c @@ -21,7 +21,8 @@ struct ssh1_bpp_state { struct crcda_ctx *crcda_ctx; - void *compctx, *decompctx; + ssh_compressor *compctx; + ssh_decompressor *decompctx; BinaryPacketProtocol bpp; }; @@ -52,9 +53,9 @@ static void ssh1_bpp_free(BinaryPacketProtocol *bpp) if (s->cipher) ssh1_cipher_free(s->cipher); if (s->compctx) - zlib_compress_cleanup(s->compctx); + ssh_compressor_free(s->compctx); if (s->decompctx) - zlib_decompress_cleanup(s->decompctx); + ssh_decompressor_free(s->decompctx); if (s->crcda_ctx) crcda_free_context(s->crcda_ctx); if (s->pktin) @@ -90,8 +91,8 @@ void ssh1_bpp_start_compression(BinaryPacketProtocol *bpp) assert(!s->compctx); assert(!s->decompctx); - s->compctx = zlib_compress_init(); - s->decompctx = zlib_decompress_init(); + s->compctx = ssh_compressor_new(&ssh_zlib); + s->decompctx = ssh_decompressor_new(&ssh_zlib); } static void ssh1_bpp_handle_input(BinaryPacketProtocol *bpp) @@ -157,9 +158,9 @@ static void ssh1_bpp_handle_input(BinaryPacketProtocol *bpp) if (s->decompctx) { unsigned char *decompblk; int decomplen; - if (!zlib_decompress_block(s->decompctx, - s->data + s->pad, s->length + 1, - &decompblk, &decomplen)) { + if (!ssh_decompressor_decompress( + s->decompctx, s->data + s->pad, s->length + 1, + &decompblk, &decomplen)) { s->bpp.error = dupprintf( "Zlib decompression encountered invalid data"); crStopV; @@ -248,8 +249,8 @@ static void ssh1_bpp_format_packet(BinaryPacketProtocol *bpp, PktOut *pkt) if (s->compctx) { unsigned char *compblk; int complen; - zlib_compress_block(s->compctx, pkt->data + 12, pkt->length - 12, - &compblk, &complen, 0); + ssh_compressor_compress(s->compctx, pkt->data + 12, pkt->length - 12, + &compblk, &complen, 0); /* Replace the uncompressed packet data with the compressed * version. */ pkt->length = 12; diff --git a/ssh2bpp.c b/ssh2bpp.c index ff957b05..0b95d7fe 100644 --- a/ssh2bpp.c +++ b/ssh2bpp.c @@ -14,8 +14,6 @@ struct ssh2_bpp_direction { ssh2_cipher *cipher; ssh2_mac *mac; int etm_mode; - const struct ssh_compress *comp; - void *comp_ctx; }; struct ssh2_bpp_state { @@ -28,6 +26,11 @@ struct ssh2_bpp_state { PktIn *pktin; struct ssh2_bpp_direction in, out; + /* comp and decomp logically belong in the per-direction + * substructure, except that they have different types */ + ssh_decompressor *in_decomp; + ssh_compressor *out_comp; + int pending_newkeys; BinaryPacketProtocol bpp; @@ -61,14 +64,14 @@ static void ssh2_bpp_free(BinaryPacketProtocol *bpp) ssh2_cipher_free(s->out.cipher); if (s->out.mac) ssh2_mac_free(s->out.mac); - if (s->out.comp_ctx) - s->out.comp->compress_cleanup(s->out.comp_ctx); + if (s->out_comp) + ssh_compressor_free(s->out_comp); if (s->in.cipher) ssh2_cipher_free(s->in.cipher); if (s->in.mac) ssh2_mac_free(s->in.mac); - if (s->in.comp_ctx) - s->in.comp->decompress_cleanup(s->in.comp_ctx); + if (s->in_decomp) + ssh_decompressor_free(s->in_decomp); if (s->pktin) ssh_unref_packet(s->pktin); sfree(s); @@ -78,7 +81,7 @@ void ssh2_bpp_new_outgoing_crypto( BinaryPacketProtocol *bpp, const struct ssh2_cipheralg *cipher, const void *ckey, const void *iv, const struct ssh2_macalg *mac, int etm_mode, const void *mac_key, - const struct ssh_compress *compression) + const struct ssh_compression_alg *compression) { struct ssh2_bpp_state *s; assert(bpp->vt == &ssh2_bpp_vtable); @@ -88,8 +91,8 @@ void ssh2_bpp_new_outgoing_crypto( ssh2_cipher_free(s->out.cipher); if (s->out.mac) ssh2_mac_free(s->out.mac); - if (s->out.comp_ctx) - s->out.comp->compress_cleanup(s->out.comp_ctx); + if (s->out_comp) + ssh_compressor_free(s->out_comp); if (cipher) { s->out.cipher = ssh2_cipher_new(cipher); @@ -106,18 +109,17 @@ void ssh2_bpp_new_outgoing_crypto( s->out.mac = NULL; } - s->out.comp = compression; - /* out_comp is always non-NULL, because no compression is - * indicated by ssh_comp_none. So compress_init always exists, but - * it may return a null out_comp_ctx. */ - s->out.comp_ctx = compression->compress_init(); + /* 'compression' is always non-NULL, because no compression is + * indicated by ssh_comp_none. But this setup call may return a + * null out_comp. */ + s->out_comp = ssh_compressor_new(compression); } void ssh2_bpp_new_incoming_crypto( BinaryPacketProtocol *bpp, const struct ssh2_cipheralg *cipher, const void *ckey, const void *iv, const struct ssh2_macalg *mac, int etm_mode, const void *mac_key, - const struct ssh_compress *compression) + const struct ssh_compression_alg *compression) { struct ssh2_bpp_state *s; assert(bpp->vt == &ssh2_bpp_vtable); @@ -127,8 +129,8 @@ void ssh2_bpp_new_incoming_crypto( ssh2_cipher_free(s->in.cipher); if (s->in.mac) ssh2_mac_free(s->in.mac); - if (s->in.comp_ctx) - s->in.comp->decompress_cleanup(s->in.comp_ctx); + if (s->in_decomp) + ssh_decompressor_free(s->in_decomp); if (cipher) { s->in.cipher = ssh2_cipher_new(cipher); @@ -145,11 +147,10 @@ void ssh2_bpp_new_incoming_crypto( s->in.mac = NULL; } - s->in.comp = compression; - /* in_comp is always non-NULL, because no compression is - * indicated by ssh_comp_none. So compress_init always exists, but - * it may return a null in_comp_ctx. */ - s->in.comp_ctx = compression->decompress_init(); + /* 'compression' is always non-NULL, because no compression is + * indicated by ssh_comp_none. But this setup call may return a + * null in_decomp. */ + s->in_decomp = ssh_decompressor_new(compression); /* Clear the pending_newkeys flag, so that handle_input below will * start consuming the input data again. */ @@ -419,8 +420,8 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp) { unsigned char *newpayload; int newlen; - if (s->in.comp && s->in.comp->decompress( - s->in.comp_ctx, s->data + 5, s->length - 5, + if (s->in_decomp && ssh_decompressor_decompress( + s->in_decomp, s->data + 5, s->length - 5, &newpayload, &newlen)) { if (s->maxlen < newlen + 5) { PktIn *old_pktin = s->pktin; @@ -526,7 +527,7 @@ static void ssh2_bpp_format_packet_inner(struct ssh2_bpp_state *s, PktOut *pkt) cipherblk = s->out.cipher ? ssh2_cipher_alg(s->out.cipher)->blksize : 8; cipherblk = cipherblk < 8 ? 8 : cipherblk; /* or 8 if blksize < 8 */ - if (s->out.comp && s->out.comp_ctx) { + if (s->out_comp) { unsigned char *newpayload; int minlen, newlen; @@ -544,8 +545,8 @@ static void ssh2_bpp_format_packet_inner(struct ssh2_bpp_state *s, PktOut *pkt) minlen -= 8; /* length field + min padding */ } - s->out.comp->compress(s->out.comp_ctx, pkt->data + 5, pkt->length - 5, - &newpayload, &newlen, minlen); + ssh_compressor_compress(s->out_comp, pkt->data + 5, pkt->length - 5, + &newpayload, &newlen, minlen); pkt->length = 5; put_data(pkt, newpayload, newlen); sfree(newpayload); @@ -608,7 +609,7 @@ static void ssh2_bpp_format_packet(BinaryPacketProtocol *bpp, PktOut *pkt) { struct ssh2_bpp_state *s = FROMFIELD(bpp, struct ssh2_bpp_state, bpp); - if (pkt->minlen > 0 && !(s->out.comp && s->out.comp_ctx)) { + if (pkt->minlen > 0 && !s->out_comp) { /* * If we've been told to pad the packet out to a given minimum * length, but we're not compressing (and hence can't get the diff --git a/sshbpp.h b/sshbpp.h index f7e2fe2c..6e45262e 100644 --- a/sshbpp.h +++ b/sshbpp.h @@ -41,12 +41,12 @@ void ssh2_bpp_new_outgoing_crypto( BinaryPacketProtocol *bpp, const struct ssh2_cipheralg *cipher, const void *ckey, const void *iv, const struct ssh2_macalg *mac, int etm_mode, const void *mac_key, - const struct ssh_compress *compression); + const struct ssh_compression_alg *compression); void ssh2_bpp_new_incoming_crypto( BinaryPacketProtocol *bpp, const struct ssh2_cipheralg *cipher, const void *ckey, const void *iv, const struct ssh2_macalg *mac, int etm_mode, const void *mac_key, - const struct ssh_compress *compression); + const struct ssh_compression_alg *compression); BinaryPacketProtocol *ssh2_bare_bpp_new(void); diff --git a/sshzlib.c b/sshzlib.c index 17550477..ec8708b5 100644 --- a/sshzlib.c +++ b/sshzlib.c @@ -66,6 +66,10 @@ #define TRUE 1 #endif +typedef struct { const struct dummy *vt; } ssh_compressor; +typedef struct { const struct dummy *vt; } ssh_decompressor; +static const struct dummy { int i; } ssh_zlib; + #else #include "ssh.h" #endif @@ -600,37 +604,45 @@ static void zlib_match(struct LZ77Context *ectx, int distance, int len) } } -void *zlib_compress_init(void) +struct ssh_zlib_compressor { + struct LZ77Context ectx; + ssh_compressor sc; +}; + +ssh_compressor *zlib_compress_init(void) { struct Outbuf *out; - struct LZ77Context *ectx = snew(struct LZ77Context); + struct ssh_zlib_compressor *comp = snew(struct ssh_zlib_compressor); - lz77_init(ectx); - ectx->literal = zlib_literal; - ectx->match = zlib_match; + lz77_init(&comp->ectx); + comp->sc.vt = &ssh_zlib; + comp->ectx.literal = zlib_literal; + comp->ectx.match = zlib_match; out = snew(struct Outbuf); out->outbits = out->noutbits = 0; out->firstblock = 1; - ectx->userdata = out; + comp->ectx.userdata = out; - return ectx; + return &comp->sc; } -void zlib_compress_cleanup(void *handle) +void zlib_compress_cleanup(ssh_compressor *sc) { - struct LZ77Context *ectx = (struct LZ77Context *)handle; - sfree(ectx->userdata); - sfree(ectx->ictx); - sfree(ectx); + struct ssh_zlib_compressor *comp = + FROMFIELD(sc, struct ssh_zlib_compressor, sc); + sfree(comp->ectx.userdata); + sfree(comp->ectx.ictx); + sfree(comp); } -void zlib_compress_block(void *handle, unsigned char *block, int len, +void zlib_compress_block(ssh_compressor *sc, unsigned char *block, int len, unsigned char **outblock, int *outlen, int minlen) { - struct LZ77Context *ectx = (struct LZ77Context *)handle; - struct Outbuf *out = (struct Outbuf *) ectx->userdata; + struct ssh_zlib_compressor *comp = + FROMFIELD(sc, struct ssh_zlib_compressor, sc); + struct Outbuf *out = (struct Outbuf *) comp->ectx.userdata; int in_block; out->outbuf = NULL; @@ -662,7 +674,7 @@ void zlib_compress_block(void *handle, unsigned char *block, int len, /* * Do the compression. */ - lz77_compress(ectx, block, len, TRUE); + lz77_compress(&comp->ectx, block, len, TRUE); /* * End the block (by transmitting code 256, which is @@ -875,9 +887,11 @@ struct zlib_decompress_ctx { int winpos; unsigned char *outblk; int outlen, outsize; + + ssh_decompressor dc; }; -void *zlib_decompress_init(void) +ssh_decompressor *zlib_decompress_init(void) { struct zlib_decompress_ctx *dctx = snew(struct zlib_decompress_ctx); unsigned char lengths[288]; @@ -895,12 +909,14 @@ void *zlib_decompress_init(void) dctx->nbits = 0; dctx->winpos = 0; - return dctx; + dctx->dc.vt = &ssh_zlib; + return &dctx->dc; } -void zlib_decompress_cleanup(void *handle) +void zlib_decompress_cleanup(ssh_decompressor *dc) { - struct zlib_decompress_ctx *dctx = (struct zlib_decompress_ctx *)handle; + struct zlib_decompress_ctx *dctx = + FROMFIELD(dc, struct zlib_decompress_ctx, dc); if (dctx->currlentable && dctx->currlentable != dctx->staticlentable) zlib_freetable(&dctx->currlentable); @@ -958,10 +974,11 @@ static void zlib_emit_char(struct zlib_decompress_ctx *dctx, int c) #define EATBITS(n) ( dctx->nbits -= (n), dctx->bits >>= (n) ) -int zlib_decompress_block(void *handle, unsigned char *block, int len, +int zlib_decompress_block(ssh_decompressor *dc, unsigned char *block, int len, unsigned char **outblock, int *outlen) { - struct zlib_decompress_ctx *dctx = (struct zlib_decompress_ctx *)handle; + struct zlib_decompress_ctx *dctx = + FROMFIELD(dc, struct zlib_decompress_ctx, dc); const coderecord *rec; int code, blktype, rep, dist, nlen, header; static const unsigned char lenlenmap[] = { @@ -1217,7 +1234,7 @@ int main(int argc, char **argv) { unsigned char buf[16], *outbuf; int ret, outlen; - void *handle; + ssh_decompressor *handle; int noheader = FALSE, opts = TRUE; char *filename = NULL; FILE *fp; @@ -1289,7 +1306,7 @@ int main(int argc, char **argv) #else -const struct ssh_compress ssh_zlib = { +const struct ssh_compression_alg ssh_zlib = { "zlib", "zlib@openssh.com", /* delayed version */ zlib_compress_init, From aa08e6ca9157db234142abc383176475c48c0537 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Fri, 14 Sep 2018 13:47:13 +0100 Subject: [PATCH 408/607] Put a layer of abstraction in front of struct ssh_channel. Clients outside ssh.c - all implementations of Channel - will now not see the ssh_channel data type itself, but only a subobject of the interface type SshChannel. All the sshfwd_* functions have become methods in that interface type's vtable (though, wrapped in the usual kind of macros, the call sites look identical). This paves the way for me to split up the SSH-1 and SSH-2 connection layers and have each one lay out its channel bookkeeping structure as it sees fit; as long as they each provide an implementation of the sshfwd_ method family, the types behind that need not look different. A minor good effect of this is that the sshfwd_ methods are no longer global symbols, so they don't have to be stubbed in Unix Pageant to get it to compile. --- agentf.c | 4 +-- defs.h | 1 + portfwd.c | 8 ++--- ssh.c | 89 +++++++++++++++++++++++++++++++++++---------------- ssh.h | 23 +++---------- sshchan.h | 36 ++++++++++++++++++++- unix/uxpgnt.c | 14 -------- x11fwd.c | 4 +-- 8 files changed, 110 insertions(+), 69 deletions(-) diff --git a/agentf.c b/agentf.c index 65a971da..dbc1e4af 100644 --- a/agentf.c +++ b/agentf.c @@ -12,7 +12,7 @@ #include "sshchan.h" typedef struct agentf { - struct ssh_channel *c; + SshChannel *c; bufchain inbuffer; agent_pending_query *pending; int input_wanted; @@ -158,7 +158,7 @@ static const struct ChannelVtable agentf_channelvt = { chan_no_eager_close, }; -Channel *agentf_new(struct ssh_channel *c) +Channel *agentf_new(SshChannel *c) { agentf *af = snew(agentf); af->c = c; diff --git a/defs.h b/defs.h index ba61708b..e6efe0a9 100644 --- a/defs.h +++ b/defs.h @@ -54,6 +54,7 @@ typedef struct Frontend Frontend; typedef struct ssh_tag *Ssh; typedef struct Channel Channel; +typedef struct SshChannel SshChannel; typedef struct ssh_sharing_state ssh_sharing_state; typedef struct ssh_sharing_connstate ssh_sharing_connstate; diff --git a/portfwd.c b/portfwd.c index d7ad74d2..53d5234a 100644 --- a/portfwd.c +++ b/portfwd.c @@ -23,7 +23,7 @@ typedef enum { } SocksState; typedef struct PortForwarding { - struct ssh_channel *c; /* channel structure held by ssh.c */ + SshChannel *c; /* channel structure held by SSH backend */ Ssh ssh; /* instance of SSH backend itself */ /* Note that ssh need not be filled in if c is non-NULL */ Socket s; @@ -146,11 +146,11 @@ static void pfl_closing(Plug plug, const char *error_msg, int error_code, pfl_terminate(pl); } -static struct ssh_channel *wrap_send_port_open( +static SshChannel *wrap_send_port_open( Ssh ssh, const char *hostname, int port, Socket s, Channel *chan) { char *peerinfo, *description; - struct ssh_channel *toret; + SshChannel *toret; peerinfo = sk_peer_info(s); if (peerinfo) { @@ -455,7 +455,7 @@ static const struct ChannelVtable PortForwarding_channelvt = { * dynamically allocated error message string. */ char *pfd_connect(Channel **chan_ret, char *hostname,int port, - struct ssh_channel *c, Conf *conf, int addressfamily) + SshChannel *c, Conf *conf, int addressfamily) { SockAddr addr; const char *err; diff --git a/ssh.c b/ssh.c index 29f25466..eaf1f386 100644 --- a/ssh.c +++ b/ssh.c @@ -471,6 +471,28 @@ struct ssh_channel { ssh_sharing_connstate *sharectx; /* sharing context, if this is a * downstream channel */ Channel *chan; /* handle the client side of this channel, if not */ + SshChannel sc; /* entry point for chan to talk back to */ +}; + +static int sshchannel_write(SshChannel *c, const void *buf, int len); +static void sshchannel_write_eof(SshChannel *c); +static void sshchannel_unclean_close(SshChannel *c, const char *err); +static void sshchannel_unthrottle(SshChannel *c, int bufsize); +static Conf *sshchannel_get_conf(SshChannel *c); +static void sshchannel_window_override_removed(SshChannel *c); +static void sshchannel_x11_sharing_handover( + SshChannel *c, ssh_sharing_connstate *share_cs, share_channel *share_chan, + const char *peer_addr, int peer_port, int endian, + int protomajor, int protominor, const void *initial_data, int initial_len); + +const struct SshChannelVtable sshchannel_vtable = { + sshchannel_write, + sshchannel_write_eof, + sshchannel_unclean_close, + sshchannel_unthrottle, + sshchannel_get_conf, + sshchannel_window_override_removed, + sshchannel_x11_sharing_handover, }; /* @@ -3665,14 +3687,16 @@ static void ssh_channel_try_eof(struct ssh_channel *c) } } -Conf *sshfwd_get_conf(struct ssh_channel *c) +static Conf *sshchannel_get_conf(SshChannel *sc) { + struct ssh_channel *c = FROMFIELD(sc, struct ssh_channel, sc); Ssh ssh = c->ssh; return ssh->conf; } -void sshfwd_write_eof(struct ssh_channel *c) +static void sshchannel_write_eof(SshChannel *sc) { + struct ssh_channel *c = FROMFIELD(sc, struct ssh_channel, sc); Ssh ssh = c->ssh; if (ssh->state == SSH_STATE_CLOSED) @@ -3685,8 +3709,9 @@ void sshfwd_write_eof(struct ssh_channel *c) ssh_channel_try_eof(c); } -void sshfwd_unclean_close(struct ssh_channel *c, const char *err) +static void sshchannel_unclean_close(SshChannel *sc, const char *err) { + struct ssh_channel *c = FROMFIELD(sc, struct ssh_channel, sc); Ssh ssh = c->ssh; char *reason; @@ -3701,8 +3726,9 @@ void sshfwd_unclean_close(struct ssh_channel *c, const char *err) ssh2_channel_check_close(c); } -int sshfwd_write(struct ssh_channel *c, const void *buf, int len) +static int sshchannel_write(SshChannel *sc, const void *buf, int len) { + struct ssh_channel *c = FROMFIELD(sc, struct ssh_channel, sc); Ssh ssh = c->ssh; if (ssh->state == SSH_STATE_CLOSED) @@ -3711,8 +3737,9 @@ int sshfwd_write(struct ssh_channel *c, const void *buf, int len) return ssh_send_channel_data(c, buf, len); } -void sshfwd_unthrottle(struct ssh_channel *c, int bufsize) +static void sshchannel_unthrottle(SshChannel *sc, int bufsize) { + struct ssh_channel *c = FROMFIELD(sc, struct ssh_channel, sc); Ssh ssh = c->ssh; if (ssh->state == SSH_STATE_CLOSED) @@ -4225,7 +4252,7 @@ static void ssh1_smsg_x11_open(Ssh ssh, PktIn *pktin) c->ssh = ssh; ssh_channel_init(c); - c->chan = x11_new_channel(ssh->x11authtree, c, NULL, -1, FALSE); + c->chan = x11_new_channel(ssh->x11authtree, &c->sc, NULL, -1, FALSE); c->remoteid = remoteid; c->halfopen = FALSE; pkt = ssh_bpp_new_pktout(ssh->bpp, SSH1_MSG_CHANNEL_OPEN_CONFIRMATION); @@ -4255,7 +4282,7 @@ static void ssh1_smsg_agent_open(Ssh ssh, PktIn *pktin) ssh_channel_init(c); c->remoteid = remoteid; c->halfopen = FALSE; - c->chan = agentf_new(c); + c->chan = agentf_new(&c->sc); pkt = ssh_bpp_new_pktout(ssh->bpp, SSH1_MSG_CHANNEL_OPEN_CONFIRMATION); put_uint32(pkt, c->remoteid); put_uint32(pkt, c->localid); @@ -4295,7 +4322,7 @@ static void ssh1_msg_port_open(Ssh ssh, PktIn *pktin) logeventf(ssh, "Received remote port open request for %s:%d", pf.dhost, port); err = pfd_connect(&c->chan, pf.dhost, port, - c, ssh->conf, pfp->pfrec->addressfamily); + &c->sc, ssh->conf, pfp->pfrec->addressfamily); if (err != NULL) { logeventf(ssh, "Port open failed: %s", err); sfree(err); @@ -6931,6 +6958,7 @@ static void ssh_channel_init(struct ssh_channel *c) c->v.v2.throttle_state = UNTHROTTLED; bufchain_init(&c->v.v2.outbuffer); } + c->sc.vt = &sshchannel_vtable; add234(ssh->channels, c); } @@ -7454,7 +7482,7 @@ static void ssh2_msg_channel_close(Ssh ssh, PktIn *pktin) /* * Send outgoing EOF. */ - sshfwd_write_eof(c); + sshfwd_write_eof(&c->sc); /* * Make sure we don't read any more from whatever our local @@ -7790,7 +7818,8 @@ static void ssh2_msg_channel_open(Ssh ssh, PktIn *pktin) if (!ssh->X11_fwd_enabled && !ssh->connshare) error = "X11 forwarding is not enabled"; else { - c->chan = x11_new_channel(ssh->x11authtree, c, addrstr, peerport, + c->chan = x11_new_channel(ssh->x11authtree, &c->sc, + addrstr, peerport, ssh->connshare != NULL); logevent("Opened X11 forward channel"); } @@ -7830,7 +7859,7 @@ static void ssh2_msg_channel_open(Ssh ssh, PktIn *pktin) } err = pfd_connect(&c->chan, realpf->dhost, realpf->dport, - c, ssh->conf, realpf->pfrec->addressfamily); + &c->sc, ssh->conf, realpf->pfrec->addressfamily); logeventf(ssh, "Attempting to forward remote port to " "%s:%d", realpf->dhost, realpf->dport); if (err != NULL) { @@ -7845,7 +7874,7 @@ static void ssh2_msg_channel_open(Ssh ssh, PktIn *pktin) if (!ssh->agentfwd_enabled) error = "Agent forwarding is not enabled"; else - c->chan = agentf_new(c); + c->chan = agentf_new(&c->sc); } else { error = "Unsupported channel type requested"; } @@ -7879,13 +7908,13 @@ static void ssh2_msg_channel_open(Ssh ssh, PktIn *pktin) } } -void sshfwd_x11_sharing_handover(struct ssh_channel *c, - ssh_sharing_connstate *share_cs, - share_channel *share_chan, - const char *peer_addr, int peer_port, - int endian, int protomajor, int protominor, - const void *initial_data, int initial_len) +static void sshchannel_x11_sharing_handover( + SshChannel *sc, ssh_sharing_connstate *share_cs, share_channel *share_chan, + const char *peer_addr, int peer_port, int endian, + int protomajor, int protominor, const void *initial_data, int initial_len) { + struct ssh_channel *c = FROMFIELD(sc, struct ssh_channel, sc); + /* * This function is called when we've just discovered that an X * forwarding channel on which we'd been handling the initial auth @@ -7905,8 +7934,10 @@ void sshfwd_x11_sharing_handover(struct ssh_channel *c, c->chan = NULL; } -void sshfwd_window_override_removed(struct ssh_channel *c) +static void sshchannel_window_override_removed(SshChannel *sc) { + struct ssh_channel *c = FROMFIELD(sc, struct ssh_channel, sc); + /* * This function is called when a client-side Channel has just * stopped requiring an initial fixed-size window. @@ -9661,7 +9692,7 @@ static void ssh2_connection_setup(Ssh ssh) typedef struct mainchan { Ssh ssh; - struct ssh_channel *c; + SshChannel *sc; Channel chan; } mainchan; @@ -9689,7 +9720,7 @@ static mainchan *mainchan_new(Ssh ssh) { mainchan *mc = snew(mainchan); mc->ssh = ssh; - mc->c = NULL; + mc->sc = NULL; mc->chan.vt = &mainchan_channelvt; mc->chan.initial_fixed_window_size = 0; return mc; @@ -9737,7 +9768,7 @@ static void mainchan_send_eof(Channel *chan) * decided to do that because we've allocated a remote pty and * hence EOF isn't a particularly meaningful concept. */ - sshfwd_write_eof(mc->c); + sshfwd_write_eof(mc->sc); } mc->ssh->sent_console_eof = TRUE; } @@ -9796,13 +9827,15 @@ static void do_ssh2_connection(void *vctx) * Just start a direct-tcpip channel and use it as the main * channel. */ - ssh->mainchan = mc->c = ssh_send_port_open + mc->sc = ssh_send_port_open (ssh, conf_get_str(ssh->conf, CONF_ssh_nc_host), conf_get_int(ssh->conf, CONF_ssh_nc_port), "main channel", &mc->chan); + ssh->mainchan = FROMFIELD(mc->sc, struct ssh_channel, sc); ssh->ncmode = TRUE; } else { - ssh->mainchan = mc->c = snew(struct ssh_channel); + ssh->mainchan = snew(struct ssh_channel); + mc->sc = &ssh->mainchan->sc; ssh->mainchan->ssh = ssh; ssh_channel_init(ssh->mainchan); ssh->mainchan->chan = &mc->chan; @@ -11100,7 +11133,7 @@ static void ssh_special(Backend *be, Telnet_Special code) pktout = ssh_bpp_new_pktout(ssh->bpp, SSH1_CMSG_EOF); ssh_pkt_write(ssh, pktout); } else if (ssh->mainchan) { - sshfwd_write_eof(ssh->mainchan); + sshfwd_write_eof(&ssh->mainchan->sc); ssh->send_ok = 0; /* now stop trying to read from stdin */ } logevent("Sent EOF message"); @@ -11237,8 +11270,8 @@ static void ssh_unthrottle(Backend *be, int bufsize) queue_idempotent_callback(&ssh->incoming_data_consumer); } -struct ssh_channel *ssh_send_port_open(Ssh ssh, const char *hostname, int port, - const char *org, Channel *chan) +SshChannel *ssh_send_port_open(Ssh ssh, const char *hostname, int port, + const char *org, Channel *chan) { struct ssh_channel *c = snew(struct ssh_channel); PktOut *pktout; @@ -11280,7 +11313,7 @@ struct ssh_channel *ssh_send_port_open(Ssh ssh, const char *hostname, int port, ssh2_pkt_send(ssh, pktout); } - return c; + return &c->sc; } static int ssh_connected(Backend *be) diff --git a/ssh.h b/ssh.h index 7f038b9c..a4aea86e 100644 --- a/ssh.h +++ b/ssh.h @@ -9,19 +9,6 @@ struct ssh_channel; -extern int sshfwd_write(struct ssh_channel *c, const void *, int); -extern void sshfwd_write_eof(struct ssh_channel *c); -extern void sshfwd_unclean_close(struct ssh_channel *c, const char *err); -extern void sshfwd_unthrottle(struct ssh_channel *c, int bufsize); -Conf *sshfwd_get_conf(struct ssh_channel *c); -void sshfwd_window_override_removed(struct ssh_channel *c); -void sshfwd_x11_sharing_handover(struct ssh_channel *c, - ssh_sharing_connstate *share_cs, - share_channel *share_chan, - const char *peer_addr, int peer_port, - int endian, int protomajor, int protominor, - const void *initial_data, int initial_len); - /* * Buffer management constants. There are several of these for * various different purposes: @@ -734,12 +721,12 @@ void logevent(Frontend *, const char *); struct PortForwarding; /* Allocate and register a new channel for port forwarding */ -struct ssh_channel *ssh_send_port_open(Ssh ssh, const char *hostname, int port, - const char *org, Channel *chan); +SshChannel *ssh_send_port_open(Ssh ssh, const char *hostname, int port, + const char *org, Channel *chan); /* Exports from portfwd.c */ extern char *pfd_connect(Channel **chan_ret, char *hostname, int port, - struct ssh_channel *c, Conf *conf, int addressfamily); + SshChannel *c, Conf *conf, int addressfamily); struct PortListener; /* desthost == NULL indicates dynamic (SOCKS) port forwarding */ extern char *pfl_listen(char *desthost, int destport, char *srcaddr, @@ -813,7 +800,7 @@ extern struct X11Display *x11_setup_display(const char *display, Conf *); void x11_free_display(struct X11Display *disp); struct X11FakeAuth *x11_invent_fake_auth(tree234 *t, int authtype); void x11_free_fake_auth(struct X11FakeAuth *auth); -Channel *x11_new_channel(tree234 *authtree, struct ssh_channel *c, +Channel *x11_new_channel(tree234 *authtree, SshChannel *c, const char *peeraddr, int peerport, int connection_sharing_possible); char *x11_display(const char *display); @@ -845,7 +832,7 @@ void x11_get_auth_from_authfile(struct X11Display *display, int x11_identify_auth_proto(ptrlen protoname); void *x11_dehexify(ptrlen hex, int *outlen); -Channel *agentf_new(struct ssh_channel *c); +Channel *agentf_new(SshChannel *c); Bignum copybn(Bignum b); Bignum bn_power_2(int n); diff --git a/sshchan.h b/sshchan.h index 26462bc6..271cdb09 100644 --- a/sshchan.h +++ b/sshchan.h @@ -40,7 +40,7 @@ struct Channel { #define chan_send_eof(ch) ((ch)->vt->send_eof(ch)) #define chan_set_input_wanted(ch, wanted) \ ((ch)->vt->set_input_wanted(ch, wanted)) -#define chan_log_close_msg(ch) ((ch)->vt->send_eof(ch)) +#define chan_log_close_msg(ch) ((ch)->vt->log_close_msg(ch)) #define chan_want_close(ch, leof, reof) ((ch)->vt->want_close(ch, leof, reof)) /* @@ -56,4 +56,38 @@ void chan_remotely_opened_failure(Channel *chan, const char *errtext); * closing until both directions have had an EOF */ int chan_no_eager_close(Channel *, int, int); +/* ---------------------------------------------------------------------- + * This structure is owned by an SSH connection layer, and identifies + * the connection layer's end of the channel, for the Channel + * implementation to talk back to. + */ + +struct SshChannelVtable { + int (*write)(SshChannel *c, const void *, int); + void (*write_eof)(SshChannel *c); + void (*unclean_close)(SshChannel *c, const char *err); + void (*unthrottle)(SshChannel *c, int bufsize); + Conf *(*get_conf)(SshChannel *c); + void (*window_override_removed)(SshChannel *c); + void (*x11_sharing_handover)(SshChannel *c, + ssh_sharing_connstate *share_cs, + share_channel *share_chan, + const char *peer_addr, int peer_port, + int endian, int protomajor, int protominor, + const void *initial_data, int initial_len); +}; + +struct SshChannel { + const struct SshChannelVtable *vt; +}; + +#define sshfwd_write(c, buf, len) ((c)->vt->write(c, buf, len)) +#define sshfwd_write_eof(c) ((c)->vt->write_eof(c)) +#define sshfwd_unclean_close(c, err) ((c)->vt->unclean_close(c, err)) +#define sshfwd_unthrottle(c, bufsize) ((c)->vt->unthrottle(c, bufsize)) +#define sshfwd_get_conf(c) ((c)->vt->get_conf(c)) +#define sshfwd_window_override_removed(c) ((c)->vt->window_override_removed(c)) +#define sshfwd_x11_sharing_handover(c, cs, ch, pa, pp, e, pmaj, pmin, d, l) \ + ((c)->vt->x11_sharing_handover(c, cs, ch, pa, pp, e, pmaj, pmin, d, l)) + #endif /* PUTTY_SSHCHAN_H */ diff --git a/unix/uxpgnt.c b/unix/uxpgnt.c index efd93726..1b7004f8 100644 --- a/unix/uxpgnt.c +++ b/unix/uxpgnt.c @@ -156,24 +156,10 @@ static int time_to_die = FALSE; * used, because in LIFE_X11 mode we connect to the X server using a * straightforward Socket and don't try to create an ersatz SSH * forwarding too. */ -int sshfwd_write(struct ssh_channel *c, const void *data, int len) -{ return 0; } -void sshfwd_write_eof(struct ssh_channel *c) { } -void sshfwd_unclean_close(struct ssh_channel *c, const char *err) { } -void sshfwd_unthrottle(struct ssh_channel *c, int bufsize) {} -void sshfwd_window_override_removed(struct ssh_channel *c) { } void chan_remotely_opened_confirmation(Channel *chan) { } void chan_remotely_opened_failure(Channel *chan, const char *err) { } int chan_no_eager_close(Channel *chan, int s, int r) { return FALSE; } -Conf *sshfwd_get_conf(struct ssh_channel *c) { return NULL; } -void sshfwd_x11_sharing_handover(struct ssh_channel *c, - ssh_sharing_connstate *share_cs, - share_channel *share_chan, - const char *peer_addr, int peer_port, - int endian, int protomajor, int protominor, - const void *initial_data, int initial_len) {} - /* * These functions are part of the plug for our connection to the X * display, so they do get called. They needn't actually do anything, diff --git a/x11fwd.c b/x11fwd.c index f3ea5397..ed2f3b60 100644 --- a/x11fwd.c +++ b/x11fwd.c @@ -39,7 +39,7 @@ typedef struct X11Connection { int no_data_sent_to_x_client; char *peer_addr; int peer_port; - struct ssh_channel *c; /* channel structure held by ssh.c */ + SshChannel *c; /* channel structure held by SSH backend */ Socket s; const Plug_vtable *plugvt; @@ -728,7 +728,7 @@ static const struct ChannelVtable X11Connection_channelvt = { * Called to set up the X11Connection structure, though this does not * yet connect to an actual server. */ -Channel *x11_new_channel(tree234 *authtree, struct ssh_channel *c, +Channel *x11_new_channel(tree234 *authtree, SshChannel *c, const char *peeraddr, int peerport, int connection_sharing_possible) { From 895b09a4c65243265d4f155bd1b32070bbda4ec4 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Fri, 14 Sep 2018 17:04:39 +0100 Subject: [PATCH 409/607] Move port-forwarding setup out of ssh.c. The tree234 storing currently active port forwardings - both local and remote - now lives in portfwd.c, as does the complicated function that updates it based on a Conf listing the new set of desired forwardings. Local port forwardings are passed to ssh.c via the same route as before - once the listening port receives a connection and portfwd.c knows where it should be directed to (in particular, after the SOCKS exchange, if any), it calls ssh_send_port_open. Remote forwardings are now initiated by calling ssh_rportfwd_alloc, which adds an entry to the rportfwds tree (which _is_ still in ssh.c, and still confusingly sorted by a different criterion depending on SSH protocol version) and sends out the appropriate protocol request. ssh_rportfwd_remove cancels one again, sending a protocol request too. Those functions look enough like ssh_{alloc,remove}_sharing_rportfwd that I've merged those into the new pair as well - now allocating an rportfwd allows you to specify either a destination host/port or a sharing context, and returns a handy pointer you can use to cancel the forwarding later. --- defs.h | 3 + misc.c | 11 ++ misc.h | 6 + portfwd.c | 511 ++++++++++++++++++++++++++++++++++++++++++------ ssh.c | 556 ++++++++++------------------------------------------- ssh.h | 33 ++-- sshshare.c | 16 +- 7 files changed, 597 insertions(+), 539 deletions(-) diff --git a/defs.h b/defs.h index e6efe0a9..822ee71d 100644 --- a/defs.h +++ b/defs.h @@ -60,6 +60,9 @@ typedef struct ssh_sharing_state ssh_sharing_state; typedef struct ssh_sharing_connstate ssh_sharing_connstate; typedef struct share_channel share_channel; +typedef struct PortFwdManager PortFwdManager; +typedef struct PortFwdRecord PortFwdRecord; + typedef struct dlgparam dlgparam; typedef struct settings_w settings_w; diff --git a/misc.c b/misc.c index fdd5635c..f4334a04 100644 --- a/misc.c +++ b/misc.c @@ -1181,6 +1181,17 @@ int smemeq(const void *av, const void *bv, size_t len) return (0x100 - val) >> 8; } +int nullstrcmp(const char *a, const char *b) +{ + if (a == NULL && b == NULL) + return 0; + if (a == NULL) + return -1; + if (b == NULL) + return +1; + return strcmp(a, b); +} + ptrlen make_ptrlen(const void *ptr, size_t len) { ptrlen pl; diff --git a/misc.h b/misc.h index 35d9de6c..242d1a94 100644 --- a/misc.h +++ b/misc.h @@ -87,6 +87,12 @@ int validate_manual_hostkey(char *key); struct tm ltime(void); +/* + * Special form of strcmp which can cope with NULL inputs. NULL is + * defined to sort before even the empty string. + */ +int nullstrcmp(const char *a, const char *b); + ptrlen make_ptrlen(const void *ptr, size_t len); int ptrlen_eq_string(ptrlen pl, const char *str); char *mkstr(ptrlen pl); diff --git a/portfwd.c b/portfwd.c index 53d5234a..d200c78b 100644 --- a/portfwd.c +++ b/portfwd.c @@ -10,6 +10,18 @@ #include "ssh.h" #include "sshchan.h" +static void logeventf(Frontend *frontend, const char *fmt, ...) +{ + va_list ap; + char *buf; + + va_start(ap, fmt); + buf = dupvprintf(fmt, ap); + va_end(ap); + logevent(frontend, buf); + sfree(buf); +} + /* * Enumeration of values that live in the 'socks_state' field of * struct PortForwarding. @@ -139,6 +151,8 @@ static void pfd_closing(Plug plug, const char *error_msg, int error_code, } } +static void pfl_terminate(struct PortListener *pl); + static void pfl_closing(Plug plug, const char *error_msg, int error_code, int calling_back) { @@ -447,61 +461,6 @@ static const struct ChannelVtable PortForwarding_channelvt = { chan_no_eager_close, }; -/* - * Called when receiving a PORT OPEN from the server to make a - * connection to a destination host. - * - * On success, returns NULL and fills in *pf_ret. On error, returns a - * dynamically allocated error message string. - */ -char *pfd_connect(Channel **chan_ret, char *hostname,int port, - SshChannel *c, Conf *conf, int addressfamily) -{ - SockAddr addr; - const char *err; - char *dummy_realhost = NULL; - struct PortForwarding *pf; - - /* - * Try to find host. - */ - addr = name_lookup(hostname, port, &dummy_realhost, conf, addressfamily, - NULL, NULL); - if ((err = sk_addr_error(addr)) != NULL) { - char *err_ret = dupstr(err); - sk_addr_free(addr); - sfree(dummy_realhost); - return err_ret; - } - - /* - * Open socket. - */ - pf = new_portfwd_state(); - *chan_ret = &pf->chan; - pf->plugvt = &PortForwarding_plugvt; - pf->chan.initial_fixed_window_size = 0; - pf->chan.vt = &PortForwarding_channelvt; - pf->input_wanted = TRUE; - pf->ready = 1; - pf->c = c; - pf->ssh = NULL; /* we shouldn't need this */ - pf->socks_state = SOCKS_NONE; - - pf->s = new_connection(addr, dummy_realhost, port, - 0, 1, 0, 0, &pf->plugvt, conf); - sfree(dummy_realhost); - if ((err = sk_socket_error(pf->s)) != NULL) { - char *err_ret = dupstr(err); - sk_close(pf->s); - free_portfwd_state(pf); - *chan_ret = NULL; - return err_ret; - } - - return NULL; -} - /* called when someone connects to the local port */ @@ -560,12 +519,14 @@ static const Plug_vtable PortListener_plugvt = { /* * Add a new port-forwarding listener from srcaddr:port -> desthost:destport. * + * desthost == NULL indicates dynamic SOCKS port forwarding. + * * On success, returns NULL and fills in *pl_ret. On error, returns a * dynamically allocated error message string. */ -char *pfl_listen(char *desthost, int destport, char *srcaddr, - int port, Ssh ssh, Conf *conf, - struct PortListener **pl_ret, int address_family) +static char *pfl_listen(char *desthost, int destport, char *srcaddr, + int port, Ssh ssh, Conf *conf, + struct PortListener **pl_ret, int address_family) { const char *err; struct PortListener *pl; @@ -614,7 +575,7 @@ static void pfd_close(struct PortForwarding *pf) /* * Terminate a listener. */ -void pfl_terminate(struct PortListener *pl) +static void pfl_terminate(struct PortListener *pl) { if (!pl) return; @@ -676,9 +637,431 @@ static void pfd_open_failure(Channel *chan, const char *errtext) assert(chan->vt == &PortForwarding_channelvt); PortForwarding *pf = FROMFIELD(chan, PortForwarding, chan); - char *msg = dupprintf( - "Forwarded connection refused by server%s%s", - errtext ? ": " : "", errtext ? errtext : ""); - logevent(ssh_get_frontend(pf->ssh), msg); - sfree(msg); + logeventf(ssh_get_frontend(pf->ssh), + "Forwarded connection refused by server%s%s", + errtext ? ": " : "", errtext ? errtext : ""); +} + +/* ---------------------------------------------------------------------- + * Code to manage the complete set of currently active port + * forwardings, and update it from Conf. + */ + +struct PortFwdRecord { + enum { DESTROY, KEEP, CREATE } status; + int type; + unsigned sport, dport; + char *saddr, *daddr; + char *sserv, *dserv; + struct ssh_rportfwd *remote; + int addressfamily; + struct PortListener *local; +}; + +static int pfr_cmp(void *av, void *bv) +{ + PortFwdRecord *a = (PortFwdRecord *) av; + PortFwdRecord *b = (PortFwdRecord *) bv; + int i; + if (a->type > b->type) + return +1; + if (a->type < b->type) + return -1; + if (a->addressfamily > b->addressfamily) + return +1; + if (a->addressfamily < b->addressfamily) + return -1; + if ( (i = nullstrcmp(a->saddr, b->saddr)) != 0) + return i < 0 ? -1 : +1; + if (a->sport > b->sport) + return +1; + if (a->sport < b->sport) + return -1; + if (a->type != 'D') { + if ( (i = nullstrcmp(a->daddr, b->daddr)) != 0) + return i < 0 ? -1 : +1; + if (a->dport > b->dport) + return +1; + if (a->dport < b->dport) + return -1; + } + return 0; +} + +void pfr_free(PortFwdRecord *pfr) +{ + /* Dispose of any listening socket. */ + if (pfr->local) + pfl_terminate(pfr->local); + + sfree(pfr->saddr); + sfree(pfr->daddr); + sfree(pfr->sserv); + sfree(pfr->dserv); + sfree(pfr); +} + +struct PortFwdManager { + Ssh ssh; + Frontend *frontend; + Conf *conf; + tree234 *forwardings; +}; + +PortFwdManager *portfwdmgr_new(Ssh ssh) +{ + PortFwdManager *mgr = snew(PortFwdManager); + + mgr->ssh = ssh; + mgr->frontend = ssh_get_frontend(ssh); + mgr->conf = NULL; + mgr->forwardings = newtree234(pfr_cmp); + + return mgr; +} + +void portfwdmgr_close(PortFwdManager *mgr, PortFwdRecord *pfr) +{ + PortFwdRecord *realpfr = del234(mgr->forwardings, pfr); + if (realpfr == pfr) + pfr_free(pfr); +} + +void portfwdmgr_close_all(PortFwdManager *mgr) +{ + PortFwdRecord *pfr; + + while ((pfr = delpos234(mgr->forwardings, 0)) != NULL) + pfr_free(pfr); +} + +void portfwdmgr_free(PortFwdManager *mgr) +{ + portfwdmgr_close_all(mgr); + freetree234(mgr->forwardings); + if (mgr->conf) + conf_free(mgr->conf); + sfree(mgr); +} + +void portfwdmgr_config(PortFwdManager *mgr, Conf *conf) +{ + PortFwdRecord *pfr; + int i; + char *key, *val; + + if (mgr->conf) + conf_free(mgr->conf); + mgr->conf = conf_copy(conf); + + /* + * Go through the existing port forwardings and tag them + * with status==DESTROY. Any that we want to keep will be + * re-enabled (status==KEEP) as we go through the + * configuration and find out which bits are the same as + * they were before. + */ + for (i = 0; (pfr = index234(mgr->forwardings, i)) != NULL; i++) + pfr->status = DESTROY; + + for (val = conf_get_str_strs(conf, CONF_portfwd, NULL, &key); + val != NULL; + val = conf_get_str_strs(conf, CONF_portfwd, key, &key)) { + char *kp, *kp2, *vp, *vp2; + char address_family, type; + int sport, dport, sserv, dserv; + char *sports, *dports, *saddr, *host; + + kp = key; + + address_family = 'A'; + type = 'L'; + if (*kp == 'A' || *kp == '4' || *kp == '6') + address_family = *kp++; + if (*kp == 'L' || *kp == 'R') + type = *kp++; + + if ((kp2 = host_strchr(kp, ':')) != NULL) { + /* + * There's a colon in the middle of the source port + * string, which means that the part before it is + * actually a source address. + */ + char *saddr_tmp = dupprintf("%.*s", (int)(kp2 - kp), kp); + saddr = host_strduptrim(saddr_tmp); + sfree(saddr_tmp); + sports = kp2+1; + } else { + saddr = NULL; + sports = kp; + } + sport = atoi(sports); + sserv = 0; + if (sport == 0) { + sserv = 1; + sport = net_service_lookup(sports); + if (!sport) { + logeventf(mgr->frontend, "Service lookup failed for source" + " port \"%s\"", sports); + } + } + + if (type == 'L' && !strcmp(val, "D")) { + /* dynamic forwarding */ + host = NULL; + dports = NULL; + dport = -1; + dserv = 0; + type = 'D'; + } else { + /* ordinary forwarding */ + vp = val; + vp2 = vp + host_strcspn(vp, ":"); + host = dupprintf("%.*s", (int)(vp2 - vp), vp); + if (*vp2) + vp2++; + dports = vp2; + dport = atoi(dports); + dserv = 0; + if (dport == 0) { + dserv = 1; + dport = net_service_lookup(dports); + if (!dport) { + logeventf(mgr->frontend, + "Service lookup failed for destination" + " port \"%s\"", dports); + } + } + } + + if (sport && dport) { + /* Set up a description of the source port. */ + pfr = snew(PortFwdRecord); + pfr->type = type; + pfr->saddr = saddr; + pfr->sserv = sserv ? dupstr(sports) : NULL; + pfr->sport = sport; + pfr->daddr = host; + pfr->dserv = dserv ? dupstr(dports) : NULL; + pfr->dport = dport; + pfr->local = NULL; + pfr->remote = NULL; + pfr->addressfamily = (address_family == '4' ? ADDRTYPE_IPV4 : + address_family == '6' ? ADDRTYPE_IPV6 : + ADDRTYPE_UNSPEC); + + PortFwdRecord *existing = add234(mgr->forwardings, pfr); + if (existing != pfr) { + if (existing->status == DESTROY) { + /* + * We already have a port forwarding up and running + * with precisely these parameters. Hence, no need + * to do anything; simply re-tag the existing one + * as KEEP. + */ + existing->status = KEEP; + } + /* + * Anything else indicates that there was a duplicate + * in our input, which we'll silently ignore. + */ + pfr_free(pfr); + } else { + pfr->status = CREATE; + } + } else { + sfree(saddr); + sfree(host); + } + } + + /* + * Now go through and destroy any port forwardings which were + * not re-enabled. + */ + for (i = 0; (pfr = index234(mgr->forwardings, i)) != NULL; i++) { + if (pfr->status == DESTROY) { + char *message; + + message = dupprintf("%s port forwarding from %s%s%d", + pfr->type == 'L' ? "local" : + pfr->type == 'R' ? "remote" : "dynamic", + pfr->saddr ? pfr->saddr : "", + pfr->saddr ? ":" : "", + pfr->sport); + + if (pfr->type != 'D') { + char *msg2 = dupprintf("%s to %s:%d", message, + pfr->daddr, pfr->dport); + sfree(message); + message = msg2; + } + + logeventf(mgr->frontend, "Cancelling %s", message); + sfree(message); + + /* pfr->remote or pfr->local may be NULL if setting up a + * forwarding failed. */ + if (pfr->remote) { + /* + * Cancel the port forwarding at the server + * end. + * + * Actually closing the listening port on the server + * side may fail - because in SSH-1 there's no message + * in the protocol to request it! + * + * Instead, we simply remove the record of the + * forwarding from our local end, so that any + * connections the server tries to make on it are + * rejected. + */ + ssh_rportfwd_remove(mgr->ssh, pfr->remote); + } else if (pfr->local) { + pfl_terminate(pfr->local); + } + + delpos234(mgr->forwardings, i); + pfr_free(pfr); + i--; /* so we don't skip one in the list */ + } + } + + /* + * And finally, set up any new port forwardings (status==CREATE). + */ + for (i = 0; (pfr = index234(mgr->forwardings, i)) != NULL; i++) { + if (pfr->status == CREATE) { + char *sportdesc, *dportdesc; + sportdesc = dupprintf("%s%s%s%s%d%s", + pfr->saddr ? pfr->saddr : "", + pfr->saddr ? ":" : "", + pfr->sserv ? pfr->sserv : "", + pfr->sserv ? "(" : "", + pfr->sport, + pfr->sserv ? ")" : ""); + if (pfr->type == 'D') { + dportdesc = NULL; + } else { + dportdesc = dupprintf("%s:%s%s%d%s", + pfr->daddr, + pfr->dserv ? pfr->dserv : "", + pfr->dserv ? "(" : "", + pfr->dport, + pfr->dserv ? ")" : ""); + } + + if (pfr->type == 'L') { + char *err = pfl_listen(pfr->daddr, pfr->dport, + pfr->saddr, pfr->sport, + mgr->ssh, conf, &pfr->local, + pfr->addressfamily); + + logeventf(mgr->frontend, + "Local %sport %s forwarding to %s%s%s", + pfr->addressfamily == ADDRTYPE_IPV4 ? "IPv4 " : + pfr->addressfamily == ADDRTYPE_IPV6 ? "IPv6 " : "", + sportdesc, dportdesc, + err ? " failed: " : "", err ? err : ""); + if (err) + sfree(err); + } else if (pfr->type == 'D') { + char *err = pfl_listen(NULL, -1, pfr->saddr, pfr->sport, + mgr->ssh, conf, &pfr->local, + pfr->addressfamily); + + logeventf(mgr->frontend, + "Local %sport %s SOCKS dynamic forwarding%s%s", + pfr->addressfamily == ADDRTYPE_IPV4 ? "IPv4 " : + pfr->addressfamily == ADDRTYPE_IPV6 ? "IPv6 " : "", + sportdesc, + err ? " failed: " : "", err ? err : ""); + + if (err) + sfree(err); + } else { + const char *shost; + + if (pfr->saddr) { + shost = pfr->saddr; + } else if (conf_get_int(conf, CONF_rport_acceptall)) { + shost = ""; + } else { + shost = "localhost"; + } + + pfr->remote = ssh_rportfwd_alloc( + mgr->ssh, shost, pfr->sport, pfr->daddr, pfr->dport, + pfr->addressfamily, sportdesc, pfr, NULL); + + if (!pfr->remote) { + logeventf(mgr->frontend, + "Duplicate remote port forwarding to %s:%d", + pfr->daddr, pfr->dport); + pfr_free(pfr); + } else { + logeventf(mgr->frontend, "Requesting remote port %s" + " forward to %s", sportdesc, dportdesc); + } + } + sfree(sportdesc); + sfree(dportdesc); + } + } +} + +/* + * Called when receiving a PORT OPEN from the server to make a + * connection to a destination host. + * + * On success, returns NULL and fills in *pf_ret. On error, returns a + * dynamically allocated error message string. + */ +char *portfwdmgr_connect(PortFwdManager *mgr, Channel **chan_ret, + char *hostname, int port, SshChannel *c, + int addressfamily) +{ + SockAddr addr; + const char *err; + char *dummy_realhost = NULL; + struct PortForwarding *pf; + + /* + * Try to find host. + */ + addr = name_lookup(hostname, port, &dummy_realhost, mgr->conf, + addressfamily, NULL, NULL); + if ((err = sk_addr_error(addr)) != NULL) { + char *err_ret = dupstr(err); + sk_addr_free(addr); + sfree(dummy_realhost); + return err_ret; + } + + /* + * Open socket. + */ + pf = new_portfwd_state(); + *chan_ret = &pf->chan; + pf->plugvt = &PortForwarding_plugvt; + pf->chan.initial_fixed_window_size = 0; + pf->chan.vt = &PortForwarding_channelvt; + pf->input_wanted = TRUE; + pf->ready = 1; + pf->c = c; + pf->ssh = mgr->ssh; + pf->socks_state = SOCKS_NONE; + + pf->s = new_connection(addr, dummy_realhost, port, + 0, 1, 0, 0, &pf->plugvt, mgr->conf); + sfree(dummy_realhost); + if ((err = sk_socket_error(pf->s)) != NULL) { + char *err_ret = dupstr(err); + sk_close(pf->s); + free_portfwd_state(pf); + *chan_ret = NULL; + return err_ret; + } + + return NULL; } diff --git a/ssh.c b/ssh.c index eaf1f386..bedfe6af 100644 --- a/ssh.c +++ b/ssh.c @@ -527,42 +527,22 @@ struct ssh_portfwd; /* forward declaration */ struct ssh_rportfwd { unsigned sport, dport; char *shost, *dhost; - char *sportdesc; + int addressfamily; + char *log_description; /* name of remote listening port, for logging */ ssh_sharing_connstate *share_ctx; - struct ssh_portfwd *pfrec; + PortFwdRecord *pfr; }; static void free_rportfwd(struct ssh_rportfwd *pf) { if (pf) { - sfree(pf->sportdesc); + sfree(pf->log_description); sfree(pf->shost); sfree(pf->dhost); sfree(pf); } } -/* - * Separately to the rportfwd tree (which is for looking up port - * open requests from the server), a tree of _these_ structures is - * used to keep track of all the currently open port forwardings, - * so that we can reconfigure in mid-session if the user requests - * it. - */ -struct ssh_portfwd { - enum { DESTROY, KEEP, CREATE } status; - int type; - unsigned sport, dport; - char *saddr, *daddr; - char *sserv, *dserv; - struct ssh_rportfwd *remote; - int addressfamily; - struct PortListener *local; -}; -#define free_portfwd(pf) ( \ - ((pf) ? (sfree((pf)->saddr), sfree((pf)->daddr), \ - sfree((pf)->sserv), sfree((pf)->dserv)) : (void)0 ), sfree(pf) ) - static void ssh1_protocol_setup(Ssh ssh); static void ssh2_protocol_setup(Ssh ssh); static void ssh2_bare_connection_protocol_setup(Ssh ssh); @@ -746,7 +726,8 @@ struct ssh_tag { int clean_exit; int disconnect_message_seen; - tree234 *rportfwds, *portfwds; + tree234 *rportfwds; + PortFwdManager *portfwdmgr; enum { SSH_STATE_PREPACKET, @@ -1063,51 +1044,6 @@ static int ssh_rportcmp_ssh2(void *av, void *bv) return 0; } -/* - * Special form of strcmp which can cope with NULL inputs. NULL is - * defined to sort before even the empty string. - */ -static int nullstrcmp(const char *a, const char *b) -{ - if (a == NULL && b == NULL) - return 0; - if (a == NULL) - return -1; - if (b == NULL) - return +1; - return strcmp(a, b); -} - -static int ssh_portcmp(void *av, void *bv) -{ - struct ssh_portfwd *a = (struct ssh_portfwd *) av; - struct ssh_portfwd *b = (struct ssh_portfwd *) bv; - int i; - if (a->type > b->type) - return +1; - if (a->type < b->type) - return -1; - if (a->addressfamily > b->addressfamily) - return +1; - if (a->addressfamily < b->addressfamily) - return -1; - if ( (i = nullstrcmp(a->saddr, b->saddr)) != 0) - return i < 0 ? -1 : +1; - if (a->sport > b->sport) - return +1; - if (a->sport < b->sport) - return -1; - if (a->type != 'D') { - if ( (i = nullstrcmp(a->daddr, b->daddr)) != 0) - return i < 0 ? -1 : +1; - if (a->dport > b->dport) - return +1; - if (a->dport < b->dport) - return -1; - } - return 0; -} - static int alloc_channel_id(Ssh ssh) { const unsigned CHANNEL_NUMBER_OFFSET = 256; @@ -2230,18 +2166,7 @@ static int ssh_do_close(Ssh ssh, int notify_exit) * Go through port-forwardings, and close any associated * listening sockets. */ - if (ssh->portfwds) { - struct ssh_portfwd *pf; - while (NULL != (pf = index234(ssh->portfwds, 0))) { - /* Dispose of any listening socket. */ - if (pf->local) - pfl_terminate(pf->local); - del234(ssh->portfwds, pf); /* moving next one to index 0 */ - free_portfwd(pf); - } - freetree234(ssh->portfwds); - ssh->portfwds = NULL; - } + portfwdmgr_close_all(ssh->portfwdmgr); /* * Also stop attempting to connection-share. @@ -3816,58 +3741,110 @@ static void ssh_queue_handler(Ssh ssh, int msg1, int msg2, static void ssh_rportfwd_succfail(Ssh ssh, PktIn *pktin, void *ctx) { - struct ssh_rportfwd *rpf, *pf = (struct ssh_rportfwd *)ctx; + struct ssh_rportfwd *rpf = (struct ssh_rportfwd *)ctx; if (pktin->type == (ssh->version == 1 ? SSH1_SMSG_SUCCESS : SSH2_MSG_REQUEST_SUCCESS)) { logeventf(ssh, "Remote port forwarding from %s enabled", - pf->sportdesc); + rpf->log_description); } else { logeventf(ssh, "Remote port forwarding from %s refused", - pf->sportdesc); + rpf->log_description); - rpf = del234(ssh->rportfwds, pf); - assert(rpf == pf); - pf->pfrec->remote = NULL; - free_rportfwd(pf); + struct ssh_rportfwd *realpf = del234(ssh->rportfwds, rpf); + assert(realpf == rpf); + portfwdmgr_close(ssh->portfwdmgr, rpf->pfr); + free_rportfwd(rpf); } } -int ssh_alloc_sharing_rportfwd(Ssh ssh, const char *shost, int sport, - ssh_sharing_connstate *share_ctx) +struct ssh_rportfwd *ssh_rportfwd_alloc( + Ssh ssh, const char *shost, int sport, const char *dhost, int dport, + int addressfamily, const char *log_description, PortFwdRecord *pfr, + ssh_sharing_connstate *share_ctx) { - struct ssh_rportfwd *pf = snew(struct ssh_rportfwd); - pf->dhost = NULL; - pf->dport = 0; - pf->share_ctx = share_ctx; - pf->shost = dupstr(shost); - pf->sport = sport; - pf->sportdesc = NULL; + /* + * Ensure the remote port forwardings tree exists. + */ if (!ssh->rportfwds) { - assert(ssh->version == 2); - ssh->rportfwds = newtree234(ssh_rportcmp_ssh2); + if (ssh->version == 1) + ssh->rportfwds = newtree234(ssh_rportcmp_ssh1); + else + ssh->rportfwds = newtree234(ssh_rportcmp_ssh2); } - if (add234(ssh->rportfwds, pf) != pf) { - sfree(pf->shost); - sfree(pf); - return FALSE; + + struct ssh_rportfwd *rpf = snew(struct ssh_rportfwd); + + rpf->shost = dupstr(shost); + rpf->sport = sport; + rpf->dhost = dupstr(dhost); + rpf->dport = dport; + rpf->addressfamily = addressfamily; + rpf->log_description = dupstr(log_description); + rpf->pfr = pfr; + rpf->share_ctx = share_ctx; + + if (add234(ssh->rportfwds, rpf) != rpf) { + free_rportfwd(rpf); + return NULL; } - return TRUE; + + if (!rpf->share_ctx) { + PktOut *pktout; + + if (ssh->version == 1) { + pktout = ssh_bpp_new_pktout( + ssh->bpp, SSH1_CMSG_PORT_FORWARD_REQUEST); + put_uint32(pktout, rpf->sport); + put_stringz(pktout, rpf->dhost); + put_uint32(pktout, rpf->dport); + ssh_pkt_write(ssh, pktout); + ssh_queue_handler(ssh, SSH1_SMSG_SUCCESS, + SSH1_SMSG_FAILURE, + ssh_rportfwd_succfail, rpf); + } else { + pktout = ssh_bpp_new_pktout(ssh->bpp, SSH2_MSG_GLOBAL_REQUEST); + put_stringz(pktout, "tcpip-forward"); + put_bool(pktout, 1); /* want reply */ + put_stringz(pktout, rpf->shost); + put_uint32(pktout, rpf->sport); + ssh2_pkt_send(ssh, pktout); + + ssh_queue_handler(ssh, SSH2_MSG_REQUEST_SUCCESS, + SSH2_MSG_REQUEST_FAILURE, + ssh_rportfwd_succfail, rpf); + } + } + + return rpf; } -void ssh_remove_sharing_rportfwd(Ssh ssh, const char *shost, int sport, - ssh_sharing_connstate *share_ctx) +void ssh_rportfwd_remove(Ssh ssh, struct ssh_rportfwd *rpf) { - struct ssh_rportfwd pf, *realpf; + if (ssh->version == 1) { + /* + * We cannot cancel listening ports on the server side in + * SSH-1! There's no message to support it. + */ + } else if (rpf->share_ctx) { + /* + * We don't manufacture a cancel-tcpip-forward message for + * remote port forwardings being removed on behalf of a + * downstream; we just pass through the one the downstream + * sent to us. + */ + } else { + PktOut *pktout = ssh_bpp_new_pktout(ssh->bpp, SSH2_MSG_GLOBAL_REQUEST); + put_stringz(pktout, "cancel-tcpip-forward"); + put_bool(pktout, 0); /* _don't_ want reply */ + put_stringz(pktout, rpf->shost); + put_uint32(pktout, rpf->sport); + ssh2_pkt_send(ssh, pktout); + } - assert(ssh->rportfwds); - pf.shost = dupstr(shost); - pf.sport = sport; - realpf = del234(ssh->rportfwds, &pf); - assert(realpf); - assert(realpf->share_ctx == share_ctx); - sfree(realpf->shost); - sfree(realpf); + struct ssh_rportfwd *realpf = del234(ssh->rportfwds, rpf); + assert(realpf == rpf); + free_rportfwd(rpf); } static void ssh_sharing_global_request_response(Ssh ssh, PktIn *pktin, @@ -3885,334 +3862,6 @@ void ssh_sharing_queue_global_request(Ssh ssh, ssh_sharing_global_request_response, share_ctx); } -static void ssh_setup_portfwd(Ssh ssh, Conf *conf) -{ - struct ssh_portfwd *epf; - int i; - char *key, *val; - - if (!ssh->portfwds) { - ssh->portfwds = newtree234(ssh_portcmp); - } else { - /* - * Go through the existing port forwardings and tag them - * with status==DESTROY. Any that we want to keep will be - * re-enabled (status==KEEP) as we go through the - * configuration and find out which bits are the same as - * they were before. - */ - struct ssh_portfwd *epf; - int i; - for (i = 0; (epf = index234(ssh->portfwds, i)) != NULL; i++) - epf->status = DESTROY; - } - - for (val = conf_get_str_strs(conf, CONF_portfwd, NULL, &key); - val != NULL; - val = conf_get_str_strs(conf, CONF_portfwd, key, &key)) { - char *kp, *kp2, *vp, *vp2; - char address_family, type; - int sport,dport,sserv,dserv; - char *sports, *dports, *saddr, *host; - - kp = key; - - address_family = 'A'; - type = 'L'; - if (*kp == 'A' || *kp == '4' || *kp == '6') - address_family = *kp++; - if (*kp == 'L' || *kp == 'R') - type = *kp++; - - if ((kp2 = host_strchr(kp, ':')) != NULL) { - /* - * There's a colon in the middle of the source port - * string, which means that the part before it is - * actually a source address. - */ - char *saddr_tmp = dupprintf("%.*s", (int)(kp2 - kp), kp); - saddr = host_strduptrim(saddr_tmp); - sfree(saddr_tmp); - sports = kp2+1; - } else { - saddr = NULL; - sports = kp; - } - sport = atoi(sports); - sserv = 0; - if (sport == 0) { - sserv = 1; - sport = net_service_lookup(sports); - if (!sport) { - logeventf(ssh, "Service lookup failed for source" - " port \"%s\"", sports); - } - } - - if (type == 'L' && !strcmp(val, "D")) { - /* dynamic forwarding */ - host = NULL; - dports = NULL; - dport = -1; - dserv = 0; - type = 'D'; - } else { - /* ordinary forwarding */ - vp = val; - vp2 = vp + host_strcspn(vp, ":"); - host = dupprintf("%.*s", (int)(vp2 - vp), vp); - if (*vp2) - vp2++; - dports = vp2; - dport = atoi(dports); - dserv = 0; - if (dport == 0) { - dserv = 1; - dport = net_service_lookup(dports); - if (!dport) { - logeventf(ssh, "Service lookup failed for destination" - " port \"%s\"", dports); - } - } - } - - if (sport && dport) { - /* Set up a description of the source port. */ - struct ssh_portfwd *pfrec, *epfrec; - - pfrec = snew(struct ssh_portfwd); - pfrec->type = type; - pfrec->saddr = saddr; - pfrec->sserv = sserv ? dupstr(sports) : NULL; - pfrec->sport = sport; - pfrec->daddr = host; - pfrec->dserv = dserv ? dupstr(dports) : NULL; - pfrec->dport = dport; - pfrec->local = NULL; - pfrec->remote = NULL; - pfrec->addressfamily = (address_family == '4' ? ADDRTYPE_IPV4 : - address_family == '6' ? ADDRTYPE_IPV6 : - ADDRTYPE_UNSPEC); - - epfrec = add234(ssh->portfwds, pfrec); - if (epfrec != pfrec) { - if (epfrec->status == DESTROY) { - /* - * We already have a port forwarding up and running - * with precisely these parameters. Hence, no need - * to do anything; simply re-tag the existing one - * as KEEP. - */ - epfrec->status = KEEP; - } - /* - * Anything else indicates that there was a duplicate - * in our input, which we'll silently ignore. - */ - free_portfwd(pfrec); - } else { - pfrec->status = CREATE; - } - } else { - sfree(saddr); - sfree(host); - } - } - - /* - * Now go through and destroy any port forwardings which were - * not re-enabled. - */ - for (i = 0; (epf = index234(ssh->portfwds, i)) != NULL; i++) - if (epf->status == DESTROY) { - char *message; - - message = dupprintf("%s port forwarding from %s%s%d", - epf->type == 'L' ? "local" : - epf->type == 'R' ? "remote" : "dynamic", - epf->saddr ? epf->saddr : "", - epf->saddr ? ":" : "", - epf->sport); - - if (epf->type != 'D') { - char *msg2 = dupprintf("%s to %s:%d", message, - epf->daddr, epf->dport); - sfree(message); - message = msg2; - } - - logeventf(ssh, "Cancelling %s", message); - sfree(message); - - /* epf->remote or epf->local may be NULL if setting up a - * forwarding failed. */ - if (epf->remote) { - struct ssh_rportfwd *rpf = epf->remote; - PktOut *pktout; - - /* - * Cancel the port forwarding at the server - * end. - */ - if (ssh->version == 1) { - /* - * We cannot cancel listening ports on the - * server side in SSH-1! There's no message - * to support it. Instead, we simply remove - * the rportfwd record from the local end - * so that any connections the server tries - * to make on it are rejected. - */ - } else { - pktout = ssh_bpp_new_pktout( - ssh->bpp, SSH2_MSG_GLOBAL_REQUEST); - put_stringz(pktout, "cancel-tcpip-forward"); - put_bool(pktout, 0);/* _don't_ want reply */ - if (epf->saddr) { - put_stringz(pktout, epf->saddr); - } else if (conf_get_int(conf, CONF_rport_acceptall)) { - /* XXX: rport_acceptall may not represent - * what was used to open the original connection, - * since it's reconfigurable. */ - put_stringz(pktout, ""); - } else { - put_stringz(pktout, "localhost"); - } - put_uint32(pktout, epf->sport); - ssh2_pkt_send(ssh, pktout); - } - - del234(ssh->rportfwds, rpf); - free_rportfwd(rpf); - } else if (epf->local) { - pfl_terminate(epf->local); - } - - delpos234(ssh->portfwds, i); - free_portfwd(epf); - i--; /* so we don't skip one in the list */ - } - - /* - * And finally, set up any new port forwardings (status==CREATE). - */ - for (i = 0; (epf = index234(ssh->portfwds, i)) != NULL; i++) - if (epf->status == CREATE) { - char *sportdesc, *dportdesc; - sportdesc = dupprintf("%s%s%s%s%d%s", - epf->saddr ? epf->saddr : "", - epf->saddr ? ":" : "", - epf->sserv ? epf->sserv : "", - epf->sserv ? "(" : "", - epf->sport, - epf->sserv ? ")" : ""); - if (epf->type == 'D') { - dportdesc = NULL; - } else { - dportdesc = dupprintf("%s:%s%s%d%s", - epf->daddr, - epf->dserv ? epf->dserv : "", - epf->dserv ? "(" : "", - epf->dport, - epf->dserv ? ")" : ""); - } - - if (epf->type == 'L') { - char *err = pfl_listen(epf->daddr, epf->dport, - epf->saddr, epf->sport, - ssh, conf, &epf->local, - epf->addressfamily); - - logeventf(ssh, "Local %sport %s forwarding to %s%s%s", - epf->addressfamily == ADDRTYPE_IPV4 ? "IPv4 " : - epf->addressfamily == ADDRTYPE_IPV6 ? "IPv6 " : "", - sportdesc, dportdesc, - err ? " failed: " : "", err ? err : ""); - if (err) - sfree(err); - } else if (epf->type == 'D') { - char *err = pfl_listen(NULL, -1, epf->saddr, epf->sport, - ssh, conf, &epf->local, - epf->addressfamily); - - logeventf(ssh, "Local %sport %s SOCKS dynamic forwarding%s%s", - epf->addressfamily == ADDRTYPE_IPV4 ? "IPv4 " : - epf->addressfamily == ADDRTYPE_IPV6 ? "IPv6 " : "", - sportdesc, - err ? " failed: " : "", err ? err : ""); - - if (err) - sfree(err); - } else { - struct ssh_rportfwd *pf; - - /* - * Ensure the remote port forwardings tree exists. - */ - if (!ssh->rportfwds) { - if (ssh->version == 1) - ssh->rportfwds = newtree234(ssh_rportcmp_ssh1); - else - ssh->rportfwds = newtree234(ssh_rportcmp_ssh2); - } - - pf = snew(struct ssh_rportfwd); - pf->share_ctx = NULL; - pf->dhost = dupstr(epf->daddr); - pf->dport = epf->dport; - if (epf->saddr) { - pf->shost = dupstr(epf->saddr); - } else if (conf_get_int(conf, CONF_rport_acceptall)) { - pf->shost = dupstr(""); - } else { - pf->shost = dupstr("localhost"); - } - pf->sport = epf->sport; - if (add234(ssh->rportfwds, pf) != pf) { - logeventf(ssh, "Duplicate remote port forwarding to %s:%d", - epf->daddr, epf->dport); - sfree(pf); - } else { - PktOut *pktout; - - logeventf(ssh, "Requesting remote port %s" - " forward to %s", sportdesc, dportdesc); - - pf->sportdesc = sportdesc; - sportdesc = NULL; - epf->remote = pf; - pf->pfrec = epf; - - if (ssh->version == 1) { - pktout = ssh_bpp_new_pktout( - ssh->bpp, SSH1_CMSG_PORT_FORWARD_REQUEST); - put_uint32(pktout, epf->sport); - put_stringz(pktout, epf->daddr); - put_uint32(pktout, epf->dport); - ssh_pkt_write(ssh, pktout); - ssh_queue_handler(ssh, SSH1_SMSG_SUCCESS, - SSH1_SMSG_FAILURE, - ssh_rportfwd_succfail, pf); - } else { - pktout = ssh_bpp_new_pktout( - ssh->bpp, SSH2_MSG_GLOBAL_REQUEST); - put_stringz(pktout, "tcpip-forward"); - put_bool(pktout, 1);/* want reply */ - put_stringz(pktout, pf->shost); - put_uint32(pktout, pf->sport); - ssh2_pkt_send(ssh, pktout); - - ssh_queue_handler(ssh, SSH2_MSG_REQUEST_SUCCESS, - SSH2_MSG_REQUEST_FAILURE, - ssh_rportfwd_succfail, pf); - } - } - } - sfree(sportdesc); - sfree(dportdesc); - } -} - static void ssh1_smsg_stdout_stderr_data(Ssh ssh, PktIn *pktin) { ptrlen string; @@ -4321,8 +3970,8 @@ static void ssh1_msg_port_open(Ssh ssh, PktIn *pktin) logeventf(ssh, "Received remote port open request for %s:%d", pf.dhost, port); - err = pfd_connect(&c->chan, pf.dhost, port, - &c->sc, ssh->conf, pfp->pfrec->addressfamily); + err = portfwdmgr_connect(ssh->portfwdmgr, &c->chan, pf.dhost, port, + &c->sc, pfp->addressfamily); if (err != NULL) { logeventf(ssh, "Port open failed: %s", err); sfree(err); @@ -4562,7 +4211,7 @@ static void do_ssh1_connection(void *vctx) } } - ssh_setup_portfwd(ssh, ssh->conf); + portfwdmgr_config(ssh->portfwdmgr, ssh->conf); ssh->packet_dispatch[SSH1_MSG_PORT_OPEN] = ssh1_msg_port_open; if (!conf_get_int(ssh->conf, CONF_nopty)) { @@ -7858,8 +7507,9 @@ static void ssh2_msg_channel_open(Ssh ssh, PktIn *pktin) return; } - err = pfd_connect(&c->chan, realpf->dhost, realpf->dport, - &c->sc, ssh->conf, realpf->pfrec->addressfamily); + err = portfwdmgr_connect( + ssh->portfwdmgr, &c->chan, realpf->dhost, realpf->dport, + &c->sc, realpf->addressfamily); logeventf(ssh, "Attempting to forward remote port to " "%s:%d", realpf->dhost, realpf->dport); if (err != NULL) { @@ -9925,7 +9575,7 @@ static void do_ssh2_connection(void *vctx) /* * Enable port forwardings. */ - ssh_setup_portfwd(ssh, ssh->conf); + portfwdmgr_config(ssh->portfwdmgr, ssh->conf); if (ssh->mainchan && !ssh->ncmode) { /* @@ -10703,7 +10353,7 @@ static const char *ssh_init(Frontend *frontend, Backend **backend_handle, ssh->channels = NULL; ssh->rportfwds = NULL; - ssh->portfwds = NULL; + ssh->portfwdmgr = portfwdmgr_new(ssh); ssh->send_ok = 0; ssh->editing = 0; @@ -10798,6 +10448,7 @@ static void ssh_free(Backend *be) freetree234(ssh->rportfwds); ssh->rportfwds = NULL; } + portfwdmgr_free(ssh->portfwdmgr); if (ssh->x11disp) x11_free_display(ssh->x11disp); while ((auth = delpos234(ssh->x11authtree, 0)) != NULL) @@ -10864,8 +10515,7 @@ static void ssh_reconfig(Backend *be, Conf *conf) int i, rekey_time; pinger_reconfig(ssh->pinger, ssh->conf, conf); - if (ssh->portfwds) - ssh_setup_portfwd(ssh, conf); + portfwdmgr_config(ssh->portfwdmgr, conf); rekey_time = conf_get_int(conf, CONF_ssh_rekey_time); if (ssh2_timer_update(ssh, rekey_mins(rekey_time, 60))) diff --git a/ssh.h b/ssh.h index a4aea86e..4f5fc204 100644 --- a/ssh.h +++ b/ssh.h @@ -149,10 +149,6 @@ void ssh_connshare_log(Ssh ssh, int event, const char *logtext, const char *ds_err, const char *us_err); unsigned ssh_alloc_sharing_channel(Ssh ssh, ssh_sharing_connstate *connstate); void ssh_delete_sharing_channel(Ssh ssh, unsigned localid); -int ssh_alloc_sharing_rportfwd(Ssh ssh, const char *shost, int sport, - ssh_sharing_connstate *connstate); -void ssh_remove_sharing_rportfwd(Ssh ssh, const char *shost, int sport, - ssh_sharing_connstate *connstate); void ssh_sharing_queue_global_request( Ssh ssh, ssh_sharing_connstate *connstate); struct X11FakeAuth *ssh_sharing_add_x11_display( @@ -175,6 +171,23 @@ void share_setup_x11_channel(ssh_sharing_connstate *cs, share_channel *chan, int protomajor, int protominor, const void *initial_data, int initial_len); +struct ssh_rportfwd; +struct ssh_rportfwd *ssh_rportfwd_alloc( + Ssh ssh, const char *shost, int sport, const char *dhost, int dport, + int addressfamily, const char *log_description, PortFwdRecord *pfr, + ssh_sharing_connstate *share_ctx); +void ssh_rportfwd_remove(Ssh ssh, struct ssh_rportfwd *rpf); + +/* Exports from portfwd.c */ +PortFwdManager *portfwdmgr_new(Ssh ssh); +void portfwdmgr_free(PortFwdManager *mgr); +void portfwdmgr_config(PortFwdManager *mgr, Conf *conf); +void portfwdmgr_close(PortFwdManager *mgr, PortFwdRecord *pfr); +void portfwdmgr_close_all(PortFwdManager *mgr); +char *portfwdmgr_connect(PortFwdManager *mgr, Channel **chan_ret, + char *hostname, int port, SshChannel *c, + int addressfamily); + Frontend *ssh_get_frontend(Ssh ssh); #define SSH_CIPHER_IDEA 1 @@ -718,22 +731,10 @@ void random_add_heavynoise(void *noise, int length); void logevent(Frontend *, const char *); -struct PortForwarding; - /* Allocate and register a new channel for port forwarding */ SshChannel *ssh_send_port_open(Ssh ssh, const char *hostname, int port, const char *org, Channel *chan); -/* Exports from portfwd.c */ -extern char *pfd_connect(Channel **chan_ret, char *hostname, int port, - SshChannel *c, Conf *conf, int addressfamily); -struct PortListener; -/* desthost == NULL indicates dynamic (SOCKS) port forwarding */ -extern char *pfl_listen(char *desthost, int destport, char *srcaddr, - int port, Ssh ssh, Conf *conf, - struct PortListener **pl, int address_family); -extern void pfl_terminate(struct PortListener *); - /* Exports from x11fwd.c */ enum { X11_TRANS_IPV4 = 0, X11_TRANS_IPV6 = 6, X11_TRANS_UNIX = 256 diff --git a/sshshare.c b/sshshare.c index 22611e7d..a43ab9c2 100644 --- a/sshshare.c +++ b/sshshare.c @@ -242,6 +242,7 @@ struct share_forwarding { char *host; int port; int active; /* has the server sent REQUEST_SUCCESS? */ + struct ssh_rportfwd *rpf; }; struct share_xchannel_message { @@ -856,8 +857,7 @@ static void share_try_cleanup(struct ssh_sharing_connstate *cs) "cleanup after downstream went away"); strbuf_free(packet); - ssh_remove_sharing_rportfwd(cs->parent->ssh, - fwd->host, fwd->port, cs); + ssh_rportfwd_remove(cs->parent->ssh, fwd->rpf); share_remove_forwarding(cs, fwd); i--; /* don't accidentally skip one as a result */ } @@ -1306,7 +1306,8 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs, if (ptrlen_eq_string(request_name, "tcpip-forward")) { ptrlen hostpl; char *host; - int port, ret; + int port; + struct ssh_rportfwd *rpf; /* * Pick the packet apart to find the want_reply field and @@ -1328,8 +1329,9 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs, * ourselves to manufacture a failure packet and send it * back to downstream. */ - ret = ssh_alloc_sharing_rportfwd(cs->parent->ssh, host, port, cs); - if (!ret) { + rpf = ssh_rportfwd_alloc( + cs->parent->ssh, host, port, NULL, 0, 0, NULL, NULL, cs); + if (!rpf) { if (orig_wantreply) { send_packet_to_downstream(cs, SSH2_MSG_REQUEST_FAILURE, "", 0, NULL); @@ -1359,6 +1361,8 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs, globreq->fwd = fwd; globreq->want_reply = orig_wantreply; globreq->type = GLOBREQ_TCPIP_FORWARD; + + fwd->rpf = rpf; } } @@ -1395,7 +1399,7 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs, * Tell ssh.c to stop sending us channel-opens for * this forwarding. */ - ssh_remove_sharing_rportfwd(cs->parent->ssh, host, port, cs); + ssh_rportfwd_remove(cs->parent->ssh, fwd->rpf); /* * Pass the cancel request on to the SSH server, but From 8001dd4cbb9cdcd1b5431c0b289387a732cbc7ba Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Mon, 17 Sep 2018 12:14:00 +0100 Subject: [PATCH 410/607] New abstraction 'ConnectionLayer'. This is a vtable that wraps up all the functionality required from the SSH connection layer by associated modules like port forwarding and connection sharing. This extra layer of indirection adds nothing useful right now, but when I later separate the SSH-1 and SSH-2 connection layer implementations, it will be convenient for each one to be able to implement this vtable in terms of its own internal data structures. To simplify this vtable, I've moved a lot of the logging duties relating to connection sharing out of ssh.c into sshshare.c: now it handles nearly all the logging itself relating to setting up connection sharing in the first place and downstreams connecting and disconnecting. The only exception is the 'Reusing a shared connection' announcement in the console window, which is now done in ssh.c by detecting downstream status immediately after setup. --- defs.h | 1 + portfwd.c | 61 +++++++++--------- ssh.c | 179 ++++++++++++++++++++++++++++------------------------- ssh.h | 100 +++++++++++++++++++++--------- sshshare.c | 169 ++++++++++++++++++++++++++++++++++---------------- 5 files changed, 313 insertions(+), 197 deletions(-) diff --git a/defs.h b/defs.h index 822ee71d..8bd9f13e 100644 --- a/defs.h +++ b/defs.h @@ -62,6 +62,7 @@ typedef struct share_channel share_channel; typedef struct PortFwdManager PortFwdManager; typedef struct PortFwdRecord PortFwdRecord; +typedef struct ConnectionLayer ConnectionLayer; typedef struct dlgparam dlgparam; diff --git a/portfwd.c b/portfwd.c index d200c78b..07210683 100644 --- a/portfwd.c +++ b/portfwd.c @@ -35,8 +35,8 @@ typedef enum { } SocksState; typedef struct PortForwarding { - SshChannel *c; /* channel structure held by SSH backend */ - Ssh ssh; /* instance of SSH backend itself */ + SshChannel *c; /* channel structure held by SSH connection layer */ + ConnectionLayer *cl; /* the connection layer itself */ /* Note that ssh need not be filled in if c is non-NULL */ Socket s; int input_wanted; @@ -61,7 +61,7 @@ typedef struct PortForwarding { } PortForwarding; struct PortListener { - Ssh ssh; /* instance of SSH backend itself */ + ConnectionLayer *cl; Socket s; int is_dynamic; /* @@ -160,8 +160,9 @@ static void pfl_closing(Plug plug, const char *error_msg, int error_code, pfl_terminate(pl); } -static SshChannel *wrap_send_port_open( - Ssh ssh, const char *hostname, int port, Socket s, Channel *chan) +static SshChannel *wrap_lportfwd_open( + ConnectionLayer *cl, const char *hostname, int port, + Socket s, Channel *chan) { char *peerinfo, *description; SshChannel *toret; @@ -174,7 +175,7 @@ static SshChannel *wrap_send_port_open( description = dupstr("forwarding"); } - toret = ssh_send_port_open(ssh, hostname, port, description, chan); + toret = ssh_lportfwd_open(cl, hostname, port, description, chan); sfree(description); return toret; @@ -419,8 +420,8 @@ static void pfd_receive(Plug plug, int urgent, char *data, int len) */ sk_set_frozen(pf->s, 1); - pf->c = wrap_send_port_open(pf->ssh, pf->hostname, pf->port, pf->s, - &pf->chan); + pf->c = wrap_lportfwd_open(pf->cl, pf->hostname, pf->port, pf->s, + &pf->chan); } if (pf->ready) sshfwd_write(pf->c, data, len); @@ -480,7 +481,7 @@ static int pfl_accepting(Plug p, accept_fn_t constructor, accept_ctx_t ctx) pf->input_wanted = TRUE; pf->c = NULL; - pf->ssh = pl->ssh; + pf->cl = pl->cl; pf->s = s = constructor(ctx, &pf->plugvt); if ((err = sk_socket_error(s)) != NULL) { @@ -501,8 +502,8 @@ static int pfl_accepting(Plug p, accept_fn_t constructor, accept_ctx_t ctx) pf->socks_state = SOCKS_NONE; pf->hostname = dupstr(pl->hostname); pf->port = pl->port; - pf->c = wrap_send_port_open(pl->ssh, pf->hostname, pf->port, - s, &pf->chan); + pf->c = wrap_lportfwd_open(pl->cl, pf->hostname, pf->port, + s, &pf->chan); } return 0; @@ -525,7 +526,7 @@ static const Plug_vtable PortListener_plugvt = { * dynamically allocated error message string. */ static char *pfl_listen(char *desthost, int destport, char *srcaddr, - int port, Ssh ssh, Conf *conf, + int port, ConnectionLayer *cl, Conf *conf, struct PortListener **pl_ret, int address_family) { const char *err; @@ -542,7 +543,7 @@ static char *pfl_listen(char *desthost, int destport, char *srcaddr, pl->is_dynamic = FALSE; } else pl->is_dynamic = TRUE; - pl->ssh = ssh; + pl->cl = cl; pl->s = new_listener(srcaddr, port, &pl->plugvt, !conf_get_int(conf, CONF_lport_acceptall), @@ -637,7 +638,7 @@ static void pfd_open_failure(Channel *chan, const char *errtext) assert(chan->vt == &PortForwarding_channelvt); PortForwarding *pf = FROMFIELD(chan, PortForwarding, chan); - logeventf(ssh_get_frontend(pf->ssh), + logeventf(pf->cl->frontend, "Forwarded connection refused by server%s%s", errtext ? ": " : "", errtext ? errtext : ""); } @@ -702,18 +703,16 @@ void pfr_free(PortFwdRecord *pfr) } struct PortFwdManager { - Ssh ssh; - Frontend *frontend; + ConnectionLayer *cl; Conf *conf; tree234 *forwardings; }; -PortFwdManager *portfwdmgr_new(Ssh ssh) +PortFwdManager *portfwdmgr_new(ConnectionLayer *cl) { PortFwdManager *mgr = snew(PortFwdManager); - mgr->ssh = ssh; - mgr->frontend = ssh_get_frontend(ssh); + mgr->cl = cl; mgr->conf = NULL; mgr->forwardings = newtree234(pfr_cmp); @@ -801,7 +800,7 @@ void portfwdmgr_config(PortFwdManager *mgr, Conf *conf) sserv = 1; sport = net_service_lookup(sports); if (!sport) { - logeventf(mgr->frontend, "Service lookup failed for source" + logeventf(mgr->cl->frontend, "Service lookup failed for source" " port \"%s\"", sports); } } @@ -827,7 +826,7 @@ void portfwdmgr_config(PortFwdManager *mgr, Conf *conf) dserv = 1; dport = net_service_lookup(dports); if (!dport) { - logeventf(mgr->frontend, + logeventf(mgr->cl->frontend, "Service lookup failed for destination" " port \"%s\"", dports); } @@ -897,7 +896,7 @@ void portfwdmgr_config(PortFwdManager *mgr, Conf *conf) message = msg2; } - logeventf(mgr->frontend, "Cancelling %s", message); + logeventf(mgr->cl->frontend, "Cancelling %s", message); sfree(message); /* pfr->remote or pfr->local may be NULL if setting up a @@ -916,7 +915,7 @@ void portfwdmgr_config(PortFwdManager *mgr, Conf *conf) * connections the server tries to make on it are * rejected. */ - ssh_rportfwd_remove(mgr->ssh, pfr->remote); + ssh_rportfwd_remove(mgr->cl, pfr->remote); } else if (pfr->local) { pfl_terminate(pfr->local); } @@ -954,10 +953,10 @@ void portfwdmgr_config(PortFwdManager *mgr, Conf *conf) if (pfr->type == 'L') { char *err = pfl_listen(pfr->daddr, pfr->dport, pfr->saddr, pfr->sport, - mgr->ssh, conf, &pfr->local, + mgr->cl, conf, &pfr->local, pfr->addressfamily); - logeventf(mgr->frontend, + logeventf(mgr->cl->frontend, "Local %sport %s forwarding to %s%s%s", pfr->addressfamily == ADDRTYPE_IPV4 ? "IPv4 " : pfr->addressfamily == ADDRTYPE_IPV6 ? "IPv6 " : "", @@ -967,10 +966,10 @@ void portfwdmgr_config(PortFwdManager *mgr, Conf *conf) sfree(err); } else if (pfr->type == 'D') { char *err = pfl_listen(NULL, -1, pfr->saddr, pfr->sport, - mgr->ssh, conf, &pfr->local, + mgr->cl, conf, &pfr->local, pfr->addressfamily); - logeventf(mgr->frontend, + logeventf(mgr->cl->frontend, "Local %sport %s SOCKS dynamic forwarding%s%s", pfr->addressfamily == ADDRTYPE_IPV4 ? "IPv4 " : pfr->addressfamily == ADDRTYPE_IPV6 ? "IPv6 " : "", @@ -991,16 +990,16 @@ void portfwdmgr_config(PortFwdManager *mgr, Conf *conf) } pfr->remote = ssh_rportfwd_alloc( - mgr->ssh, shost, pfr->sport, pfr->daddr, pfr->dport, + mgr->cl, shost, pfr->sport, pfr->daddr, pfr->dport, pfr->addressfamily, sportdesc, pfr, NULL); if (!pfr->remote) { - logeventf(mgr->frontend, + logeventf(mgr->cl->frontend, "Duplicate remote port forwarding to %s:%d", pfr->daddr, pfr->dport); pfr_free(pfr); } else { - logeventf(mgr->frontend, "Requesting remote port %s" + logeventf(mgr->cl->frontend, "Requesting remote port %s" " forward to %s", sportdesc, dportdesc); } } @@ -1049,7 +1048,7 @@ char *portfwdmgr_connect(PortFwdManager *mgr, Channel **chan_ret, pf->input_wanted = TRUE; pf->ready = 1; pf->c = c; - pf->ssh = mgr->ssh; + pf->cl = mgr->cl; pf->socks_state = SOCKS_NONE; pf->s = new_connection(addr, dummy_realhost, port, diff --git a/ssh.c b/ssh.c index bedfe6af..9ec8553f 100644 --- a/ssh.c +++ b/ssh.c @@ -729,6 +729,8 @@ struct ssh_tag { tree234 *rportfwds; PortFwdManager *portfwdmgr; + ConnectionLayer cl; + enum { SSH_STATE_PREPACKET, SSH_STATE_BEFORE_SIZE, @@ -2199,39 +2201,6 @@ static void ssh_socket_log(Plug plug, int type, SockAddr addr, int port, ssh->session_started); } -void ssh_connshare_log(Ssh ssh, int event, const char *logtext, - const char *ds_err, const char *us_err) -{ - if (event == SHARE_NONE) { - /* In this case, 'logtext' is an error message indicating a - * reason why connection sharing couldn't be set up _at all_. - * Failing that, ds_err and us_err indicate why we couldn't be - * a downstream and an upstream respectively. */ - if (logtext) { - logeventf(ssh, "Could not set up connection sharing: %s", logtext); - } else { - if (ds_err) - logeventf(ssh, "Could not set up connection sharing" - " as downstream: %s", ds_err); - if (us_err) - logeventf(ssh, "Could not set up connection sharing" - " as upstream: %s", us_err); - } - } else if (event == SHARE_DOWNSTREAM) { - /* In this case, 'logtext' is a local endpoint address */ - logeventf(ssh, "Using existing shared connection at %s", logtext); - /* Also we should mention this in the console window to avoid - * confusing users as to why this window doesn't behave the - * usual way. */ - if ((flags & FLAG_VERBOSE) || (flags & FLAG_INTERACTIVE)) { - c_write_str(ssh,"Reusing a shared connection to this server.\r\n"); - } - } else if (event == SHARE_UPSTREAM) { - /* In this case, 'logtext' is a local endpoint address too */ - logeventf(ssh, "Sharing this connection at %s", logtext); - } -} - static void ssh_closing(Plug plug, const char *error_msg, int error_code, int calling_back) { @@ -2363,7 +2332,7 @@ static const char *connect_to_host(Ssh ssh, const char *host, int port, ssh->connshare = NULL; ssh->attempting_connshare = TRUE; /* affects socket logging behaviour */ ssh->s = ssh_connection_sharing_init( - ssh->savedhost, ssh->savedport, ssh->conf, ssh, &ssh->plugvt, + ssh->savedhost, ssh->savedport, ssh->conf, &ssh->cl, &ssh->plugvt, &ssh->connshare); ssh->attempting_connshare = FALSE; if (ssh->s != NULL) { @@ -2374,6 +2343,14 @@ static const char *connect_to_host(Ssh ssh, const char *host, int port, ssh->current_incoming_data_fn = do_ssh_connection_init; ssh->fullhostname = NULL; *realhost = dupstr(host); /* best we can do */ + + if ((flags & FLAG_VERBOSE) || (flags & FLAG_INTERACTIVE)) { + /* In an interactive session, or in verbose mode, announce + * in the console window that we're a sharing downstream, + * to avoid confusing users as to why this session doesn't + * behave in quite the usual way. */ + c_write_str(ssh,"Reusing a shared connection to this server.\r\n"); + } } else { /* * We're not a downstream, so open a normal socket. @@ -3758,11 +3735,56 @@ static void ssh_rportfwd_succfail(Ssh ssh, PktIn *pktin, void *ctx) } } -struct ssh_rportfwd *ssh_rportfwd_alloc( - Ssh ssh, const char *shost, int sport, const char *dhost, int dport, +/* Many of these vtable methods have the same names as wrapper macros + * in ssh.h, so parenthesise the names to inhibit macro expansion */ + +static struct ssh_rportfwd *(ssh_rportfwd_alloc)( + ConnectionLayer *cl, + const char *shost, int sport, const char *dhost, int dport, + int addressfamily, const char *log_description, PortFwdRecord *pfr, + ssh_sharing_connstate *share_ctx); +static void (ssh_rportfwd_remove)( + ConnectionLayer *cl, struct ssh_rportfwd *rpf); +static SshChannel *(ssh_lportfwd_open)( + ConnectionLayer *cl, const char *hostname, int port, + const char *org, Channel *chan); +static struct X11FakeAuth *(ssh_add_sharing_x11_display)( + ConnectionLayer *cl, int authtype, ssh_sharing_connstate *share_cs, + share_channel *share_chan); +static void (ssh_remove_sharing_x11_display)(ConnectionLayer *cl, + struct X11FakeAuth *auth); +static void (ssh_send_packet_from_downstream)( + ConnectionLayer *cl, unsigned id, int type, + const void *pkt, int pktlen, const char *additional_log_text); +static unsigned (ssh_alloc_sharing_channel)( + ConnectionLayer *cl, ssh_sharing_connstate *connstate); +static void (ssh_delete_sharing_channel)( + ConnectionLayer *cl, unsigned localid); +static void (ssh_sharing_queue_global_request)( + ConnectionLayer *cl, ssh_sharing_connstate *share_ctx); +static int (ssh_agent_forwarding_permitted)(ConnectionLayer *cl); + +const struct ConnectionLayerVtable ssh_connlayer_vtable = { + ssh_rportfwd_alloc, + ssh_rportfwd_remove, + ssh_lportfwd_open, + ssh_add_sharing_x11_display, + ssh_remove_sharing_x11_display, + ssh_send_packet_from_downstream, + ssh_alloc_sharing_channel, + ssh_delete_sharing_channel, + ssh_sharing_queue_global_request, + ssh_agent_forwarding_permitted, +}; + +static struct ssh_rportfwd *(ssh_rportfwd_alloc)( + ConnectionLayer *cl, + const char *shost, int sport, const char *dhost, int dport, int addressfamily, const char *log_description, PortFwdRecord *pfr, ssh_sharing_connstate *share_ctx) { + Ssh ssh = FROMFIELD(cl, struct ssh_tag, cl); + /* * Ensure the remote port forwardings tree exists. */ @@ -3819,8 +3841,10 @@ struct ssh_rportfwd *ssh_rportfwd_alloc( return rpf; } -void ssh_rportfwd_remove(Ssh ssh, struct ssh_rportfwd *rpf) +static void (ssh_rportfwd_remove)( + ConnectionLayer *cl, struct ssh_rportfwd *rpf) { + Ssh ssh = FROMFIELD(cl, struct ssh_tag, cl); if (ssh->version == 1) { /* * We cannot cancel listening ports on the server side in @@ -3855,9 +3879,10 @@ static void ssh_sharing_global_request_response(Ssh ssh, PktIn *pktin, BinarySource_UPCAST(pktin)->len); } -void ssh_sharing_queue_global_request(Ssh ssh, - ssh_sharing_connstate *share_ctx) +static void (ssh_sharing_queue_global_request)( + ConnectionLayer *cl, ssh_sharing_connstate *share_ctx) { + Ssh ssh = FROMFIELD(cl, struct ssh_tag, cl); ssh_queue_handler(ssh, SSH2_MSG_REQUEST_SUCCESS, SSH2_MSG_REQUEST_FAILURE, ssh_sharing_global_request_response, share_ctx); } @@ -4129,8 +4154,9 @@ static void ssh1_send_ttymode(BinarySink *bs, } } -int ssh_agent_forwarding_permitted(Ssh ssh) +static int (ssh_agent_forwarding_permitted)(ConnectionLayer *cl) { + Ssh ssh = FROMFIELD(cl, struct ssh_tag, cl); return conf_get_int(ssh->conf, CONF_agentfwd) && agent_exists(); } @@ -4156,7 +4182,7 @@ static void do_ssh1_connection(void *vctx) ssh->packet_dispatch[SSH1_MSG_CHANNEL_DATA] = ssh1_msg_channel_data; ssh->packet_dispatch[SSH1_SMSG_EXIT_STATUS] = ssh1_smsg_exit_status; - if (ssh_agent_forwarding_permitted(ssh)) { + if (ssh_agent_forwarding_permitted(&ssh->cl)) { logevent("Requesting agent forwarding"); pkt = ssh_bpp_new_pktout(ssh->bpp, SSH1_CMSG_AGENT_REQUEST_FORWARDING); ssh_pkt_write(ssh, pkt); @@ -6945,37 +6971,6 @@ static void ssh_check_termination(Ssh ssh) } } -void ssh_sharing_downstream_connected(Ssh ssh, unsigned id, - const char *peerinfo) -{ - if (peerinfo) - logeventf(ssh, "Connection sharing downstream #%u connected from %s", - id, peerinfo); - else - logeventf(ssh, "Connection sharing downstream #%u connected", id); -} - -void ssh_sharing_downstream_disconnected(Ssh ssh, unsigned id) -{ - logeventf(ssh, "Connection sharing downstream #%u disconnected", id); - ssh_check_termination(ssh); -} - -void ssh_sharing_logf(Ssh ssh, unsigned id, const char *logfmt, ...) -{ - va_list ap; - char *buf; - - va_start(ap, logfmt); - buf = dupvprintf(logfmt, ap); - va_end(ap); - if (id) - logeventf(ssh, "Connection sharing downstream #%u: %s", id, buf); - else - logeventf(ssh, "Connection sharing: %s", buf); - sfree(buf); -} - /* * Close any local socket and free any local resources associated with * a channel. This converts the channel into a zombie. @@ -7416,10 +7411,11 @@ static void ssh2_msg_global_request(Ssh ssh, PktIn *pktin) } } -struct X11FakeAuth *ssh_sharing_add_x11_display( - Ssh ssh, int authtype, ssh_sharing_connstate *share_cs, +static struct X11FakeAuth *(ssh_add_sharing_x11_display)( + ConnectionLayer *cl, int authtype, ssh_sharing_connstate *share_cs, share_channel *share_chan) { + Ssh ssh = FROMFIELD(cl, struct ssh_tag, cl); struct X11FakeAuth *auth; /* @@ -7434,8 +7430,10 @@ struct X11FakeAuth *ssh_sharing_add_x11_display( return auth; } -void ssh_sharing_remove_x11_display(Ssh ssh, struct X11FakeAuth *auth) +static void (ssh_remove_sharing_x11_display)( + ConnectionLayer *cl, struct X11FakeAuth *auth) { + Ssh ssh = FROMFIELD(cl, struct ssh_tag, cl); del234(ssh->x11authtree, auth); x11_free_fake_auth(auth); } @@ -9477,8 +9475,8 @@ static void do_ssh2_connection(void *vctx) * Just start a direct-tcpip channel and use it as the main * channel. */ - mc->sc = ssh_send_port_open - (ssh, conf_get_str(ssh->conf, CONF_ssh_nc_host), + mc->sc = ssh_lportfwd_open + (&ssh->cl, conf_get_str(ssh->conf, CONF_ssh_nc_host), conf_get_int(ssh->conf, CONF_ssh_nc_port), "main channel", &mc->chan); ssh->mainchan = FROMFIELD(mc->sc, struct ssh_channel, sc); @@ -9603,7 +9601,7 @@ static void do_ssh2_connection(void *vctx) } /* Potentially enable agent forwarding. */ - if (ssh_agent_forwarding_permitted(ssh)) + if (ssh_agent_forwarding_permitted(&ssh->cl)) ssh2_setup_agent(ssh->mainchan, NULL, NULL); /* Now allocate a pty for the session. */ @@ -10351,9 +10349,12 @@ static const char *ssh_init(Frontend *frontend, Backend **backend_handle, ssh->term_width = conf_get_int(ssh->conf, CONF_width); ssh->term_height = conf_get_int(ssh->conf, CONF_height); + ssh->cl.vt = &ssh_connlayer_vtable; + ssh->cl.frontend = ssh->frontend; + ssh->channels = NULL; ssh->rportfwds = NULL; - ssh->portfwdmgr = portfwdmgr_new(ssh); + ssh->portfwdmgr = portfwdmgr_new(&ssh->cl); ssh->send_ok = 0; ssh->editing = 0; @@ -10861,8 +10862,10 @@ static void ssh_special(Backend *be, Telnet_Special code) } } -unsigned ssh_alloc_sharing_channel(Ssh ssh, ssh_sharing_connstate *connstate) +static unsigned (ssh_alloc_sharing_channel)( + ConnectionLayer *cl, ssh_sharing_connstate *connstate) { + Ssh ssh = FROMFIELD(cl, struct ssh_tag, cl); struct ssh_channel *c; c = snew(struct ssh_channel); @@ -10873,8 +10876,9 @@ unsigned ssh_alloc_sharing_channel(Ssh ssh, ssh_sharing_connstate *connstate) return c->localid; } -void ssh_delete_sharing_channel(Ssh ssh, unsigned localid) +static void (ssh_delete_sharing_channel)(ConnectionLayer *cl, unsigned localid) { + Ssh ssh = FROMFIELD(cl, struct ssh_tag, cl); struct ssh_channel *c; c = find234(ssh->channels, &localid, ssh_channelfind); @@ -10882,10 +10886,11 @@ void ssh_delete_sharing_channel(Ssh ssh, unsigned localid) ssh_channel_destroy(c); } -void ssh_send_packet_from_downstream(Ssh ssh, unsigned id, int type, - const void *data, int datalen, - const char *additional_log_text) +static void (ssh_send_packet_from_downstream)( + ConnectionLayer *cl, unsigned id, int type, + const void *data, int datalen, const char *additional_log_text) { + Ssh ssh = FROMFIELD(cl, struct ssh_tag, cl); PktOut *pkt; pkt = ssh_bpp_new_pktout(ssh->bpp, type); @@ -10920,9 +10925,11 @@ static void ssh_unthrottle(Backend *be, int bufsize) queue_idempotent_callback(&ssh->incoming_data_consumer); } -SshChannel *ssh_send_port_open(Ssh ssh, const char *hostname, int port, - const char *org, Channel *chan) +static SshChannel *(ssh_lportfwd_open)( + ConnectionLayer *cl, const char *hostname, int port, + const char *org, Channel *chan) { + Ssh ssh = FROMFIELD(cl, struct ssh_tag, cl); struct ssh_channel *c = snew(struct ssh_channel); PktOut *pktout; diff --git a/ssh.h b/ssh.h index 4f5fc204..a0085179 100644 --- a/ssh.h +++ b/ssh.h @@ -135,8 +135,8 @@ void ssh_unref_packet(PktIn *pkt); void ssh_free_pktout(PktOut *pkt); extern Socket ssh_connection_sharing_init( - const char *host, int port, Conf *conf, Ssh ssh, Plug sshplug, - ssh_sharing_state **state); + const char *host, int port, Conf *conf, ConnectionLayer *cl, + Plug sshplug, ssh_sharing_state **state); int ssh_share_test_for_upstream(const char *host, int port, Conf *conf); void share_got_pkt_from_server(ssh_sharing_connstate *ctx, int type, const void *pkt, int pktlen); @@ -147,22 +147,6 @@ int share_ndownstreams(ssh_sharing_state *state); void ssh_connshare_log(Ssh ssh, int event, const char *logtext, const char *ds_err, const char *us_err); -unsigned ssh_alloc_sharing_channel(Ssh ssh, ssh_sharing_connstate *connstate); -void ssh_delete_sharing_channel(Ssh ssh, unsigned localid); -void ssh_sharing_queue_global_request( - Ssh ssh, ssh_sharing_connstate *connstate); -struct X11FakeAuth *ssh_sharing_add_x11_display( - Ssh ssh, int authtype, ssh_sharing_connstate *share_cs, - share_channel *share_chan); -void ssh_sharing_remove_x11_display(Ssh ssh, struct X11FakeAuth *auth); -void ssh_send_packet_from_downstream(Ssh ssh, unsigned id, int type, - const void *pkt, int pktlen, - const char *additional_log_text); -void ssh_sharing_downstream_connected(Ssh ssh, unsigned id, - const char *peerinfo); -void ssh_sharing_downstream_disconnected(Ssh ssh, unsigned id); -void ssh_sharing_logf(Ssh ssh, unsigned id, const char *logfmt, ...); -int ssh_agent_forwarding_permitted(Ssh ssh); void share_setup_x11_channel(ssh_sharing_connstate *cs, share_channel *chan, unsigned upstream_id, unsigned server_id, unsigned server_currwin, unsigned server_maxpkt, @@ -172,14 +156,78 @@ void share_setup_x11_channel(ssh_sharing_connstate *cs, share_channel *chan, const void *initial_data, int initial_len); struct ssh_rportfwd; -struct ssh_rportfwd *ssh_rportfwd_alloc( - Ssh ssh, const char *shost, int sport, const char *dhost, int dport, - int addressfamily, const char *log_description, PortFwdRecord *pfr, - ssh_sharing_connstate *share_ctx); -void ssh_rportfwd_remove(Ssh ssh, struct ssh_rportfwd *rpf); + +struct ConnectionLayerVtable { + /* Allocate and free remote-to-local port forwardings, called by + * PortFwdManager or by connection sharing */ + struct ssh_rportfwd *(*rportfwd_alloc)( + ConnectionLayer *cl, + const char *shost, int sport, const char *dhost, int dport, + int addressfamily, const char *log_description, PortFwdRecord *pfr, + ssh_sharing_connstate *share_ctx); + void (*rportfwd_remove)(ConnectionLayer *cl, struct ssh_rportfwd *rpf); + + /* Open a local-to-remote port forwarding channel, called by + * PortFwdManager */ + SshChannel *(*lportfwd_open)( + ConnectionLayer *cl, const char *hostname, int port, + const char *org, Channel *chan); + + /* Add and remove X11 displays for connection sharing downstreams */ + struct X11FakeAuth *(*add_sharing_x11_display)( + ConnectionLayer *cl, int authtype, ssh_sharing_connstate *share_cs, + share_channel *share_chan); + void (*remove_sharing_x11_display)( + ConnectionLayer *cl, struct X11FakeAuth *auth); + + /* Pass through an outgoing SSH packet from a downstream */ + void (*send_packet_from_downstream)( + ConnectionLayer *cl, unsigned id, int type, + const void *pkt, int pktlen, const char *additional_log_text); + + /* Allocate/free an upstream channel number associated with a + * sharing downstream */ + unsigned (*alloc_sharing_channel)(ConnectionLayer *cl, + ssh_sharing_connstate *connstate); + void (*delete_sharing_channel)(ConnectionLayer *cl, unsigned localid); + + /* Indicate that a downstream has sent a global request with the + * want-reply flag, so that when a reply arrives it will be passed + * back to that downstrean */ + void (*sharing_queue_global_request)( + ConnectionLayer *cl, ssh_sharing_connstate *connstate); + + /* Query whether the connection layer is doing agent forwarding */ + int (*agent_forwarding_permitted)(ConnectionLayer *cl); +}; + +struct ConnectionLayer { + Frontend *frontend; + const struct ConnectionLayerVtable *vt; +}; + +#define ssh_rportfwd_alloc(cl, sh, sp, dh, dp, af, ld, pfr, share) \ + ((cl)->vt->rportfwd_alloc(cl, sh, sp, dh, dp, af, ld, pfr, share)) +#define ssh_rportfwd_remove(cl, rpf) ((cl)->vt->rportfwd_remove(cl, rpf)) +#define ssh_lportfwd_open(cl, h, p, org, chan) \ + ((cl)->vt->lportfwd_open(cl, h, p, org, chan)) +#define ssh_add_sharing_x11_display(cl, auth, cs, ch) \ + ((cl)->vt->add_sharing_x11_display(cl, auth, cs, ch)) +#define ssh_remove_sharing_x11_display(cl, fa) \ + ((cl)->vt->remove_sharing_x11_display(cl, fa)) +#define ssh_send_packet_from_downstream(cl, id, type, pkt, len, log) \ + ((cl)->vt->send_packet_from_downstream(cl, id, type, pkt, len, log)) +#define ssh_alloc_sharing_channel(cl, cs) \ + ((cl)->vt->alloc_sharing_channel(cl, cs)) +#define ssh_delete_sharing_channel(cl, ch) \ + ((cl)->vt->delete_sharing_channel(cl, ch)) +#define ssh_sharing_queue_global_request(cl, cs) \ + ((cl)->vt->sharing_queue_global_request(cl, cs)) +#define ssh_agent_forwarding_permitted(cl) \ + ((cl)->vt->agent_forwarding_permitted(cl)) /* Exports from portfwd.c */ -PortFwdManager *portfwdmgr_new(Ssh ssh); +PortFwdManager *portfwdmgr_new(ConnectionLayer *cl); void portfwdmgr_free(PortFwdManager *mgr); void portfwdmgr_config(PortFwdManager *mgr, Conf *conf); void portfwdmgr_close(PortFwdManager *mgr, PortFwdRecord *pfr); @@ -731,10 +779,6 @@ void random_add_heavynoise(void *noise, int length); void logevent(Frontend *, const char *); -/* Allocate and register a new channel for port forwarding */ -SshChannel *ssh_send_port_open(Ssh ssh, const char *hostname, int port, - const char *org, Channel *chan); - /* Exports from x11fwd.c */ enum { X11_TRANS_IPV4 = 0, X11_TRANS_IPV6 = 6, X11_TRANS_UNIX = 256 diff --git a/sshshare.c b/sshshare.c index a43ab9c2..7515d117 100644 --- a/sshshare.c +++ b/sshshare.c @@ -144,7 +144,7 @@ struct ssh_sharing_state { Socket listensock; /* the master listening Socket */ tree234 *connections; /* holds ssh_sharing_connstates */ unsigned nextid; /* preferred id for next connstate */ - Ssh ssh; /* instance of the ssh backend */ + ConnectionLayer *cl; /* instance of the ssh connection layer */ char *server_verstring; /* server version string after "SSH-" */ const Plug_vtable *plugvt; @@ -618,7 +618,7 @@ static void share_remove_channel(struct ssh_sharing_connstate *cs, del234(cs->channels_by_us, chan); del234(cs->channels_by_server, chan); if (chan->x11_auth_upstream) - ssh_sharing_remove_x11_display(cs->parent->ssh, + ssh_remove_sharing_x11_display(cs->parent->cl, chan->x11_auth_upstream); sfree(chan->x11_auth_data); sfree(chan); @@ -703,6 +703,45 @@ static void share_remove_forwarding(struct ssh_sharing_connstate *cs, sfree(fwd); } +static void logeventf(Frontend *frontend, const char *fmt, ...) +{ + va_list ap; + char *buf; + + va_start(ap, fmt); + buf = dupvprintf(fmt, ap); + va_end(ap); + logevent(frontend, buf); + sfree(buf); +} + +static void log_downstream(struct ssh_sharing_connstate *cs, + const char *logfmt, ...) +{ + va_list ap; + char *buf; + + va_start(ap, logfmt); + buf = dupvprintf(logfmt, ap); + va_end(ap); + logeventf(cs->parent->cl->frontend, + "Connection sharing downstream #%u: %s", cs->id, buf); + sfree(buf); +} + +static void log_general(struct ssh_sharing_state *sharestate, + const char *logfmt, ...) +{ + va_list ap; + char *buf; + + va_start(ap, logfmt); + buf = dupvprintf(logfmt, ap); + va_end(ap); + logeventf(sharestate->cl->frontend, "Connection sharing: %s", buf); + sfree(buf); +} + static void send_packet_to_downstream(struct ssh_sharing_connstate *cs, int type, const void *pkt, int pktlen, struct share_channel *chan) @@ -790,7 +829,7 @@ static void share_try_cleanup(struct ssh_sharing_connstate *cs) put_stringz(packet, reason); put_stringz(packet, lang); ssh_send_packet_from_downstream( - cs->parent->ssh, cs->id, SSH2_MSG_CHANNEL_OPEN_FAILURE, + cs->parent->cl, cs->id, SSH2_MSG_CHANNEL_OPEN_FAILURE, packet->s, packet->len, "cleanup after downstream went away"); strbuf_free(packet); @@ -819,7 +858,7 @@ static void share_try_cleanup(struct ssh_sharing_connstate *cs) packet = strbuf_new(); put_uint32(packet, chan->server_id); ssh_send_packet_from_downstream( - cs->parent->ssh, cs->id, SSH2_MSG_CHANNEL_CLOSE, + cs->parent->cl, cs->id, SSH2_MSG_CHANNEL_CLOSE, packet->s, packet->len, "cleanup after downstream went away"); strbuf_free(packet); @@ -828,7 +867,7 @@ static void share_try_cleanup(struct ssh_sharing_connstate *cs) chan->state = SENT_CLOSE; } else { /* In this case, we _can_ clear up the channel now. */ - ssh_delete_sharing_channel(cs->parent->ssh, chan->upstream_id); + ssh_delete_sharing_channel(cs->parent->cl, chan->upstream_id); share_remove_channel(cs, chan); i--; /* don't accidentally skip one as a result */ } @@ -852,12 +891,12 @@ static void share_try_cleanup(struct ssh_sharing_connstate *cs) put_stringz(packet, fwd->host); put_uint32(packet, fwd->port); ssh_send_packet_from_downstream( - cs->parent->ssh, cs->id, SSH2_MSG_GLOBAL_REQUEST, + cs->parent->cl, cs->id, SSH2_MSG_GLOBAL_REQUEST, packet->s, packet->len, "cleanup after downstream went away"); strbuf_free(packet); - ssh_rportfwd_remove(cs->parent->ssh, fwd->rpf); + ssh_rportfwd_remove(cs->parent->cl, fwd->rpf); share_remove_forwarding(cs, fwd); i--; /* don't accidentally skip one as a result */ } @@ -870,7 +909,7 @@ static void share_try_cleanup(struct ssh_sharing_connstate *cs) * Now we're _really_ done, so we can get rid of cs completely. */ del234(cs->parent->connections, cs); - ssh_sharing_downstream_disconnected(cs->parent->ssh, cs->id); + log_downstream(cs, "disconnected"); share_connstate_free(cs); } } @@ -919,8 +958,7 @@ static void share_closing(Plug plug, const char *error_msg, int error_code, /* do nothing */; else #endif - ssh_sharing_logf(cs->parent->ssh, cs->id, - "Socket error: %s", error_msg); + log_downstream(cs, "Socket error: %s", error_msg); } share_begin_cleanup(cs); } @@ -979,7 +1017,7 @@ void share_dead_xchannel_respond(struct ssh_sharing_connstate *cs, strbuf *packet = strbuf_new(); put_uint32(packet, xc->server_id); ssh_send_packet_from_downstream - (cs->parent->ssh, cs->id, SSH2_MSG_CHANNEL_FAILURE, + (cs->parent->cl, cs->id, SSH2_MSG_CHANNEL_FAILURE, packet->s, packet->len, "downstream refused X channel open"); strbuf_free(packet); @@ -995,7 +1033,7 @@ void share_dead_xchannel_respond(struct ssh_sharing_connstate *cs, } xc->msgtail = NULL; if (delete) { - ssh_delete_sharing_channel(cs->parent->ssh, xc->upstream_id); + ssh_delete_sharing_channel(cs->parent->cl, xc->upstream_id); share_remove_xchannel(cs, xc); } } @@ -1031,7 +1069,7 @@ void share_xchannel_confirmation(struct ssh_sharing_connstate *cs, put_uint32(packet, xc->server_id); put_uint32(packet, downstream_window - xc->window); ssh_send_packet_from_downstream( - cs->parent->ssh, cs->id, SSH2_MSG_CHANNEL_WINDOW_ADJUST, + cs->parent->cl, cs->id, SSH2_MSG_CHANNEL_WINDOW_ADJUST, packet->s, packet->len, "window adjustment after downstream accepted X channel"); strbuf_free(packet); @@ -1047,7 +1085,7 @@ void share_xchannel_failure(struct ssh_sharing_connstate *cs, strbuf *packet = strbuf_new(); put_uint32(packet, xc->server_id); ssh_send_packet_from_downstream( - cs->parent->ssh, cs->id, SSH2_MSG_CHANNEL_CLOSE, + cs->parent->cl, cs->id, SSH2_MSG_CHANNEL_CLOSE, packet->s, packet->len, "downstream refused X channel open"); strbuf_free(packet); @@ -1115,7 +1153,7 @@ void share_setup_x11_channel(ssh_sharing_connstate *cs, share_channel *chan, * If this was a once-only X forwarding, clean it up now. */ if (chan->x11_one_shot) { - ssh_sharing_remove_x11_display(cs->parent->ssh, + ssh_remove_sharing_x11_display(cs->parent->cl, chan->x11_auth_upstream); chan->x11_auth_upstream = NULL; sfree(chan->x11_auth_data); @@ -1221,11 +1259,11 @@ void share_got_pkt_from_server(ssh_sharing_connstate *cs, int type, } } } else if (type == SSH2_MSG_CHANNEL_OPEN_FAILURE) { - ssh_delete_sharing_channel(cs->parent->ssh, chan->upstream_id); + ssh_delete_sharing_channel(cs->parent->cl, chan->upstream_id); share_remove_channel(cs, chan); } else if (type == SSH2_MSG_CHANNEL_CLOSE) { if (chan->state == SENT_CLOSE) { - ssh_delete_sharing_channel(cs->parent->ssh, + ssh_delete_sharing_channel(cs->parent->cl, chan->upstream_id); share_remove_channel(cs, chan); if (!cs->sock) { @@ -1330,7 +1368,7 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs, * back to downstream. */ rpf = ssh_rportfwd_alloc( - cs->parent->ssh, host, port, NULL, 0, 0, NULL, NULL, cs); + cs->parent->cl, host, port, NULL, 0, 0, NULL, NULL, cs); if (!rpf) { if (orig_wantreply) { send_packet_to_downstream(cs, SSH2_MSG_REQUEST_FAILURE, @@ -1346,10 +1384,10 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs, */ pkt[wantreplypos] = 1; ssh_send_packet_from_downstream - (cs->parent->ssh, cs->id, type, pkt, pktlen, + (cs->parent->cl, cs->id, type, pkt, pktlen, orig_wantreply ? NULL : "upstream added want_reply flag"); fwd = share_add_forwarding(cs, host, port); - ssh_sharing_queue_global_request(cs->parent->ssh, cs); + ssh_sharing_queue_global_request(cs->parent->cl, cs); if (fwd) { globreq = snew(struct share_globreq); @@ -1399,7 +1437,7 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs, * Tell ssh.c to stop sending us channel-opens for * this forwarding. */ - ssh_rportfwd_remove(cs->parent->ssh, fwd->rpf); + ssh_rportfwd_remove(cs->parent->cl, fwd->rpf); /* * Pass the cancel request on to the SSH server, but @@ -1409,9 +1447,9 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs, */ pkt[wantreplypos] = 1; ssh_send_packet_from_downstream - (cs->parent->ssh, cs->id, type, pkt, pktlen, + (cs->parent->cl, cs->id, type, pkt, pktlen, orig_wantreply ? NULL : "upstream added want_reply flag"); - ssh_sharing_queue_global_request(cs->parent->ssh, cs); + ssh_sharing_queue_global_request(cs->parent->cl, cs); /* * And queue a globreq so that when the reply comes @@ -1445,7 +1483,7 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs, get_string(src); id_pos = src->pos; old_id = get_uint32(src); - new_id = ssh_alloc_sharing_channel(cs->parent->ssh, cs); + new_id = ssh_alloc_sharing_channel(cs->parent->cl, cs); get_uint32(src); /* skip initial window size */ maxpkt = get_uint32(src); if (get_err(src)) { @@ -1454,7 +1492,7 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs, } share_add_channel(cs, old_id, new_id, 0, UNACKNOWLEDGED, maxpkt); PUT_32BIT(pkt + id_pos, new_id); - ssh_send_packet_from_downstream(cs->parent->ssh, cs->id, + ssh_send_packet_from_downstream(cs->parent->cl, cs->id, type, pkt, pktlen, NULL); break; @@ -1477,7 +1515,7 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs, /* This server id may refer to either a halfchannel or an xchannel. */ hc = NULL, xc = NULL; /* placate optimiser */ if ((hc = share_find_halfchannel(cs, server_id)) != NULL) { - new_id = ssh_alloc_sharing_channel(cs->parent->ssh, cs); + new_id = ssh_alloc_sharing_channel(cs->parent->cl, cs); } else if ((xc = share_find_xchannel_by_server(cs, server_id)) != NULL) { new_id = xc->upstream_id; @@ -1491,7 +1529,7 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs, chan = share_add_channel(cs, old_id, new_id, server_id, OPEN, maxpkt); if (hc) { - ssh_send_packet_from_downstream(cs->parent->ssh, cs->id, + ssh_send_packet_from_downstream(cs->parent->cl, cs->id, type, pkt, pktlen, NULL); share_remove_halfchannel(cs, hc); } else if (xc) { @@ -1515,7 +1553,7 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs, /* This server id may refer to either a halfchannel or an xchannel. */ if ((hc = share_find_halfchannel(cs, server_id)) != NULL) { - ssh_send_packet_from_downstream(cs->parent->ssh, cs->id, + ssh_send_packet_from_downstream(cs->parent->cl, cs->id, type, pkt, pktlen, NULL); share_remove_halfchannel(cs, hc); } else if ((xc = share_find_xchannel_by_server(cs, server_id)) @@ -1569,7 +1607,7 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs, * a parent session channel.) */ if (ptrlen_eq_string(request_name, "auth-agent-req@openssh.com") && - !ssh_agent_forwarding_permitted(cs->parent->ssh)) { + !ssh_agent_forwarding_permitted(cs->parent->cl)) { chan = share_find_channel_by_server(cs, server_id); if (chan) { @@ -1643,7 +1681,7 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs, chan->x11_auth_data = x11_dehexify(auth_data, &chan->x11_auth_datalen); chan->x11_auth_upstream = - ssh_sharing_add_x11_display(cs->parent->ssh, auth_proto, + ssh_add_sharing_x11_display(cs->parent->cl, auth_proto, cs, chan); chan->x11_one_shot = single_connection; @@ -1661,7 +1699,7 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs, put_stringz(packet, chan->x11_auth_upstream->datastring); put_uint32(packet, screen); ssh_send_packet_from_downstream( - cs->parent->ssh, cs->id, SSH2_MSG_CHANNEL_REQUEST, + cs->parent->cl, cs->id, SSH2_MSG_CHANNEL_REQUEST, packet->s, packet->len, NULL); strbuf_free(packet); @@ -1669,13 +1707,13 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs, } } - ssh_send_packet_from_downstream(cs->parent->ssh, cs->id, + ssh_send_packet_from_downstream(cs->parent->cl, cs->id, type, pkt, pktlen, NULL); if (type == SSH2_MSG_CHANNEL_CLOSE && pktlen >= 4) { chan = share_find_channel_by_server(cs, server_id); if (chan) { if (chan->state == RCVD_CLOSE) { - ssh_delete_sharing_channel(cs->parent->ssh, + ssh_delete_sharing_channel(cs->parent->cl, chan->upstream_id); share_remove_channel(cs, chan); } else { @@ -1757,9 +1795,8 @@ static void share_receive(Plug plug, int urgent, char *data, int len) } if (cs->recvlen > 0 && cs->recvbuf[cs->recvlen-1] == '\015') cs->recvlen--; /* trim off \r before \n */ - ssh_sharing_logf(cs->parent->ssh, cs->id, - "Downstream version string: %.*s", - cs->recvlen, cs->recvbuf); + log_downstream(cs, "Downstream version string: %.*s", + cs->recvlen, cs->recvbuf); cs->got_verstring = TRUE; /* @@ -1813,8 +1850,7 @@ static void share_listen_closing(Plug plug, const char *error_msg, { ssh_sharing_state *sharestate = FROMFIELD(plug, ssh_sharing_state, plugvt); if (error_msg) - ssh_sharing_logf(sharestate->ssh, 0, - "listening socket: %s", error_msg); + log_general(sharestate, "listening socket: %s", error_msg); sk_close(sharestate->listensock); sharestate->listensock = NULL; } @@ -1923,7 +1959,9 @@ static int share_listen_accepting(Plug plug, cs->globreq_head = cs->globreq_tail = NULL; peerinfo = sk_peer_info(cs->sock); - ssh_sharing_downstream_connected(sharestate->ssh, cs->id, peerinfo); + log_downstream(cs, "connected%s%s", + peerinfo ? " from " : "", peerinfo ? peerinfo : ""); + sfree(peerinfo); return 0; @@ -2024,14 +2062,14 @@ static const Plug_vtable ssh_sharing_listen_plugvt = { * to the upstream; otherwise (whether or not we have established an * upstream) we return NULL. */ -Socket ssh_connection_sharing_init(const char *host, int port, - Conf *conf, Ssh ssh, Plug sshplug, - ssh_sharing_state **state) +Socket ssh_connection_sharing_init( + const char *host, int port, Conf *conf, ConnectionLayer *cl, + Plug sshplug, ssh_sharing_state **state) { int result, can_upstream, can_downstream; char *logtext, *ds_err, *us_err; char *sockname; - Socket sock; + Socket sock, toret = NULL; struct ssh_sharing_state *sharestate; if (!conf_get_int(conf, CONF_ssh_connection_sharing)) @@ -2065,10 +2103,6 @@ Socket ssh_connection_sharing_init(const char *host, int port, result = platform_ssh_share( sockname, conf, sshplug, &sharestate->plugvt, &sock, &logtext, &ds_err, &us_err, can_upstream, can_downstream); - ssh_connshare_log(ssh, result, logtext, ds_err, us_err); - sfree(logtext); - sfree(ds_err); - sfree(us_err); switch (result) { case SHARE_NONE: /* @@ -2076,11 +2110,29 @@ Socket ssh_connection_sharing_init(const char *host, int port, * went wrong setting the socket up). Free the upstream * structure and return NULL. */ + + if (logtext) { + /* For this result, if 'logtext' is not NULL then it is an + * error message indicating a reason why connection sharing + * couldn't be set up _at all_ */ + logeventf(cl->frontend, + "Could not set up connection sharing: %s", logtext); + } else { + /* Failing that, ds_err and us_err indicate why we + * couldn't be a downstream and an upstream respectively */ + if (ds_err) + logeventf(cl->frontend, "Could not set up connection sharing" + " as downstream: %s", ds_err); + if (us_err) + logeventf(cl->frontend, "Could not set up connection sharing" + " as upstream: %s", us_err); + } + assert(sock == NULL); *state = NULL; sfree(sharestate); sfree(sockname); - return NULL; + break; case SHARE_DOWNSTREAM: /* @@ -2088,10 +2140,16 @@ Socket ssh_connection_sharing_init(const char *host, int port, * don't need after all, and return the downstream socket as a * replacement for an ordinary SSH connection. */ + + /* 'logtext' is a local endpoint address */ + logeventf(cl->frontend, + "Using existing shared connection at %s", logtext); + *state = NULL; sfree(sharestate); sfree(sockname); - return sock; + toret = sock; + break; case SHARE_UPSTREAM: /* @@ -2099,15 +2157,22 @@ Socket ssh_connection_sharing_init(const char *host, int port, * to the caller; return NULL, to tell ssh.c that it has to * make an ordinary connection after all. */ + + /* 'logtext' is a local endpoint address */ + logeventf(cl->frontend, "Sharing this connection at %s", logtext); + *state = sharestate; sharestate->listensock = sock; sharestate->connections = newtree234(share_connstate_cmp); - sharestate->ssh = ssh; + sharestate->cl = cl; sharestate->server_verstring = NULL; sharestate->sockname = sockname; sharestate->nextid = 1; - return NULL; + break; } - return NULL; + sfree(logtext); + sfree(ds_err); + sfree(us_err); + return toret; } From ff7418af730b02d963ff15a660f60811b2c2577a Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Wed, 19 Sep 2018 12:57:33 +0100 Subject: [PATCH 411/607] tree234.c: minor fixes to the test suite. Added a missing #include of string.h; arranged that the test program reports the number of errors detected at the end so I don't have to search its entire output for "ERROR"; made the test program return a nonzero exit status if any error was found. --- tree234.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tree234.c b/tree234.c index d3c5293d..6c826309 100644 --- a/tree234.c +++ b/tree234.c @@ -1014,6 +1014,9 @@ void *del234(tree234 * t, void *e) */ #include +#include + +int n_errors = 0; /* * Error reporting function. @@ -1026,6 +1029,7 @@ void error(char *fmt, ...) vfprintf(stdout, fmt, ap); va_end(ap); printf("\n"); + n_errors++; } /* The array representation of the data. */ @@ -1480,7 +1484,8 @@ int main(void) delpostest(j); } - return 0; + printf("%d errors found\n", n_errors); + return (n_errors != 0); } #endif From b2d0bd0da4ab023bb5f9b59bfccebd2e09b14f07 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Wed, 19 Sep 2018 12:58:54 +0100 Subject: [PATCH 412/607] tree234.c: new search234() system. This is a thing I've been meaning to set up for a while: it's a pull-based search system (that is, the caller takes each step of the search manually, rather than providing a callback), which lets the caller inspect every step of the search, including the index of each candidate element in the tree. This allows flexible kinds of query that play the element and its index off against each other. I've also rewritten the existing findrelpos234() search function using the new one as a primitive, because that simplifies it a lot! --- tree234.c | 298 ++++++++++++++++++++++++++++++++++++++---------------- tree234.h | 35 +++++++ 2 files changed, 245 insertions(+), 88 deletions(-) diff --git a/tree234.c b/tree234.c index 6c826309..ea8ff9ee 100644 --- a/tree234.c +++ b/tree234.c @@ -107,6 +107,18 @@ static int countnode234(node234 * n) return count; } +/* + * Internal function to return the number of elements in a node. + */ +static int elements234(node234 *n) +{ + int i; + for (i = 0; i < 3; i++) + if (!n->elems[i]) + break; + return i; +} + /* * Count the elements in a tree. */ @@ -514,99 +526,66 @@ void *index234(tree234 * t, int index) void *findrelpos234(tree234 * t, void *e, cmpfn234 cmp, int relation, int *index) { - node234 *n; - void *ret; - int c; - int idx, ecount, kcount, cmpret; + search234_state ss; + int reldir = (relation == REL234_LT || relation == REL234_LE ? -1 : + relation == REL234_GT || relation == REL234_GE ? +1 : 0); + int equal_permitted = (relation != REL234_LT && relation != REL234_GT); + void *toret; - if (t->root == NULL) - return NULL; + /* Only LT / GT relations are permitted with a null query element. */ + assert(!(equal_permitted && !e)); if (cmp == NULL) cmp = t->cmp; - n = t->root; + search234_start(&ss, t); + while (ss.element) { + int cmpret; + + if (e) { + cmpret = cmp(e, ss.element); + } else { + cmpret = -reldir; /* invent a fixed compare result */ + } + + if (cmpret == 0) { + /* + * We've found an element that compares exactly equal to + * the query element. + */ + if (equal_permitted) { + /* If our search relation permits equality, we've + * finished already. */ + if (index) + *index = ss.index; + return ss.element; + } else { + /* Otherwise, pretend this element was slightly too + * big/small, according to the direction of search. */ + cmpret = reldir; + } + } + + search234_step(&ss, cmpret); + } + /* - * Attempt to find the element itself. + * No element compares equal to the one we were after, but + * ss.index indicates the index that element would have if it were + * inserted. + * + * So if our search relation is EQ, we must simply return failure. */ - idx = 0; - ecount = -1; + if (relation == REL234_EQ) + return NULL; + /* - * Prepare a fake `cmp' result if e is NULL. + * Otherwise, we must do an index lookup for the previous index + * (if we're going left - LE or LT) or this index (if we're going + * right - GE or GT). */ - cmpret = 0; - if (e == NULL) { - assert(relation == REL234_LT || relation == REL234_GT); - if (relation == REL234_LT) - cmpret = +1; /* e is a max: always greater */ - else if (relation == REL234_GT) - cmpret = -1; /* e is a min: always smaller */ - } - while (1) { - for (kcount = 0; kcount < 4; kcount++) { - if (kcount >= 3 || n->elems[kcount] == NULL || - (c = cmpret ? cmpret : cmp(e, n->elems[kcount])) < 0) { - break; - } - if (n->kids[kcount]) - idx += n->counts[kcount]; - if (c == 0) { - ecount = kcount; - break; - } - idx++; - } - if (ecount >= 0) - break; - if (n->kids[kcount]) - n = n->kids[kcount]; - else - break; - } - - if (ecount >= 0) { - /* - * We have found the element we're looking for. It's - * n->elems[ecount], at tree index idx. If our search - * relation is EQ, LE or GE we can now go home. - */ - if (relation != REL234_LT && relation != REL234_GT) { - if (index) - *index = idx; - return n->elems[ecount]; - } - - /* - * Otherwise, we'll do an indexed lookup for the previous - * or next element. (It would be perfectly possible to - * implement these search types in a non-counted tree by - * going back up from where we are, but far more fiddly.) - */ - if (relation == REL234_LT) - idx--; - else - idx++; - } else { - /* - * We've found our way to the bottom of the tree and we - * know where we would insert this node if we wanted to: - * we'd put it in in place of the (empty) subtree - * n->kids[kcount], and it would have index idx - * - * But the actual element isn't there. So if our search - * relation is EQ, we're doomed. - */ - if (relation == REL234_EQ) - return NULL; - - /* - * Otherwise, we must do an index lookup for index idx-1 - * (if we're going left - LE or LT) or index idx (if we're - * going right - GE or GT). - */ - if (relation == REL234_LT || relation == REL234_LE) { - idx--; - } + if (relation == REL234_LT || relation == REL234_LE) { + ss.index--; } /* @@ -614,10 +593,10 @@ void *findrelpos234(tree234 * t, void *e, cmpfn234 cmp, * to do the rest. This will return NULL if the index is out of * bounds, which is exactly what we want. */ - ret = index234(t, idx); - if (ret && index) - *index = idx; - return ret; + toret = index234(t, ss.index); + if (toret && index) + *index = ss.index; + return toret; } void *find234(tree234 * t, void *e, cmpfn234 cmp) { @@ -632,6 +611,80 @@ void *findpos234(tree234 * t, void *e, cmpfn234 cmp, int *index) return findrelpos234(t, e, cmp, REL234_EQ, index); } +void search234_start(search234_state *state, tree234 *t) +{ + state->_node = t->root; + state->_base = 0; /* index of first element in this node's subtree */ + state->_last = -1; /* indicate that this node is not previously visted */ + search234_step(state, 0); +} +void search234_step(search234_state *state, int direction) +{ + node234 *node = state->_node; + int i; + + if (!node) { + state->element = NULL; + state->index = 0; + return; + } + + if (state->_last != -1) { + /* + * We're already pointing at some element of a node, so we + * should restrict to the elements left or right of it, + * depending on the requested search direction. + */ + assert(direction); + assert(node); + + if (direction > 0) { + state->_lo = state->_last + 1; + direction = +1; + } else { + state->_hi = state->_last - 1; + direction = -1; + } + + if (state->_lo > state->_hi) { + /* + * We've run out of elements in this node, i.e. we've + * narrowed to nothing but a child pointer. Descend to + * that child, and update _base to the leftmost index of + * its subtree. + */ + for (i = 0; i < state->_lo; i++) + state->_base += 1 + node->counts[i]; + state->_node = node = node->kids[state->_lo]; + state->_last = -1; + } + } + + if (state->_last == -1) { + /* + * We've just entered a new node - either because of the above + * code, or because we were called from search234_start - and + * anything in that node is a viable answer. + */ + state->_lo = 0; + state->_hi = node ? elements234(node)-1 : 0; + } + + /* + * Now we've got something we can return. + */ + if (!node) { + state->element = NULL; + state->index = state->_base; + } else { + state->_last = (state->_lo + state->_hi) / 2; + state->element = node->elems[state->_last]; + state->index = state->_base + state->_last; + for (i = 0; i <= state->_last; i++) + state->index += node->counts[i]; + } +} + /* * Delete an element e in a 2-3-4 tree. Does not free the element, * merely removes all links to it from the tree nodes. @@ -1418,6 +1471,73 @@ int findtest(void) } } +void searchtest_recurse(search234_state ss, int lo, int hi, + char **expected, char *directionbuf, + char *directionptr) +{ + *directionptr = '\0'; + + if (!ss.element) { + if (lo != hi) { + error("search234(%s) gave NULL for non-empty interval [%d,%d)", + directionbuf, lo, hi); + } else if (ss.index != lo) { + error("search234(%s) gave index %d should be %d", + directionbuf, ss.index, lo); + } else { + printf("%*ssearch234(%s) gave NULL,%d\n", + (int)(directionptr-directionbuf) * 2, "", directionbuf, + ss.index); + } + } else if (lo == hi) { + error("search234(%s) gave %s for empty interval [%d,%d)", + directionbuf, (char *)ss.element, lo, hi); + } else if (ss.element != expected[ss.index]) { + error("search234(%s) gave element %s should be %s", + directionbuf, (char *)ss.element, expected[ss.index]); + } else if (ss.index < lo || ss.index >= hi) { + error("search234(%s) gave index %d should be in [%d,%d)", + directionbuf, ss.index, lo, hi); + return; + } else { + search234_state next; + + printf("%*ssearch234(%s) gave %s,%d\n", + (int)(directionptr-directionbuf) * 2, "", directionbuf, + (char *)ss.element, ss.index); + + next = ss; + search234_step(&next, -1); + *directionptr = '-'; + searchtest_recurse(next, lo, ss.index, + expected, directionbuf, directionptr+1); + + next = ss; + search234_step(&next, +1); + *directionptr = '+'; + searchtest_recurse(next, ss.index+1, hi, + expected, directionbuf, directionptr+1); + } +} + +void searchtest(void) +{ + char *expected[NSTR], *p; + char directionbuf[NSTR * 10]; + int n; + search234_state ss; + + printf("beginning searchtest:"); + for (n = 0; (p = index234(tree, n)) != NULL; n++) { + expected[n] = p; + printf(" %d=%s", n, p); + } + printf(" count=%d\n", n); + + search234_start(&ss, tree); + searchtest_recurse(ss, 0, n, expected, directionbuf, directionbuf); +} + int main(void) { int in[NSTR]; @@ -1432,6 +1552,7 @@ int main(void) cmp = mycmp; verify(); + searchtest(); for (i = 0; i < 10000; i++) { j = randomnumber(&seed); j %= NSTR; @@ -1446,6 +1567,7 @@ int main(void) in[j] = 1; } findtest(); + searchtest(); } while (arraylen > 0) { diff --git a/tree234.h b/tree234.h index ba743087..55cbe360 100644 --- a/tree234.h +++ b/tree234.h @@ -132,6 +132,41 @@ void *findpos234(tree234 * t, void *e, cmpfn234 cmp, int *index); void *findrelpos234(tree234 * t, void *e, cmpfn234 cmp, int relation, int *index); +/* + * A more general search type still. Use search234_start() to + * initialise one of these state structures; it will fill in + * state->element with an element of the tree, and state->index with + * the index of that element. If you don't like that element, call + * search234_step, with direction == -1 if you want an element earlier + * in the tree, or +1 if you want a later one. + * + * If either function returns state->element == NULL, then you've + * narrowed the search to a point between two adjacent elements, so + * there are no further elements left to return consistent with the + * constraints you've imposed. In this case, state->index tells you + * how many elements come before the point you narrowed down to. After + * this, you mustn't call search234_step again (unless the state + * structure is first reinitialised). + * + * The use of this search system is that you get both the candidate + * element _and_ its index at every stage, so you can use both of them + * to make your decision. Also, you can remember element pointers from + * earlier in the search. + * + * The fields beginning with underscores are private to the + * implementation, and only exposed so that clients can know how much + * space to allocate for the structure as a whole. Don't modify them. + * (Except that it's safe to copy the whole structure.) + */ +typedef struct search234_state { + void *element; + int index; + int _lo, _hi, _last, _base; + void *_node; +} search234_state; +void search234_start(search234_state *state, tree234 *t); +void search234_step(search234_state *state, int direction); + /* * Delete an element e in a 2-3-4 tree. Does not free the element, * merely removes all links to it from the tree nodes. From 61f18ac451e4e056a69f8431e66a4a371652307c Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Wed, 19 Sep 2018 13:20:03 +0100 Subject: [PATCH 413/607] Reimplement alloc_channel_id using search234. This replaces the previous log(n)^2 algorithm for channel-number allocation, which binary-searched the space of tree indices using a log-time call to index234() at each step, with a single log-time pass down the tree which only has to check the returned channel number against the returned tree index at each step. I'm under no illusions that this was a critical performance issue, but it's been offending my sense of algorithmic elegance for a while. --- ssh.c | 50 ++++++++++++++++++++++---------------------------- 1 file changed, 22 insertions(+), 28 deletions(-) diff --git a/ssh.c b/ssh.c index 9ec8553f..6e55107d 100644 --- a/ssh.c +++ b/ssh.c @@ -1046,42 +1046,36 @@ static int ssh_rportcmp_ssh2(void *av, void *bv) return 0; } -static int alloc_channel_id(Ssh ssh) +static unsigned alloc_channel_id(Ssh ssh) { const unsigned CHANNEL_NUMBER_OFFSET = 256; - unsigned low, high, mid; - int tsize; - struct ssh_channel *c; + search234_state ss; /* - * First-fit allocation of channel numbers: always pick the - * lowest unused one. To do this, binary-search using the - * counted B-tree to find the largest channel ID which is in a - * contiguous sequence from the beginning. (Precisely - * everything in that sequence must have ID equal to its tree - * index plus CHANNEL_NUMBER_OFFSET.) + * First-fit allocation of channel numbers: we always pick the + * lowest unused one. + * + * Every channel before that, and no channel after it, has an ID + * exactly equal to its tree index plus CHANNEL_NUMBER_OFFSET. So + * we can use the search234 system to identify the length of that + * initial sequence, in a single log-time pass down the channels + * tree. */ - tsize = count234(ssh->channels); - - low = -1; - high = tsize; - while (high - low > 1) { - mid = (high + low) / 2; - c = index234(ssh->channels, mid); - if (c->localid == mid + CHANNEL_NUMBER_OFFSET) - low = mid; /* this one is fine */ - else - high = mid; /* this one is past it */ + search234_start(&ss, ssh->channels); + while (ss.element) { + struct ssh_channel *c = (struct ssh_channel *)ss.element; + if (c->localid == ss.index + CHANNEL_NUMBER_OFFSET) + search234_step(&ss, +1); + else + search234_step(&ss, -1); } + /* - * Now low points to either -1, or the tree index of the - * largest ID in the initial sequence. + * Now ss.index gives exactly the number of channels in that + * initial sequence. So adding CHANNEL_NUMBER_OFFSET to it must + * give precisely the lowest unused channel number. */ - { - unsigned i = low + 1 + CHANNEL_NUMBER_OFFSET; - assert(NULL == find234(ssh->channels, &i, ssh_channelfind)); - } - return low + 1 + CHANNEL_NUMBER_OFFSET; + return ss.index + CHANNEL_NUMBER_OFFSET; } static void c_write_stderr(int trusted, const void *vbuf, int len) From a3130487631dbb565355b2125b766c7e286a623e Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Wed, 19 Sep 2018 17:37:00 +0100 Subject: [PATCH 414/607] New utility function logevent_and_free. This should make it easier to do formatted-string based logging outside ssh.c, because I can wrap up a local macro in any source file I like that expands to logevent_and_free(wherever my Frontend is, dupprintf(macro argument)). It caused yet another stub function to be needed in testbn, but there we go. (Also, while I'm here, removed a redundant declaration of logevent itself from ssh.h. The one in putty.h is all we need.) --- misc.c | 6 ++++++ misc.h | 7 +++++++ ssh.h | 2 -- testbn.c | 3 +++ windows/winpgen.c | 3 +++ windows/winpgnt.c | 3 +++ 6 files changed, 22 insertions(+), 2 deletions(-) diff --git a/misc.c b/misc.c index f4334a04..1a528923 100644 --- a/misc.c +++ b/misc.c @@ -337,6 +337,12 @@ void burnstr(char *string) /* sfree(str), only clear it first */ } } +void logevent_and_free(Frontend *frontend, char *s) +{ + logevent(frontend, s); + sfree(s); +} + int toint(unsigned u) { /* diff --git a/misc.h b/misc.h index 242d1a94..40191724 100644 --- a/misc.h +++ b/misc.h @@ -31,6 +31,13 @@ char *dupprintf(const char *fmt, ...) char *dupvprintf(const char *fmt, va_list ap); void burnstr(char *string); +/* + * Pass a dynamically allocated string to logevent and immediately + * free it. Intended for use by wrapper macros which pass the return + * value of dupprintf straight to this. + */ +void logevent_and_free(Frontend *frontend, char *msg); + struct strbuf { char *s; unsigned char *u; diff --git a/ssh.h b/ssh.h index a0085179..8a411710 100644 --- a/ssh.h +++ b/ssh.h @@ -777,8 +777,6 @@ int random_byte(void); void random_add_noise(void *noise, int length); void random_add_heavynoise(void *noise, int length); -void logevent(Frontend *, const char *); - /* Exports from x11fwd.c */ enum { X11_TRANS_IPV4 = 0, X11_TRANS_IPV6 = 6, X11_TRANS_UNIX = 256 diff --git a/testbn.c b/testbn.c index 05f62767..16529e27 100644 --- a/testbn.c +++ b/testbn.c @@ -7,6 +7,7 @@ * testdata/bignum.py. */ +#include #include #include #include @@ -31,6 +32,8 @@ int random_byte(void) return 0; } +void logevent(Frontend *frontend, const char *msg) { assert(0); } + #define fromxdigit(c) ( (c)>'9' ? ((c)&0xDF) - 'A' + 10 : (c) - '0' ) /* For Unix in particular, but harmless if this main() is reused elsewhere */ diff --git a/windows/winpgen.c b/windows/winpgen.c index d2840113..d951fa6b 100644 --- a/windows/winpgen.c +++ b/windows/winpgen.c @@ -60,6 +60,9 @@ void nonfatal(const char *fmt, ...) sfree(stuff); } +/* Stub needed to link against misc.c */ +void logevent(Frontend *frontend, const char *msg) { assert(0); } + /* ---------------------------------------------------------------------- * Progress report code. This is really horrible :-) */ diff --git a/windows/winpgnt.c b/windows/winpgnt.c index 3734ab17..0f89b810 100644 --- a/windows/winpgnt.c +++ b/windows/winpgnt.c @@ -113,6 +113,9 @@ static void unmungestr(char *in, char *out, int outlen) return; } +/* Stub needed to link against misc.c */ +void logevent(Frontend *frontend, const char *msg) { assert(0); } + static int has_security; struct PassphraseProcStruct { From ce0b672e787ff2f542ff2863b0e8cd914a929292 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Wed, 19 Sep 2018 17:58:25 +0100 Subject: [PATCH 415/607] Macro to make a ptrlen out of a string literal. I'm quite surprised I haven't needed this for anything else yet. I suppose if I had it, I could have written most of my ptrlen_eq_strings in terms of it, and saved a lot of gratuitous runtime strlens. --- misc.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/misc.h b/misc.h index 40191724..4e0d8b2d 100644 --- a/misc.h +++ b/misc.h @@ -107,6 +107,12 @@ int string_length_for_printf(size_t); /* Derive two printf arguments from a ptrlen, suitable for "%.*s" */ #define PTRLEN_PRINTF(pl) \ string_length_for_printf((pl).len), (const char *)(pl).ptr +/* Make a ptrlen out of a compile-time string literal. We try to + * enforce that it _is_ a string literal by token-pasting "" on to it, + * which should provoke a compile error if it's any other kind of + * string. */ +#define PTRLEN_LITERAL(stringlit) \ + TYPECHECK("" stringlit "", make_ptrlen(stringlit, sizeof(stringlit)-1)) /* Wipe sensitive data out of memory that's about to be freed. Simpler * than memset because we don't need the fill char parameter; also From 370ff150ab21db45ade9edf37967676122b0a526 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Wed, 19 Sep 2018 17:59:38 +0100 Subject: [PATCH 416/607] Move bug flag definitions out into ssh.h. With a new shiny list-macro system that will allocate power-of-2 values for them without me having to manually keep the numbers straight. --- ssh.c | 17 ----------------- ssh.h | 26 ++++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 17 deletions(-) diff --git a/ssh.c b/ssh.c index 6e55107d..7031a554 100644 --- a/ssh.c +++ b/ssh.c @@ -47,23 +47,6 @@ static const char *const ssh2_disconnect_reasons[] = { "illegal user name", }; -/* - * Various remote-bug flags. - */ -#define BUG_CHOKES_ON_SSH1_IGNORE 1 -#define BUG_SSH2_HMAC 2 -#define BUG_NEEDS_SSH1_PLAIN_PASSWORD 4 -#define BUG_CHOKES_ON_RSA 8 -#define BUG_SSH2_RSA_PADDING 16 -#define BUG_SSH2_DERIVEKEY 32 -#define BUG_SSH2_REKEY 64 -#define BUG_SSH2_PK_SESSIONID 128 -#define BUG_SSH2_MAXPKT 256 -#define BUG_CHOKES_ON_SSH2_IGNORE 512 -#define BUG_CHOKES_ON_WINADJ 1024 -#define BUG_SENDS_LATE_REQUEST_REPLY 2048 -#define BUG_SSH2_OLDGEX 4096 - #define DH_MIN_SIZE 1024 #define DH_MAX_SIZE 8192 diff --git a/ssh.h b/ssh.h index 8a411710..7dbd31fe 100644 --- a/ssh.h +++ b/ssh.h @@ -1266,3 +1266,29 @@ const char *ssh2_pkt_type(Pkt_KCtx pkt_kctx, Pkt_ACtx pkt_actx, int type); * format. */ void old_keyfile_warning(void); + +/* + * Flags indicating implementation bugs that we know how to mitigate + * if we think the other end has them. + */ +#define SSH_IMPL_BUG_LIST(X) \ + X(BUG_CHOKES_ON_SSH1_IGNORE) \ + X(BUG_SSH2_HMAC) \ + X(BUG_NEEDS_SSH1_PLAIN_PASSWORD) \ + X(BUG_CHOKES_ON_RSA) \ + X(BUG_SSH2_RSA_PADDING) \ + X(BUG_SSH2_DERIVEKEY) \ + X(BUG_SSH2_REKEY) \ + X(BUG_SSH2_PK_SESSIONID) \ + X(BUG_SSH2_MAXPKT) \ + X(BUG_CHOKES_ON_SSH2_IGNORE) \ + X(BUG_CHOKES_ON_WINADJ) \ + X(BUG_SENDS_LATE_REQUEST_REPLY) \ + X(BUG_SSH2_OLDGEX) \ + /* end of list */ +#define TMP_DECLARE_LOG2_ENUM(thing) log2_##thing, +enum { SSH_IMPL_BUG_LIST(TMP_DECLARE_LOG2_ENUM) }; +#undef TMP_DECLARE_LOG2_ENUM +#define TMP_DECLARE_REAL_ENUM(thing) thing = 1 << log2_##thing, +enum { SSH_IMPL_BUG_LIST(TMP_DECLARE_REAL_ENUM) }; +#undef TMP_DECLARE_REAL_ENUM From af8e526a7dfd7c7d5cdaa3e429a9b87cbf75073a Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Wed, 19 Sep 2018 17:37:00 +0100 Subject: [PATCH 417/607] Move version string exchange out into a BPP. Getting it out of the overgrown ssh.c is worthwhile in itself! But there are other benefits of this reorganisation too. One is that I get to remove ssh->current_incoming_data_fn, because now _all_ incoming network data is handled by whatever the current BPP is. So now we only indirect through the BPP, not through some other preliminary function pointer _and_ the BPP. Another is that all _outgoing_ network data is now handled centrally, including our outgoing version string - which means that a hex dump of that string now shows up in the raw-data log file, from which it was previously conspicuous by its absence. --- Recipe | 2 +- ssh.c | 650 +++++-------------------------------------------- sshbpp.h | 17 ++ sshverstring.c | 602 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 686 insertions(+), 585 deletions(-) create mode 100644 sshverstring.c diff --git a/Recipe b/Recipe index b735ac47..a2728c08 100644 --- a/Recipe +++ b/Recipe @@ -251,7 +251,7 @@ NONSSH = telnet raw rlogin ldisc pinger # SSH back end (putty, plink, pscp, psftp). SSH = ssh ssh1bpp ssh2bpp ssh2bpp-bare ssh1censor ssh2censor - + sshcrc sshdes sshmd5 sshrsa sshrand sshsha sshblowf + + sshverstring sshcrc sshdes sshmd5 sshrsa sshrand sshsha sshblowf + sshdh sshcrcda sshpubk sshzlib sshdss x11fwd portfwd + sshaes sshccp sshsh256 sshsh512 sshbn wildcard pinger ssharcf + sshgssc pgssapi sshshare sshecc aqsync marshal nullplug agentf diff --git a/ssh.c b/ssh.c index 7031a554..9ac60d27 100644 --- a/ssh.c +++ b/ssh.c @@ -661,6 +661,7 @@ enum RekeyClass { struct ssh_tag { char *v_c, *v_s; + struct ssh_version_receiver version_receiver; ssh_hash *exhash; Socket s; @@ -795,7 +796,6 @@ struct ssh_tag { BinaryPacketProtocol *bpp; void (*general_packet_processing)(Ssh ssh, PktIn *pkt); - void (*current_incoming_data_fn) (Ssh ssh); void (*current_user_input_fn) (Ssh ssh); /* @@ -1149,26 +1149,6 @@ static void ssh_pkt_write(Ssh ssh, PktOut *pkt) queue_idempotent_callback(&ssh->outgoing_data_sender); } -static int ssh_versioncmp(const char *a, const char *b) -{ - char *ae, *be; - unsigned long av, bv; - - av = strtoul(a, &ae, 10); - bv = strtoul(b, &be, 10); - if (av != bv) - return (av < bv ? -1 : +1); - if (*ae == '.') - ae++; - if (*be == '.') - be++; - av = strtoul(ae, &ae, 10); - bv = strtoul(be, &be, 10); - if (av != bv) - return (av < bv ? -1 : +1); - return 0; -} - /* * Packet construction functions. Mostly shared between SSH-1 and SSH-2. */ @@ -1346,258 +1326,6 @@ static void ssh2_add_sigblob(Ssh ssh, PktOut *pkt, put_string(pkt, sigblob, sigblob_len); } -/* - * Examine the remote side's version string and compare it against - * a list of known buggy implementations. - */ -static void ssh_detect_bugs(Ssh ssh, char *vstring) -{ - char *imp; /* pointer to implementation part */ - imp = vstring; - imp += strcspn(imp, "-"); - if (*imp) imp++; - imp += strcspn(imp, "-"); - if (*imp) imp++; - - ssh->remote_bugs = 0; - - /* - * General notes on server version strings: - * - Not all servers reporting "Cisco-1.25" have all the bugs listed - * here -- in particular, we've heard of one that's perfectly happy - * with SSH1_MSG_IGNOREs -- but this string never seems to change, - * so we can't distinguish them. - */ - if (conf_get_int(ssh->conf, CONF_sshbug_ignore1) == FORCE_ON || - (conf_get_int(ssh->conf, CONF_sshbug_ignore1) == AUTO && - (!strcmp(imp, "1.2.18") || !strcmp(imp, "1.2.19") || - !strcmp(imp, "1.2.20") || !strcmp(imp, "1.2.21") || - !strcmp(imp, "1.2.22") || !strcmp(imp, "Cisco-1.25") || - !strcmp(imp, "OSU_1.4alpha3") || !strcmp(imp, "OSU_1.5alpha4")))) { - /* - * These versions don't support SSH1_MSG_IGNORE, so we have - * to use a different defence against password length - * sniffing. - */ - ssh->remote_bugs |= BUG_CHOKES_ON_SSH1_IGNORE; - logevent("We believe remote version has SSH-1 ignore bug"); - } - - if (conf_get_int(ssh->conf, CONF_sshbug_plainpw1) == FORCE_ON || - (conf_get_int(ssh->conf, CONF_sshbug_plainpw1) == AUTO && - (!strcmp(imp, "Cisco-1.25") || !strcmp(imp, "OSU_1.4alpha3")))) { - /* - * These versions need a plain password sent; they can't - * handle having a null and a random length of data after - * the password. - */ - ssh->remote_bugs |= BUG_NEEDS_SSH1_PLAIN_PASSWORD; - logevent("We believe remote version needs a plain SSH-1 password"); - } - - if (conf_get_int(ssh->conf, CONF_sshbug_rsa1) == FORCE_ON || - (conf_get_int(ssh->conf, CONF_sshbug_rsa1) == AUTO && - (!strcmp(imp, "Cisco-1.25")))) { - /* - * These versions apparently have no clue whatever about - * RSA authentication and will panic and die if they see - * an AUTH_RSA message. - */ - ssh->remote_bugs |= BUG_CHOKES_ON_RSA; - logevent("We believe remote version can't handle SSH-1 RSA authentication"); - } - - if (conf_get_int(ssh->conf, CONF_sshbug_hmac2) == FORCE_ON || - (conf_get_int(ssh->conf, CONF_sshbug_hmac2) == AUTO && - !wc_match("* VShell", imp) && - (wc_match("2.1.0*", imp) || wc_match("2.0.*", imp) || - wc_match("2.2.0*", imp) || wc_match("2.3.0*", imp) || - wc_match("2.1 *", imp)))) { - /* - * These versions have the HMAC bug. - */ - ssh->remote_bugs |= BUG_SSH2_HMAC; - logevent("We believe remote version has SSH-2 HMAC bug"); - } - - if (conf_get_int(ssh->conf, CONF_sshbug_derivekey2) == FORCE_ON || - (conf_get_int(ssh->conf, CONF_sshbug_derivekey2) == AUTO && - !wc_match("* VShell", imp) && - (wc_match("2.0.0*", imp) || wc_match("2.0.10*", imp) ))) { - /* - * These versions have the key-derivation bug (failing to - * include the literal shared secret in the hashes that - * generate the keys). - */ - ssh->remote_bugs |= BUG_SSH2_DERIVEKEY; - logevent("We believe remote version has SSH-2 key-derivation bug"); - } - - if (conf_get_int(ssh->conf, CONF_sshbug_rsapad2) == FORCE_ON || - (conf_get_int(ssh->conf, CONF_sshbug_rsapad2) == AUTO && - (wc_match("OpenSSH_2.[5-9]*", imp) || - wc_match("OpenSSH_3.[0-2]*", imp) || - wc_match("mod_sftp/0.[0-8]*", imp) || - wc_match("mod_sftp/0.9.[0-8]", imp)))) { - /* - * These versions have the SSH-2 RSA padding bug. - */ - ssh->remote_bugs |= BUG_SSH2_RSA_PADDING; - logevent("We believe remote version has SSH-2 RSA padding bug"); - } - - if (conf_get_int(ssh->conf, CONF_sshbug_pksessid2) == FORCE_ON || - (conf_get_int(ssh->conf, CONF_sshbug_pksessid2) == AUTO && - wc_match("OpenSSH_2.[0-2]*", imp))) { - /* - * These versions have the SSH-2 session-ID bug in - * public-key authentication. - */ - ssh->remote_bugs |= BUG_SSH2_PK_SESSIONID; - logevent("We believe remote version has SSH-2 public-key-session-ID bug"); - } - - if (conf_get_int(ssh->conf, CONF_sshbug_rekey2) == FORCE_ON || - (conf_get_int(ssh->conf, CONF_sshbug_rekey2) == AUTO && - (wc_match("DigiSSH_2.0", imp) || - wc_match("OpenSSH_2.[0-4]*", imp) || - wc_match("OpenSSH_2.5.[0-3]*", imp) || - wc_match("Sun_SSH_1.0", imp) || - wc_match("Sun_SSH_1.0.1", imp) || - /* All versions <= 1.2.6 (they changed their format in 1.2.7) */ - wc_match("WeOnlyDo-*", imp)))) { - /* - * These versions have the SSH-2 rekey bug. - */ - ssh->remote_bugs |= BUG_SSH2_REKEY; - logevent("We believe remote version has SSH-2 rekey bug"); - } - - if (conf_get_int(ssh->conf, CONF_sshbug_maxpkt2) == FORCE_ON || - (conf_get_int(ssh->conf, CONF_sshbug_maxpkt2) == AUTO && - (wc_match("1.36_sshlib GlobalSCAPE", imp) || - wc_match("1.36 sshlib: GlobalScape", imp)))) { - /* - * This version ignores our makpkt and needs to be throttled. - */ - ssh->remote_bugs |= BUG_SSH2_MAXPKT; - logevent("We believe remote version ignores SSH-2 maximum packet size"); - } - - if (conf_get_int(ssh->conf, CONF_sshbug_ignore2) == FORCE_ON) { - /* - * Servers that don't support SSH2_MSG_IGNORE. Currently, - * none detected automatically. - */ - ssh->remote_bugs |= BUG_CHOKES_ON_SSH2_IGNORE; - logevent("We believe remote version has SSH-2 ignore bug"); - } - - if (conf_get_int(ssh->conf, CONF_sshbug_oldgex2) == FORCE_ON || - (conf_get_int(ssh->conf, CONF_sshbug_oldgex2) == AUTO && - (wc_match("OpenSSH_2.[235]*", imp)))) { - /* - * These versions only support the original (pre-RFC4419) - * SSH-2 GEX request, and disconnect with a protocol error if - * we use the newer version. - */ - ssh->remote_bugs |= BUG_SSH2_OLDGEX; - logevent("We believe remote version has outdated SSH-2 GEX"); - } - - if (conf_get_int(ssh->conf, CONF_sshbug_winadj) == FORCE_ON) { - /* - * Servers that don't support our winadj request for one - * reason or another. Currently, none detected automatically. - */ - ssh->remote_bugs |= BUG_CHOKES_ON_WINADJ; - logevent("We believe remote version has winadj bug"); - } - - if (conf_get_int(ssh->conf, CONF_sshbug_chanreq) == FORCE_ON || - (conf_get_int(ssh->conf, CONF_sshbug_chanreq) == AUTO && - (wc_match("OpenSSH_[2-5].*", imp) || - wc_match("OpenSSH_6.[0-6]*", imp) || - wc_match("dropbear_0.[2-4][0-9]*", imp) || - wc_match("dropbear_0.5[01]*", imp)))) { - /* - * These versions have the SSH-2 channel request bug. - * OpenSSH 6.7 and above do not: - * https://bugzilla.mindrot.org/show_bug.cgi?id=1818 - * dropbear_0.52 and above do not: - * https://secure.ucc.asn.au/hg/dropbear/rev/cd02449b709c - */ - ssh->remote_bugs |= BUG_SENDS_LATE_REQUEST_REPLY; - logevent("We believe remote version has SSH-2 channel request bug"); - } -} - -/* - * The `software version' part of an SSH version string is required - * to contain no spaces or minus signs. - */ -static void ssh_fix_verstring(char *str) -{ - /* Eat "-". */ - while (*str && *str != '-') str++; - assert(*str == '-'); str++; - - /* Convert minus signs and spaces in the remaining string into - * underscores. */ - while (*str) { - if (*str == '-' || *str == ' ') - *str = '_'; - str++; - } -} - -/* - * Send an appropriate SSH version string. - */ -static void ssh_send_verstring(Ssh ssh, const char *protoname, char *svers) -{ - char *verstring; - - if (ssh->version == 2) { - /* - * Construct a v2 version string. - */ - verstring = dupprintf("%s2.0-%s\015\012", protoname, sshver); - } else { - /* - * Construct a v1 version string. - */ - assert(!strcmp(protoname, "SSH-")); /* no v1 bare connection protocol */ - verstring = dupprintf("SSH-%s-%s\012", - (ssh_versioncmp(svers, "1.5") <= 0 ? - svers : "1.5"), - sshver); - } - - ssh_fix_verstring(verstring + strlen(protoname)); -#ifdef FUZZING - /* FUZZING make PuTTY insecure, so make live use difficult. */ - verstring[0] = 'I'; -#endif - - if (ssh->version == 2) { - size_t len; - /* - * Record our version string. - */ - len = strcspn(verstring, "\015\012"); - ssh->v_c = snewn(len + 1, char); - memcpy(ssh->v_c, verstring, len); - ssh->v_c[len] = 0; - } - - logeventf(ssh, "We claim version: %.*s", - strcspn(verstring, "\015\012"), verstring); - bufchain_add(&ssh->outgoing_data, verstring, strlen(verstring)); - queue_idempotent_callback(&ssh->outgoing_data_sender); - sfree(verstring); -} - static void ssh_feed_to_bpp(Ssh ssh) { PacketQueueNode *prev_tail = ssh->pq_full.end.prev; @@ -1628,342 +1356,83 @@ static void ssh_feed_to_bpp(Ssh ssh) queue_idempotent_callback(&ssh->pq_full_consumer); } -static void do_ssh_init(Ssh ssh) +static void ssh_got_ssh_version(struct ssh_version_receiver *rcv, + int major_version) { - static const char protoname[] = "SSH-"; - - struct do_ssh_init_state { - int crLine; - int vslen; - char *vstring; - char *version; - int vstrsize; - int i; - int proto1, proto2; - }; - crState(do_ssh_init_state); - - crBeginState; + Ssh ssh = FROMFIELD(rcv, struct ssh_tag, version_receiver); + BinaryPacketProtocol *old_bpp; /* - * Search for a line beginning with the protocol name prefix in - * the input. + * Queue an outgoing-data run: if the version string has been sent + * late rather than early, it'll still be sitting on our output + * raw data queue. */ - s->i = 0; - while (1) { - char prefix[sizeof(protoname)-1]; - - /* - * Every time round this loop, we're at the start of a new - * line, so look for the prefix. - */ - crMaybeWaitUntilV( - bufchain_size(&ssh->incoming_data) >= sizeof(prefix)); - bufchain_fetch(&ssh->incoming_data, prefix, sizeof(prefix)); - if (!memcmp(prefix, protoname, sizeof(prefix))) { - bufchain_consume(&ssh->incoming_data, sizeof(prefix)); - break; - } - - /* - * If we didn't find it, consume data until we see a newline. - */ - while (1) { - int len; - void *data; - char *nl; - - crMaybeWaitUntilV(bufchain_size(&ssh->incoming_data) > 0); - bufchain_prefix(&ssh->incoming_data, &data, &len); - if ((nl = memchr(data, '\012', len)) != NULL) { - bufchain_consume(&ssh->incoming_data, nl - (char *)data + 1); - break; - } else { - bufchain_consume(&ssh->incoming_data, len); - } - } - } - - ssh->session_started = TRUE; - ssh->agentfwd_enabled = FALSE; + queue_idempotent_callback(&ssh->outgoing_data_sender); /* - * Now read the rest of the greeting line. + * We don't support choosing a major protocol version dynamically, + * so this should always be the same value we set up in + * connect_to_host(). */ - s->vstrsize = sizeof(protoname) + 16; - s->vstring = snewn(s->vstrsize, char); - strcpy(s->vstring, protoname); - s->vslen = strlen(protoname); - s->i = 0; - do { - int len; - void *data; - char *nl; - - crMaybeWaitUntilV(bufchain_size(&ssh->incoming_data) > 0); - bufchain_prefix(&ssh->incoming_data, &data, &len); - if ((nl = memchr(data, '\012', len)) != NULL) { - len = nl - (char *)data + 1; - } - - if (s->vslen + len >= s->vstrsize - 1) { - s->vstrsize = (s->vslen + len) * 5 / 4 + 32; - s->vstring = sresize(s->vstring, s->vstrsize, char); - } + assert(ssh->version == major_version); - memcpy(s->vstring + s->vslen, data, len); - s->vslen += len; - bufchain_consume(&ssh->incoming_data, len); + old_bpp = ssh->bpp; + ssh->remote_bugs = ssh_verstring_get_bugs(old_bpp); - } while (s->vstring[s->vslen-1] != '\012'); + if (!ssh->bare_connection) { + if (ssh->version == 2) { + /* + * Retrieve both version strings from the old BPP before + * we free it. + */ + ssh->v_s = dupstr(ssh_verstring_get_remote(old_bpp)); + ssh->v_c = dupstr(ssh_verstring_get_local(old_bpp)); - s->vstring[s->vslen] = 0; - s->vstring[strcspn(s->vstring, "\015\012")] = '\0';/* remove EOL chars */ + /* + * Initialise SSH-2 protocol. + */ + ssh2_protocol_setup(ssh); + ssh->general_packet_processing = ssh2_general_packet_processing; + ssh->current_user_input_fn = NULL; + } else { + /* + * Initialise SSH-1 protocol. + */ + ssh1_protocol_setup(ssh); + ssh->current_user_input_fn = ssh1_login_input; + } - logeventf(ssh, "Server version: %s", s->vstring); - ssh_detect_bugs(ssh, s->vstring); + if (ssh->version == 2) + queue_idempotent_callback(&ssh->ssh2_transport_icb); - /* - * Decide which SSH protocol version to support. - */ - s->version = dupprintf( - "%.*s", (int)strcspn(s->vstring + strlen(protoname), "-"), - s->vstring + strlen(protoname)); - - /* Anything strictly below "2.0" means protocol 1 is supported. */ - s->proto1 = ssh_versioncmp(s->version, "2.0") < 0; - /* Anything greater or equal to "1.99" means protocol 2 is supported. */ - s->proto2 = ssh_versioncmp(s->version, "1.99") >= 0; - - if (conf_get_int(ssh->conf, CONF_sshprot) == 0) { - if (!s->proto1) { - bombout(("SSH protocol version 1 required by our configuration " - "but not provided by server")); - crStopV; - } - } else if (conf_get_int(ssh->conf, CONF_sshprot) == 3) { - if (!s->proto2) { - bombout(("SSH protocol version 2 required by our configuration " - "but server only provides (old, insecure) SSH-1")); - crStopV; - } } else { - /* No longer support values 1 or 2 for CONF_sshprot */ - assert(!"Unexpected value for CONF_sshprot"); - } - - if (s->proto2 && (conf_get_int(ssh->conf, CONF_sshprot) >= 2 || !s->proto1)) - ssh->version = 2; - else - ssh->version = 1; - - logeventf(ssh, "Using SSH protocol version %d", ssh->version); + assert(ssh->version == 2); /* can't do SSH-1 bare connection! */ + logeventf(ssh, "Using bare ssh-connection protocol"); - /* Send the version string, if we haven't already */ - if (conf_get_int(ssh->conf, CONF_sshprot) != 3) - ssh_send_verstring(ssh, protoname, s->version); + ssh2_bare_connection_protocol_setup(ssh); + ssh->current_user_input_fn = ssh2_connection_input; - sfree(s->version); - - if (ssh->version == 2) { - size_t len; - /* - * Record their version string. - */ - len = strcspn(s->vstring, "\015\012"); - ssh->v_s = snewn(len + 1, char); - memcpy(ssh->v_s, s->vstring, len); - ssh->v_s[len] = 0; - - /* - * Initialise SSH-2 protocol. - */ - ssh2_protocol_setup(ssh); - ssh->general_packet_processing = ssh2_general_packet_processing; - ssh->current_user_input_fn = NULL; - } else { - /* - * Initialise SSH-1 protocol. - */ - ssh1_protocol_setup(ssh); - ssh->current_user_input_fn = ssh1_login_input; } + ssh->bpp->out_raw = &ssh->outgoing_data; ssh->bpp->in_raw = &ssh->incoming_data; ssh->bpp->in_pq = &ssh->pq_full; ssh->bpp->pls = &ssh->pls; ssh->bpp->logctx = ssh->logctx; - ssh->current_incoming_data_fn = ssh_feed_to_bpp; queue_idempotent_callback(&ssh->incoming_data_consumer); queue_idempotent_callback(&ssh->user_input_consumer); - if (ssh->version == 2) - queue_idempotent_callback(&ssh->ssh2_transport_icb); update_specials_menu(ssh->frontend); ssh->state = SSH_STATE_BEFORE_SIZE; ssh->pinger = pinger_new(ssh->conf, &ssh->backend); - sfree(s->vstring); - - crFinishV; -} - -static void do_ssh_connection_init(Ssh ssh) -{ - /* - * Ordinary SSH begins with the banner "SSH-x.y-...". This is just - * the ssh-connection part, extracted and given a trivial binary - * packet protocol, so we replace 'SSH-' at the start with a new - * name. In proper SSH style (though of course this part of the - * proper SSH protocol _isn't_ subject to this kind of - * DNS-domain-based extension), we define the new name in our - * extension space. - */ - static const char protoname[] = - "SSHCONNECTION@putty.projects.tartarus.org-"; - - struct do_ssh_connection_init_state { - int crLine; - int vslen; - char *vstring; - char *version; - int vstrsize; - int i; - }; - crState(do_ssh_connection_init_state); - - crBeginState; - - /* - * Search for a line beginning with the protocol name prefix in - * the input. - */ - s->i = 0; - while (1) { - char prefix[sizeof(protoname)-1]; - + if (ssh->bare_connection) { /* - * Every time round this loop, we're at the start of a new - * line, so look for the prefix. + * Get connection protocol under way. */ - crMaybeWaitUntilV( - bufchain_size(&ssh->incoming_data) >= sizeof(prefix)); - bufchain_fetch(&ssh->incoming_data, prefix, sizeof(prefix)); - if (!memcmp(prefix, protoname, sizeof(prefix))) { - bufchain_consume(&ssh->incoming_data, sizeof(prefix)); - break; - } - - /* - * If we didn't find it, consume data until we see a newline. - */ - while (1) { - int len; - void *data; - char *nl; - - crMaybeWaitUntilV(bufchain_size(&ssh->incoming_data) > 0); - bufchain_prefix(&ssh->incoming_data, &data, &len); - if ((nl = memchr(data, '\012', len)) != NULL) { - bufchain_consume(&ssh->incoming_data, nl - (char *)data + 1); - break; - } else { - bufchain_consume(&ssh->incoming_data, len); - } - } - } - - /* - * Now read the rest of the greeting line. - */ - s->vstrsize = sizeof(protoname) + 16; - s->vstring = snewn(s->vstrsize, char); - strcpy(s->vstring, protoname); - s->vslen = strlen(protoname); - s->i = 0; - do { - int len; - void *data; - char *nl; - - crMaybeWaitUntilV(bufchain_size(&ssh->incoming_data) > 0); - bufchain_prefix(&ssh->incoming_data, &data, &len); - if ((nl = memchr(data, '\012', len)) != NULL) { - len = nl - (char *)data + 1; - } - - if (s->vslen + len >= s->vstrsize - 1) { - s->vstrsize = (s->vslen + len) * 5 / 4 + 32; - s->vstring = sresize(s->vstring, s->vstrsize, char); - } - - memcpy(s->vstring + s->vslen, data, len); - s->vslen += len; - bufchain_consume(&ssh->incoming_data, len); - - } while (s->vstring[s->vslen-1] != '\012'); - - s->vstring[s->vslen] = 0; - s->vstring[strcspn(s->vstring, "\015\012")] = '\0';/* remove EOL chars */ - - ssh->agentfwd_enabled = FALSE; - - logeventf(ssh, "Server version: %s", s->vstring); - ssh_detect_bugs(ssh, s->vstring); - - /* - * Decide which SSH protocol version to support. This is easy in - * bare ssh-connection mode: only 2.0 is legal. - */ - s->version = dupprintf( - "%.*s", (int)strcspn(s->vstring + strlen(protoname), "-"), - s->vstring + strlen(protoname)); - - if (ssh_versioncmp(s->version, "2.0") < 0) { - bombout(("Server announces compatibility with SSH-1 in bare ssh-connection protocol")); - crStopV; + do_ssh2_connection(ssh); } - if (conf_get_int(ssh->conf, CONF_sshprot) == 0) { - bombout(("Bare ssh-connection protocol cannot be run in SSH-1-only mode")); - crStopV; - } - - ssh->version = 2; - - logeventf(ssh, "Using bare ssh-connection protocol"); - - /* Send the version string, if we haven't already */ - ssh_send_verstring(ssh, protoname, s->version); - - sfree(s->version); - - /* - * Initialise bare connection protocol. - */ - ssh2_bare_connection_protocol_setup(ssh); - ssh->bpp->out_raw = &ssh->outgoing_data; - ssh->bpp->in_raw = &ssh->incoming_data; - ssh->bpp->in_pq = &ssh->pq_full; - ssh->bpp->pls = &ssh->pls; - ssh->bpp->logctx = ssh->logctx; - ssh->current_incoming_data_fn = ssh_feed_to_bpp; - queue_idempotent_callback(&ssh->incoming_data_consumer); - ssh->current_user_input_fn = ssh2_connection_input; - queue_idempotent_callback(&ssh->user_input_consumer); - - update_specials_menu(ssh->frontend); - ssh->state = SSH_STATE_BEFORE_SIZE; - ssh->pinger = pinger_new(ssh->conf, &ssh->backend); - - /* - * Get connection protocol under way. - */ - do_ssh2_connection(ssh); - - sfree(s->vstring); - - crFinishV; } static void ssh_set_frozen(Ssh ssh, int frozen) @@ -1981,7 +1450,7 @@ static void ssh_process_incoming_data(void *ctx) return; if (!ssh->frozen) - ssh->current_incoming_data_fn(ssh); + ssh_feed_to_bpp(ssh); if (ssh->state == SSH_STATE_CLOSED) /* yes, check _again_ */ return; @@ -2317,7 +1786,6 @@ static const char *connect_to_host(Ssh ssh, const char *host, int port, * We are a downstream. */ ssh->bare_connection = TRUE; - ssh->current_incoming_data_fn = do_ssh_connection_init; ssh->fullhostname = NULL; *realhost = dupstr(host); /* best we can do */ @@ -2332,7 +1800,6 @@ static const char *connect_to_host(Ssh ssh, const char *host, int port, /* * We're not a downstream, so open a normal socket. */ - ssh->current_incoming_data_fn = do_ssh_init; /* * Try to find host. @@ -2358,20 +1825,35 @@ static const char *connect_to_host(Ssh ssh, const char *host, int port, /* * The SSH version number is always fixed (since we no longer support - * fallback between versions), so set it now, and if it's SSH-2, - * send the version string now too. + * fallback between versions), so set it now. */ sshprot = conf_get_int(ssh->conf, CONF_sshprot); assert(sshprot == 0 || sshprot == 3); if (sshprot == 0) /* SSH-1 only */ ssh->version = 1; - if (sshprot == 3 && !ssh->bare_connection) { + if (sshprot == 3 || ssh->bare_connection) { /* SSH-2 only */ ssh->version = 2; - ssh_send_verstring(ssh, "SSH-", NULL); } + /* + * Set up the initial BPP that will do the version string + * exchange. + */ + ssh->version_receiver.got_ssh_version = ssh_got_ssh_version; + ssh->bpp = ssh_verstring_new( + ssh->conf, ssh->frontend, ssh->bare_connection, + ssh->version == 1 ? "1.5" : "2.0", &ssh->version_receiver); + ssh->bpp->out_raw = &ssh->outgoing_data; + ssh->bpp->in_raw = &ssh->incoming_data; + /* + * And call its handle_input method right now, in case it wants to + * send the outgoing version string immediately. + */ + ssh_bpp_handle_input(ssh->bpp); + queue_idempotent_callback(&ssh->outgoing_data_sender); + /* * loghost, if configured, overrides realhost. */ diff --git a/sshbpp.h b/sshbpp.h index 6e45262e..a8820cf1 100644 --- a/sshbpp.h +++ b/sshbpp.h @@ -50,4 +50,21 @@ void ssh2_bpp_new_incoming_crypto( BinaryPacketProtocol *ssh2_bare_bpp_new(void); +/* + * The initial code to handle the SSH version exchange is also + * structured as an implementation of BinaryPacketProtocol, because + * that makes it easy to switch from that to the next BPP once it + * tells us which one we're using. + */ +struct ssh_version_receiver { + void (*got_ssh_version)(struct ssh_version_receiver *rcv, + int major_version); +}; +BinaryPacketProtocol *ssh_verstring_new( + Conf *conf, Frontend *frontend, int bare_connection_mode, + const char *protoversion, struct ssh_version_receiver *rcv); +const char *ssh_verstring_get_remote(BinaryPacketProtocol *); +const char *ssh_verstring_get_local(BinaryPacketProtocol *); +int ssh_verstring_get_bugs(BinaryPacketProtocol *); + #endif /* PUTTY_SSHBPP_H */ diff --git a/sshverstring.c b/sshverstring.c new file mode 100644 index 00000000..a9b1e46c --- /dev/null +++ b/sshverstring.c @@ -0,0 +1,602 @@ +/* + * Code to handle the initial SSH version string exchange. + */ + +#include +#include +#include + +#include "putty.h" +#include "ssh.h" +#include "sshbpp.h" +#include "sshcr.h" + +#define PREFIX_MAXLEN 64 + +struct ssh_verstring_state { + int crState; + + Conf *conf; + Frontend *frontend; + ptrlen prefix_wanted; + char *our_protoversion; + struct ssh_version_receiver *receiver; + + int send_early; + + int found_prefix; + int major_protoversion; + int remote_bugs; + char prefix[PREFIX_MAXLEN]; + char *vstring; + int vslen, vstrsize; + char *protoversion; + const char *softwareversion; + + char *our_vstring; + int i; + + BinaryPacketProtocol bpp; +}; + +static void ssh_verstring_free(BinaryPacketProtocol *bpp); +static void ssh_verstring_handle_input(BinaryPacketProtocol *bpp); +static PktOut *ssh_verstring_new_pktout(int type); +static void ssh_verstring_format_packet(BinaryPacketProtocol *bpp, PktOut *); + +const struct BinaryPacketProtocolVtable ssh_verstring_vtable = { + ssh_verstring_free, + ssh_verstring_handle_input, + ssh_verstring_new_pktout, + ssh_verstring_format_packet, +}; + +static void ssh_detect_bugs(struct ssh_verstring_state *s); +static int ssh_version_includes_v1(const char *ver); +static int ssh_version_includes_v2(const char *ver); + +BinaryPacketProtocol *ssh_verstring_new( + Conf *conf, Frontend *frontend, int bare_connection_mode, + const char *protoversion, struct ssh_version_receiver *rcv) +{ + struct ssh_verstring_state *s = snew(struct ssh_verstring_state); + + memset(s, 0, sizeof(struct ssh_verstring_state)); + + if (!bare_connection_mode) { + s->prefix_wanted = PTRLEN_LITERAL("SSH-"); + } else { + /* + * Ordinary SSH begins with the banner "SSH-x.y-...". Here, + * we're going to be speaking just the ssh-connection + * subprotocol, extracted and given a trivial binary packet + * protocol, so we need a new banner. + * + * The new banner is like the ordinary SSH banner, but + * replaces the prefix 'SSH-' at the start with a new name. In + * proper SSH style (though of course this part of the proper + * SSH protocol _isn't_ subject to this kind of + * DNS-domain-based extension), we define the new name in our + * extension space. + */ + s->prefix_wanted = PTRLEN_LITERAL( + "SSHCONNECTION@putty.projects.tartarus.org-"); + } + assert(s->prefix_wanted.len <= PREFIX_MAXLEN); + + s->conf = conf_copy(conf); + s->frontend = frontend; + s->our_protoversion = dupstr(protoversion); + s->receiver = rcv; + + /* + * We send our version string early if we can. But if it includes + * SSH-1, we can't, because we have to take the other end into + * account too (see below). + */ + s->send_early = !ssh_version_includes_v1(protoversion); + + s->bpp.vt = &ssh_verstring_vtable; + return &s->bpp; +} + +void ssh_verstring_free(BinaryPacketProtocol *bpp) +{ + struct ssh_verstring_state *s = + FROMFIELD(bpp, struct ssh_verstring_state, bpp); + conf_free(s->conf); + sfree(s->vstring); + sfree(s->protoversion); + sfree(s->our_vstring); + sfree(s->our_protoversion); + sfree(s); +} + +static int ssh_versioncmp(const char *a, const char *b) +{ + char *ae, *be; + unsigned long av, bv; + + av = strtoul(a, &ae, 10); + bv = strtoul(b, &be, 10); + if (av != bv) + return (av < bv ? -1 : +1); + if (*ae == '.') + ae++; + if (*be == '.') + be++; + av = strtoul(ae, &ae, 10); + bv = strtoul(be, &be, 10); + if (av != bv) + return (av < bv ? -1 : +1); + return 0; +} + +static int ssh_version_includes_v1(const char *ver) +{ + return ssh_versioncmp(ver, "2.0") < 0; +} + +static int ssh_version_includes_v2(const char *ver) +{ + return ssh_versioncmp(ver, "1.99") >= 0; +} + +#define vs_logevent(printf_args) \ + logevent_and_free(s->frontend, dupprintf printf_args) + +static void ssh_verstring_send(struct ssh_verstring_state *s) +{ + char *p; + int sv_pos; + + /* + * Construct our outgoing version string. + */ + s->our_vstring = dupprintf( + "%.*s%s-%s", + (int)s->prefix_wanted.len, (const char *)s->prefix_wanted.ptr, + s->our_protoversion, sshver); + sv_pos = s->prefix_wanted.len + strlen(s->our_protoversion) + 1; + + /* Convert minus signs and spaces in the software version string + * into underscores. */ + for (p = s->our_vstring + sv_pos; *p; p++) { + if (*p == '-' || *p == ' ') + *p = '_'; + } + +#ifdef FUZZING + /* + * Replace the first character of the string with an "I" if we're + * compiling this code for fuzzing - i.e. the protocol prefix + * becomes "ISH-" instead of "SSH-". + * + * This is irrelevant to any real client software (the only thing + * reading the output of PuTTY built for fuzzing is the fuzzer, + * which can adapt to whatever it sees anyway). But it's a safety + * precaution making it difficult to accidentally run such a + * version of PuTTY (which would be hugely insecure) against a + * live peer implementation. + * + * (So the replacement prefix "ISH" notionally stands for + * 'Insecure Shell', of course.) + */ + s->our_vstring[0] = 'I'; +#endif + + /* + * Now send that version string, plus trailing \r\n or just \n + * (the latter in SSH-1 mode). + */ + bufchain_add(s->bpp.out_raw, s->our_vstring, strlen(s->our_vstring)); + if (ssh_version_includes_v2(s->our_protoversion)) + bufchain_add(s->bpp.out_raw, "\015", 1); + bufchain_add(s->bpp.out_raw, "\012", 1); + + vs_logevent(("We claim version: %s", s->our_vstring)); +} + +void ssh_verstring_handle_input(BinaryPacketProtocol *bpp) +{ + struct ssh_verstring_state *s = + FROMFIELD(bpp, struct ssh_verstring_state, bpp); + + crBegin(s->crState); + + /* + * If we're sending our version string up front before seeing the + * other side's, then do it now. + */ + if (s->send_early) + ssh_verstring_send(s); + + /* + * Search for a line beginning with the protocol name prefix in + * the input. + */ + s->i = 0; + while (1) { + /* + * Every time round this loop, we're at the start of a new + * line, so look for the prefix. + */ + crMaybeWaitUntilV(bufchain_size(s->bpp.in_raw) >= + s->prefix_wanted.len); + bufchain_fetch(s->bpp.in_raw, s->prefix, s->prefix_wanted.len); + if (!memcmp(s->prefix, s->prefix_wanted.ptr, s->prefix_wanted.len)) { + bufchain_consume(s->bpp.in_raw, s->prefix_wanted.len); + break; + } + + /* + * If we didn't find it, consume data until we see a newline. + */ + while (1) { + int len; + void *data; + char *nl; + + crMaybeWaitUntilV(bufchain_size(s->bpp.in_raw) > 0); + bufchain_prefix(s->bpp.in_raw, &data, &len); + if ((nl = memchr(data, '\012', len)) != NULL) { + bufchain_consume(s->bpp.in_raw, nl - (char *)data + 1); + break; + } else { + bufchain_consume(s->bpp.in_raw, len); + } + } + } + + s->found_prefix = TRUE; + + /* + * Start a buffer to store the full greeting line. + */ + s->vstrsize = s->prefix_wanted.len + 16; + s->vstring = snewn(s->vstrsize, char); + memcpy(s->vstring, s->prefix_wanted.ptr, s->prefix_wanted.len); + s->vslen = s->prefix_wanted.len; + + /* + * Now read the rest of the greeting line. + */ + s->i = 0; + do { + int len; + void *data; + char *nl; + + crMaybeWaitUntilV(bufchain_size(s->bpp.in_raw) > 0); + bufchain_prefix(s->bpp.in_raw, &data, &len); + if ((nl = memchr(data, '\012', len)) != NULL) { + len = nl - (char *)data + 1; + } + + if (s->vslen + len >= s->vstrsize - 1) { + s->vstrsize = (s->vslen + len) * 5 / 4 + 32; + s->vstring = sresize(s->vstring, s->vstrsize, char); + } + + memcpy(s->vstring + s->vslen, data, len); + s->vslen += len; + bufchain_consume(s->bpp.in_raw, len); + + } while (s->vstring[s->vslen-1] != '\012'); + + /* + * Trim \r and \n from the version string, and replace them with + * a NUL terminator. + */ + while (s->vslen > 0 && + (s->vstring[s->vslen-1] == '\r' || + s->vstring[s->vslen-1] == '\n')) + s->vslen--; + s->vstring[s->vslen] = '\0'; + + vs_logevent(("Remote version: %s", s->vstring)); + + /* + * Pick out the protocol version and software version. The former + * goes in a separately allocated string, so that s->vstring + * remains intact for later use in key exchange; the latter is the + * tail of s->vstring, so it doesn't need to be allocated. + */ + { + const char *pv_start = s->vstring + s->prefix_wanted.len; + int pv_len = strcspn(pv_start, "-"); + s->protoversion = dupprintf("%.*s", pv_len, pv_start); + s->softwareversion = pv_start + pv_len; + if (*s->softwareversion) { + assert(*s->softwareversion == '-'); + s->softwareversion++; + } + } + + ssh_detect_bugs(s); + + /* + * Figure out what actual SSH protocol version we're speaking. + */ + if (ssh_version_includes_v2(s->our_protoversion) && + ssh_version_includes_v2(s->protoversion)) { + /* + * We're doing SSH-2. + */ + s->major_protoversion = 2; + } else if (ssh_version_includes_v1(s->our_protoversion) && + ssh_version_includes_v1(s->protoversion)) { + /* + * We're doing SSH-1. + */ + s->major_protoversion = 1; + + /* + * There are multiple minor versions of SSH-1, and the + * protocol does not specify that the minimum of client + * and server versions is used. So we must adjust our + * outgoing protocol version to be no higher than that of + * the other side. + */ + if (!s->send_early && + ssh_versioncmp(s->our_protoversion, s->protoversion) > 0) { + sfree(s->our_protoversion); + s->our_protoversion = dupstr(s->protoversion); + } + } else { + /* + * Unable to agree on a major protocol version at all. + */ + if (!ssh_version_includes_v2(s->our_protoversion)) { + s->bpp.error = dupstr( + "SSH protocol version 1 required by our configuration " + "but not provided by remote"); + } else { + s->bpp.error = dupstr( + "SSH protocol version 2 required by our configuration " + "but remote only provides (old, insecure) SSH-1"); + } + crStopV; + } + + vs_logevent(("Using SSH protocol version %d", s->major_protoversion)); + + if (!s->send_early) { + /* + * If we didn't send our version string early, construct and + * send it now, because now we know what it is. + */ + ssh_verstring_send(s); + } + + /* + * And we're done. Notify our receiver that we now know our + * protocol version. This will cause it to disconnect us from the + * input stream and ultimately free us, because our job is now + * done. + */ + s->receiver->got_ssh_version(s->receiver, s->major_protoversion); + + crFinishV; +} + +static PktOut *ssh_verstring_new_pktout(int type) +{ + assert(0 && "Should never try to send packets during SSH version " + "string exchange"); + return NULL; +} + +static void ssh_verstring_format_packet(BinaryPacketProtocol *bpp, PktOut *pkg) +{ + assert(0 && "Should never try to send packets during SSH version " + "string exchange"); +} + +/* + * Examine the remote side's version string, and compare it against a + * list of known buggy implementations. + */ +static void ssh_detect_bugs(struct ssh_verstring_state *s) +{ + const char *imp = s->softwareversion; + + s->remote_bugs = 0; + + /* + * General notes on server version strings: + * - Not all servers reporting "Cisco-1.25" have all the bugs listed + * here -- in particular, we've heard of one that's perfectly happy + * with SSH1_MSG_IGNOREs -- but this string never seems to change, + * so we can't distinguish them. + */ + if (conf_get_int(s->conf, CONF_sshbug_ignore1) == FORCE_ON || + (conf_get_int(s->conf, CONF_sshbug_ignore1) == AUTO && + (!strcmp(imp, "1.2.18") || !strcmp(imp, "1.2.19") || + !strcmp(imp, "1.2.20") || !strcmp(imp, "1.2.21") || + !strcmp(imp, "1.2.22") || !strcmp(imp, "Cisco-1.25") || + !strcmp(imp, "OSU_1.4alpha3") || !strcmp(imp, "OSU_1.5alpha4")))) { + /* + * These versions don't support SSH1_MSG_IGNORE, so we have + * to use a different defence against password length + * sniffing. + */ + s->remote_bugs |= BUG_CHOKES_ON_SSH1_IGNORE; + vs_logevent(("We believe remote version has SSH-1 ignore bug")); + } + + if (conf_get_int(s->conf, CONF_sshbug_plainpw1) == FORCE_ON || + (conf_get_int(s->conf, CONF_sshbug_plainpw1) == AUTO && + (!strcmp(imp, "Cisco-1.25") || !strcmp(imp, "OSU_1.4alpha3")))) { + /* + * These versions need a plain password sent; they can't + * handle having a null and a random length of data after + * the password. + */ + s->remote_bugs |= BUG_NEEDS_SSH1_PLAIN_PASSWORD; + vs_logevent(("We believe remote version needs a " + "plain SSH-1 password")); + } + + if (conf_get_int(s->conf, CONF_sshbug_rsa1) == FORCE_ON || + (conf_get_int(s->conf, CONF_sshbug_rsa1) == AUTO && + (!strcmp(imp, "Cisco-1.25")))) { + /* + * These versions apparently have no clue whatever about + * RSA authentication and will panic and die if they see + * an AUTH_RSA message. + */ + s->remote_bugs |= BUG_CHOKES_ON_RSA; + vs_logevent(("We believe remote version can't handle SSH-1 " + "RSA authentication")); + } + + if (conf_get_int(s->conf, CONF_sshbug_hmac2) == FORCE_ON || + (conf_get_int(s->conf, CONF_sshbug_hmac2) == AUTO && + !wc_match("* VShell", imp) && + (wc_match("2.1.0*", imp) || wc_match("2.0.*", imp) || + wc_match("2.2.0*", imp) || wc_match("2.3.0*", imp) || + wc_match("2.1 *", imp)))) { + /* + * These versions have the HMAC bug. + */ + s->remote_bugs |= BUG_SSH2_HMAC; + vs_logevent(("We believe remote version has SSH-2 HMAC bug")); + } + + if (conf_get_int(s->conf, CONF_sshbug_derivekey2) == FORCE_ON || + (conf_get_int(s->conf, CONF_sshbug_derivekey2) == AUTO && + !wc_match("* VShell", imp) && + (wc_match("2.0.0*", imp) || wc_match("2.0.10*", imp) ))) { + /* + * These versions have the key-derivation bug (failing to + * include the literal shared secret in the hashes that + * generate the keys). + */ + s->remote_bugs |= BUG_SSH2_DERIVEKEY; + vs_logevent(("We believe remote version has SSH-2 " + "key-derivation bug")); + } + + if (conf_get_int(s->conf, CONF_sshbug_rsapad2) == FORCE_ON || + (conf_get_int(s->conf, CONF_sshbug_rsapad2) == AUTO && + (wc_match("OpenSSH_2.[5-9]*", imp) || + wc_match("OpenSSH_3.[0-2]*", imp) || + wc_match("mod_sftp/0.[0-8]*", imp) || + wc_match("mod_sftp/0.9.[0-8]", imp)))) { + /* + * These versions have the SSH-2 RSA padding bug. + */ + s->remote_bugs |= BUG_SSH2_RSA_PADDING; + vs_logevent(("We believe remote version has SSH-2 RSA padding bug")); + } + + if (conf_get_int(s->conf, CONF_sshbug_pksessid2) == FORCE_ON || + (conf_get_int(s->conf, CONF_sshbug_pksessid2) == AUTO && + wc_match("OpenSSH_2.[0-2]*", imp))) { + /* + * These versions have the SSH-2 session-ID bug in + * public-key authentication. + */ + s->remote_bugs |= BUG_SSH2_PK_SESSIONID; + vs_logevent(("We believe remote version has SSH-2 " + "public-key-session-ID bug")); + } + + if (conf_get_int(s->conf, CONF_sshbug_rekey2) == FORCE_ON || + (conf_get_int(s->conf, CONF_sshbug_rekey2) == AUTO && + (wc_match("DigiSSH_2.0", imp) || + wc_match("OpenSSH_2.[0-4]*", imp) || + wc_match("OpenSSH_2.5.[0-3]*", imp) || + wc_match("Sun_SSH_1.0", imp) || + wc_match("Sun_SSH_1.0.1", imp) || + /* All versions <= 1.2.6 (they changed their format in 1.2.7) */ + wc_match("WeOnlyDo-*", imp)))) { + /* + * These versions have the SSH-2 rekey bug. + */ + s->remote_bugs |= BUG_SSH2_REKEY; + vs_logevent(("We believe remote version has SSH-2 rekey bug")); + } + + if (conf_get_int(s->conf, CONF_sshbug_maxpkt2) == FORCE_ON || + (conf_get_int(s->conf, CONF_sshbug_maxpkt2) == AUTO && + (wc_match("1.36_sshlib GlobalSCAPE", imp) || + wc_match("1.36 sshlib: GlobalScape", imp)))) { + /* + * This version ignores our makpkt and needs to be throttled. + */ + s->remote_bugs |= BUG_SSH2_MAXPKT; + vs_logevent(("We believe remote version ignores SSH-2 " + "maximum packet size")); + } + + if (conf_get_int(s->conf, CONF_sshbug_ignore2) == FORCE_ON) { + /* + * Servers that don't support SSH2_MSG_IGNORE. Currently, + * none detected automatically. + */ + s->remote_bugs |= BUG_CHOKES_ON_SSH2_IGNORE; + vs_logevent(("We believe remote version has SSH-2 ignore bug")); + } + + if (conf_get_int(s->conf, CONF_sshbug_oldgex2) == FORCE_ON || + (conf_get_int(s->conf, CONF_sshbug_oldgex2) == AUTO && + (wc_match("OpenSSH_2.[235]*", imp)))) { + /* + * These versions only support the original (pre-RFC4419) + * SSH-2 GEX request, and disconnect with a protocol error if + * we use the newer version. + */ + s->remote_bugs |= BUG_SSH2_OLDGEX; + vs_logevent(("We believe remote version has outdated SSH-2 GEX")); + } + + if (conf_get_int(s->conf, CONF_sshbug_winadj) == FORCE_ON) { + /* + * Servers that don't support our winadj request for one + * reason or another. Currently, none detected automatically. + */ + s->remote_bugs |= BUG_CHOKES_ON_WINADJ; + vs_logevent(("We believe remote version has winadj bug")); + } + + if (conf_get_int(s->conf, CONF_sshbug_chanreq) == FORCE_ON || + (conf_get_int(s->conf, CONF_sshbug_chanreq) == AUTO && + (wc_match("OpenSSH_[2-5].*", imp) || + wc_match("OpenSSH_6.[0-6]*", imp) || + wc_match("dropbear_0.[2-4][0-9]*", imp) || + wc_match("dropbear_0.5[01]*", imp)))) { + /* + * These versions have the SSH-2 channel request bug. + * OpenSSH 6.7 and above do not: + * https://bugzilla.mindrot.org/show_bug.cgi?id=1818 + * dropbear_0.52 and above do not: + * https://secure.ucc.asn.au/hg/dropbear/rev/cd02449b709c + */ + s->remote_bugs |= BUG_SENDS_LATE_REQUEST_REPLY; + vs_logevent(("We believe remote version has SSH-2 " + "channel request bug")); + } +} + +const char *ssh_verstring_get_remote(BinaryPacketProtocol *bpp) +{ + struct ssh_verstring_state *s = + FROMFIELD(bpp, struct ssh_verstring_state, bpp); + return s->vstring; +} + +const char *ssh_verstring_get_local(BinaryPacketProtocol *bpp) +{ + struct ssh_verstring_state *s = + FROMFIELD(bpp, struct ssh_verstring_state, bpp); + return s->our_vstring; +} + +int ssh_verstring_get_bugs(BinaryPacketProtocol *bpp) +{ + struct ssh_verstring_state *s = + FROMFIELD(bpp, struct ssh_verstring_state, bpp); + return s->remote_bugs; +} From 63a14f26f78097c3ee5aa8ea8160efbe3c62b5cd Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Wed, 19 Sep 2018 18:22:36 +0100 Subject: [PATCH 418/607] Rework handling of untrusted terminal data. Now there's a centralised routine in misc.c to do the sanitisation, which copies data on to an outgoing bufchain. This allows me to remove from_backend_untrusted() completely from the frontend API, simplifying code in several places. Two use cases for untrusted-terminal-data sanitisation were in the terminal.c prompts handler, and in the collection of SSH-2 userauth banners. Both of those were writing output to a bufchain anyway, so it was very convenient to just replace a bufchain_add with sanitise_term_data and then not have to worry about it again. There was also a simplistic sanitiser in uxcons.c, which I've now replaced with a call to the good one - and in wincons.c there was a FIXME saying I ought to get round to that, which now I have! --- misc.c | 27 +++++++++++++++++++++++++++ misc.h | 2 ++ pscp.c | 9 --------- psftp.c | 9 --------- putty.h | 2 -- ssh.c | 16 ++++++---------- terminal.c | 29 ++++++++++------------------- unix/gtkwin.c | 5 ----- unix/uxcons.c | 15 ++++++++++----- unix/uxplink.c | 10 ---------- windows/wincons.c | 12 ++++++++++-- windows/window.c | 5 ----- windows/winplink.c | 10 ---------- 13 files changed, 65 insertions(+), 86 deletions(-) diff --git a/misc.c b/misc.c index 1a528923..42a4a228 100644 --- a/misc.c +++ b/misc.c @@ -826,6 +826,33 @@ int bufchain_try_fetch_consume(bufchain *ch, void *data, int len) } } +/* ---------------------------------------------------------------------- + * Sanitise terminal output that we have reason not to trust, e.g. + * because it appears in the login banner or password prompt from a + * server, which we'd rather not permit to use arbitrary escape + * sequences. + */ + +void sanitise_term_data(bufchain *out, const void *vdata, int len) +{ + const char *data = (const char *)vdata; + int i; + + /* + * FIXME: this method of sanitisation is ASCII-centric. It would + * be nice to permit SSH banners and the like to contain printable + * Unicode, but that would need a lot more complicated code here + * (not to mention knowing what character set it should interpret + * the data as). + */ + for (i = 0; i < len; i++) { + if (data[i] == '\n') + bufchain_add(out, "\r\n", 2); + else if (data[i] >= ' ' && data[i] < 0x7F) + bufchain_add(out, data + i, 1); + } +} + /* ---------------------------------------------------------------------- * My own versions of malloc, realloc and free. Because I want * malloc and realloc to bomb out and exit the program if they run diff --git a/misc.h b/misc.h index 4e0d8b2d..b63df049 100644 --- a/misc.h +++ b/misc.h @@ -90,6 +90,8 @@ void bufchain_fetch(bufchain *ch, void *data, int len); void bufchain_fetch_consume(bufchain *ch, void *data, int len); int bufchain_try_fetch_consume(bufchain *ch, void *data, int len); +void sanitise_term_data(bufchain *out, const void *vdata, int len); + int validate_manual_hostkey(char *key); struct tm ltime(void); diff --git a/pscp.c b/pscp.c index 594f119f..67029f94 100644 --- a/pscp.c +++ b/pscp.c @@ -196,15 +196,6 @@ int from_backend(Frontend *frontend, int is_stderr, return 0; } -int from_backend_untrusted(Frontend *frontend, const void *data, int len) -{ - /* - * No "untrusted" output should get here (the way the code is - * currently, it's all diverted by FLAG_STDERR). - */ - assert(!"Unexpected call to from_backend_untrusted()"); - return 0; /* not reached */ -} int from_backend_eof(Frontend *frontend) { /* diff --git a/psftp.c b/psftp.c index d57b118e..4eb4068d 100644 --- a/psftp.c +++ b/psftp.c @@ -2551,15 +2551,6 @@ int from_backend(Frontend *frontend, int is_stderr, return 0; } -int from_backend_untrusted(Frontend *frontend, const void *data, int len) -{ - /* - * No "untrusted" output should get here (the way the code is - * currently, it's all diverted by FLAG_STDERR). - */ - assert(!"Unexpected call to from_backend_untrusted()"); - return 0; /* not reached */ -} int from_backend_eof(Frontend *frontend) { /* diff --git a/putty.h b/putty.h index dd43e8c4..5bb7974f 100644 --- a/putty.h +++ b/putty.h @@ -712,7 +712,6 @@ void frontend_echoedit_update(Frontend *frontend, int echo, int edit); * shutdown. */ void update_specials_menu(Frontend *frontend); int from_backend(Frontend *frontend, int is_stderr, const void *data, int len); -int from_backend_untrusted(Frontend *frontend, const void *data, int len); /* Called when the back end wants to indicate that EOF has arrived on * the server-to-client stream. Returns FALSE to indicate that we * intend to keep the session open in the other direction, or TRUE to @@ -1130,7 +1129,6 @@ void term_request_copy(Terminal *, const int *clipboards, int n_clipboards); void term_request_paste(Terminal *, int clipboard); void term_seen_key_event(Terminal *); int term_data(Terminal *, int is_stderr, const void *data, int len); -int term_data_untrusted(Terminal *, const void *data, int len); void term_provide_backend(Terminal *term, Backend *backend); void term_provide_logctx(Terminal *term, LogContext *logctx); void term_set_focus(Terminal *term, int has_focus); diff --git a/ssh.c b/ssh.c index 9ac60d27..c8365cae 100644 --- a/ssh.c +++ b/ssh.c @@ -1078,14 +1078,6 @@ static void c_write(Ssh ssh, const void *buf, int len) from_backend(ssh->frontend, 1, buf, len); } -static void c_write_untrusted(Ssh ssh, const void *buf, int len) -{ - if (flags & FLAG_STDERR) - c_write_stderr(0, buf, len); - else - from_backend_untrusted(ssh->frontend, buf, len); -} - static void c_write_str(Ssh ssh, const char *buf) { c_write(ssh, buf, strlen(buf)); @@ -7066,7 +7058,7 @@ static void ssh2_msg_userauth_banner(Ssh ssh, PktIn *pktin) bufchain_size(&ssh->banner) <= 131072) { ptrlen banner = get_string(pktin); if (banner.len) - bufchain_add(&ssh->banner, banner.ptr, banner.len); + sanitise_term_data(&ssh->banner, banner.ptr, banner.len); } } @@ -7679,11 +7671,15 @@ static void do_ssh2_userauth(void *vctx) * banner _anyway_, and moreover the printing of * the banner will screw up processing on the * output of (say) plink.) + * + * The banner data has been sanitised already by this + * point, so we can safely send it straight to the + * output channel. */ if (size && (flags & (FLAG_VERBOSE | FLAG_INTERACTIVE))) { char *banner = snewn(size, char); bufchain_fetch(&ssh->banner, banner, size); - c_write_untrusted(ssh, banner, size); + c_write(ssh, banner, size); sfree(banner); } bufchain_clear(&ssh->banner); diff --git a/terminal.c b/terminal.c index a8bd6fc7..621d81de 100644 --- a/terminal.c +++ b/terminal.c @@ -6624,10 +6624,8 @@ int term_ldisc(Terminal *term, int option) return FALSE; } -int term_data(Terminal *term, int is_stderr, const void *data, int len) +static void term_added_data(Terminal *term) { - bufchain_add(&term->inbuf, data, len); - if (!term->in_term_out) { term->in_term_out = TRUE; term_reset_cblink(term); @@ -6640,6 +6638,12 @@ int term_data(Terminal *term, int is_stderr, const void *data, int len) term_out(term); term->in_term_out = FALSE; } +} + +int term_data(Terminal *term, int is_stderr, const void *data, int len) +{ + bufchain_add(&term->inbuf, data, len); + term_added_data(term); /* * term_out() always completely empties inbuf. Therefore, @@ -6663,23 +6667,10 @@ int term_data(Terminal *term, int is_stderr, const void *data, int len) return 0; } -/* - * Write untrusted data to the terminal. - * The only control character that should be honoured is \n (which - * will behave as a CRLF). - */ -int term_data_untrusted(Terminal *term, const void *vdata, int len) +static void term_data_untrusted(Terminal *term, const void *data, int len) { - const char *data = (const char *)vdata; - int i; - /* FIXME: more sophisticated checking? */ - for (i = 0; i < len; i++) { - if (data[i] == '\n') - term_data(term, 1, "\r\n", 2); - else if (data[i] & 0x60) - term_data(term, 1, data + i, 1); - } - return 0; /* assumes that term_data() always returns 0 */ + sanitise_term_data(&term->inbuf, data, len); + term_added_data(term); } void term_provide_logctx(Terminal *term, LogContext *logctx) diff --git a/unix/gtkwin.c b/unix/gtkwin.c index 46b62782..eb3f201f 100644 --- a/unix/gtkwin.c +++ b/unix/gtkwin.c @@ -305,11 +305,6 @@ int from_backend(Frontend *inst, int is_stderr, const void *data, int len) return term_data(inst->term, is_stderr, data, len); } -int from_backend_untrusted(Frontend *inst, const void *data, int len) -{ - return term_data_untrusted(inst->term, data, len); -} - int from_backend_eof(Frontend *inst) { return TRUE; /* do respond to incoming EOF with outgoing */ diff --git a/unix/uxcons.c b/unix/uxcons.c index b4fecce1..cf3603a4 100644 --- a/unix/uxcons.c +++ b/unix/uxcons.c @@ -448,11 +448,16 @@ static void console_close(FILE *outfp, int infd) static void console_prompt_text(FILE *outfp, const char *data, int len) { - int i; - - for (i = 0; i < len; i++) - if ((data[i] & 0x60) || (data[i] == '\n')) - fputc(data[i], outfp); + bufchain sanitised; + void *vdata; + + bufchain_init(&sanitised); + sanitise_term_data(&sanitised, data, len); + while (bufchain_size(&sanitised) > 0) { + bufchain_prefix(&sanitised, &vdata, &len); + fwrite(vdata, 1, len, outfp); + bufchain_consume(&sanitised, len); + } fflush(outfp); } diff --git a/unix/uxplink.c b/unix/uxplink.c index 56bdf533..b058dcd0 100644 --- a/unix/uxplink.c +++ b/unix/uxplink.c @@ -413,16 +413,6 @@ int from_backend(Frontend *frontend, int is_stderr, } } -int from_backend_untrusted(Frontend *frontend, const void *data, int len) -{ - /* - * No "untrusted" output should get here (the way the code is - * currently, it's all diverted by FLAG_STDERR). - */ - assert(!"Unexpected call to from_backend_untrusted()"); - return 0; /* not reached */ -} - int from_backend_eof(Frontend *frontend) { assert(outgoingeof == EOF_NO); diff --git a/windows/wincons.c b/windows/wincons.c index 10367be8..34ed6a30 100644 --- a/windows/wincons.c +++ b/windows/wincons.c @@ -348,8 +348,16 @@ void logevent(Frontend *frontend, const char *string) static void console_data_untrusted(HANDLE hout, const char *data, int len) { DWORD dummy; - /* FIXME: control-character filtering */ - WriteFile(hout, data, len, &dummy, NULL); + bufchain sanitised; + void *vdata; + + bufchain_init(&sanitised); + sanitise_term_data(&sanitised, data, len); + while (bufchain_size(&sanitised) > 0) { + bufchain_prefix(&sanitised, &vdata, &len); + WriteFile(hout, vdata, len, &dummy, NULL); + bufchain_consume(&sanitised, len); + } } int console_get_userpass_input(prompts_t *p) diff --git a/windows/window.c b/windows/window.c index eb0f5e01..b73de782 100644 --- a/windows/window.c +++ b/windows/window.c @@ -5922,11 +5922,6 @@ int from_backend(Frontend *frontend, int is_stderr, const void *data, int len) return term_data(term, is_stderr, data, len); } -int from_backend_untrusted(Frontend *frontend, const void *data, int len) -{ - return term_data_untrusted(term, data, len); -} - int from_backend_eof(Frontend *frontend) { return TRUE; /* do respond to incoming EOF with outgoing */ diff --git a/windows/winplink.c b/windows/winplink.c index c156d740..c647a65a 100644 --- a/windows/winplink.c +++ b/windows/winplink.c @@ -114,16 +114,6 @@ int from_backend(Frontend *frontend, int is_stderr, return handle_backlog(stdout_handle) + handle_backlog(stderr_handle); } -int from_backend_untrusted(Frontend *frontend, const void *data, int len) -{ - /* - * No "untrusted" output should get here (the way the code is - * currently, it's all diverted by FLAG_STDERR). - */ - assert(!"Unexpected call to from_backend_untrusted()"); - return 0; /* not reached */ -} - int from_backend_eof(Frontend *frontend) { handle_write_eof(stdout_handle); From 6e24b7d5898b1f3d9b5a1e4f0eb71632d182bb9c Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Wed, 19 Sep 2018 21:56:11 +0100 Subject: [PATCH 419/607] Extend PacketQueue to take PktOut as well. Some upcoming restructuring I've got planned will need to pass output packets back and forth on queues, as well as input ones. So here's a change that arranges that we can have a PktInQueue and a PktOutQueue, sharing most of their implementation via a PacketQueueBase structure which links together the PacketQueueNode fields in the two packet structures. There's a tricksy bit of macro manoeuvring to get all of this type-checked, so that I can't accidentally link a PktOut on to a PktInQueue or vice versa. It works by having the main queue functions wrapped by macros; when receiving a packet structure on input, they type-check it against the queue structure and then automatically look up its qnode field to pass to the underlying PacketQueueBase function; on output, they translate a returned PacketQueueNode back to its containing packet type by calling a 'get' function pointer. --- ssh.c | 146 ++++++++++++++++++++++++++++--------------------------- ssh.h | 46 ++++++++++++++---- sshbpp.h | 2 +- 3 files changed, 111 insertions(+), 83 deletions(-) diff --git a/ssh.c b/ssh.c index c8365cae..b38a281b 100644 --- a/ssh.c +++ b/ssh.c @@ -547,61 +547,83 @@ static PktOut *ssh2_gss_authpacket(Ssh ssh, Ssh_gss_ctx gss_ctx, #endif static void ssh2_msg_unexpected(Ssh ssh, PktIn *pktin); -void pq_init(struct PacketQueue *pq) +void pq_base_push(PacketQueueBase *pqb, PacketQueueNode *node) { - pq->end.next = pq->end.prev = &pq->end; -} - -void pq_push(struct PacketQueue *pq, PktIn *pkt) -{ - PacketQueueNode *node = &pkt->qnode; assert(!node->next); assert(!node->prev); - node->next = &pq->end; - node->prev = pq->end.prev; + node->next = &pqb->end; + node->prev = pqb->end.prev; node->next->prev = node; node->prev->next = node; } -void pq_push_front(struct PacketQueue *pq, PktIn *pkt) +void pq_base_push_front(PacketQueueBase *pqb, PacketQueueNode *node) { - PacketQueueNode *node = &pkt->qnode; assert(!node->next); assert(!node->prev); - node->prev = &pq->end; - node->next = pq->end.next; + node->prev = &pqb->end; + node->next = pqb->end.next; node->next->prev = node; node->prev->next = node; } -PktIn *pq_peek(struct PacketQueue *pq) +static PktIn *pq_in_get(PacketQueueBase *pqb, int pop) { - if (pq->end.next == &pq->end) + PacketQueueNode *node = pqb->end.next; + if (node == &pqb->end) return NULL; - return FROMFIELD(pq->end.next, PktIn, qnode); + + if (pop) { + node->next->prev = node->prev; + node->prev->next = node->next; + node->prev = node->next = NULL; + } + + return FROMFIELD(node, PktIn, qnode); } -PktIn *pq_pop(struct PacketQueue *pq) +static PktOut *pq_out_get(PacketQueueBase *pqb, int pop) { - PacketQueueNode *node = pq->end.next; - if (node == &pq->end) + PacketQueueNode *node = pqb->end.next; + if (node == &pqb->end) return NULL; - node->next->prev = node->prev; - node->prev->next = node->next; - node->prev = node->next = NULL; + if (pop) { + node->next->prev = node->prev; + node->prev->next = node->next; + node->prev = node->next = NULL; + } + + return FROMFIELD(node, PktOut, qnode); +} - return FROMFIELD(node, PktIn, qnode); +void pq_in_init(PktInQueue *pq) +{ + pq->pqb.end.next = pq->pqb.end.prev = &pq->pqb.end; + pq->get = pq_in_get; } -void pq_clear(struct PacketQueue *pq) +void pq_out_init(PktOutQueue *pq) +{ + pq->pqb.end.next = pq->pqb.end.prev = &pq->pqb.end; + pq->get = pq_out_get; +} + +void pq_in_clear(PktInQueue *pq) { PktIn *pkt; while ((pkt = pq_pop(pq)) != NULL) ssh_unref_packet(pkt); } -int pq_empty_on_to_front_of(struct PacketQueue *src, struct PacketQueue *dest) +void pq_out_clear(PktOutQueue *pq) +{ + PktOut *pkt; + while ((pkt = pq_pop(pq)) != NULL) + ssh_free_pktout(pkt); +} + +int pq_base_empty_on_to_front_of(PacketQueueBase *src, PacketQueueBase *dest) { struct PacketQueueNode *srcfirst, *srclast; @@ -727,8 +749,7 @@ struct ssh_tag { int sent_console_eof; int got_pty; /* affects EOF behaviour on main channel */ - PktOut **queue; - int queuelen, queuesize; + PktOutQueue outq; int queueing; /* @@ -765,22 +786,22 @@ struct ssh_tag { int incoming_data_seen_eof; char *incoming_data_eof_message; - struct PacketQueue pq_full; + PktInQueue pq_full; struct IdempotentCallback pq_full_consumer; - struct PacketQueue pq_ssh1_login; + PktInQueue pq_ssh1_login; struct IdempotentCallback ssh1_login_icb; - struct PacketQueue pq_ssh1_connection; + PktInQueue pq_ssh1_connection; struct IdempotentCallback ssh1_connection_icb; - struct PacketQueue pq_ssh2_transport; + PktInQueue pq_ssh2_transport; struct IdempotentCallback ssh2_transport_icb; - struct PacketQueue pq_ssh2_userauth; + PktInQueue pq_ssh2_userauth; struct IdempotentCallback ssh2_userauth_icb; - struct PacketQueue pq_ssh2_connection; + PktInQueue pq_ssh2_connection; struct IdempotentCallback ssh2_connection_icb; bufchain user_input; @@ -1165,21 +1186,6 @@ static void ssh_pkt_BinarySink_write(BinarySink *bs, ssh_pkt_adddata(pkt, data, len); } -/* - * Queue an SSH-2 packet. - */ -static void ssh2_pkt_queue(Ssh ssh, PktOut *pkt) -{ - assert(ssh->queueing); - - if (ssh->queuelen >= ssh->queuesize) { - ssh->queuesize = ssh->queuelen + 32; - ssh->queue = sresize(ssh->queue, ssh->queuesize, PktOut *); - } - - ssh->queue[ssh->queuelen++] = pkt; -} - /* * Either queue or send a packet, depending on whether queueing is * set. @@ -1187,7 +1193,7 @@ static void ssh2_pkt_queue(Ssh ssh, PktOut *pkt) static void ssh2_pkt_send(Ssh ssh, PktOut *pkt) { if (ssh->queueing) { - ssh2_pkt_queue(ssh, pkt); + pq_push(&ssh->outq, pkt); } else { ssh_pkt_write(ssh, pkt); } @@ -1226,13 +1232,12 @@ static void ssh_send_outgoing_data(void *ctx) */ static void ssh2_pkt_queuesend(Ssh ssh) { - int i; + PktOut *pkt; assert(!ssh->queueing); - for (i = 0; i < ssh->queuelen; i++) - ssh_pkt_write(ssh, ssh->queue[i]); - ssh->queuelen = 0; + while ((pkt = pq_pop(&ssh->outq)) != NULL) + ssh_pkt_write(ssh, pkt); } #if 0 @@ -1320,7 +1325,7 @@ static void ssh2_add_sigblob(Ssh ssh, PktOut *pkt, static void ssh_feed_to_bpp(Ssh ssh) { - PacketQueueNode *prev_tail = ssh->pq_full.end.prev; + PacketQueueNode *prev_tail = ssh->pq_full.pqb.end.prev; assert(ssh->bpp); ssh_bpp_handle_input(ssh->bpp); @@ -1344,7 +1349,7 @@ static void ssh_feed_to_bpp(Ssh ssh) ssh->disconnect_message_seen = TRUE; } - if (ssh->pq_full.end.prev != prev_tail) + if (ssh->pq_full.pqb.end.prev != prev_tail) queue_idempotent_callback(&ssh->pq_full_consumer); } @@ -9731,27 +9736,27 @@ static const char *ssh_init(Frontend *frontend, Backend **backend_handle, ssh->incoming_data_consumer.fn = ssh_process_incoming_data; ssh->incoming_data_consumer.ctx = ssh; ssh->incoming_data_consumer.queued = FALSE; - pq_init(&ssh->pq_full); + pq_in_init(&ssh->pq_full); ssh->pq_full_consumer.fn = ssh_process_pq_full; ssh->pq_full_consumer.ctx = ssh; ssh->pq_full_consumer.queued = FALSE; - pq_init(&ssh->pq_ssh1_login); + pq_in_init(&ssh->pq_ssh1_login); ssh->ssh1_login_icb.fn = do_ssh1_login; ssh->ssh1_login_icb.ctx = ssh; ssh->ssh1_login_icb.queued = FALSE; - pq_init(&ssh->pq_ssh1_connection); + pq_in_init(&ssh->pq_ssh1_connection); ssh->ssh1_connection_icb.fn = do_ssh1_connection; ssh->ssh1_connection_icb.ctx = ssh; ssh->ssh1_connection_icb.queued = FALSE; - pq_init(&ssh->pq_ssh2_transport); + pq_in_init(&ssh->pq_ssh2_transport); ssh->ssh2_transport_icb.fn = do_ssh2_transport; ssh->ssh2_transport_icb.ctx = ssh; ssh->ssh2_transport_icb.queued = FALSE; - pq_init(&ssh->pq_ssh2_userauth); + pq_in_init(&ssh->pq_ssh2_userauth); ssh->ssh2_userauth_icb.fn = do_ssh2_userauth; ssh->ssh2_userauth_icb.ctx = ssh; ssh->ssh2_userauth_icb.queued = FALSE; - pq_init(&ssh->pq_ssh2_connection); + pq_in_init(&ssh->pq_ssh2_connection); ssh->ssh2_connection_icb.fn = do_ssh2_connection; ssh->ssh2_connection_icb.ctx = ssh; ssh->ssh2_connection_icb.queued = FALSE; @@ -9771,8 +9776,7 @@ static const char *ssh_init(Frontend *frontend, Backend **backend_handle, ssh->mainchan = NULL; ssh->throttled_all = 0; ssh->v1_stdout_throttling = 0; - ssh->queue = NULL; - ssh->queuelen = ssh->queuesize = 0; + pq_out_init(&ssh->outq); ssh->queueing = FALSE; ssh->qhead = ssh->qtail = NULL; ssh->deferred_rekey_reason = NULL; @@ -9862,9 +9866,7 @@ static void ssh_free(Backend *be) dh_cleanup(ssh->dh_ctx); sfree(ssh->savedhost); - while (ssh->queuelen-- > 0) - ssh_free_pktout(ssh->queue[ssh->queuelen]); - sfree(ssh->queue); + pq_out_clear(&ssh->outq); while (ssh->qhead) { struct queued_handler *qh = ssh->qhead; @@ -9920,12 +9922,12 @@ static void ssh_free(Backend *be) bufchain_clear(&ssh->incoming_data); bufchain_clear(&ssh->outgoing_data); sfree(ssh->incoming_data_eof_message); - pq_clear(&ssh->pq_full); - pq_clear(&ssh->pq_ssh1_login); - pq_clear(&ssh->pq_ssh1_connection); - pq_clear(&ssh->pq_ssh2_transport); - pq_clear(&ssh->pq_ssh2_userauth); - pq_clear(&ssh->pq_ssh2_connection); + pq_in_clear(&ssh->pq_full); + pq_in_clear(&ssh->pq_ssh1_login); + pq_in_clear(&ssh->pq_ssh1_connection); + pq_in_clear(&ssh->pq_ssh2_transport); + pq_in_clear(&ssh->pq_ssh2_userauth); + pq_in_clear(&ssh->pq_ssh2_connection); bufchain_clear(&ssh->user_input); sfree(ssh->v_c); sfree(ssh->v_s); diff --git a/ssh.h b/ssh.h index 7dbd31fe..7ed45101 100644 --- a/ssh.h +++ b/ssh.h @@ -81,20 +81,46 @@ typedef struct PktOut { unsigned downstream_id; const char *additional_log_text; + PacketQueueNode qnode; /* for linking this packet on to a queue */ BinarySink_IMPLEMENTATION; } PktOut; -typedef struct PacketQueue { +typedef struct PacketQueueBase { PacketQueueNode end; -} PacketQueue; - -void pq_init(struct PacketQueue *pq); -void pq_push(struct PacketQueue *pq, PktIn *pkt); -void pq_push_front(struct PacketQueue *pq, PktIn *pkt); -PktIn *pq_peek(struct PacketQueue *pq); -PktIn *pq_pop(struct PacketQueue *pq); -void pq_clear(struct PacketQueue *pq); -int pq_empty_on_to_front_of(struct PacketQueue *src, struct PacketQueue *dest); +} PacketQueueBase; + +typedef struct PktInQueue { + PacketQueueBase pqb; + PktIn *(*get)(PacketQueueBase *, int pop); +} PktInQueue; + +typedef struct PktOutQueue { + PacketQueueBase pqb; + PktOut *(*get)(PacketQueueBase *, int pop); +} PktOutQueue; + +void pq_base_init(PacketQueueBase *pqb); +void pq_base_push(PacketQueueBase *pqb, PacketQueueNode *node); +void pq_base_push_front(PacketQueueBase *pqb, PacketQueueNode *node); +int pq_base_empty_on_to_front_of(PacketQueueBase *src, PacketQueueBase *dest); + +void pq_in_init(PktInQueue *pq); +void pq_out_init(PktOutQueue *pq); +void pq_in_clear(PktInQueue *pq); +void pq_out_clear(PktOutQueue *pq); + +#define pq_push(pq, pkt) \ + TYPECHECK((pq)->get(&(pq)->pqb, FALSE) == pkt, \ + pq_base_push(&(pq)->pqb, &(pkt)->qnode)) +#define pq_push_front(pq, pkt) \ + TYPECHECK((pq)->get(&(pq)->pqb, FALSE) == pkt, \ + pq_base_push_front(&(pq)->pqb, &(pkt)->qnode)) +#define pq_peek(pq) ((pq)->get(&(pq)->pqb, FALSE)) +#define pq_pop(pq) ((pq)->get(&(pq)->pqb, TRUE)) +#define pq_empty_on_to_front_of(src, dst) \ + TYPECHECK((src)->get(&(src)->pqb, FALSE) == \ + (dst)->get(&(dst)->pqb, FALSE), \ + pq_base_empty_on_to_front_of(&(src)->pqb, &(dst)->pqb)) /* * Packet type contexts, so that ssh2_pkt_type can correctly decode diff --git a/sshbpp.h b/sshbpp.h index a8820cf1..953add3a 100644 --- a/sshbpp.h +++ b/sshbpp.h @@ -17,7 +17,7 @@ struct BinaryPacketProtocolVtable { struct BinaryPacketProtocol { const struct BinaryPacketProtocolVtable *vt; bufchain *in_raw, *out_raw; - PacketQueue *in_pq; + PktInQueue *in_pq; PacketLogSettings *pls; LogContext *logctx; From 242c074646b250682a5d41540ab91e67b02757a5 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Wed, 19 Sep 2018 21:56:44 +0100 Subject: [PATCH 420/607] Move low-level functions out into sshcommon.c. These are essentially data-structure maintenance, and it seems silly to have them be part of the same file that manages the topmost structure of the SSH connection. --- Recipe | 2 +- ssh.c | 148 ----------------------------------------------- sshcommon.c | 161 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 162 insertions(+), 149 deletions(-) create mode 100644 sshcommon.c diff --git a/Recipe b/Recipe index a2728c08..87fc0b67 100644 --- a/Recipe +++ b/Recipe @@ -250,7 +250,7 @@ GTKMAIN = gtkmain cmdline NONSSH = telnet raw rlogin ldisc pinger # SSH back end (putty, plink, pscp, psftp). -SSH = ssh ssh1bpp ssh2bpp ssh2bpp-bare ssh1censor ssh2censor +SSH = ssh sshcommon ssh1bpp ssh2bpp ssh2bpp-bare ssh1censor ssh2censor + sshverstring sshcrc sshdes sshmd5 sshrsa sshrand sshsha sshblowf + sshdh sshcrcda sshpubk sshzlib sshdss x11fwd portfwd + sshaes sshccp sshsh256 sshsh512 sshbn wildcard pinger ssharcf diff --git a/ssh.c b/ssh.c index b38a281b..c73218eb 100644 --- a/ssh.c +++ b/ssh.c @@ -278,8 +278,6 @@ enum { PKT_END, PKT_INT, PKT_CHAR, PKT_DATA, PKT_STR, PKT_BIGNUM, }; -static void ssh_pkt_ensure(struct PktOut *, int length); -static void ssh_pkt_adddata(struct PktOut *, const void *data, int len); static void ssh2_pkt_send(Ssh, struct PktOut *); static void do_ssh1_login(void *vctx); static void do_ssh2_userauth(void *vctx); @@ -547,100 +545,6 @@ static PktOut *ssh2_gss_authpacket(Ssh ssh, Ssh_gss_ctx gss_ctx, #endif static void ssh2_msg_unexpected(Ssh ssh, PktIn *pktin); -void pq_base_push(PacketQueueBase *pqb, PacketQueueNode *node) -{ - assert(!node->next); - assert(!node->prev); - node->next = &pqb->end; - node->prev = pqb->end.prev; - node->next->prev = node; - node->prev->next = node; -} - -void pq_base_push_front(PacketQueueBase *pqb, PacketQueueNode *node) -{ - assert(!node->next); - assert(!node->prev); - node->prev = &pqb->end; - node->next = pqb->end.next; - node->next->prev = node; - node->prev->next = node; -} - -static PktIn *pq_in_get(PacketQueueBase *pqb, int pop) -{ - PacketQueueNode *node = pqb->end.next; - if (node == &pqb->end) - return NULL; - - if (pop) { - node->next->prev = node->prev; - node->prev->next = node->next; - node->prev = node->next = NULL; - } - - return FROMFIELD(node, PktIn, qnode); -} - -static PktOut *pq_out_get(PacketQueueBase *pqb, int pop) -{ - PacketQueueNode *node = pqb->end.next; - if (node == &pqb->end) - return NULL; - - if (pop) { - node->next->prev = node->prev; - node->prev->next = node->next; - node->prev = node->next = NULL; - } - - return FROMFIELD(node, PktOut, qnode); -} - -void pq_in_init(PktInQueue *pq) -{ - pq->pqb.end.next = pq->pqb.end.prev = &pq->pqb.end; - pq->get = pq_in_get; -} - -void pq_out_init(PktOutQueue *pq) -{ - pq->pqb.end.next = pq->pqb.end.prev = &pq->pqb.end; - pq->get = pq_out_get; -} - -void pq_in_clear(PktInQueue *pq) -{ - PktIn *pkt; - while ((pkt = pq_pop(pq)) != NULL) - ssh_unref_packet(pkt); -} - -void pq_out_clear(PktOutQueue *pq) -{ - PktOut *pkt; - while ((pkt = pq_pop(pq)) != NULL) - ssh_free_pktout(pkt); -} - -int pq_base_empty_on_to_front_of(PacketQueueBase *src, PacketQueueBase *dest) -{ - struct PacketQueueNode *srcfirst, *srclast; - - if (src->end.next == &src->end) - return FALSE; - - srcfirst = src->end.next; - srclast = src->end.prev; - srcfirst->prev = &dest->end; - srclast->next = dest->end.next; - srcfirst->prev->next = srcfirst; - srclast->next->prev = srclast; - src->end.next = src->end.prev = &src->end; - - return TRUE; -} - struct queued_handler; struct queued_handler { int msg1, msg2; @@ -1104,34 +1008,6 @@ static void c_write_str(Ssh ssh, const char *buf) c_write(ssh, buf, strlen(buf)); } -void ssh_unref_packet(PktIn *pkt) -{ - if (--pkt->refcount <= 0) - sfree(pkt); -} - -void ssh_free_pktout(PktOut *pkt) -{ - sfree(pkt->data); - sfree(pkt); -} - -static void ssh_pkt_BinarySink_write(BinarySink *bs, - const void *data, size_t len); -PktOut *ssh_new_packet(void) -{ - PktOut *pkt = snew(PktOut); - - BinarySink_INIT(pkt, ssh_pkt_BinarySink_write); - pkt->data = NULL; - pkt->length = 0; - pkt->maxlen = 0; - pkt->downstream_id = 0; - pkt->additional_log_text = NULL; - - return pkt; -} - static int s_write(Ssh ssh, const void *data, int len) { if (len && ssh->logctx) @@ -1162,30 +1038,6 @@ static void ssh_pkt_write(Ssh ssh, PktOut *pkt) queue_idempotent_callback(&ssh->outgoing_data_sender); } -/* - * Packet construction functions. Mostly shared between SSH-1 and SSH-2. - */ -static void ssh_pkt_ensure(PktOut *pkt, int length) -{ - if (pkt->maxlen < length) { - pkt->maxlen = length + 256; - pkt->data = sresize(pkt->data, pkt->maxlen, unsigned char); - } -} -static void ssh_pkt_adddata(PktOut *pkt, const void *data, int len) -{ - pkt->length += len; - ssh_pkt_ensure(pkt, pkt->length); - memcpy(pkt->data + pkt->length - len, data, len); -} - -static void ssh_pkt_BinarySink_write(BinarySink *bs, - const void *data, size_t len) -{ - PktOut *pkt = BinarySink_DOWNCAST(bs, PktOut); - ssh_pkt_adddata(pkt, data, len); -} - /* * Either queue or send a packet, depending on whether queueing is * set. diff --git a/sshcommon.c b/sshcommon.c new file mode 100644 index 00000000..7af086fe --- /dev/null +++ b/sshcommon.c @@ -0,0 +1,161 @@ +/* + * Supporting routines used in common by all the various components of + * the SSH system. + */ + +#include + +#include "ssh.h" +#include "sshchan.h" + +/* ---------------------------------------------------------------------- + * Implementation of PacketQueue. + */ + +void pq_base_push(PacketQueueBase *pqb, PacketQueueNode *node) +{ + assert(!node->next); + assert(!node->prev); + node->next = &pqb->end; + node->prev = pqb->end.prev; + node->next->prev = node; + node->prev->next = node; +} + +void pq_base_push_front(PacketQueueBase *pqb, PacketQueueNode *node) +{ + assert(!node->next); + assert(!node->prev); + node->prev = &pqb->end; + node->next = pqb->end.next; + node->next->prev = node; + node->prev->next = node; +} + +static PktIn *pq_in_get(PacketQueueBase *pqb, int pop) +{ + PacketQueueNode *node = pqb->end.next; + if (node == &pqb->end) + return NULL; + + if (pop) { + node->next->prev = node->prev; + node->prev->next = node->next; + node->prev = node->next = NULL; + } + + return FROMFIELD(node, PktIn, qnode); +} + +static PktOut *pq_out_get(PacketQueueBase *pqb, int pop) +{ + PacketQueueNode *node = pqb->end.next; + if (node == &pqb->end) + return NULL; + + if (pop) { + node->next->prev = node->prev; + node->prev->next = node->next; + node->prev = node->next = NULL; + } + + return FROMFIELD(node, PktOut, qnode); +} + +void pq_in_init(PktInQueue *pq) +{ + pq->pqb.end.next = pq->pqb.end.prev = &pq->pqb.end; + pq->get = pq_in_get; +} + +void pq_out_init(PktOutQueue *pq) +{ + pq->pqb.end.next = pq->pqb.end.prev = &pq->pqb.end; + pq->get = pq_out_get; +} + +void pq_in_clear(PktInQueue *pq) +{ + PktIn *pkt; + while ((pkt = pq_pop(pq)) != NULL) + ssh_unref_packet(pkt); +} + +void pq_out_clear(PktOutQueue *pq) +{ + PktOut *pkt; + while ((pkt = pq_pop(pq)) != NULL) + ssh_free_pktout(pkt); +} + +int pq_base_empty_on_to_front_of(PacketQueueBase *src, PacketQueueBase *dest) +{ + struct PacketQueueNode *srcfirst, *srclast; + + if (src->end.next == &src->end) + return FALSE; + + srcfirst = src->end.next; + srclast = src->end.prev; + srcfirst->prev = &dest->end; + srclast->next = dest->end.next; + srcfirst->prev->next = srcfirst; + srclast->next->prev = srclast; + src->end.next = src->end.prev = &src->end; + + return TRUE; +} + +/* ---------------------------------------------------------------------- + * Low-level functions for the packet structures themselves. + */ + +static void ssh_pkt_BinarySink_write(BinarySink *bs, + const void *data, size_t len); +PktOut *ssh_new_packet(void) +{ + PktOut *pkt = snew(PktOut); + + BinarySink_INIT(pkt, ssh_pkt_BinarySink_write); + pkt->data = NULL; + pkt->length = 0; + pkt->maxlen = 0; + pkt->downstream_id = 0; + pkt->additional_log_text = NULL; + pkt->qnode.next = pkt->qnode.prev = NULL; + + return pkt; +} + +static void ssh_pkt_ensure(PktOut *pkt, int length) +{ + if (pkt->maxlen < length) { + pkt->maxlen = length + 256; + pkt->data = sresize(pkt->data, pkt->maxlen, unsigned char); + } +} +static void ssh_pkt_adddata(PktOut *pkt, const void *data, int len) +{ + pkt->length += len; + ssh_pkt_ensure(pkt, pkt->length); + memcpy(pkt->data + pkt->length - len, data, len); +} + +static void ssh_pkt_BinarySink_write(BinarySink *bs, + const void *data, size_t len) +{ + PktOut *pkt = BinarySink_DOWNCAST(bs, PktOut); + ssh_pkt_adddata(pkt, data, len); +} + +void ssh_unref_packet(PktIn *pkt) +{ + if (--pkt->refcount <= 0) + sfree(pkt); +} + +void ssh_free_pktout(PktOut *pkt) +{ + sfree(pkt->data); + sfree(pkt); +} From 04226693e3cbaf412cacf879073627158d807a1d Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Wed, 19 Sep 2018 20:52:12 +0100 Subject: [PATCH 421/607] Get rid of ssh_set_frozen. We used it to suppress reading from the network at every point during protocol setup where PuTTY was waiting for a user response to a dialog box (e.g. a host key warning). The purpose of this was to avoid dropping an important packet while the coroutine was listening to one of its other input parameters (as it were). But now everything is queue-based, packets will stay queued until we're ready to look at them anyway; so it's better _not_ to freeze the connection, so that messages we _can_ handle in between (e.g. SSH_MSG_DEBUG or SSH_MSG_IGNORE) can still be processed. That dispenses with all uses of ssh_set_frozen except for its use by ssh_throttle_conn to exert back-pressure on the server in SSH1 which doesn't have per-channel windows. So I've moved that last use _into_ ssh_throttle_conn, and now the function is completely gone. --- ssh.c | 36 ++++++++++++------------------------ 1 file changed, 12 insertions(+), 24 deletions(-) diff --git a/ssh.c b/ssh.c index c73218eb..f5cf7142 100644 --- a/ssh.c +++ b/ssh.c @@ -1284,13 +1284,6 @@ static void ssh_got_ssh_version(struct ssh_version_receiver *rcv, } } -static void ssh_set_frozen(Ssh ssh, int frozen) -{ - if (ssh->s) - sk_set_frozen(ssh->s, frozen); - ssh->frozen = frozen; -} - static void ssh_process_incoming_data(void *ctx) { Ssh ssh = (Ssh)ctx; @@ -1720,13 +1713,23 @@ static const char *connect_to_host(Ssh ssh, const char *host, int port, static void ssh_throttle_conn(Ssh ssh, int adjust) { int old_count = ssh->conn_throttle_count; + int frozen; + ssh->conn_throttle_count += adjust; assert(ssh->conn_throttle_count >= 0); + if (ssh->conn_throttle_count && !old_count) { - ssh_set_frozen(ssh, 1); + frozen = TRUE; } else if (!ssh->conn_throttle_count && old_count) { - ssh_set_frozen(ssh, 0); + frozen = FALSE; + } else { + return; /* don't change current frozen state */ } + + ssh->frozen = frozen; + + if (ssh->s) + sk_set_frozen(ssh->s, frozen); } static void ssh_channel_check_throttle(struct ssh_channel *c) @@ -2025,7 +2028,6 @@ static void do_ssh1_login(void *vctx) sfree(keystr); crStopV; } else if (s->dlgret < 0) { /* none configured; use standard handling */ - ssh_set_frozen(ssh, 1); s->dlgret = verify_ssh_host_key(ssh->frontend, ssh->savedhost, ssh->savedport, "rsa", keystr, fingerprint, @@ -2039,7 +2041,6 @@ static void do_ssh1_login(void *vctx) crWaitUntilV(ssh->user_response >= 0); s->dlgret = ssh->user_response; } - ssh_set_frozen(ssh, 0); if (s->dlgret == 0) { ssh_disconnect(ssh, "User aborted at host key verification", @@ -2111,7 +2112,6 @@ static void do_ssh1_login(void *vctx) /* Warn about chosen cipher if necessary. */ if (warn) { - ssh_set_frozen(ssh, 1); s->dlgret = askalg(ssh->frontend, "cipher", cipher_string, ssh_dialog_callback, ssh); if (s->dlgret < 0) { @@ -2119,7 +2119,6 @@ static void do_ssh1_login(void *vctx) crWaitUntilV(ssh->user_response >= 0); s->dlgret = ssh->user_response; } - ssh_set_frozen(ssh, 0); if (s->dlgret == 0) { ssh_disconnect(ssh, "User aborted at cipher warning", NULL, 0, TRUE); @@ -4625,7 +4624,6 @@ static void do_ssh2_transport(void *vctx) BinarySource_UPCAST(pktin)->len + 1); if (s->warn_kex) { - ssh_set_frozen(ssh, 1); s->dlgret = askalg(ssh->frontend, "key-exchange algorithm", ssh->kex->name, ssh_dialog_callback, ssh); @@ -4634,7 +4632,6 @@ static void do_ssh2_transport(void *vctx) crWaitUntilV(ssh->user_response >= 0); s->dlgret = ssh->user_response; } - ssh_set_frozen(ssh, 0); if (s->dlgret == 0) { ssh_disconnect(ssh, "User aborted at kex warning", NULL, 0, TRUE); @@ -4646,8 +4643,6 @@ static void do_ssh2_transport(void *vctx) int j, k; char *betteralgs; - ssh_set_frozen(ssh, 1); - /* * Change warning box wording depending on why we chose a * warning-level host key algorithm. If it's because @@ -4695,7 +4690,6 @@ static void do_ssh2_transport(void *vctx) crWaitUntilV(ssh->user_response >= 0); s->dlgret = ssh->user_response; } - ssh_set_frozen(ssh, 0); if (s->dlgret == 0) { ssh_disconnect(ssh, "User aborted at host key warning", NULL, 0, TRUE); @@ -4704,7 +4698,6 @@ static void do_ssh2_transport(void *vctx) } if (s->warn_cscipher) { - ssh_set_frozen(ssh, 1); s->dlgret = askalg(ssh->frontend, "client-to-server cipher", s->out.cipher->name, @@ -4714,7 +4707,6 @@ static void do_ssh2_transport(void *vctx) crWaitUntilV(ssh->user_response >= 0); s->dlgret = ssh->user_response; } - ssh_set_frozen(ssh, 0); if (s->dlgret == 0) { ssh_disconnect(ssh, "User aborted at cipher warning", NULL, 0, TRUE); @@ -4723,7 +4715,6 @@ static void do_ssh2_transport(void *vctx) } if (s->warn_sccipher) { - ssh_set_frozen(ssh, 1); s->dlgret = askalg(ssh->frontend, "server-to-client cipher", s->in.cipher->name, @@ -4733,7 +4724,6 @@ static void do_ssh2_transport(void *vctx) crWaitUntilV(ssh->user_response >= 0); s->dlgret = ssh->user_response; } - ssh_set_frozen(ssh, 0); if (s->dlgret == 0) { ssh_disconnect(ssh, "User aborted at cipher warning", NULL, 0, TRUE); @@ -5498,7 +5488,6 @@ static void do_ssh2_transport(void *vctx) bombout(("Host key did not appear in manually configured list")); crStopV; } else if (s->dlgret < 0) { /* none configured; use standard handling */ - ssh_set_frozen(ssh, 1); s->dlgret = verify_ssh_host_key(ssh->frontend, ssh->savedhost, ssh->savedport, ssh_key_cache_id(s->hkey), @@ -5512,7 +5501,6 @@ static void do_ssh2_transport(void *vctx) crWaitUntilV(ssh->user_response >= 0); s->dlgret = ssh->user_response; } - ssh_set_frozen(ssh, 0); if (s->dlgret == 0) { ssh_disconnect(ssh, "Aborted at host key verification", NULL, 0, TRUE); From 6a5d4d083abc6245b6d36e3d223a4404d30c1dff Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Wed, 19 Sep 2018 20:30:40 +0100 Subject: [PATCH 422/607] Make pq_empty_on_to_front_of more general. It's really just a concatenator for a pair of linked lists, but unhelpfully restricted in which of the lists it replaces with the output. Better to have a three-argument function that puts the output wherever you like, whether it overlaps either or neither one of the inputs. --- ssh.c | 4 ++- ssh.h | 11 +++++--- sshcommon.c | 74 ++++++++++++++++++++++++++++++++++++++++++----------- 3 files changed, 69 insertions(+), 20 deletions(-) diff --git a/ssh.c b/ssh.c index f5cf7142..2749f23f 100644 --- a/ssh.c +++ b/ssh.c @@ -8846,8 +8846,10 @@ static void do_ssh2_connection(void *vctx) * matches any of the table entries we've just modified will go to * the right handler function, and won't come here to confuse us. */ - if (pq_empty_on_to_front_of(&ssh->pq_ssh2_connection, &ssh->pq_full)) + if (pq_peek(&ssh->pq_ssh2_connection)) { + pq_concatenate(&ssh->pq_full, &ssh->pq_ssh2_connection, &ssh->pq_full); queue_idempotent_callback(&ssh->pq_full_consumer); + } /* * Now the connection protocol is properly up and running, with diff --git a/ssh.h b/ssh.h index 7ed45101..f4ef94ef 100644 --- a/ssh.h +++ b/ssh.h @@ -102,7 +102,8 @@ typedef struct PktOutQueue { void pq_base_init(PacketQueueBase *pqb); void pq_base_push(PacketQueueBase *pqb, PacketQueueNode *node); void pq_base_push_front(PacketQueueBase *pqb, PacketQueueNode *node); -int pq_base_empty_on_to_front_of(PacketQueueBase *src, PacketQueueBase *dest); +void pq_base_concatenate(PacketQueueBase *dest, + PacketQueueBase *q1, PacketQueueBase *q2); void pq_in_init(PktInQueue *pq); void pq_out_init(PktOutQueue *pq); @@ -117,10 +118,12 @@ void pq_out_clear(PktOutQueue *pq); pq_base_push_front(&(pq)->pqb, &(pkt)->qnode)) #define pq_peek(pq) ((pq)->get(&(pq)->pqb, FALSE)) #define pq_pop(pq) ((pq)->get(&(pq)->pqb, TRUE)) -#define pq_empty_on_to_front_of(src, dst) \ - TYPECHECK((src)->get(&(src)->pqb, FALSE) == \ +#define pq_concatenate(dst, q1, q2) \ + TYPECHECK((q1)->get(&(q1)->pqb, FALSE) == \ + (dst)->get(&(dst)->pqb, FALSE) && \ + (q2)->get(&(q2)->pqb, FALSE) == \ (dst)->get(&(dst)->pqb, FALSE), \ - pq_base_empty_on_to_front_of(&(src)->pqb, &(dst)->pqb)) + pq_base_concatenate(&(dst)->pqb, &(q1)->pqb, &(q2)->pqb)) /* * Packet type contexts, so that ssh2_pkt_type can correctly decode diff --git a/sshcommon.c b/sshcommon.c index 7af086fe..856a8358 100644 --- a/sshcommon.c +++ b/sshcommon.c @@ -88,22 +88,66 @@ void pq_out_clear(PktOutQueue *pq) ssh_free_pktout(pkt); } -int pq_base_empty_on_to_front_of(PacketQueueBase *src, PacketQueueBase *dest) +/* + * Concatenate the contents of the two queues q1 and q2, and leave the + * result in qdest. qdest must be either empty, or one of the input + * queues. + */ +void pq_base_concatenate(PacketQueueBase *qdest, + PacketQueueBase *q1, PacketQueueBase *q2) { - struct PacketQueueNode *srcfirst, *srclast; - - if (src->end.next == &src->end) - return FALSE; - - srcfirst = src->end.next; - srclast = src->end.prev; - srcfirst->prev = &dest->end; - srclast->next = dest->end.next; - srcfirst->prev->next = srcfirst; - srclast->next->prev = srclast; - src->end.next = src->end.prev = &src->end; - - return TRUE; + struct PacketQueueNode *head1, *tail1, *head2, *tail2; + + /* + * Extract the contents from both input queues, and empty them. + */ + + head1 = (q1->end.next == &q1->end ? NULL : q1->end.next); + tail1 = (q1->end.prev == &q1->end ? NULL : q1->end.prev); + head2 = (q2->end.next == &q2->end ? NULL : q2->end.next); + tail2 = (q2->end.prev == &q2->end ? NULL : q2->end.prev); + + q1->end.next = q1->end.prev = &q1->end; + q2->end.next = q2->end.prev = &q2->end; + + /* + * Link the two lists together, handling the case where one or + * both is empty. + */ + + if (tail1) + tail1->next = head2; + else + head1 = head2; + + if (head2) + head2->prev = tail1; + else + tail2 = head1; + + /* + * Check the destination queue is currently empty. (If it was one + * of the input queues, then it will be, because we emptied both + * of those just a moment ago.) + */ + + assert(qdest->end.next == &qdest->end); + assert(qdest->end.prev == &qdest->end); + + /* + * If our concatenated list has anything in it, then put it in + * dest. + */ + + if (!head1) { + assert(!tail2); + } else { + assert(tail2); + qdest->end.next = head1; + qdest->end.prev = tail2; + head1->prev = &qdest->end; + tail2->next = &qdest->end; + } } /* ---------------------------------------------------------------------- From 64f95e633469844b86f4d62c03ae991c4b64ffee Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Wed, 19 Sep 2018 20:31:19 +0100 Subject: [PATCH 423/607] Move the zombiechan implementation into sshcommon.c. It doesn't really have to be in ssh.c sharing that file's internal data structures; it's as much an independent object implementation as any of the less trivial Channel instances. So it's another thing we can get out of that too-large source file. --- ssh.c | 67 ----------------------------------------------------- sshchan.h | 12 ++++++++++ sshcommon.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 76 insertions(+), 67 deletions(-) diff --git a/ssh.c b/ssh.c index 2749f23f..17e9075d 100644 --- a/ssh.c +++ b/ssh.c @@ -1357,73 +1357,6 @@ int chan_no_eager_close(Channel *chan, int sent_local_eof, int rcvd_remote_eof) return FALSE; /* default: never proactively ask for a close */ } -/* - * Trivial channel vtable for handling 'zombie channels' - those whose - * local source of data has already been shut down or otherwise - * stopped existing - so that we don't have to give them a null - * 'Channel *' and special-case that all over the place. - */ - -static void zombiechan_free(Channel *chan); -static int zombiechan_send(Channel *chan, int is_stderr, const void *, int); -static void zombiechan_set_input_wanted(Channel *chan, int wanted); -static void zombiechan_do_nothing(Channel *chan); -static void zombiechan_open_failure(Channel *chan, const char *); -static int zombiechan_want_close(Channel *chan, int sent_eof, int rcvd_eof); -static char *zombiechan_log_close_msg(Channel *chan) { return NULL; } - -static const struct ChannelVtable zombiechan_channelvt = { - zombiechan_free, - zombiechan_do_nothing, /* open_confirmation */ - zombiechan_open_failure, - zombiechan_send, - zombiechan_do_nothing, /* send_eof */ - zombiechan_set_input_wanted, - zombiechan_log_close_msg, - zombiechan_want_close, -}; - -Channel *zombiechan_new(void) -{ - Channel *chan = snew(Channel); - chan->vt = &zombiechan_channelvt; - chan->initial_fixed_window_size = 0; - return chan; -} - -static void zombiechan_free(Channel *chan) -{ - assert(chan->vt == &zombiechan_channelvt); - sfree(chan); -} - -static void zombiechan_do_nothing(Channel *chan) -{ - assert(chan->vt == &zombiechan_channelvt); -} - -static void zombiechan_open_failure(Channel *chan, const char *errtext) -{ - assert(chan->vt == &zombiechan_channelvt); -} - -static int zombiechan_send(Channel *chan, int is_stderr, - const void *data, int length) -{ - assert(chan->vt == &zombiechan_channelvt); - return 0; -} - -static void zombiechan_set_input_wanted(Channel *chan, int enable) -{ - assert(chan->vt == &zombiechan_channelvt); -} - -static int zombiechan_want_close(Channel *chan, int sent_eof, int rcvd_eof) -{ - return TRUE; -} - static int ssh_do_close(Ssh ssh, int notify_exit) { int ret = 0; diff --git a/sshchan.h b/sshchan.h index 271cdb09..e2bc28b0 100644 --- a/sshchan.h +++ b/sshchan.h @@ -56,6 +56,18 @@ void chan_remotely_opened_failure(Channel *chan, const char *errtext); * closing until both directions have had an EOF */ int chan_no_eager_close(Channel *, int, int); +/* + * Constructor for a trivial do-nothing implementation of + * ChannelVtable. Used for 'zombie' channels, i.e. channels whose + * proper local source of data has been shut down or otherwise stopped + * existing, but the SSH side is still there and needs some kind of a + * Channel implementation to talk to. In particular, the want_close + * method for this channel always returns 'yes, please close this + * channel asap', regardless of whether local and/or remote EOF have + * been sent - indeed, even if _neither_ has. + */ +Channel *zombiechan_new(void); + /* ---------------------------------------------------------------------- * This structure is owned by an SSH connection layer, and identifies * the connection layer's end of the channel, for the Channel diff --git a/sshcommon.c b/sshcommon.c index 856a8358..8bab9beb 100644 --- a/sshcommon.c +++ b/sshcommon.c @@ -203,3 +203,67 @@ void ssh_free_pktout(PktOut *pkt) sfree(pkt->data); sfree(pkt); } +/* ---------------------------------------------------------------------- + * Implement zombiechan_new() and its trivial vtable. + */ + +static void zombiechan_free(Channel *chan); +static int zombiechan_send(Channel *chan, int is_stderr, const void *, int); +static void zombiechan_set_input_wanted(Channel *chan, int wanted); +static void zombiechan_do_nothing(Channel *chan); +static void zombiechan_open_failure(Channel *chan, const char *); +static int zombiechan_want_close(Channel *chan, int sent_eof, int rcvd_eof); +static char *zombiechan_log_close_msg(Channel *chan) { return NULL; } + +static const struct ChannelVtable zombiechan_channelvt = { + zombiechan_free, + zombiechan_do_nothing, /* open_confirmation */ + zombiechan_open_failure, + zombiechan_send, + zombiechan_do_nothing, /* send_eof */ + zombiechan_set_input_wanted, + zombiechan_log_close_msg, + zombiechan_want_close, +}; + +Channel *zombiechan_new(void) +{ + Channel *chan = snew(Channel); + chan->vt = &zombiechan_channelvt; + chan->initial_fixed_window_size = 0; + return chan; +} + +static void zombiechan_free(Channel *chan) +{ + assert(chan->vt == &zombiechan_channelvt); + sfree(chan); +} + +static void zombiechan_do_nothing(Channel *chan) +{ + assert(chan->vt == &zombiechan_channelvt); +} + +static void zombiechan_open_failure(Channel *chan, const char *errtext) +{ + assert(chan->vt == &zombiechan_channelvt); +} + +static int zombiechan_send(Channel *chan, int is_stderr, + const void *data, int length) +{ + assert(chan->vt == &zombiechan_channelvt); + return 0; +} + +static void zombiechan_set_input_wanted(Channel *chan, int enable) +{ + assert(chan->vt == &zombiechan_channelvt); +} + +static int zombiechan_want_close(Channel *chan, int sent_eof, int rcvd_eof) +{ + return TRUE; +} + From 783f03d5ede052ad03c5311974e532609a0a7fa3 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Wed, 19 Sep 2018 20:32:27 +0100 Subject: [PATCH 424/607] Move the default Channel methods into sshcommon.c. Those don't need any of ssh.c's internal facilities either. --- ssh.c | 15 --------------- sshcommon.c | 19 +++++++++++++++++++ 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/ssh.c b/ssh.c index 17e9075d..7a2b26fa 100644 --- a/ssh.c +++ b/ssh.c @@ -1342,21 +1342,6 @@ static void ssh_process_user_input(void *ctx) ssh->current_user_input_fn(ssh); } -void chan_remotely_opened_confirmation(Channel *chan) -{ - assert(0 && "this channel type should never receive OPEN_CONFIRMATION"); -} - -void chan_remotely_opened_failure(Channel *chan, const char *errtext) -{ - assert(0 && "this channel type should never receive OPEN_FAILURE"); -} - -int chan_no_eager_close(Channel *chan, int sent_local_eof, int rcvd_remote_eof) -{ - return FALSE; /* default: never proactively ask for a close */ -} - static int ssh_do_close(Ssh ssh, int notify_exit) { int ret = 0; diff --git a/sshcommon.c b/sshcommon.c index 8bab9beb..ec471544 100644 --- a/sshcommon.c +++ b/sshcommon.c @@ -267,3 +267,22 @@ static int zombiechan_want_close(Channel *chan, int sent_eof, int rcvd_eof) return TRUE; } +/* ---------------------------------------------------------------------- + * Centralised standard methods for other channel implementations to + * borrow. + */ + +void chan_remotely_opened_confirmation(Channel *chan) +{ + assert(0 && "this channel type should never receive OPEN_CONFIRMATION"); +} + +void chan_remotely_opened_failure(Channel *chan, const char *errtext) +{ + assert(0 && "this channel type should never receive OPEN_FAILURE"); +} + +int chan_no_eager_close(Channel *chan, int sent_local_eof, int rcvd_remote_eof) +{ + return FALSE; /* default: never proactively ask for a close */ +} From 12abb953945f19b4aab6ca56dde0d2acd1c692c7 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Wed, 19 Sep 2018 20:36:40 +0100 Subject: [PATCH 425/607] Move the ttymode formatter into sshcommon.c. While I'm at it, I've brought it all into a single function: the parsing of data from Conf, the list of modes, and even the old callback system for writing to the destination buffer is now a simple if statement that formats mode parameters as byte or uint32 depending on SSH version. Also, the terminal speeds and the end byte are part of the same setup, so it's all together in one place instead of scattered all over ssh.c. --- ssh.c | 190 ++-------------------------------------------------- ssh.h | 5 ++ sshcommon.c | 180 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 191 insertions(+), 184 deletions(-) diff --git a/ssh.c b/ssh.c index 7a2b26fa..3d91a672 100644 --- a/ssh.c +++ b/ssh.c @@ -50,111 +50,6 @@ static const char *const ssh2_disconnect_reasons[] = { #define DH_MIN_SIZE 1024 #define DH_MAX_SIZE 8192 -/* - * Codes for terminal modes. - * Most of these are the same in SSH-1 and SSH-2. - * This list is derived from RFC 4254 and - * SSH-1 RFC-1.2.31. - */ -static const struct ssh_ttymode { - const char* const mode; - int opcode; - enum { TTY_OP_CHAR, TTY_OP_BOOL } type; -} ssh_ttymodes[] = { - /* "V" prefix discarded for special characters relative to SSH specs */ - { "INTR", 1, TTY_OP_CHAR }, - { "QUIT", 2, TTY_OP_CHAR }, - { "ERASE", 3, TTY_OP_CHAR }, - { "KILL", 4, TTY_OP_CHAR }, - { "EOF", 5, TTY_OP_CHAR }, - { "EOL", 6, TTY_OP_CHAR }, - { "EOL2", 7, TTY_OP_CHAR }, - { "START", 8, TTY_OP_CHAR }, - { "STOP", 9, TTY_OP_CHAR }, - { "SUSP", 10, TTY_OP_CHAR }, - { "DSUSP", 11, TTY_OP_CHAR }, - { "REPRINT", 12, TTY_OP_CHAR }, - { "WERASE", 13, TTY_OP_CHAR }, - { "LNEXT", 14, TTY_OP_CHAR }, - { "FLUSH", 15, TTY_OP_CHAR }, - { "SWTCH", 16, TTY_OP_CHAR }, - { "STATUS", 17, TTY_OP_CHAR }, - { "DISCARD", 18, TTY_OP_CHAR }, - { "IGNPAR", 30, TTY_OP_BOOL }, - { "PARMRK", 31, TTY_OP_BOOL }, - { "INPCK", 32, TTY_OP_BOOL }, - { "ISTRIP", 33, TTY_OP_BOOL }, - { "INLCR", 34, TTY_OP_BOOL }, - { "IGNCR", 35, TTY_OP_BOOL }, - { "ICRNL", 36, TTY_OP_BOOL }, - { "IUCLC", 37, TTY_OP_BOOL }, - { "IXON", 38, TTY_OP_BOOL }, - { "IXANY", 39, TTY_OP_BOOL }, - { "IXOFF", 40, TTY_OP_BOOL }, - { "IMAXBEL", 41, TTY_OP_BOOL }, - { "IUTF8", 42, TTY_OP_BOOL }, - { "ISIG", 50, TTY_OP_BOOL }, - { "ICANON", 51, TTY_OP_BOOL }, - { "XCASE", 52, TTY_OP_BOOL }, - { "ECHO", 53, TTY_OP_BOOL }, - { "ECHOE", 54, TTY_OP_BOOL }, - { "ECHOK", 55, TTY_OP_BOOL }, - { "ECHONL", 56, TTY_OP_BOOL }, - { "NOFLSH", 57, TTY_OP_BOOL }, - { "TOSTOP", 58, TTY_OP_BOOL }, - { "IEXTEN", 59, TTY_OP_BOOL }, - { "ECHOCTL", 60, TTY_OP_BOOL }, - { "ECHOKE", 61, TTY_OP_BOOL }, - { "PENDIN", 62, TTY_OP_BOOL }, /* XXX is this a real mode? */ - { "OPOST", 70, TTY_OP_BOOL }, - { "OLCUC", 71, TTY_OP_BOOL }, - { "ONLCR", 72, TTY_OP_BOOL }, - { "OCRNL", 73, TTY_OP_BOOL }, - { "ONOCR", 74, TTY_OP_BOOL }, - { "ONLRET", 75, TTY_OP_BOOL }, - { "CS7", 90, TTY_OP_BOOL }, - { "CS8", 91, TTY_OP_BOOL }, - { "PARENB", 92, TTY_OP_BOOL }, - { "PARODD", 93, TTY_OP_BOOL } -}; - -/* Miscellaneous other tty-related constants. */ -#define SSH_TTY_OP_END 0 -/* The opcodes for ISPEED/OSPEED differ between SSH-1 and SSH-2. */ -#define SSH1_TTY_OP_ISPEED 192 -#define SSH1_TTY_OP_OSPEED 193 -#define SSH2_TTY_OP_ISPEED 128 -#define SSH2_TTY_OP_OSPEED 129 - -/* Helper functions for parsing tty-related config. */ -static unsigned int ssh_tty_parse_specchar(char *s) -{ - unsigned int ret; - if (*s) { - char *next = NULL; - ret = ctrlparse(s, &next); - if (!next) ret = s[0]; - } else { - ret = 255; /* special value meaning "don't set" */ - } - return ret; -} -static unsigned int ssh_tty_parse_boolean(char *s) -{ - if (stricmp(s, "yes") == 0 || - stricmp(s, "on") == 0 || - stricmp(s, "true") == 0 || - stricmp(s, "+") == 0) - return 1; /* true */ - else if (stricmp(s, "no") == 0 || - stricmp(s, "off") == 0 || - stricmp(s, "false") == 0 || - stricmp(s, "-") == 0) - return 0; /* false */ - else - return (atoi(s) != 0); -} - /* Safely convert rekey_time to unsigned long minutes */ static unsigned long rekey_mins(int rekey_time, unsigned long def) { @@ -870,41 +765,6 @@ static void bomb_out(Ssh ssh, char *text) #define bombout(msg) bomb_out(ssh, dupprintf msg) -/* Helper function for common bits of parsing ttymodes. */ -static void parse_ttymodes( - BinarySink *bs, Ssh ssh, - void (*do_mode)(BinarySink *, const struct ssh_ttymode *, char *)) -{ - int i; - const struct ssh_ttymode *mode; - char *val; - - for (i = 0; i < lenof(ssh_ttymodes); i++) { - mode = ssh_ttymodes + i; - /* Every mode known to the current version of the code should be - * mentioned; this was ensured when settings were loaded. */ - val = conf_get_str_str(ssh->conf, CONF_ttymodes, mode->mode); - - /* - * val[0] can be - * - 'V', indicating that an explicit value follows it; - * - 'A', indicating that we should pass the value through from - * the local environment via get_ttymode; or - * - 'N', indicating that we should explicitly not send this - * mode. - */ - if (val[0] == 'A') { - val = get_ttymode(ssh->frontend, mode->mode); - if (val) { - do_mode(bs, mode, val); - sfree(val); - } - } else if (val[0] == 'V') { - do_mode(bs, mode, val + 1); /* skip the 'V' */ - } /* else 'N', or something from the future we don't understand */ - } -} - static int ssh_channelcmp(void *av, void *bv) { struct ssh_channel *a = (struct ssh_channel *) av; @@ -3363,22 +3223,6 @@ static void ssh1_smsg_exit_status(Ssh ssh, PktIn *pktin) ssh_disconnect(ssh, NULL, NULL, 0, TRUE); } -/* Helper function to deal with sending tty modes for REQUEST_PTY */ -static void ssh1_send_ttymode(BinarySink *bs, - const struct ssh_ttymode *mode, char *val) -{ - put_byte(bs, mode->opcode); - - switch (mode->type) { - case TTY_OP_CHAR: - put_byte(bs, ssh_tty_parse_specchar(val)); - break; - case TTY_OP_BOOL: - put_byte(bs, ssh_tty_parse_boolean(val)); - break; - } -} - static int (ssh_agent_forwarding_permitted)(ConnectionLayer *cl) { Ssh ssh = FROMFIELD(cl, struct ssh_tag, cl); @@ -3478,12 +3322,9 @@ static void do_ssh1_connection(void *vctx) put_uint32(pkt, ssh->term_width); put_uint32(pkt, 0); /* width in pixels */ put_uint32(pkt, 0); /* height in pixels */ - parse_ttymodes(BinarySink_UPCAST(pkt), ssh, ssh1_send_ttymode); - put_byte(pkt, SSH1_TTY_OP_ISPEED); - put_uint32(pkt, ssh->ispeed); - put_byte(pkt, SSH1_TTY_OP_OSPEED); - put_uint32(pkt, ssh->ospeed); - put_byte(pkt, SSH_TTY_OP_END); + write_ttymodes_to_packet_from_conf( + BinarySink_UPCAST(pkt), ssh->frontend, ssh->conf, + 1, ssh->ospeed, ssh->ispeed); ssh_pkt_write(ssh, pkt); ssh->state = SSH_STATE_INTERMED; crMaybeWaitUntilV((pktin = pq_pop(&ssh->pq_ssh1_connection)) != NULL); @@ -6825,22 +6666,6 @@ static void ssh2_msg_userauth_banner(Ssh ssh, PktIn *pktin) } } -/* Helper function to deal with sending tty modes for "pty-req" */ -static void ssh2_send_ttymode(BinarySink *bs, - const struct ssh_ttymode *mode, char *val) -{ - put_byte(bs, mode->opcode); - - switch (mode->type) { - case TTY_OP_CHAR: - put_uint32(bs, ssh_tty_parse_specchar(val)); - break; - case TTY_OP_BOOL: - put_uint32(bs, ssh_tty_parse_boolean(val)); - break; - } -} - static void ssh2_setup_x11(struct ssh_channel *c, PktIn *pktin, void *ctx) { @@ -6935,12 +6760,9 @@ static void ssh2_setup_pty(struct ssh_channel *c, PktIn *pktin, put_uint32(pktout, 0); /* pixel height */ { strbuf *modebuf = strbuf_new(); - parse_ttymodes(BinarySink_UPCAST(modebuf), ssh, ssh2_send_ttymode); - put_byte(modebuf, SSH2_TTY_OP_ISPEED); - put_uint32(modebuf, ssh->ispeed); - put_byte(modebuf, SSH2_TTY_OP_OSPEED); - put_uint32(modebuf, ssh->ospeed); - put_byte(modebuf, SSH_TTY_OP_END); + write_ttymodes_to_packet_from_conf( + BinarySink_UPCAST(modebuf), ssh->frontend, ssh->conf, + 2, ssh->ospeed, ssh->ispeed); put_stringsb(pktout, modebuf); } ssh2_pkt_send(ssh, pktout); diff --git a/ssh.h b/ssh.h index f4ef94ef..bfeb20df 100644 --- a/ssh.h +++ b/ssh.h @@ -1321,3 +1321,8 @@ enum { SSH_IMPL_BUG_LIST(TMP_DECLARE_LOG2_ENUM) }; #define TMP_DECLARE_REAL_ENUM(thing) thing = 1 << log2_##thing, enum { SSH_IMPL_BUG_LIST(TMP_DECLARE_REAL_ENUM) }; #undef TMP_DECLARE_REAL_ENUM + +/* Shared function that writes tty modes into a pty request */ +void write_ttymodes_to_packet_from_conf( + BinarySink *bs, Frontend *frontend, Conf *conf, + int ssh_version, int ospeed, int ispeed); diff --git a/sshcommon.c b/sshcommon.c index ec471544..024b64c7 100644 --- a/sshcommon.c +++ b/sshcommon.c @@ -4,7 +4,9 @@ */ #include +#include +#include "putty.h" #include "ssh.h" #include "sshchan.h" @@ -286,3 +288,181 @@ int chan_no_eager_close(Channel *chan, int sent_local_eof, int rcvd_remote_eof) { return FALSE; /* default: never proactively ask for a close */ } + +/* ---------------------------------------------------------------------- + * Common routine to marshal tty modes into an SSH packet. + */ + +void write_ttymodes_to_packet_from_conf( + BinarySink *bs, Frontend *frontend, Conf *conf, + int ssh_version, int ospeed, int ispeed) +{ + int i; + + /* + * Codes for terminal modes. + * Most of these are the same in SSH-1 and SSH-2. + * This list is derived from RFC 4254 and + * SSH-1 RFC-1.2.31. + */ + static const struct ssh_ttymode { + const char *mode; + int opcode; + enum { TTY_OP_CHAR, TTY_OP_BOOL } type; + } ssh_ttymodes[] = { + /* "V" prefix discarded for special characters relative to SSH specs */ + { "INTR", 1, TTY_OP_CHAR }, + { "QUIT", 2, TTY_OP_CHAR }, + { "ERASE", 3, TTY_OP_CHAR }, + { "KILL", 4, TTY_OP_CHAR }, + { "EOF", 5, TTY_OP_CHAR }, + { "EOL", 6, TTY_OP_CHAR }, + { "EOL2", 7, TTY_OP_CHAR }, + { "START", 8, TTY_OP_CHAR }, + { "STOP", 9, TTY_OP_CHAR }, + { "SUSP", 10, TTY_OP_CHAR }, + { "DSUSP", 11, TTY_OP_CHAR }, + { "REPRINT", 12, TTY_OP_CHAR }, + { "WERASE", 13, TTY_OP_CHAR }, + { "LNEXT", 14, TTY_OP_CHAR }, + { "FLUSH", 15, TTY_OP_CHAR }, + { "SWTCH", 16, TTY_OP_CHAR }, + { "STATUS", 17, TTY_OP_CHAR }, + { "DISCARD", 18, TTY_OP_CHAR }, + { "IGNPAR", 30, TTY_OP_BOOL }, + { "PARMRK", 31, TTY_OP_BOOL }, + { "INPCK", 32, TTY_OP_BOOL }, + { "ISTRIP", 33, TTY_OP_BOOL }, + { "INLCR", 34, TTY_OP_BOOL }, + { "IGNCR", 35, TTY_OP_BOOL }, + { "ICRNL", 36, TTY_OP_BOOL }, + { "IUCLC", 37, TTY_OP_BOOL }, + { "IXON", 38, TTY_OP_BOOL }, + { "IXANY", 39, TTY_OP_BOOL }, + { "IXOFF", 40, TTY_OP_BOOL }, + { "IMAXBEL", 41, TTY_OP_BOOL }, + { "IUTF8", 42, TTY_OP_BOOL }, + { "ISIG", 50, TTY_OP_BOOL }, + { "ICANON", 51, TTY_OP_BOOL }, + { "XCASE", 52, TTY_OP_BOOL }, + { "ECHO", 53, TTY_OP_BOOL }, + { "ECHOE", 54, TTY_OP_BOOL }, + { "ECHOK", 55, TTY_OP_BOOL }, + { "ECHONL", 56, TTY_OP_BOOL }, + { "NOFLSH", 57, TTY_OP_BOOL }, + { "TOSTOP", 58, TTY_OP_BOOL }, + { "IEXTEN", 59, TTY_OP_BOOL }, + { "ECHOCTL", 60, TTY_OP_BOOL }, + { "ECHOKE", 61, TTY_OP_BOOL }, + { "PENDIN", 62, TTY_OP_BOOL }, /* XXX is this a real mode? */ + { "OPOST", 70, TTY_OP_BOOL }, + { "OLCUC", 71, TTY_OP_BOOL }, + { "ONLCR", 72, TTY_OP_BOOL }, + { "OCRNL", 73, TTY_OP_BOOL }, + { "ONOCR", 74, TTY_OP_BOOL }, + { "ONLRET", 75, TTY_OP_BOOL }, + { "CS7", 90, TTY_OP_BOOL }, + { "CS8", 91, TTY_OP_BOOL }, + { "PARENB", 92, TTY_OP_BOOL }, + { "PARODD", 93, TTY_OP_BOOL } + }; + + /* Miscellaneous other tty-related constants. */ + enum { + /* The opcodes for ISPEED/OSPEED differ between SSH-1 and SSH-2. */ + SSH1_TTY_OP_ISPEED = 192, + SSH1_TTY_OP_OSPEED = 193, + SSH2_TTY_OP_ISPEED = 128, + SSH2_TTY_OP_OSPEED = 129, + + SSH_TTY_OP_END = 0 + }; + + for (i = 0; i < lenof(ssh_ttymodes); i++) { + const struct ssh_ttymode *mode = ssh_ttymodes + i; + const char *sval = conf_get_str_str(conf, CONF_ttymodes, mode->mode); + char *to_free = NULL; + + /* Every mode known to the current version of the code should be + * mentioned; this was ensured when settings were loaded. */ + + /* + * sval[0] can be + * - 'V', indicating that an explicit value follows it; + * - 'A', indicating that we should pass the value through from + * the local environment via get_ttymode; or + * - 'N', indicating that we should explicitly not send this + * mode. + */ + if (sval[0] == 'A') { + sval = to_free = get_ttymode(frontend, mode->mode); + } else if (sval[0] == 'V') { + sval++; /* skip the 'V' */ + } else { + /* else 'N', or something from the future we don't understand */ + continue; + } + + if (sval) { + /* + * Parse the string representation of the tty mode + * into the integer value it will take on the wire. + */ + unsigned ival = 0; + + switch (mode->type) { + case TTY_OP_CHAR: + if (*sval) { + char *next = NULL; + /* We know ctrlparse won't write to the string, so + * casting away const is ugly but allowable. */ + ival = ctrlparse((char *)sval, &next); + if (!next) + ival = sval[0]; + } else { + ival = 255; /* special value meaning "don't set" */ + } + break; + case TTY_OP_BOOL: + if (stricmp(sval, "yes") == 0 || + stricmp(sval, "on") == 0 || + stricmp(sval, "true") == 0 || + stricmp(sval, "+") == 0) + ival = 1; /* true */ + else if (stricmp(sval, "no") == 0 || + stricmp(sval, "off") == 0 || + stricmp(sval, "false") == 0 || + stricmp(sval, "-") == 0) + ival = 0; /* false */ + else + ival = (atoi(sval) != 0); + break; + default: + assert(0 && "Bad mode->type"); + } + + /* + * And write it into the output packet. The parameter + * value is formatted as a byte in SSH-1, but a uint32 + * in SSH-2. + */ + put_byte(bs, mode->opcode); + if (ssh_version == 1) + put_byte(bs, ival); + else + put_uint32(bs, ival); + } + + sfree(to_free); + } + + /* + * Finish off with the terminal speeds (which are formatted as + * uint32 in both protocol versions) and the end marker. + */ + put_byte(bs, ssh_version == 1 ? SSH1_TTY_OP_ISPEED : SSH2_TTY_OP_ISPEED); + put_uint32(bs, ispeed); + put_byte(bs, ssh_version == 1 ? SSH1_TTY_OP_OSPEED : SSH2_TTY_OP_OSPEED); + put_uint32(bs, ospeed); + put_byte(bs, SSH_TTY_OP_END); +} From 968252bbdcca15fc73060a5bc709c3dbbc96c5ca Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Wed, 19 Sep 2018 20:37:12 +0100 Subject: [PATCH 426/607] Move alloc_channel_id into sshcommon.c. That function _did_ depend on ssh.c's internal facilities, namely the layout of 'struct ssh_channel'. In place of that, it now takes an extra integer argument telling it where to find the channel id in whatever data structure you give it a tree of - so now I can split up the SSH-1 and SSH-2 channel handling without losing the services of that nice channel-number allocator. --- ssh.c | 34 +--------------------------------- ssh.h | 8 ++++++++ sshcommon.c | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 33 deletions(-) diff --git a/ssh.c b/ssh.c index 3d91a672..d5f203b0 100644 --- a/ssh.c +++ b/ssh.c @@ -814,38 +814,6 @@ static int ssh_rportcmp_ssh2(void *av, void *bv) return 0; } -static unsigned alloc_channel_id(Ssh ssh) -{ - const unsigned CHANNEL_NUMBER_OFFSET = 256; - search234_state ss; - - /* - * First-fit allocation of channel numbers: we always pick the - * lowest unused one. - * - * Every channel before that, and no channel after it, has an ID - * exactly equal to its tree index plus CHANNEL_NUMBER_OFFSET. So - * we can use the search234 system to identify the length of that - * initial sequence, in a single log-time pass down the channels - * tree. - */ - search234_start(&ss, ssh->channels); - while (ss.element) { - struct ssh_channel *c = (struct ssh_channel *)ss.element; - if (c->localid == ss.index + CHANNEL_NUMBER_OFFSET) - search234_step(&ss, +1); - else - search234_step(&ss, -1); - } - - /* - * Now ss.index gives exactly the number of channels in that - * initial sequence. So adding CHANNEL_NUMBER_OFFSET to it must - * give precisely the lowest unused channel number. - */ - return ss.index + CHANNEL_NUMBER_OFFSET; -} - static void c_write_stderr(int trusted, const void *vbuf, int len) { const char *buf = (const char *)vbuf; @@ -5676,7 +5644,7 @@ static int ssh_is_simple(Ssh ssh) static void ssh_channel_init(struct ssh_channel *c) { Ssh ssh = c->ssh; - c->localid = alloc_channel_id(ssh); + c->localid = alloc_channel_id(ssh->channels, struct ssh_channel); c->closes = 0; c->pending_eof = FALSE; c->throttling_conn = FALSE; diff --git a/ssh.h b/ssh.h index bfeb20df..fc61aa31 100644 --- a/ssh.h +++ b/ssh.h @@ -1326,3 +1326,11 @@ enum { SSH_IMPL_BUG_LIST(TMP_DECLARE_REAL_ENUM) }; void write_ttymodes_to_packet_from_conf( BinarySink *bs, Frontend *frontend, Conf *conf, int ssh_version, int ospeed, int ispeed); + +/* Shared system for allocating local SSH channel ids. Expects to be + * passed a tree full of structs that have a field called 'localid' of + * type unsigned, and will check that! */ +unsigned alloc_channel_id_general(tree234 *channels, size_t localid_offset); +#define alloc_channel_id(tree, type) \ + TYPECHECK(&((type *)0)->localid == (unsigned *)0, \ + alloc_channel_id_general(tree, offsetof(type, localid))) diff --git a/sshcommon.c b/sshcommon.c index 024b64c7..28f28cf9 100644 --- a/sshcommon.c +++ b/sshcommon.c @@ -466,3 +466,40 @@ void write_ttymodes_to_packet_from_conf( put_uint32(bs, ospeed); put_byte(bs, SSH_TTY_OP_END); } + +/* ---------------------------------------------------------------------- + * Routine for allocating a new channel ID, given a means of finding + * the index field in a given channel structure. + */ + +unsigned alloc_channel_id_general(tree234 *channels, size_t localid_offset) +{ + const unsigned CHANNEL_NUMBER_OFFSET = 256; + search234_state ss; + + /* + * First-fit allocation of channel numbers: we always pick the + * lowest unused one. + * + * Every channel before that, and no channel after it, has an ID + * exactly equal to its tree index plus CHANNEL_NUMBER_OFFSET. So + * we can use the search234 system to identify the length of that + * initial sequence, in a single log-time pass down the channels + * tree. + */ + search234_start(&ss, channels); + while (ss.element) { + unsigned localid = *(unsigned *)((char *)ss.element + localid_offset); + if (localid == ss.index + CHANNEL_NUMBER_OFFSET) + search234_step(&ss, +1); + else + search234_step(&ss, -1); + } + + /* + * Now ss.index gives exactly the number of channels in that + * initial sequence. So adding CHANNEL_NUMBER_OFFSET to it must + * give precisely the lowest unused channel number. + */ + return ss.index + CHANNEL_NUMBER_OFFSET; +} From 26364bb6a125ff9631ca350d8feae3fecb25c85e Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Wed, 19 Sep 2018 20:39:25 +0100 Subject: [PATCH 427/607] Move comma-separated string functions into sshcommon.c. These are just string handling, after all. They could even move into misc.c if any non-SSH-related code ever had a need for them. --- ssh.c | 53 ----------------------------------------------------- ssh.h | 5 +++++ sshcommon.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 53 deletions(-) diff --git a/ssh.c b/ssh.c index d5f203b0..a8d93ad1 100644 --- a/ssh.c +++ b/ssh.c @@ -3464,59 +3464,6 @@ static void ssh1_protocol_setup(Ssh ssh) ssh->packet_dispatch[SSH1_MSG_DEBUG] = ssh1_msg_debug; } -/* - * Utility routines for decoding comma-separated strings in KEXINIT. - */ -static int first_in_commasep_string(char const *needle, char const *haystack, - int haylen) -{ - int needlen; - if (!needle || !haystack) /* protect against null pointers */ - return 0; - needlen = strlen(needle); - - if (haylen >= needlen && /* haystack is long enough */ - !memcmp(needle, haystack, needlen) && /* initial match */ - (haylen == needlen || haystack[needlen] == ',') - /* either , or EOS follows */ - ) - return 1; - return 0; -} - -static int in_commasep_string(char const *needle, char const *haystack, - int haylen) -{ - char *p; - - if (!needle || !haystack) /* protect against null pointers */ - return 0; - /* - * Is it at the start of the string? - */ - if (first_in_commasep_string(needle, haystack, haylen)) - return 1; - /* - * If not, search for the next comma and resume after that. - * If no comma found, terminate. - */ - p = memchr(haystack, ',', haylen); - if (!p) return 0; - /* + 1 to skip over comma */ - return in_commasep_string(needle, p + 1, haylen - (p + 1 - haystack)); -} - -/* - * Add a value to a strbuf containing a comma-separated list. - */ -static void add_to_commasep(strbuf *buf, const char *data) -{ - if (buf->len > 0) - put_byte(buf, ','); - put_data(buf, data, strlen(data)); -} - - /* * SSH-2 key derivation (RFC 4253 section 7.2). */ diff --git a/ssh.h b/ssh.h index fc61aa31..16224330 100644 --- a/ssh.h +++ b/ssh.h @@ -1334,3 +1334,8 @@ unsigned alloc_channel_id_general(tree234 *channels, size_t localid_offset); #define alloc_channel_id(tree, type) \ TYPECHECK(&((type *)0)->localid == (unsigned *)0, \ alloc_channel_id_general(tree, offsetof(type, localid))) + +int first_in_commasep_string(char const *needle, char const *haystack, + int haylen); +int in_commasep_string(char const *needle, char const *haystack, int haylen); +void add_to_commasep(strbuf *buf, const char *data); diff --git a/sshcommon.c b/sshcommon.c index 28f28cf9..371d6c30 100644 --- a/sshcommon.c +++ b/sshcommon.c @@ -503,3 +503,54 @@ unsigned alloc_channel_id_general(tree234 *channels, size_t localid_offset) */ return ss.index + CHANNEL_NUMBER_OFFSET; } + +/* ---------------------------------------------------------------------- + * Functions for handling the comma-separated strings used to store + * lists of protocol identifiers in SSH-2. + */ + +int first_in_commasep_string(char const *needle, char const *haystack, + int haylen) +{ + int needlen; + if (!needle || !haystack) /* protect against null pointers */ + return 0; + needlen = strlen(needle); + + if (haylen >= needlen && /* haystack is long enough */ + !memcmp(needle, haystack, needlen) && /* initial match */ + (haylen == needlen || haystack[needlen] == ',') + /* either , or EOS follows */ + ) + return 1; + return 0; +} + +int in_commasep_string(char const *needle, char const *haystack, int haylen) +{ + char *p; + + if (!needle || !haystack) /* protect against null pointers */ + return FALSE; + /* + * Is it at the start of the string? + */ + if (first_in_commasep_string(needle, haystack, haylen)) + return TRUE; + /* + * If not, search for the next comma and resume after that. + * If no comma found, terminate. + */ + p = memchr(haystack, ',', haylen); + if (!p) + return FALSE; + /* + 1 to skip over comma */ + return in_commasep_string(needle, p + 1, haylen - (p + 1 - haystack)); +} + +void add_to_commasep(strbuf *buf, const char *data) +{ + if (buf->len > 0) + put_byte(buf, ','); + put_data(buf, data, strlen(data)); +} From 3ad919f9e921472ab5b298cd456c82cfcc07eb4b Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Wed, 19 Sep 2018 20:40:21 +0100 Subject: [PATCH 428/607] Move ssh{1,2}_pkt_type into sshcommon.c. These are already called from multiple places to translate packet type codes into text, so let's put them somewhere nicely central. --- ssh.c | 110 ------------------------------------------------- sshcommon.c | 115 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 115 insertions(+), 110 deletions(-) diff --git a/ssh.c b/ssh.c index a8d93ad1..5cc1373c 100644 --- a/ssh.c +++ b/ssh.c @@ -58,116 +58,6 @@ static unsigned long rekey_mins(int rekey_time, unsigned long def) return (unsigned long)rekey_time; } -#define translate(x) if (type == x) return #x -#define translatek(x,ctx) if (type == x && (pkt_kctx == ctx)) return #x -#define translatea(x,ctx) if (type == x && (pkt_actx == ctx)) return #x -const char *ssh1_pkt_type(int type) -{ - translate(SSH1_MSG_DISCONNECT); - translate(SSH1_SMSG_PUBLIC_KEY); - translate(SSH1_CMSG_SESSION_KEY); - translate(SSH1_CMSG_USER); - translate(SSH1_CMSG_AUTH_RSA); - translate(SSH1_SMSG_AUTH_RSA_CHALLENGE); - translate(SSH1_CMSG_AUTH_RSA_RESPONSE); - translate(SSH1_CMSG_AUTH_PASSWORD); - translate(SSH1_CMSG_REQUEST_PTY); - translate(SSH1_CMSG_WINDOW_SIZE); - translate(SSH1_CMSG_EXEC_SHELL); - translate(SSH1_CMSG_EXEC_CMD); - translate(SSH1_SMSG_SUCCESS); - translate(SSH1_SMSG_FAILURE); - translate(SSH1_CMSG_STDIN_DATA); - translate(SSH1_SMSG_STDOUT_DATA); - translate(SSH1_SMSG_STDERR_DATA); - translate(SSH1_CMSG_EOF); - translate(SSH1_SMSG_EXIT_STATUS); - translate(SSH1_MSG_CHANNEL_OPEN_CONFIRMATION); - translate(SSH1_MSG_CHANNEL_OPEN_FAILURE); - translate(SSH1_MSG_CHANNEL_DATA); - translate(SSH1_MSG_CHANNEL_CLOSE); - translate(SSH1_MSG_CHANNEL_CLOSE_CONFIRMATION); - translate(SSH1_SMSG_X11_OPEN); - translate(SSH1_CMSG_PORT_FORWARD_REQUEST); - translate(SSH1_MSG_PORT_OPEN); - translate(SSH1_CMSG_AGENT_REQUEST_FORWARDING); - translate(SSH1_SMSG_AGENT_OPEN); - translate(SSH1_MSG_IGNORE); - translate(SSH1_CMSG_EXIT_CONFIRMATION); - translate(SSH1_CMSG_X11_REQUEST_FORWARDING); - translate(SSH1_CMSG_AUTH_RHOSTS_RSA); - translate(SSH1_MSG_DEBUG); - translate(SSH1_CMSG_REQUEST_COMPRESSION); - translate(SSH1_CMSG_AUTH_TIS); - translate(SSH1_SMSG_AUTH_TIS_CHALLENGE); - translate(SSH1_CMSG_AUTH_TIS_RESPONSE); - translate(SSH1_CMSG_AUTH_CCARD); - translate(SSH1_SMSG_AUTH_CCARD_CHALLENGE); - translate(SSH1_CMSG_AUTH_CCARD_RESPONSE); - return "unknown"; -} -const char *ssh2_pkt_type(Pkt_KCtx pkt_kctx, Pkt_ACtx pkt_actx, int type) -{ - translatea(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE,SSH2_PKTCTX_GSSAPI); - translatea(SSH2_MSG_USERAUTH_GSSAPI_TOKEN,SSH2_PKTCTX_GSSAPI); - translatea(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE,SSH2_PKTCTX_GSSAPI); - translatea(SSH2_MSG_USERAUTH_GSSAPI_ERROR,SSH2_PKTCTX_GSSAPI); - translatea(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK,SSH2_PKTCTX_GSSAPI); - translatea(SSH2_MSG_USERAUTH_GSSAPI_MIC, SSH2_PKTCTX_GSSAPI); - translate(SSH2_MSG_DISCONNECT); - translate(SSH2_MSG_IGNORE); - translate(SSH2_MSG_UNIMPLEMENTED); - translate(SSH2_MSG_DEBUG); - translate(SSH2_MSG_SERVICE_REQUEST); - translate(SSH2_MSG_SERVICE_ACCEPT); - translate(SSH2_MSG_KEXINIT); - translate(SSH2_MSG_NEWKEYS); - translatek(SSH2_MSG_KEXDH_INIT, SSH2_PKTCTX_DHGROUP); - translatek(SSH2_MSG_KEXDH_REPLY, SSH2_PKTCTX_DHGROUP); - translatek(SSH2_MSG_KEX_DH_GEX_REQUEST_OLD, SSH2_PKTCTX_DHGEX); - translatek(SSH2_MSG_KEX_DH_GEX_REQUEST, SSH2_PKTCTX_DHGEX); - translatek(SSH2_MSG_KEX_DH_GEX_GROUP, SSH2_PKTCTX_DHGEX); - translatek(SSH2_MSG_KEX_DH_GEX_INIT, SSH2_PKTCTX_DHGEX); - translatek(SSH2_MSG_KEX_DH_GEX_REPLY, SSH2_PKTCTX_DHGEX); - translatek(SSH2_MSG_KEXRSA_PUBKEY, SSH2_PKTCTX_RSAKEX); - translatek(SSH2_MSG_KEXRSA_SECRET, SSH2_PKTCTX_RSAKEX); - translatek(SSH2_MSG_KEXRSA_DONE, SSH2_PKTCTX_RSAKEX); - translatek(SSH2_MSG_KEX_ECDH_INIT, SSH2_PKTCTX_ECDHKEX); - translatek(SSH2_MSG_KEX_ECDH_REPLY, SSH2_PKTCTX_ECDHKEX); - translatek(SSH2_MSG_KEXGSS_INIT, SSH2_PKTCTX_GSSKEX); - translatek(SSH2_MSG_KEXGSS_CONTINUE, SSH2_PKTCTX_GSSKEX); - translatek(SSH2_MSG_KEXGSS_COMPLETE, SSH2_PKTCTX_GSSKEX); - translatek(SSH2_MSG_KEXGSS_HOSTKEY, SSH2_PKTCTX_GSSKEX); - translatek(SSH2_MSG_KEXGSS_ERROR, SSH2_PKTCTX_GSSKEX); - translatek(SSH2_MSG_KEXGSS_GROUPREQ, SSH2_PKTCTX_GSSKEX); - translatek(SSH2_MSG_KEXGSS_GROUP, SSH2_PKTCTX_GSSKEX); - translate(SSH2_MSG_USERAUTH_REQUEST); - translate(SSH2_MSG_USERAUTH_FAILURE); - translate(SSH2_MSG_USERAUTH_SUCCESS); - translate(SSH2_MSG_USERAUTH_BANNER); - translatea(SSH2_MSG_USERAUTH_PK_OK, SSH2_PKTCTX_PUBLICKEY); - translatea(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ, SSH2_PKTCTX_PASSWORD); - translatea(SSH2_MSG_USERAUTH_INFO_REQUEST, SSH2_PKTCTX_KBDINTER); - translatea(SSH2_MSG_USERAUTH_INFO_RESPONSE, SSH2_PKTCTX_KBDINTER); - translate(SSH2_MSG_GLOBAL_REQUEST); - translate(SSH2_MSG_REQUEST_SUCCESS); - translate(SSH2_MSG_REQUEST_FAILURE); - translate(SSH2_MSG_CHANNEL_OPEN); - translate(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION); - translate(SSH2_MSG_CHANNEL_OPEN_FAILURE); - translate(SSH2_MSG_CHANNEL_WINDOW_ADJUST); - translate(SSH2_MSG_CHANNEL_DATA); - translate(SSH2_MSG_CHANNEL_EXTENDED_DATA); - translate(SSH2_MSG_CHANNEL_EOF); - translate(SSH2_MSG_CHANNEL_CLOSE); - translate(SSH2_MSG_CHANNEL_REQUEST); - translate(SSH2_MSG_CHANNEL_SUCCESS); - translate(SSH2_MSG_CHANNEL_FAILURE); - return "unknown"; -} -#undef translate -#undef translatec - /* Enumeration values for fields in SSH-1 packets */ enum { PKT_END, PKT_INT, PKT_CHAR, PKT_DATA, PKT_STR, PKT_BIGNUM, diff --git a/sshcommon.c b/sshcommon.c index 371d6c30..b98c9a62 100644 --- a/sshcommon.c +++ b/sshcommon.c @@ -554,3 +554,118 @@ void add_to_commasep(strbuf *buf, const char *data) put_byte(buf, ','); put_data(buf, data, strlen(data)); } + +/* ---------------------------------------------------------------------- + * Functions for translating SSH packet type codes into their symbolic + * string names. + */ + +#define translate(x) if (type == x) return #x +#define translatek(x,ctx) if (type == x && (pkt_kctx == ctx)) return #x +#define translatea(x,ctx) if (type == x && (pkt_actx == ctx)) return #x +const char *ssh1_pkt_type(int type) +{ + translate(SSH1_MSG_DISCONNECT); + translate(SSH1_SMSG_PUBLIC_KEY); + translate(SSH1_CMSG_SESSION_KEY); + translate(SSH1_CMSG_USER); + translate(SSH1_CMSG_AUTH_RSA); + translate(SSH1_SMSG_AUTH_RSA_CHALLENGE); + translate(SSH1_CMSG_AUTH_RSA_RESPONSE); + translate(SSH1_CMSG_AUTH_PASSWORD); + translate(SSH1_CMSG_REQUEST_PTY); + translate(SSH1_CMSG_WINDOW_SIZE); + translate(SSH1_CMSG_EXEC_SHELL); + translate(SSH1_CMSG_EXEC_CMD); + translate(SSH1_SMSG_SUCCESS); + translate(SSH1_SMSG_FAILURE); + translate(SSH1_CMSG_STDIN_DATA); + translate(SSH1_SMSG_STDOUT_DATA); + translate(SSH1_SMSG_STDERR_DATA); + translate(SSH1_CMSG_EOF); + translate(SSH1_SMSG_EXIT_STATUS); + translate(SSH1_MSG_CHANNEL_OPEN_CONFIRMATION); + translate(SSH1_MSG_CHANNEL_OPEN_FAILURE); + translate(SSH1_MSG_CHANNEL_DATA); + translate(SSH1_MSG_CHANNEL_CLOSE); + translate(SSH1_MSG_CHANNEL_CLOSE_CONFIRMATION); + translate(SSH1_SMSG_X11_OPEN); + translate(SSH1_CMSG_PORT_FORWARD_REQUEST); + translate(SSH1_MSG_PORT_OPEN); + translate(SSH1_CMSG_AGENT_REQUEST_FORWARDING); + translate(SSH1_SMSG_AGENT_OPEN); + translate(SSH1_MSG_IGNORE); + translate(SSH1_CMSG_EXIT_CONFIRMATION); + translate(SSH1_CMSG_X11_REQUEST_FORWARDING); + translate(SSH1_CMSG_AUTH_RHOSTS_RSA); + translate(SSH1_MSG_DEBUG); + translate(SSH1_CMSG_REQUEST_COMPRESSION); + translate(SSH1_CMSG_AUTH_TIS); + translate(SSH1_SMSG_AUTH_TIS_CHALLENGE); + translate(SSH1_CMSG_AUTH_TIS_RESPONSE); + translate(SSH1_CMSG_AUTH_CCARD); + translate(SSH1_SMSG_AUTH_CCARD_CHALLENGE); + translate(SSH1_CMSG_AUTH_CCARD_RESPONSE); + return "unknown"; +} +const char *ssh2_pkt_type(Pkt_KCtx pkt_kctx, Pkt_ACtx pkt_actx, int type) +{ + translatea(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE,SSH2_PKTCTX_GSSAPI); + translatea(SSH2_MSG_USERAUTH_GSSAPI_TOKEN,SSH2_PKTCTX_GSSAPI); + translatea(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE,SSH2_PKTCTX_GSSAPI); + translatea(SSH2_MSG_USERAUTH_GSSAPI_ERROR,SSH2_PKTCTX_GSSAPI); + translatea(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK,SSH2_PKTCTX_GSSAPI); + translatea(SSH2_MSG_USERAUTH_GSSAPI_MIC, SSH2_PKTCTX_GSSAPI); + translate(SSH2_MSG_DISCONNECT); + translate(SSH2_MSG_IGNORE); + translate(SSH2_MSG_UNIMPLEMENTED); + translate(SSH2_MSG_DEBUG); + translate(SSH2_MSG_SERVICE_REQUEST); + translate(SSH2_MSG_SERVICE_ACCEPT); + translate(SSH2_MSG_KEXINIT); + translate(SSH2_MSG_NEWKEYS); + translatek(SSH2_MSG_KEXDH_INIT, SSH2_PKTCTX_DHGROUP); + translatek(SSH2_MSG_KEXDH_REPLY, SSH2_PKTCTX_DHGROUP); + translatek(SSH2_MSG_KEX_DH_GEX_REQUEST_OLD, SSH2_PKTCTX_DHGEX); + translatek(SSH2_MSG_KEX_DH_GEX_REQUEST, SSH2_PKTCTX_DHGEX); + translatek(SSH2_MSG_KEX_DH_GEX_GROUP, SSH2_PKTCTX_DHGEX); + translatek(SSH2_MSG_KEX_DH_GEX_INIT, SSH2_PKTCTX_DHGEX); + translatek(SSH2_MSG_KEX_DH_GEX_REPLY, SSH2_PKTCTX_DHGEX); + translatek(SSH2_MSG_KEXRSA_PUBKEY, SSH2_PKTCTX_RSAKEX); + translatek(SSH2_MSG_KEXRSA_SECRET, SSH2_PKTCTX_RSAKEX); + translatek(SSH2_MSG_KEXRSA_DONE, SSH2_PKTCTX_RSAKEX); + translatek(SSH2_MSG_KEX_ECDH_INIT, SSH2_PKTCTX_ECDHKEX); + translatek(SSH2_MSG_KEX_ECDH_REPLY, SSH2_PKTCTX_ECDHKEX); + translatek(SSH2_MSG_KEXGSS_INIT, SSH2_PKTCTX_GSSKEX); + translatek(SSH2_MSG_KEXGSS_CONTINUE, SSH2_PKTCTX_GSSKEX); + translatek(SSH2_MSG_KEXGSS_COMPLETE, SSH2_PKTCTX_GSSKEX); + translatek(SSH2_MSG_KEXGSS_HOSTKEY, SSH2_PKTCTX_GSSKEX); + translatek(SSH2_MSG_KEXGSS_ERROR, SSH2_PKTCTX_GSSKEX); + translatek(SSH2_MSG_KEXGSS_GROUPREQ, SSH2_PKTCTX_GSSKEX); + translatek(SSH2_MSG_KEXGSS_GROUP, SSH2_PKTCTX_GSSKEX); + translate(SSH2_MSG_USERAUTH_REQUEST); + translate(SSH2_MSG_USERAUTH_FAILURE); + translate(SSH2_MSG_USERAUTH_SUCCESS); + translate(SSH2_MSG_USERAUTH_BANNER); + translatea(SSH2_MSG_USERAUTH_PK_OK, SSH2_PKTCTX_PUBLICKEY); + translatea(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ, SSH2_PKTCTX_PASSWORD); + translatea(SSH2_MSG_USERAUTH_INFO_REQUEST, SSH2_PKTCTX_KBDINTER); + translatea(SSH2_MSG_USERAUTH_INFO_RESPONSE, SSH2_PKTCTX_KBDINTER); + translate(SSH2_MSG_GLOBAL_REQUEST); + translate(SSH2_MSG_REQUEST_SUCCESS); + translate(SSH2_MSG_REQUEST_FAILURE); + translate(SSH2_MSG_CHANNEL_OPEN); + translate(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION); + translate(SSH2_MSG_CHANNEL_OPEN_FAILURE); + translate(SSH2_MSG_CHANNEL_WINDOW_ADJUST); + translate(SSH2_MSG_CHANNEL_DATA); + translate(SSH2_MSG_CHANNEL_EXTENDED_DATA); + translate(SSH2_MSG_CHANNEL_EOF); + translate(SSH2_MSG_CHANNEL_CLOSE); + translate(SSH2_MSG_CHANNEL_REQUEST); + translate(SSH2_MSG_CHANNEL_SUCCESS); + translate(SSH2_MSG_CHANNEL_FAILURE); + return "unknown"; +} +#undef translate +#undef translatec From 93f2df9b837194e678449947d8cf73517e87165c Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Wed, 19 Sep 2018 21:28:21 +0100 Subject: [PATCH 429/607] New system for tracking data-limit-based rekeys. I've removed the encrypted_len fields from PktIn and PktOut, which were used to communicate from the BPP to ssh.c how much each packet contributed to the amount of data encrypted with a given set of cipher keys. It seems more sensible to have the BPP itself keep that counter - especially since only one of the three BPPs even needs to count it at all. So now there's a new DataTransferStats structure which the BPP updates, and ssh.c only needs to check it for overflow and reset the limits. --- ssh.c | 49 ++++++++++++++++++++++++++++++++----------------- ssh.h | 2 -- ssh2bpp-bare.c | 2 -- ssh2bpp.c | 10 +++++++--- sshbpp.h | 27 ++++++++++++++++++++++++++- 5 files changed, 65 insertions(+), 25 deletions(-) diff --git a/ssh.c b/ssh.c index 5cc1373c..e3dba149 100644 --- a/ssh.c +++ b/ssh.c @@ -559,8 +559,8 @@ struct ssh_tag { * Track incoming and outgoing data sizes and time, for * size-based rekeys. */ - unsigned long incoming_data_size, outgoing_data_size; unsigned long max_data_size; + struct DataTransferStats stats; int kex_in_progress; unsigned long next_rekey, last_rekey; const char *deferred_rekey_reason; @@ -781,10 +781,9 @@ static void ssh_send_outgoing_data(void *ctx) backlog = s_write(ssh, data, len); bufchain_consume(&ssh->outgoing_data, len); - ssh->outgoing_data_size += len; if (ssh->version == 2 && !ssh->kex_in_progress && - !ssh->bare_connection && ssh->max_data_size != 0 && - ssh->outgoing_data_size > ssh->max_data_size) { + ssh->state != SSH_STATE_PREPACKET && + !ssh->bare_connection && !ssh->stats.out.running) { ssh->rekey_reason = "too much data sent"; ssh->rekey_class = RK_NORMAL; queue_idempotent_callback(&ssh->ssh2_transport_icb); @@ -5131,7 +5130,9 @@ static void do_ssh2_transport(void *vctx) */ s->pktout = ssh_bpp_new_pktout(ssh->bpp, SSH2_MSG_NEWKEYS); ssh_pkt_write(ssh, s->pktout); - ssh->outgoing_data_size = 0; /* start counting from here */ + /* Start counting down the outgoing-data limit for these cipher keys. */ + ssh->stats.out.running = TRUE; + ssh->stats.out.remaining = ssh->max_data_size; /* * We've sent client NEWKEYS, so create and initialise @@ -5204,7 +5205,9 @@ static void do_ssh2_transport(void *vctx) bombout(("expected new-keys packet from server")); crStopV; } - ssh->incoming_data_size = 0; /* start counting from here */ + /* Start counting down the incoming-data limit for these cipher keys. */ + ssh->stats.in.running = TRUE; + ssh->stats.in.remaining = ssh->max_data_size; /* * We've seen server NEWKEYS, so create and initialise @@ -5363,8 +5366,9 @@ static void do_ssh2_transport(void *vctx) ssh->rekey_reason); /* Reset the counters, so that at least this message doesn't * hit the event log _too_ often. */ - ssh->outgoing_data_size = 0; - ssh->incoming_data_size = 0; + ssh->stats.in.running = ssh->stats.out.running = TRUE; + ssh->stats.in.remaining = ssh->stats.out.remaining = + ssh->max_data_size; (void) ssh2_timer_update(ssh, 0); goto wait_for_rekey; /* this is still utterly horrid */ } else { @@ -8649,7 +8653,7 @@ static void ssh2_protocol_setup(Ssh ssh) { int i; - ssh->bpp = ssh2_bpp_new(); + ssh->bpp = ssh2_bpp_new(&ssh->stats); #ifndef NO_GSSAPI /* Load and pick the highest GSS library on the preference list. */ @@ -9055,10 +9059,8 @@ static void ssh2_timer(void *ctx, unsigned long now) static void ssh2_general_packet_processing(Ssh ssh, PktIn *pktin) { - ssh->incoming_data_size += pktin->encrypted_len; - if (!ssh->kex_in_progress && - ssh->max_data_size != 0 && - ssh->incoming_data_size > ssh->max_data_size) { + if (!ssh->kex_in_progress && ssh->max_data_size != 0 && + ssh->state != SSH_STATE_PREPACKET && !ssh->stats.in.running) { ssh->rekey_reason = "too much data received"; ssh->rekey_class = RK_NORMAL; queue_idempotent_callback(&ssh->ssh2_transport_icb); @@ -9213,7 +9215,7 @@ static const char *ssh_init(Frontend *frontend, Backend **backend_handle, ssh->pinger = NULL; - ssh->incoming_data_size = ssh->outgoing_data_size = 0L; + memset(&ssh->stats, 0, sizeof(ssh->stats)); ssh->max_data_size = parse_blocksize(conf_get_str(ssh->conf, CONF_ssh_rekey_data)); ssh->kex_in_progress = FALSE; @@ -9371,9 +9373,22 @@ static void ssh_reconfig(Backend *be, Conf *conf) CONF_ssh_rekey_data)); if (old_max_data_size != ssh->max_data_size && ssh->max_data_size != 0) { - if (ssh->outgoing_data_size > ssh->max_data_size || - ssh->incoming_data_size > ssh->max_data_size) - rekeying = "data limit lowered"; + if (ssh->max_data_size < old_max_data_size) { + unsigned long diff = old_max_data_size - ssh->max_data_size; + + /* Intentionally use bitwise OR instead of logical, so + * that we decrement both counters even if the first one + * runs out */ + if ((DTS_CONSUME(&ssh->stats, out, diff) != 0) | + (DTS_CONSUME(&ssh->stats, in, diff) != 0)) + rekeying = "data limit lowered"; + } else { + unsigned long diff = ssh->max_data_size - old_max_data_size; + if (ssh->stats.out.running) + ssh->stats.out.remaining += diff; + if (ssh->stats.in.running) + ssh->stats.in.remaining += diff; + } } if (conf_get_int(ssh->conf, CONF_compression) != diff --git a/ssh.h b/ssh.h index 16224330..fd8d1677 100644 --- a/ssh.h +++ b/ssh.h @@ -59,7 +59,6 @@ typedef struct PktIn { int refcount; int type; unsigned long sequence; /* SSH-2 incoming sequence number */ - long encrypted_len; /* for SSH-2 total-size counting */ PacketQueueNode qnode; /* for linking this packet on to a queue */ BinarySource_IMPLEMENTATION; } PktIn; @@ -71,7 +70,6 @@ typedef struct PktOut { long minlen; /* SSH-2: ensure wire length is at least this */ unsigned char *data; /* allocated storage */ long maxlen; /* amount of storage allocated for `data' */ - long encrypted_len; /* for SSH-2 total-size counting */ /* Extra metadata used in SSH packet logging mode, allowing us to * log in the packet header line that the packet came from a diff --git a/ssh2bpp-bare.c b/ssh2bpp-bare.c index bdf49a21..e16c8509 100644 --- a/ssh2bpp-bare.c +++ b/ssh2bpp-bare.c @@ -79,8 +79,6 @@ static void ssh2_bare_bpp_handle_input(BinaryPacketProtocol *bpp) s->pktin->refcount = 1; s->data = snew_plus_get_aux(s->pktin); - s->pktin->encrypted_len = s->packetlen; - s->pktin->sequence = s->incoming_sequence++; /* diff --git a/ssh2bpp.c b/ssh2bpp.c index 0b95d7fe..2b7f4654 100644 --- a/ssh2bpp.c +++ b/ssh2bpp.c @@ -24,6 +24,7 @@ struct ssh2_bpp_state { unsigned char *data; unsigned cipherblk; PktIn *pktin; + struct DataTransferStats *stats; struct ssh2_bpp_direction in, out; /* comp and decomp logically belong in the per-direction @@ -48,11 +49,12 @@ const struct BinaryPacketProtocolVtable ssh2_bpp_vtable = { ssh2_bpp_format_packet, }; -BinaryPacketProtocol *ssh2_bpp_new(void) +BinaryPacketProtocol *ssh2_bpp_new(struct DataTransferStats *stats) { struct ssh2_bpp_state *s = snew(struct ssh2_bpp_state); memset(s, 0, sizeof(*s)); s->bpp.vt = &ssh2_bpp_vtable; + s->stats = stats; return &s->bpp; } @@ -407,7 +409,8 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp) s->payload = s->len - s->pad - 1; s->length = s->payload + 5; - s->pktin->encrypted_len = s->packetlen; + + DTS_CONSUME(s->stats, in, s->packetlen); s->pktin->sequence = s->in.sequence++; @@ -601,7 +604,8 @@ static void ssh2_bpp_format_packet_inner(struct ssh2_bpp_state *s, PktOut *pkt) } s->out.sequence++; /* whether or not we MACed */ - pkt->encrypted_len = origlen + padding; + + DTS_CONSUME(s->stats, out, origlen + padding); } diff --git a/sshbpp.h b/sshbpp.h index 953add3a..a1c9d0ac 100644 --- a/sshbpp.h +++ b/sshbpp.h @@ -36,7 +36,32 @@ void ssh1_bpp_new_cipher(BinaryPacketProtocol *bpp, const void *session_key); void ssh1_bpp_start_compression(BinaryPacketProtocol *bpp); -BinaryPacketProtocol *ssh2_bpp_new(void); +/* + * Structure that tracks how much data is sent and received, for + * purposes of triggering an SSH-2 rekey when either one gets over a + * configured limit. In each direction, the flag 'running' indicates + * that we haven't hit the limit yet, and 'remaining' tracks how much + * longer until we do. The macro DTS_CONSUME subtracts a given amount + * from the counter in a particular direction, and evaluates to a + * boolean indicating whether the limit has been hit. + * + * The limit is sticky: once 'running' has flipped to false, + * 'remaining' is no longer decremented, so it shouldn't dangerously + * wrap round. + */ +struct DataTransferStats { + struct { + int running; + unsigned long remaining; + } in, out; +}; +#define DTS_CONSUME(stats, direction, size) \ + ((stats)->direction.running && \ + (stats)->direction.remaining <= (size) ? \ + ((stats)->direction.running = FALSE, TRUE) : \ + ((stats)->direction.remaining -= (size), FALSE)) + +BinaryPacketProtocol *ssh2_bpp_new(struct DataTransferStats *stats); void ssh2_bpp_new_outgoing_crypto( BinaryPacketProtocol *bpp, const struct ssh2_cipheralg *cipher, const void *ckey, const void *iv, From 91a624fb70230a885656e74c89865270b27c9de9 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Thu, 20 Sep 2018 16:58:43 +0100 Subject: [PATCH 430/607] sshaes.c: add some missing clang target attributes. The helper functions mm_shuffle_pd_i0 and mm_shuffle_pd_i1 need the FUNC_ISA macro (which expands to __attribute__((target("sse4.1,aes"))) when building with clang) in order to avoid a build error complaining that their use of the _mm_shuffle_pd intrinsic is illegal without at least sse2. This build error is new in the recently released clang 7.0.0, compared to the svn trunk revision I was previously building with. But it certainly seems plausible to me, so I assume there's been some pre-release tightening up of the error reporting. In any case, those helper functions are only ever called from other functions with the same attribute, so it shouldn't cause trouble. --- sshaes.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sshaes.c b/sshaes.c index 5259396f..c5c05d21 100644 --- a/sshaes.c +++ b/sshaes.c @@ -1243,6 +1243,7 @@ INLINE static int supports_aes_ni() * Wrapper of SHUFPD instruction for MSVC */ #ifdef _MSC_VER +FUNC_ISA INLINE static __m128i mm_shuffle_pd_i0(__m128i a, __m128i b) { union { @@ -1255,6 +1256,7 @@ INLINE static __m128i mm_shuffle_pd_i0(__m128i a, __m128i b) return ru.i; } +FUNC_ISA INLINE static __m128i mm_shuffle_pd_i1(__m128i a, __m128i b) { union { From e71798a265a3e425c609dd464039319dfe33318f Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Thu, 20 Sep 2018 17:42:48 +0100 Subject: [PATCH 431/607] Fix copy-paste error in sshdes.c. Apparently introduced just now in commit 6c5cc49e2; thanks to Colin Harrison for pointing it out very promptly. All this FROMFIELD business, helpful as it is, doesn't change the fact that you can still absentmindedly cast something to the wrong type if you're specifying the type explicitly! --- sshdes.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sshdes.c b/sshdes.c index c3afe3eb..d35c894e 100644 --- a/sshdes.c +++ b/sshdes.c @@ -821,13 +821,13 @@ static void des3_ssh1_sesskey(ssh1_cipher *cipher, const void *key) static void des3_ssh1_encrypt_blk(ssh1_cipher *cipher, void *blk, int len) { - struct des_ssh1_ctx *ctx = FROMFIELD(cipher, struct des_ssh1_ctx, vt); + struct des3_ssh1_ctx *ctx = FROMFIELD(cipher, struct des3_ssh1_ctx, vt); des_3cbc_encrypt(blk, len, ctx->contexts); } static void des3_ssh1_decrypt_blk(ssh1_cipher *cipher, void *blk, int len) { - struct des_ssh1_ctx *ctx = FROMFIELD(cipher, struct des_ssh1_ctx, vt); + struct des3_ssh1_ctx *ctx = FROMFIELD(cipher, struct des3_ssh1_ctx, vt); des_3cbc_decrypt(blk, len, ctx->contexts+3); } From e1b52ae721ef5b41fb80d88b3e645bee47deadd5 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Thu, 20 Sep 2018 23:46:45 +0100 Subject: [PATCH 432/607] Remove duplicate typedef of AESContext. Pavel Kryukov points out that ssh.h has this typedef, so sshaes.c doesn't have to have it too, and in C89 mode it's an error to have it twice. --- sshaes.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sshaes.c b/sshaes.c index c5c05d21..06e82f54 100644 --- a/sshaes.c +++ b/sshaes.c @@ -48,8 +48,6 @@ # define INLINE #endif -typedef struct AESContext AESContext; - struct AESContext { word32 keysched_buf[(MAX_NR + 1) * NB + 3]; word32 invkeysched_buf[(MAX_NR + 1) * NB + 3]; From 361efee621af9eb1f4899cc6757cba0b715aab73 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Fri, 21 Sep 2018 16:26:57 +0100 Subject: [PATCH 433/607] Reinstate setting of ssh->session_started. When PuTTY is configured to display stderr diagnostics from the proxy command but only until the main session starts, this flag is how the SSH backend indicates the point at which the session starts. It was previously set during version-string parsing, and I forgot to find a new home for it when I moved the version string parsing out into the new verstring BPP module in commit af8e526a7. Now reinstated, at the point where that BPP gets back to us and tells us what protocol version it's chosen. --- ssh.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ssh.c b/ssh.c index e3dba149..02a3ebc8 100644 --- a/ssh.c +++ b/ssh.c @@ -928,6 +928,14 @@ static void ssh_got_ssh_version(struct ssh_version_receiver *rcv, Ssh ssh = FROMFIELD(rcv, struct ssh_tag, version_receiver); BinaryPacketProtocol *old_bpp; + /* + * This is as good a time as any to stop printing proxy-command + * diagnostics in the terminal window, on the assumption that the + * proxy command must by now have made a sensible connection and + * the real session output will start shortly. + */ + ssh->session_started = TRUE; + /* * Queue an outgoing-data run: if the version string has been sent * late rather than early, it'll still be sitting on our output From e230751853ce8f6d87a0b935a36e5429eb36e1e2 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Fri, 21 Sep 2018 16:15:49 +0100 Subject: [PATCH 434/607] Remove FLAG_STDERR completely. Originally, it controlled whether ssh.c should send terminal messages (such as login and password prompts) to terminal.c or to stderr. But we've had the from_backend() abstraction for ages now, which even has an existing flag to indicate that the data is stderr rather than stdout data; applications which set FLAG_STDERR are precisely those that link against uxcons or wincons, so from_backend will do the expected thing anyway with data sent to it with that flag set. So there's no reason ssh.c can't just unconditionally pass everything through that, and remove the special case. FLAG_STDERR was also used by winproxy and uxproxy to decide whether to capture standard error from a local proxy command, or whether to let the proxy command send its diagnostics directly to the usual standard error. On reflection, I think it's better to unconditionally capture the proxy's stderr, for three reasons. Firstly, it means proxy diagnostics are prefixed with 'proxy:' so that you can tell them apart from any other stderr spew (which used to be particularly confusing if both the main application and the proxy command were instances of Plink); secondly, proxy diagnostics are now reliably copied to packet log files along with all the other Event Log entries, even by command-line tools; and thirdly, this means the option to suppress proxy command diagnostics after the main session starts will actually _work_ in the command-line tools, which it previously couldn't. A more minor structure change is that copying of Event Log messages to stderr in verbose mode is now done by wincons/uxcons, instead of centrally in logging.c (since logging.c can now no longer check FLAG_STDERR to decide whether to do it). The total amount of code to do this is considerably smaller than the defensive-sounding comment in logevent.c explaining why I did it the other way instead :-) --- logging.c | 13 ++----------- pscp.c | 2 +- psftp.c | 2 +- putty.h | 7 +------ ssh.c | 17 ++--------------- unix/uxcons.c | 8 +++++--- unix/uxplink.c | 2 +- unix/uxproxy.c | 25 ++++--------------------- windows/wincons.c | 4 ++++ windows/winplink.c | 2 +- windows/winproxy.c | 26 +++++++++----------------- 11 files changed, 31 insertions(+), 77 deletions(-) diff --git a/logging.c b/logging.c index b1fb638b..0393b7bf 100644 --- a/logging.c +++ b/logging.c @@ -219,20 +219,11 @@ void logtraffic(LogContext *ctx, unsigned char c, int logmode) } /* - * Log an Event Log entry. Used in SSH packet logging mode; this is - * also as convenient a place as any to put the output of Event Log - * entries to stderr when a command-line tool is in verbose mode. - * (In particular, this is a better place to put it than in the - * front ends, because it only has to be done once for all - * platforms. Platforms which don't have a meaningful stderr can - * just avoid defining FLAG_STDERR. + * Log an Event Log entry. Used in SSH packet logging mode, to copy + * the Event Log entries into the same log file as the packet data. */ void log_eventlog(LogContext *ctx, const char *event) { - if ((flags & FLAG_STDERR) && (flags & FLAG_VERBOSE)) { - fprintf(stderr, "%s\n", event); - fflush(stderr); - } /* If we don't have a context yet (eg winnet.c init) then skip entirely */ if (!ctx) return; diff --git a/pscp.c b/pscp.c index 67029f94..5c698e19 100644 --- a/pscp.c +++ b/pscp.c @@ -2283,7 +2283,7 @@ int psftp_main(int argc, char *argv[]) default_protocol = PROT_TELNET; - flags = FLAG_STDERR + flags = 0 #ifdef FLAG_SYNCAGENT | FLAG_SYNCAGENT #endif diff --git a/psftp.c b/psftp.c index 4eb4068d..4d9ce87d 100644 --- a/psftp.c +++ b/psftp.c @@ -2872,7 +2872,7 @@ int psftp_main(int argc, char *argv[]) int modeflags = 0; char *batchfile = NULL; - flags = FLAG_STDERR | FLAG_INTERACTIVE + flags = FLAG_INTERACTIVE #ifdef FLAG_SYNCAGENT | FLAG_SYNCAGENT #endif diff --git a/putty.h b/putty.h index 5bb7974f..4b02c06f 100644 --- a/putty.h +++ b/putty.h @@ -520,10 +520,6 @@ extern const char *const appname; * * FLAG_VERBOSE is set when the user requests verbose details. * - * FLAG_STDERR is set in command-line applications (which have a - * functioning stderr that it makes sense to write to) and not in - * GUI applications (which don't). - * * FLAG_INTERACTIVE is set when a full interactive shell session is * being run, _either_ because no remote command has been provided * _or_ because the application is GUI and can't run non- @@ -538,8 +534,7 @@ extern const char *const appname; * avoid collision. */ #define FLAG_VERBOSE 0x0001 -#define FLAG_STDERR 0x0002 -#define FLAG_INTERACTIVE 0x0004 +#define FLAG_INTERACTIVE 0x0002 GLOBAL int flags; /* diff --git a/ssh.c b/ssh.c index 02a3ebc8..38640387 100644 --- a/ssh.c +++ b/ssh.c @@ -704,21 +704,9 @@ static int ssh_rportcmp_ssh2(void *av, void *bv) return 0; } -static void c_write_stderr(int trusted, const void *vbuf, int len) -{ - const char *buf = (const char *)vbuf; - int i; - for (i = 0; i < len; i++) - if (buf[i] != '\r' && (trusted || buf[i] == '\n' || (buf[i] & 0x60))) - fputc(buf[i], stderr); -} - static void c_write(Ssh ssh, const void *buf, int len) { - if (flags & FLAG_STDERR) - c_write_stderr(1, buf, len); - else - from_backend(ssh->frontend, 1, buf, len); + from_backend(ssh->frontend, 1, buf, len); } static void c_write_str(Ssh ssh, const char *buf) @@ -1866,8 +1854,7 @@ static void do_ssh1_login(void *vctx) { char *userlog = dupprintf("Sent username \"%s\"", ssh->username); logevent(userlog); - if (flags & FLAG_INTERACTIVE && - (!((flags & FLAG_STDERR) && (flags & FLAG_VERBOSE)))) { + if ((flags & FLAG_VERBOSE) || (flags & FLAG_INTERACTIVE)) { c_write_str(ssh, userlog); c_write_str(ssh, "\r\n"); } diff --git a/unix/uxcons.c b/unix/uxcons.c index cf3603a4..c476cbf8 100644 --- a/unix/uxcons.c +++ b/unix/uxcons.c @@ -413,12 +413,14 @@ void console_provide_logctx(LogContext *logctx) void logevent(Frontend *frontend, const char *string) { struct termios cf; - if ((flags & FLAG_STDERR) && (flags & FLAG_VERBOSE)) + if (flags & FLAG_VERBOSE) { premsg(&cf); + fprintf(stderr, "%s\n", string); + fflush(stderr); + postmsg(&cf); + } if (console_logctx) log_eventlog(console_logctx, string); - if ((flags & FLAG_STDERR) && (flags & FLAG_VERBOSE)) - postmsg(&cf); } /* diff --git a/unix/uxplink.c b/unix/uxplink.c index b058dcd0..9ef5841b 100644 --- a/unix/uxplink.c +++ b/unix/uxplink.c @@ -610,7 +610,7 @@ int main(int argc, char **argv) bufchain_init(&stderr_data); outgoingeof = EOF_NO; - flags = FLAG_STDERR | FLAG_STDERR_TTY; + flags = FLAG_STDERR_TTY; cmdline_tooltype |= (TOOLTYPE_HOST_ARG | TOOLTYPE_HOST_ARG_CAN_BE_SESSION | diff --git a/unix/uxproxy.c b/unix/uxproxy.c index 74be9b2d..bd702f29 100644 --- a/unix/uxproxy.c +++ b/unix/uxproxy.c @@ -299,18 +299,6 @@ Socket platform_new_connection(SockAddr addr, const char *hostname, if (proxytype == PROXY_CMD) { cmd = format_telnet_command(addr, port, conf); - if (flags & FLAG_STDERR) { - /* If we have a sensible stderr, the proxy command can - * send its own standard error there, so we won't - * interfere. */ - cmd_err_pipe[0] = cmd_err_pipe[1] = -1; - } else { - /* If we don't have a sensible stderr, we should catch the - * proxy command's standard error to put in our event - * log. */ - cmd_err_pipe[0] = cmd_err_pipe[1] = 0; - } - { char *logmsg = dupprintf("Starting local proxy command: %s", cmd); plug_log(plug, 2, NULL, 0, logmsg, 0); @@ -323,15 +311,14 @@ Socket platform_new_connection(SockAddr addr, const char *hostname, */ if (pipe(to_cmd_pipe) < 0 || pipe(from_cmd_pipe) < 0 || - (cmd_err_pipe[0] == 0 && pipe(cmd_err_pipe) < 0)) { + pipe(cmd_err_pipe) < 0) { ret->error = dupprintf("pipe: %s", strerror(errno)); sfree(cmd); return &ret->sockvt; } cloexec(to_cmd_pipe[1]); cloexec(from_cmd_pipe[0]); - if (cmd_err_pipe[0] >= 0) - cloexec(cmd_err_pipe[0]); + cloexec(cmd_err_pipe[0]); pid = fork(); @@ -346,10 +333,7 @@ Socket platform_new_connection(SockAddr addr, const char *hostname, dup2(from_cmd_pipe[1], 1); close(to_cmd_pipe[0]); close(from_cmd_pipe[1]); - if (cmd_err_pipe[0] >= 0) { - dup2(cmd_err_pipe[1], 2); - close(cmd_err_pipe[1]); - } + dup2(cmd_err_pipe[1], 2); noncloexec(0); noncloexec(1); execl("/bin/sh", "sh", "-c", cmd, (void *)NULL); @@ -360,8 +344,7 @@ Socket platform_new_connection(SockAddr addr, const char *hostname, close(to_cmd_pipe[0]); close(from_cmd_pipe[1]); - if (cmd_err_pipe[0] >= 0) - close(cmd_err_pipe[1]); + close(cmd_err_pipe[1]); ret->to_cmd = to_cmd_pipe[1]; ret->from_cmd = from_cmd_pipe[0]; diff --git a/windows/wincons.c b/windows/wincons.c index 34ed6a30..7fb3e90b 100644 --- a/windows/wincons.c +++ b/windows/wincons.c @@ -342,6 +342,10 @@ void console_provide_logctx(LogContext *logctx) void logevent(Frontend *frontend, const char *string) { + if (flags & FLAG_VERBOSE) { + fprintf(stderr, "%s\n", string); + fflush(stderr); + } log_eventlog(console_logctx, string); } diff --git a/windows/winplink.c b/windows/winplink.c index c647a65a..e8da54ec 100644 --- a/windows/winplink.c +++ b/windows/winplink.c @@ -302,7 +302,7 @@ int main(int argc, char **argv) default_protocol = PROT_SSH; default_port = 22; - flags = FLAG_STDERR; + flags = 0; cmdline_tooltype |= (TOOLTYPE_HOST_ARG | TOOLTYPE_HOST_ARG_CAN_BE_SESSION | diff --git a/windows/winproxy.c b/windows/winproxy.c index ad73d9af..7a313181 100644 --- a/windows/winproxy.c +++ b/windows/winproxy.c @@ -66,23 +66,15 @@ Socket platform_new_connection(SockAddr addr, const char *hostname, return ret; } - if (flags & FLAG_STDERR) { - /* If we have a sensible stderr, the proxy command can send - * its own standard error there, so we won't interfere. */ - us_from_cmd_err = cmd_err_to_us = NULL; - } else { - /* If we don't have a sensible stderr, we should catch the - * proxy command's standard error to put in our event log. */ - if (!CreatePipe(&us_from_cmd_err, &cmd_err_to_us, &sa, 0)) { - Socket ret = new_error_socket - ("Unable to create pipes for proxy command", plug); - sfree(cmd); - CloseHandle(us_from_cmd); - CloseHandle(cmd_to_us); - CloseHandle(us_to_cmd); - CloseHandle(cmd_from_us); - return ret; - } + if (!CreatePipe(&us_from_cmd_err, &cmd_err_to_us, &sa, 0)) { + Socket ret = new_error_socket + ("Unable to create pipes for proxy command", plug); + sfree(cmd); + CloseHandle(us_from_cmd); + CloseHandle(cmd_to_us); + CloseHandle(us_to_cmd); + CloseHandle(cmd_from_us); + return ret; } SetHandleInformation(us_to_cmd, HANDLE_FLAG_INHERIT, 0); From a19faa452726e1c2c9897834a9139e2a0a0bca04 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Fri, 21 Sep 2018 16:53:45 +0100 Subject: [PATCH 435/607] Minor header-file cleanups. Moved the typedef of BinaryPacketProtocol into defs.h on the general principle that it's just the kind of thing that ought to go there; also removed the declaration of pq_base_init from ssh.h on the grounds that there's never been any such function! (At least, not in public source control - it existed in an early draft of commit 6e24b7d58.) --- defs.h | 2 ++ ssh.h | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/defs.h b/defs.h index 8bd9f13e..47f7c9ba 100644 --- a/defs.h +++ b/defs.h @@ -90,6 +90,8 @@ typedef struct ptrlen { typedef struct logblank_t logblank_t; +typedef struct BinaryPacketProtocol BinaryPacketProtocol; + /* Do a compile-time type-check of 'to_check' (without evaluating it), * as a side effect of returning the value 'to_return'. Note that * although this macro double-*expands* to_return, it always diff --git a/ssh.h b/ssh.h index fd8d1677..aa6a6075 100644 --- a/ssh.h +++ b/ssh.h @@ -97,7 +97,6 @@ typedef struct PktOutQueue { PktOut *(*get)(PacketQueueBase *, int pop); } PktOutQueue; -void pq_base_init(PacketQueueBase *pqb); void pq_base_push(PacketQueueBase *pqb, PacketQueueNode *node); void pq_base_push_front(PacketQueueBase *pqb, PacketQueueNode *node); void pq_base_concatenate(PacketQueueBase *dest, From 562cdd4df1b2c741fec90bc80954d76da7a33266 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Fri, 21 Sep 2018 18:00:07 +0100 Subject: [PATCH 436/607] Fix mishandling of refusal to compress in SSH-1. I've just noticed that we call ssh1_bpp_start_compression even if the server responded to our compression request with SSH1_SMSG_FAILURE! Also, while I'm here, there's a potential race condition if the server were to send an unrelated message (such as SSH1_MSG_IGNORE) immediately after the SSH1_SMSG_SUCCESS that indicates compression being enabled - the BPP would try to decode the compressed IGNORE message before the SUCCESS got to the higher layer that would tell the BPP it should have enabled compression. Fixed that by changing the method by which we tell the BPP what's going on. --- ssh.c | 7 ++++--- ssh1bpp.c | 23 +++++++++++++++++------ sshbpp.h | 6 +++++- 3 files changed, 26 insertions(+), 10 deletions(-) diff --git a/ssh.c b/ssh.c index 38640387..1e22cb8f 100644 --- a/ssh.c +++ b/ssh.c @@ -3200,6 +3200,7 @@ static void do_ssh1_connection(void *vctx) pkt = ssh_bpp_new_pktout(ssh->bpp, SSH1_CMSG_REQUEST_COMPRESSION); put_uint32(pkt, 6); /* gzip compression level */ ssh_pkt_write(ssh, pkt); + ssh1_bpp_requested_compression(ssh->bpp); crMaybeWaitUntilV((pktin = pq_pop(&ssh->pq_ssh1_connection)) != NULL); if (pktin->type != SSH1_SMSG_SUCCESS && pktin->type != SSH1_SMSG_FAILURE) { @@ -3207,9 +3208,9 @@ static void do_ssh1_connection(void *vctx) crStopV; } else if (pktin->type == SSH1_SMSG_FAILURE) { c_write_str(ssh, "Server refused to compress\r\n"); - } - logevent("Started zlib (RFC1950) compression"); - ssh1_bpp_start_compression(ssh->bpp); + } else { + logevent("Started zlib (RFC1950) compression"); + } } /* diff --git a/ssh1bpp.c b/ssh1bpp.c index a1fd78c9..702ffb8b 100644 --- a/ssh1bpp.c +++ b/ssh1bpp.c @@ -21,6 +21,7 @@ struct ssh1_bpp_state { struct crcda_ctx *crcda_ctx; + int pending_compression_request; ssh_compressor *compctx; ssh_decompressor *decompctx; @@ -82,17 +83,13 @@ void ssh1_bpp_new_cipher(BinaryPacketProtocol *bpp, } } -void ssh1_bpp_start_compression(BinaryPacketProtocol *bpp) +void ssh1_bpp_requested_compression(BinaryPacketProtocol *bpp) { struct ssh1_bpp_state *s; assert(bpp->vt == &ssh1_bpp_vtable); s = FROMFIELD(bpp, struct ssh1_bpp_state, bpp); - assert(!s->compctx); - assert(!s->decompctx); - - s->compctx = ssh_compressor_new(&ssh_zlib); - s->decompctx = ssh_decompressor_new(&ssh_zlib); + s->pending_compression_request = TRUE; } static void ssh1_bpp_handle_input(BinaryPacketProtocol *bpp) @@ -210,6 +207,20 @@ static void ssh1_bpp_handle_input(BinaryPacketProtocol *bpp) if (type == SSH1_MSG_DISCONNECT) s->bpp.seen_disconnect = TRUE; + + if (type == SSH1_SMSG_SUCCESS && s->pending_compression_request) { + assert(!s->compctx); + assert(!s->decompctx); + + s->compctx = ssh_compressor_new(&ssh_zlib); + s->decompctx = ssh_decompressor_new(&ssh_zlib); + + s->pending_compression_request = FALSE; + } + + if (type == SSH1_SMSG_FAILURE && s->pending_compression_request) { + s->pending_compression_request = FALSE; + } } } crFinishV; diff --git a/sshbpp.h b/sshbpp.h index a1c9d0ac..8fc02960 100644 --- a/sshbpp.h +++ b/sshbpp.h @@ -34,7 +34,11 @@ BinaryPacketProtocol *ssh1_bpp_new(void); void ssh1_bpp_new_cipher(BinaryPacketProtocol *bpp, const struct ssh1_cipheralg *cipher, const void *session_key); -void ssh1_bpp_start_compression(BinaryPacketProtocol *bpp); +/* requested_compression() notifies the SSH-1 BPP that we've just sent + * a request to enable compression, which means that on receiving the + * next SSH1_SMSG_SUCCESS or SSH1_SMSG_FAILURE message, it should set + * up zlib compression if it was SUCCESS. */ +void ssh1_bpp_requested_compression(BinaryPacketProtocol *bpp); /* * Structure that tracks how much data is sent and received, for From f7821f530f738ab68a5545dbd175b18310317fdf Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 22 Sep 2018 09:32:08 +0100 Subject: [PATCH 437/607] Fix paste error in the new pq_concatenate. Commit 6a5d4d083 introduced a foolish list-handling bug: concatenating a non-empty queue to an empty queue would set the tail of the output list to the _head_ of the non-empty one, instead of to its tail. Of course, you don't notice this until you have more than one packet in the queue in question! --- sshcommon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sshcommon.c b/sshcommon.c index b98c9a62..757580ff 100644 --- a/sshcommon.c +++ b/sshcommon.c @@ -125,7 +125,7 @@ void pq_base_concatenate(PacketQueueBase *qdest, if (head2) head2->prev = tail1; else - tail2 = head1; + tail2 = tail1; /* * Check the destination queue is currently empty. (If it was one From 5eb4efce01a814574f5a4f123239ce939c65e0da Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 22 Sep 2018 12:22:07 +0100 Subject: [PATCH 438/607] Remove a fixed-size buffer in pscp.c. Pavel Kryukov reports that gcc 8 didn't like that buffer being the same size as the one from which I was sprintf("%s")ing into it. The easiest fix is to stop trying to guess buffer sizes and use dupprintf. --- pscp.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pscp.c b/pscp.c index 5c698e19..6a76b798 100644 --- a/pscp.c +++ b/pscp.c @@ -852,13 +852,14 @@ int scp_send_filename(const char *name, uint64 size, int permissions) sfree(fullname); return 0; } else { - char buf[40]; + char *buf; char sizestr[40]; uint64_decimal(size, sizestr); if (permissions < 0) permissions = 0644; - sprintf(buf, "C%04o %s ", (int)(permissions & 07777), sizestr); + buf = dupprintf("C%04o %s ", (int)(permissions & 07777), sizestr); backend_send(backend, buf, strlen(buf)); + sfree(buf); backend_send(backend, name, strlen(name)); backend_send(backend, "\n", 1); return response(); From ed70e6014cbe43baf5d5e0c3261c4d99e6bc9473 Mon Sep 17 00:00:00 2001 From: "Pavel I. Kryukov" Date: Sat, 22 Sep 2018 14:37:24 +0300 Subject: [PATCH 439/607] Remove a fixed-size buffer in cmdgen.c. This patch solves the same problem as in previous commit: the fixed-size buffer may have less size than data placed into it. --- cmdgen.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cmdgen.c b/cmdgen.c index 034b9154..610a8c4a 100644 --- a/cmdgen.c +++ b/cmdgen.c @@ -1281,14 +1281,15 @@ int main(int argc, char **argv) setup_passphrases(NULL); test(0, "puttygen", "-L", filename, "-o", pubfilename, NULL); { - char cmdbuf[256]; + char *cmdbuf; fp = NULL; - sprintf(cmdbuf, "ssh-keygen -l -f '%s' > '%s'", + cmdbuf = dupprintf("ssh-keygen -l -f '%s' > '%s'", pubfilename, tmpfilename1); if (system(cmdbuf) || (fp = get_fp(tmpfilename1)) == NULL) { printf("UNABLE to test fingerprint matching against OpenSSH"); } + sfree(cmdbuf); } /* From 26f7a2ac723629bc0f56728eff3eb99f4dd742e6 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 23 Sep 2018 09:30:37 +0100 Subject: [PATCH 440/607] Add missing 'static' to BPP vtable definitions. Vtable objects only need to be globally visible throughout the code if they're used directly in some interchangeable way, e.g. by passing them to a constructor like cipher_new that's the same for all implementations of the vtable, or by directly looking up public data fields in the vtable itself. But the BPPs are never used like that: each BPP has its own constructor function with a different type signature, so the BPP types are not interchangeable in any way _before_ an instance of one has been constructed. Hence, their vtable objects don't need external linkage. --- ssh1bpp.c | 2 +- ssh2bpp-bare.c | 2 +- ssh2bpp.c | 2 +- sshverstring.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ssh1bpp.c b/ssh1bpp.c index 702ffb8b..90942587 100644 --- a/ssh1bpp.c +++ b/ssh1bpp.c @@ -33,7 +33,7 @@ static void ssh1_bpp_handle_input(BinaryPacketProtocol *bpp); static PktOut *ssh1_bpp_new_pktout(int type); static void ssh1_bpp_format_packet(BinaryPacketProtocol *bpp, PktOut *pkt); -const struct BinaryPacketProtocolVtable ssh1_bpp_vtable = { +static const struct BinaryPacketProtocolVtable ssh1_bpp_vtable = { ssh1_bpp_free, ssh1_bpp_handle_input, ssh1_bpp_new_pktout, diff --git a/ssh2bpp-bare.c b/ssh2bpp-bare.c index e16c8509..45f757f6 100644 --- a/ssh2bpp-bare.c +++ b/ssh2bpp-bare.c @@ -25,7 +25,7 @@ static void ssh2_bare_bpp_handle_input(BinaryPacketProtocol *bpp); static PktOut *ssh2_bare_bpp_new_pktout(int type); static void ssh2_bare_bpp_format_packet(BinaryPacketProtocol *bpp, PktOut *); -const struct BinaryPacketProtocolVtable ssh2_bare_bpp_vtable = { +static const struct BinaryPacketProtocolVtable ssh2_bare_bpp_vtable = { ssh2_bare_bpp_free, ssh2_bare_bpp_handle_input, ssh2_bare_bpp_new_pktout, diff --git a/ssh2bpp.c b/ssh2bpp.c index 2b7f4654..49ab8cfd 100644 --- a/ssh2bpp.c +++ b/ssh2bpp.c @@ -42,7 +42,7 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp); static PktOut *ssh2_bpp_new_pktout(int type); static void ssh2_bpp_format_packet(BinaryPacketProtocol *bpp, PktOut *pkt); -const struct BinaryPacketProtocolVtable ssh2_bpp_vtable = { +static const struct BinaryPacketProtocolVtable ssh2_bpp_vtable = { ssh2_bpp_free, ssh2_bpp_handle_input, ssh2_bpp_new_pktout, diff --git a/sshverstring.c b/sshverstring.c index a9b1e46c..37644276 100644 --- a/sshverstring.c +++ b/sshverstring.c @@ -44,7 +44,7 @@ static void ssh_verstring_handle_input(BinaryPacketProtocol *bpp); static PktOut *ssh_verstring_new_pktout(int type); static void ssh_verstring_format_packet(BinaryPacketProtocol *bpp, PktOut *); -const struct BinaryPacketProtocolVtable ssh_verstring_vtable = { +static const struct BinaryPacketProtocolVtable ssh_verstring_vtable = { ssh_verstring_free, ssh_verstring_handle_input, ssh_verstring_new_pktout, From f4fbaa1bd987dea038282e514d99162789f0a697 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Mon, 24 Sep 2018 09:35:52 +0100 Subject: [PATCH 441/607] Rework special-commands system to add an integer argument. In order to list cross-certifiable host keys in the GUI specials menu, the SSH backend has been inventing new values on the end of the Telnet_Special enumeration, starting from the value TS_LOCALSTART. This is inelegant, and also makes it awkward to break up special handlers (e.g. to dispatch different specials to different SSH layers), since if all you know about a special is that it's somewhere in the TS_LOCALSTART+n space, you can't tell what _general kind_ of thing it is. Also, if I ever need another open-ended set of specials in future, I'll have to remember which TS_LOCALSTART+n codes are in which set. So here's a revamp that causes every special to take an extra integer argument. For all previously numbered specials, this argument is passed as zero and ignored, but there's a new main special code for SSH host key cross-certification, in which the integer argument is an index into the backend's list of available keys. TS_LOCALSTART is now a thing of the past: if I need any other open-ended sets of specials in future, I can add a new top-level code with a nicely separated space of arguments. While I'm at it, I've removed the legacy misnomer 'Telnet_Special' from the code completely; the enum is now SessionSpecialCode, the struct containing full details of a menu entry is SessionSpecial, and the enum values now start SS_ rather than TS_. --- defs.h | 2 + ldisc.c | 20 ++++---- pinger.c | 4 +- pscp.c | 4 +- psftp.c | 6 +-- putty.h | 89 ++++++++++++++++++++++----------- raw.c | 6 +-- rlogin.c | 4 +- ssh.c | 119 +++++++++++++++++++++++---------------------- telnet.c | 81 +++++++++++++----------------- testback.c | 8 +-- unix/gtkcompat.h | 1 + unix/gtkwin.c | 27 +++++----- unix/uxplink.c | 4 +- unix/uxpty.c | 4 +- unix/uxser.c | 12 ++--- windows/window.c | 13 ++--- windows/winplink.c | 2 +- windows/winser.c | 12 ++--- 19 files changed, 224 insertions(+), 194 deletions(-) diff --git a/defs.h b/defs.h index 47f7c9ba..f45abfec 100644 --- a/defs.h +++ b/defs.h @@ -70,6 +70,8 @@ typedef struct settings_w settings_w; typedef struct settings_r settings_r; typedef struct settings_e settings_e; +typedef struct SessionSpecial SessionSpecial; + /* Note indirection: for historical reasons (it used to be closer to * the OS socket type), the type that most code uses for a socket is * 'Socket', not 'Socket *'. So an implementation of Socket or Plug diff --git a/ldisc.c b/ldisc.c index e17b13c7..f411174a 100644 --- a/ldisc.c +++ b/ldisc.c @@ -217,7 +217,7 @@ void ldisc_send(Ldisc *ldisc, const void *vbuf, int len, int interactive) bsb(ldisc, plen(ldisc, ldisc->buf[ldisc->buflen - 1])); ldisc->buflen--; } - backend_special(ldisc->backend, TS_EL); + backend_special(ldisc->backend, SS_EL, 0); /* * We don't send IP, SUSP or ABORT if the user has * configured telnet specials off! This breaks @@ -226,11 +226,11 @@ void ldisc_send(Ldisc *ldisc, const void *vbuf, int len, int interactive) if (!ldisc->telnet_keyboard) goto default_case; if (c == CTRL('C')) - backend_special(ldisc->backend, TS_IP); + backend_special(ldisc->backend, SS_IP, 0); if (c == CTRL('Z')) - backend_special(ldisc->backend, TS_SUSP); + backend_special(ldisc->backend, SS_SUSP, 0); if (c == CTRL('\\')) - backend_special(ldisc->backend, TS_ABORT); + backend_special(ldisc->backend, SS_ABORT, 0); break; case CTRL('R'): /* redraw line */ if (ECHOING) { @@ -245,7 +245,7 @@ void ldisc_send(Ldisc *ldisc, const void *vbuf, int len, int interactive) break; case CTRL('D'): /* logout or send */ if (ldisc->buflen == 0) { - backend_special(ldisc->backend, TS_EOF); + backend_special(ldisc->backend, SS_EOF, 0); } else { backend_send(ldisc->backend, ldisc->buf, ldisc->buflen); ldisc->buflen = 0; @@ -288,7 +288,7 @@ void ldisc_send(Ldisc *ldisc, const void *vbuf, int len, int interactive) if (ldisc->protocol == PROT_RAW) backend_send(ldisc->backend, "\r\n", 2); else if (ldisc->protocol == PROT_TELNET && ldisc->telnet_newline) - backend_special(ldisc->backend, TS_EOL); + backend_special(ldisc->backend, SS_EOL, 0); else backend_send(ldisc->backend, "\r", 1); if (ECHOING) @@ -325,24 +325,24 @@ void ldisc_send(Ldisc *ldisc, const void *vbuf, int len, int interactive) switch (buf[0]) { case CTRL('M'): if (ldisc->protocol == PROT_TELNET && ldisc->telnet_newline) - backend_special(ldisc->backend, TS_EOL); + backend_special(ldisc->backend, SS_EOL, 0); else backend_send(ldisc->backend, "\r", 1); break; case CTRL('?'): case CTRL('H'): if (ldisc->telnet_keyboard) { - backend_special(ldisc->backend, TS_EC); + backend_special(ldisc->backend, SS_EC, 0); break; } case CTRL('C'): if (ldisc->telnet_keyboard) { - backend_special(ldisc->backend, TS_IP); + backend_special(ldisc->backend, SS_IP, 0); break; } case CTRL('Z'): if (ldisc->telnet_keyboard) { - backend_special(ldisc->backend, TS_SUSP); + backend_special(ldisc->backend, SS_SUSP, 0); break; } diff --git a/pinger.c b/pinger.c index c83b71d2..672e86f9 100644 --- a/pinger.c +++ b/pinger.c @@ -1,5 +1,5 @@ /* - * pinger.c: centralised module that deals with sending TS_PING + * pinger.c: centralised module that deals with sending SS_PING * keepalives, to avoid replicating this code in multiple backends. */ @@ -19,7 +19,7 @@ static void pinger_timer(void *ctx, unsigned long now) Pinger pinger = (Pinger)ctx; if (pinger->pending && now == pinger->next) { - backend_special(pinger->backend, TS_PING); + backend_special(pinger->backend, SS_PING, 0); pinger->pending = FALSE; pinger_schedule(pinger); } diff --git a/pscp.c b/pscp.c index 6a76b798..2ae32826 100644 --- a/pscp.c +++ b/pscp.c @@ -293,7 +293,7 @@ static void bump(const char *fmt, ...) if (backend && backend_connected(backend)) { char ch; - backend_special(backend, TS_EOF); + backend_special(backend, SS_EOF, 0); sent_eof = TRUE; ssh_scp_recv(&ch, 1); } @@ -2367,7 +2367,7 @@ int psftp_main(int argc, char *argv[]) if (backend && backend_connected(backend)) { char ch; - backend_special(backend, TS_EOF); + backend_special(backend, SS_EOF, 0); sent_eof = TRUE; ssh_scp_recv(&ch, 1); } diff --git a/psftp.c b/psftp.c index 4d9ce87d..c20bfb44 100644 --- a/psftp.c +++ b/psftp.c @@ -973,7 +973,7 @@ int sftp_cmd_close(struct sftp_command *cmd) if (backend_connected(backend)) { char ch; - backend_special(backend, TS_EOF); + backend_special(backend, SS_EOF, 0); sent_eof = TRUE; sftp_recvdata(&ch, 1); } @@ -2355,7 +2355,7 @@ void do_sftp_cleanup() { char ch; if (backend) { - backend_special(backend, TS_EOF); + backend_special(backend, SS_EOF, 0); sent_eof = TRUE; sftp_recvdata(&ch, 1); backend_free(backend); @@ -2965,7 +2965,7 @@ int psftp_main(int argc, char *argv[]) if (backend && backend_connected(backend)) { char ch; - backend_special(backend, TS_EOF); + backend_special(backend, SS_EOF, 0); sent_eof = TRUE; sftp_recvdata(&ch, 1); } diff --git a/putty.h b/putty.h index 4b02c06f..db39f2aa 100644 --- a/putty.h +++ b/putty.h @@ -172,34 +172,67 @@ struct unicode_data { #define LGTYP_PACKETS 3 /* logmode: SSH data packets */ #define LGTYP_SSHRAW 4 /* logmode: SSH raw data */ +/* + * Enumeration of 'special commands' that can be sent during a + * session, separately from the byte stream of ordinary session data. + */ typedef enum { - /* Actual special commands. Originally Telnet, but some codes have - * been re-used for similar specials in other protocols. */ - TS_AYT, TS_BRK, TS_SYNCH, TS_EC, TS_EL, TS_GA, TS_NOP, TS_ABORT, - TS_AO, TS_IP, TS_SUSP, TS_EOR, TS_EOF, TS_LECHO, TS_RECHO, TS_PING, - TS_EOL, - /* Special command for SSH. */ - TS_REKEY, - /* POSIX-style signals. (not Telnet) */ - TS_SIGABRT, TS_SIGALRM, TS_SIGFPE, TS_SIGHUP, TS_SIGILL, - TS_SIGINT, TS_SIGKILL, TS_SIGPIPE, TS_SIGQUIT, TS_SIGSEGV, - TS_SIGTERM, TS_SIGUSR1, TS_SIGUSR2, - /* Pseudo-specials used for constructing the specials menu. */ - TS_SEP, /* Separator */ - TS_SUBMENU, /* Start a new submenu with specified name */ - TS_EXITMENU, /* Exit current submenu or end of specials */ - /* Starting point for protocols to invent special-action codes - * that can't live in this enum at all, e.g. because they change - * with every session. - * - * Of course, this must remain the last value in this - * enumeration. */ - TS_LOCALSTART -} Telnet_Special; + /* + * Commands that are generally useful in multiple backends. + */ + SS_BRK, /* serial-line break */ + SS_EOF, /* end-of-file on session input */ + SS_NOP, /* transmit data with no effect */ + SS_PING, /* try to keep the session alive (probably, but not + * necessarily, implemented as SS_NOP) */ -struct telnet_special { + /* + * Commands specific to Telnet. + */ + SS_AYT, /* Are You There */ + SS_SYNCH, /* Synch */ + SS_EC, /* Erase Character */ + SS_EL, /* Erase Line */ + SS_GA, /* Go Ahead */ + SS_ABORT, /* Abort Process */ + SS_AO, /* Abort Output */ + SS_IP, /* Interrupt Process */ + SS_SUSP, /* Suspend Process */ + SS_EOR, /* End Of Record */ + SS_EOL, /* Telnet end-of-line sequence (CRLF, as opposed to CR + * NUL that escapes a literal CR) */ + + /* + * Commands specific to SSH. + */ + SS_REKEY, /* trigger an immediate repeat key exchange */ + SS_XCERT, /* cross-certify another host key ('arg' indicates which) */ + + /* + * Send a POSIX-style signal. (Useful in SSH and also pterm.) + */ + SS_SIGABRT, SS_SIGALRM, SS_SIGFPE, SS_SIGHUP, SS_SIGILL, + SS_SIGINT, SS_SIGKILL, SS_SIGPIPE, SS_SIGQUIT, SS_SIGSEGV, + SS_SIGTERM, SS_SIGUSR1, SS_SIGUSR2, + + /* + * These aren't really special commands, but they appear in the + * enumeration because the list returned from + * backend_get_specials() will use them to specify the structure + * of the GUI specials menu. + */ + SS_SEP, /* Separator */ + SS_SUBMENU, /* Start a new submenu with specified name */ + SS_EXITMENU, /* Exit current submenu, or end of entire specials list */ +} SessionSpecialCode; + +/* + * The structure type returned from backend_get_specials. + */ +struct SessionSpecial { const char *name; - int code; + SessionSpecialCode code; + int arg; }; typedef enum { @@ -457,8 +490,8 @@ struct Backend_vtable { /* sendbuffer() does the same thing but without attempting a send */ int (*sendbuffer) (Backend *be); void (*size) (Backend *be, int width, int height); - void (*special) (Backend *be, Telnet_Special code); - const struct telnet_special *(*get_specials) (Backend *be); + void (*special) (Backend *be, SessionSpecialCode code, int arg); + const SessionSpecial *(*get_specials) (Backend *be); int (*connected) (Backend *be); int (*exitcode) (Backend *be); /* If back->sendok() returns FALSE, the backend doesn't currently @@ -488,7 +521,7 @@ struct Backend_vtable { #define backend_send(be, buf, len) ((be)->vt->send(be, buf, len)) #define backend_sendbuffer(be) ((be)->vt->sendbuffer(be)) #define backend_size(be, w, h) ((be)->vt->size(be, w, h)) -#define backend_special(be, code) ((be)->vt->special(be, code)) +#define backend_special(be, code, arg) ((be)->vt->special(be, code, arg)) #define backend_get_specials(be) ((be)->vt->get_specials(be)) #define backend_connected(be) ((be)->vt->connected(be)) #define backend_exitcode(be) ((be)->vt->exitcode(be)) diff --git a/raw.c b/raw.c index df280139..fea38a9a 100644 --- a/raw.c +++ b/raw.c @@ -231,10 +231,10 @@ static void raw_size(Backend *be, int width, int height) /* * Send raw special codes. We only handle outgoing EOF here. */ -static void raw_special(Backend *be, Telnet_Special code) +static void raw_special(Backend *be, SessionSpecialCode code, int arg) { Raw raw = FROMFIELD(be, struct raw_backend_data, backend); - if (code == TS_EOF && raw->s) { + if (code == SS_EOF && raw->s) { sk_write_eof(raw->s); raw->sent_socket_eof= TRUE; raw_check_close(raw); @@ -247,7 +247,7 @@ static void raw_special(Backend *be, Telnet_Special code) * Return a list of the special codes that make sense in this * protocol. */ -static const struct telnet_special *raw_get_specials(Backend *be) +static const SessionSpecial *raw_get_specials(Backend *be) { return NULL; } diff --git a/rlogin.c b/rlogin.c index 05dd7dbb..3055ee7f 100644 --- a/rlogin.c +++ b/rlogin.c @@ -328,7 +328,7 @@ static void rlogin_size(Backend *be, int width, int height) /* * Send rlogin special codes. */ -static void rlogin_special(Backend *be, Telnet_Special code) +static void rlogin_special(Backend *be, SessionSpecialCode code, int arg) { /* Do nothing! */ return; @@ -338,7 +338,7 @@ static void rlogin_special(Backend *be, Telnet_Special code) * Return a list of the special codes that make sense in this * protocol. */ -static const struct telnet_special *rlogin_get_specials(Backend *be) +static const SessionSpecial *rlogin_get_specials(Backend *be) { return NULL; } diff --git a/ssh.c b/ssh.c index 1e22cb8f..bc153887 100644 --- a/ssh.c +++ b/ssh.c @@ -313,7 +313,7 @@ static void ssh1_protocol_setup(Ssh ssh); static void ssh2_protocol_setup(Ssh ssh); static void ssh2_bare_connection_protocol_setup(Ssh ssh); static void ssh_size(Backend *be, int width, int height); -static void ssh_special(Backend *be, Telnet_Special); +static void ssh_special(Backend *be, SessionSpecialCode, int arg); static int ssh2_try_send(struct ssh_channel *c); static int ssh_send_channel_data(struct ssh_channel *c, const char *buf, int len); @@ -592,7 +592,7 @@ struct ssh_tag { /* * The last list returned from get_specials. */ - struct telnet_special *specials; + SessionSpecial *specials; /* * List of host key algorithms for which we _don't_ have a stored @@ -3243,7 +3243,7 @@ static void do_ssh1_connection(void *vctx) if (ssh->size_needed) backend_size(&ssh->backend, ssh->term_width, ssh->term_height); if (ssh->eof_needed) - backend_special(&ssh->backend, TS_EOF); + backend_special(&ssh->backend, SS_EOF, 0); if (ssh->ldisc) ldisc_echoedit_update(ssh->ldisc); /* cause ldisc to notice changes */ @@ -8524,7 +8524,7 @@ static void do_ssh2_connection(void *vctx) if (ssh->size_needed) backend_size(&ssh->backend, ssh->term_width, ssh->term_height); if (ssh->eof_needed) - backend_special(&ssh->backend, TS_EOF); + backend_special(&ssh->backend, SS_EOF, 0); /* * Transfer data! @@ -9514,40 +9514,40 @@ static void ssh_size(Backend *be, int width, int height) * Return a list of the special codes that make sense in this * protocol. */ -static const struct telnet_special *ssh_get_specials(Backend *be) +static const SessionSpecial *ssh_get_specials(Backend *be) { - static const struct telnet_special ssh1_ignore_special[] = { - {"IGNORE message", TS_NOP} + static const SessionSpecial ssh1_ignore_special[] = { + {"IGNORE message", SS_NOP} }; - static const struct telnet_special ssh2_ignore_special[] = { - {"IGNORE message", TS_NOP}, + static const SessionSpecial ssh2_ignore_special[] = { + {"IGNORE message", SS_NOP}, }; - static const struct telnet_special ssh2_rekey_special[] = { - {"Repeat key exchange", TS_REKEY}, + static const SessionSpecial ssh2_rekey_special[] = { + {"Repeat key exchange", SS_REKEY}, }; - static const struct telnet_special ssh2_session_specials[] = { - {NULL, TS_SEP}, - {"Break", TS_BRK}, + static const SessionSpecial ssh2_session_specials[] = { + {NULL, SS_SEP}, + {"Break", SS_BRK}, /* These are the signal names defined by RFC 4254. * They include all the ISO C signals, but are a subset of the POSIX * required signals. */ - {"SIGINT (Interrupt)", TS_SIGINT}, - {"SIGTERM (Terminate)", TS_SIGTERM}, - {"SIGKILL (Kill)", TS_SIGKILL}, - {"SIGQUIT (Quit)", TS_SIGQUIT}, - {"SIGHUP (Hangup)", TS_SIGHUP}, - {"More signals", TS_SUBMENU}, - {"SIGABRT", TS_SIGABRT}, {"SIGALRM", TS_SIGALRM}, - {"SIGFPE", TS_SIGFPE}, {"SIGILL", TS_SIGILL}, - {"SIGPIPE", TS_SIGPIPE}, {"SIGSEGV", TS_SIGSEGV}, - {"SIGUSR1", TS_SIGUSR1}, {"SIGUSR2", TS_SIGUSR2}, - {NULL, TS_EXITMENU} + {"SIGINT (Interrupt)", SS_SIGINT}, + {"SIGTERM (Terminate)", SS_SIGTERM}, + {"SIGKILL (Kill)", SS_SIGKILL}, + {"SIGQUIT (Quit)", SS_SIGQUIT}, + {"SIGHUP (Hangup)", SS_SIGHUP}, + {"More signals", SS_SUBMENU}, + {"SIGABRT", SS_SIGABRT}, {"SIGALRM", SS_SIGALRM}, + {"SIGFPE", SS_SIGFPE}, {"SIGILL", SS_SIGILL}, + {"SIGPIPE", SS_SIGPIPE}, {"SIGSEGV", SS_SIGSEGV}, + {"SIGUSR1", SS_SIGUSR1}, {"SIGUSR2", SS_SIGUSR2}, + {NULL, SS_EXITMENU} }; - static const struct telnet_special specials_end[] = { - {NULL, TS_EXITMENU} + static const SessionSpecial specials_end[] = { + {NULL, SS_EXITMENU} }; - struct telnet_special *specials = NULL; + SessionSpecial *specials = NULL; int nspecials = 0, specialsize = 0; Ssh ssh = FROMFIELD(be, struct ssh_tag, backend); @@ -9559,9 +9559,9 @@ static const struct telnet_special *ssh_get_specials(Backend *be) int len = lenof(name); \ if (nspecials + len > specialsize) { \ specialsize = (nspecials + len) * 5 / 4 + 32; \ - specials = sresize(specials, specialsize, struct telnet_special); \ + specials = sresize(specials, specialsize, SessionSpecial); \ } \ - memcpy(specials+nspecials, name, len*sizeof(struct telnet_special)); \ + memcpy(specials+nspecials, name, len*sizeof(SessionSpecial)); \ nspecials += len; \ } while (0) @@ -9580,22 +9580,23 @@ static const struct telnet_special *ssh_get_specials(Backend *be) ADD_SPECIALS(ssh2_session_specials); if (ssh->n_uncert_hostkeys) { - static const struct telnet_special uncert_start[] = { - {NULL, TS_SEP}, - {"Cache new host key type", TS_SUBMENU}, + static const SessionSpecial uncert_start[] = { + {NULL, SS_SEP}, + {"Cache new host key type", SS_SUBMENU}, }; - static const struct telnet_special uncert_end[] = { - {NULL, TS_EXITMENU}, + static const SessionSpecial uncert_end[] = { + {NULL, SS_EXITMENU}, }; int i; ADD_SPECIALS(uncert_start); for (i = 0; i < ssh->n_uncert_hostkeys; i++) { - struct telnet_special uncert[1]; + SessionSpecial uncert[1]; const ssh_keyalg *alg = hostkey_algs[ssh->uncert_hostkeys[i]].alg; uncert[0].name = alg->ssh_id; - uncert[0].code = TS_LOCALSTART + ssh->uncert_hostkeys[i]; + uncert[0].code = SS_XCERT; + uncert[0].arg = ssh->uncert_hostkeys[i]; ADD_SPECIALS(uncert); } ADD_SPECIALS(uncert_end); @@ -9616,22 +9617,22 @@ static const struct telnet_special *ssh_get_specials(Backend *be) } /* - * Send special codes. TS_EOF is useful for `plink', so you + * Send special codes. SS_EOF is useful for `plink', so you * can send an EOF and collect resulting output (e.g. `plink * hostname sort'). */ -static void ssh_special(Backend *be, Telnet_Special code) +static void ssh_special(Backend *be, SessionSpecialCode code, int arg) { Ssh ssh = FROMFIELD(be, struct ssh_tag, backend); PktOut *pktout; - if (code == TS_EOF) { + if (code == SS_EOF) { if (ssh->state != SSH_STATE_SESSION) { /* * Buffer the EOF in case we are pre-SESSION, so we can * send it as soon as we reach SESSION. */ - if (code == TS_EOF) + if (code == SS_EOF) ssh->eof_needed = TRUE; return; } @@ -9643,7 +9644,7 @@ static void ssh_special(Backend *be, Telnet_Special code) ssh->send_ok = 0; /* now stop trying to read from stdin */ } logevent("Sent EOF message"); - } else if (code == TS_PING || code == TS_NOP) { + } else if (code == SS_PING || code == SS_NOP) { if (ssh->state == SSH_STATE_CLOSED || ssh->state == SSH_STATE_PREPACKET) return; if (ssh->version == 1) { @@ -9659,15 +9660,15 @@ static void ssh_special(Backend *be, Telnet_Special code) ssh_pkt_write(ssh, pktout); } } - } else if (code == TS_REKEY) { + } else if (code == SS_REKEY) { if (!ssh->kex_in_progress && !ssh->bare_connection && ssh->version == 2) { ssh->rekey_reason = "at user request"; ssh->rekey_class = RK_NORMAL; queue_idempotent_callback(&ssh->ssh2_transport_icb); } - } else if (code >= TS_LOCALSTART) { - ssh->hostkey_alg = hostkey_algs[code - TS_LOCALSTART].alg; + } else if (code == SS_XCERT) { + ssh->hostkey_alg = hostkey_algs[arg].alg; ssh->cross_certifying = TRUE; if (!ssh->kex_in_progress && !ssh->bare_connection && ssh->version == 2) { @@ -9675,7 +9676,7 @@ static void ssh_special(Backend *be, Telnet_Special code) ssh->rekey_class = RK_NORMAL; queue_idempotent_callback(&ssh->ssh2_transport_icb); } - } else if (code == TS_BRK) { + } else if (code == SS_BRK) { if (ssh->state == SSH_STATE_CLOSED || ssh->state == SSH_STATE_PREPACKET) return; if (ssh->version == 1) { @@ -9688,19 +9689,19 @@ static void ssh_special(Backend *be, Telnet_Special code) } else { /* Is is a POSIX signal? */ const char *signame = NULL; - if (code == TS_SIGABRT) signame = "ABRT"; - if (code == TS_SIGALRM) signame = "ALRM"; - if (code == TS_SIGFPE) signame = "FPE"; - if (code == TS_SIGHUP) signame = "HUP"; - if (code == TS_SIGILL) signame = "ILL"; - if (code == TS_SIGINT) signame = "INT"; - if (code == TS_SIGKILL) signame = "KILL"; - if (code == TS_SIGPIPE) signame = "PIPE"; - if (code == TS_SIGQUIT) signame = "QUIT"; - if (code == TS_SIGSEGV) signame = "SEGV"; - if (code == TS_SIGTERM) signame = "TERM"; - if (code == TS_SIGUSR1) signame = "USR1"; - if (code == TS_SIGUSR2) signame = "USR2"; + if (code == SS_SIGABRT) signame = "ABRT"; + if (code == SS_SIGALRM) signame = "ALRM"; + if (code == SS_SIGFPE) signame = "FPE"; + if (code == SS_SIGHUP) signame = "HUP"; + if (code == SS_SIGILL) signame = "ILL"; + if (code == SS_SIGINT) signame = "INT"; + if (code == SS_SIGKILL) signame = "KILL"; + if (code == SS_SIGPIPE) signame = "PIPE"; + if (code == SS_SIGQUIT) signame = "QUIT"; + if (code == SS_SIGSEGV) signame = "SEGV"; + if (code == SS_SIGTERM) signame = "TERM"; + if (code == SS_SIGUSR1) signame = "USR1"; + if (code == SS_SIGUSR2) signame = "USR2"; /* The SSH-2 protocol does in principle support arbitrary named * signals, including signame@domain, but we don't support those. */ if (signame) { diff --git a/telnet.c b/telnet.c index 7e62e301..171b4210 100644 --- a/telnet.c +++ b/telnet.c @@ -914,7 +914,7 @@ static void telnet_size(Backend *be, int width, int height) /* * Send Telnet special codes. */ -static void telnet_special(Backend *be, Telnet_Special code) +static void telnet_special(Backend *be, SessionSpecialCode code, int arg) { Telnet telnet = FROMFIELD(be, struct telnet_tag, backend); unsigned char b[2]; @@ -924,55 +924,55 @@ static void telnet_special(Backend *be, Telnet_Special code) b[0] = IAC; switch (code) { - case TS_AYT: + case SS_AYT: b[1] = AYT; telnet->bufsize = sk_write(telnet->s, b, 2); break; - case TS_BRK: + case SS_BRK: b[1] = BREAK; telnet->bufsize = sk_write(telnet->s, b, 2); break; - case TS_EC: + case SS_EC: b[1] = EC; telnet->bufsize = sk_write(telnet->s, b, 2); break; - case TS_EL: + case SS_EL: b[1] = EL; telnet->bufsize = sk_write(telnet->s, b, 2); break; - case TS_GA: + case SS_GA: b[1] = GA; telnet->bufsize = sk_write(telnet->s, b, 2); break; - case TS_NOP: + case SS_NOP: b[1] = NOP; telnet->bufsize = sk_write(telnet->s, b, 2); break; - case TS_ABORT: + case SS_ABORT: b[1] = ABORT; telnet->bufsize = sk_write(telnet->s, b, 2); break; - case TS_AO: + case SS_AO: b[1] = AO; telnet->bufsize = sk_write(telnet->s, b, 2); break; - case TS_IP: + case SS_IP: b[1] = IP; telnet->bufsize = sk_write(telnet->s, b, 2); break; - case TS_SUSP: + case SS_SUSP: b[1] = SUSP; telnet->bufsize = sk_write(telnet->s, b, 2); break; - case TS_EOR: + case SS_EOR: b[1] = EOR; telnet->bufsize = sk_write(telnet->s, b, 2); break; - case TS_EOF: + case SS_EOF: b[1] = xEOF; telnet->bufsize = sk_write(telnet->s, b, 2); break; - case TS_EOL: + case SS_EOL: /* In BINARY mode, CR-LF becomes just CR - * and without the NUL suffix too. */ if (telnet->opt_states[o_we_bin.index] == ACTIVE) @@ -980,25 +980,12 @@ static void telnet_special(Backend *be, Telnet_Special code) else telnet->bufsize = sk_write(telnet->s, "\r\n", 2); break; - case TS_SYNCH: + case SS_SYNCH: b[1] = DM; telnet->bufsize = sk_write(telnet->s, b, 1); telnet->bufsize = sk_write_oob(telnet->s, b + 1, 1); break; - case TS_RECHO: - if (telnet->opt_states[o_echo.index] == INACTIVE || - telnet->opt_states[o_echo.index] == REALLY_INACTIVE) { - telnet->opt_states[o_echo.index] = REQUESTED; - send_opt(telnet, o_echo.send, o_echo.option); - } - break; - case TS_LECHO: - if (telnet->opt_states[o_echo.index] == ACTIVE) { - telnet->opt_states[o_echo.index] = REQUESTED; - send_opt(telnet, o_echo.nsend, o_echo.option); - } - break; - case TS_PING: + case SS_PING: if (telnet->opt_states[o_they_sga.index] == ACTIVE) { b[1] = NOP; telnet->bufsize = sk_write(telnet->s, b, 2); @@ -1009,25 +996,25 @@ static void telnet_special(Backend *be, Telnet_Special code) } } -static const struct telnet_special *telnet_get_specials(Backend *be) +static const SessionSpecial *telnet_get_specials(Backend *be) { - static const struct telnet_special specials[] = { - {"Are You There", TS_AYT}, - {"Break", TS_BRK}, - {"Synch", TS_SYNCH}, - {"Erase Character", TS_EC}, - {"Erase Line", TS_EL}, - {"Go Ahead", TS_GA}, - {"No Operation", TS_NOP}, - {NULL, TS_SEP}, - {"Abort Process", TS_ABORT}, - {"Abort Output", TS_AO}, - {"Interrupt Process", TS_IP}, - {"Suspend Process", TS_SUSP}, - {NULL, TS_SEP}, - {"End Of Record", TS_EOR}, - {"End Of File", TS_EOF}, - {NULL, TS_EXITMENU} + static const SessionSpecial specials[] = { + {"Are You There", SS_AYT}, + {"Break", SS_BRK}, + {"Synch", SS_SYNCH}, + {"Erase Character", SS_EC}, + {"Erase Line", SS_EL}, + {"Go Ahead", SS_GA}, + {"No Operation", SS_NOP}, + {NULL, SS_SEP}, + {"Abort Process", SS_ABORT}, + {"Abort Output", SS_AO}, + {"Interrupt Process", SS_IP}, + {"Suspend Process", SS_SUSP}, + {NULL, SS_SEP}, + {"End Of Record", SS_EOR}, + {"End Of File", SS_EOF}, + {NULL, SS_EXITMENU} }; return specials; } diff --git a/testback.c b/testback.c index 01a7e6e0..dfddf93f 100644 --- a/testback.c +++ b/testback.c @@ -43,8 +43,8 @@ static int null_send(Backend *, const char *, int); static int loop_send(Backend *, const char *, int); static int null_sendbuffer(Backend *); static void null_size(Backend *, int, int); -static void null_special(Backend *, Telnet_Special); -static const struct telnet_special *null_get_specials(Backend *); +static void null_special(Backend *, SessionSpecialCode, int); +static const SessionSpecial *null_get_specials(Backend *); static int null_connected(Backend *); static int null_exitcode(Backend *); static int null_sendok(Backend *); @@ -126,11 +126,11 @@ static void null_size(Backend *be, int width, int height) { } -static void null_special(Backend *be, Telnet_Special code) { +static void null_special(Backend *be, SessionSpecialCode code, int arg) { } -static const struct telnet_special *null_get_specials (Backend *be) { +static const SessionSpecial *null_get_specials (Backend *be) { return NULL; } diff --git a/unix/gtkcompat.h b/unix/gtkcompat.h index c0341c34..03947a79 100644 --- a/unix/gtkcompat.h +++ b/unix/gtkcompat.h @@ -33,6 +33,7 @@ #define g_signal_handler_disconnect gtk_signal_disconnect #define g_object_get_data gtk_object_get_data #define g_object_set_data gtk_object_set_data +#define g_object_set_data_full gtk_object_set_data_full #define g_object_ref_sink gtk_object_sink #define GDK_GRAB_SUCCESS GrabSuccess diff --git a/unix/gtkwin.c b/unix/gtkwin.c index eb3f201f..a391f361 100644 --- a/unix/gtkwin.c +++ b/unix/gtkwin.c @@ -1573,10 +1573,10 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) if (event->keyval == GDK_KEY_Break && (event->state & GDK_CONTROL_MASK)) { #ifdef KEY_EVENT_DIAGNOSTICS - debug((" - Ctrl-Break special case, sending TS_BRK\n")); + debug((" - Ctrl-Break special case, sending SS_BRK\n")); #endif if (inst->backend) - backend_special(inst->backend, TS_BRK); + backend_special(inst->backend, SS_BRK, 0); return TRUE; } @@ -4414,11 +4414,10 @@ void copy_all_menuitem(GtkMenuItem *item, gpointer data) void special_menuitem(GtkMenuItem *item, gpointer data) { Frontend *inst = (Frontend *)data; - int code = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(item), - "user-data")); + SessionSpecial *sc = g_object_get_data(G_OBJECT(item), "user-data"); if (inst->backend) - backend_special(inst->backend, code); + backend_special(inst->backend, sc->code, sc->arg); } void about_menuitem(GtkMenuItem *item, gpointer data) @@ -4915,9 +4914,11 @@ void set_window_icon(GtkWidget *window, const char *const *const *icon, #endif } +static void free_special_cmd(gpointer data) { sfree(data); } + void update_specials_menu(Frontend *inst) { - const struct telnet_special *specials; + const SessionSpecial *specials; if (inst->backend) specials = backend_get_specials(inst->backend); @@ -4936,7 +4937,7 @@ void update_specials_menu(Frontend *inst) for (i = 0; nesting > 0; i++) { GtkWidget *menuitem = NULL; switch (specials[i].code) { - case TS_SUBMENU: + case SS_SUBMENU: assert (nesting < 2); saved_menu = menu; /* XXX lame stacking */ menu = gtk_menu_new(); @@ -4947,20 +4948,24 @@ void update_specials_menu(Frontend *inst) menuitem = NULL; nesting++; break; - case TS_EXITMENU: + case SS_EXITMENU: nesting--; if (nesting) { menu = saved_menu; /* XXX lame stacking */ saved_menu = NULL; } break; - case TS_SEP: + case SS_SEP: menuitem = gtk_menu_item_new(); break; default: menuitem = gtk_menu_item_new_with_label(specials[i].name); - g_object_set_data(G_OBJECT(menuitem), "user-data", - GINT_TO_POINTER(specials[i].code)); + { + SessionSpecial *sc = snew(SessionSpecial); + *sc = specials[i]; /* structure copy */ + g_object_set_data_full(G_OBJECT(menuitem), "user-data", + sc, free_special_cmd); + } g_signal_connect(G_OBJECT(menuitem), "activate", G_CALLBACK(special_menuitem), inst); break; diff --git a/unix/uxplink.c b/unix/uxplink.c index 9ef5841b..c211309b 100644 --- a/unix/uxplink.c +++ b/unix/uxplink.c @@ -464,7 +464,7 @@ static void from_tty(void *vbuf, unsigned len) break; case FF00: if (*p == '\0') { - backend_special(backend, TS_BRK); + backend_special(backend, SS_BRK, 0); } else { /* * Pretend that PARMRK wasn't set. This involves @@ -991,7 +991,7 @@ int main(int argc, char **argv) perror("stdin: read"); exit(1); } else if (ret == 0) { - backend_special(backend, TS_EOF); + backend_special(backend, SS_EOF, 0); sending = FALSE; /* send nothing further after this */ } else { if (local_tty) diff --git a/unix/uxpty.c b/unix/uxpty.c index a5c770d4..a8429d76 100644 --- a/unix/uxpty.c +++ b/unix/uxpty.c @@ -1159,7 +1159,7 @@ static void pty_size(Backend *be, int width, int height) /* * Send special codes. */ -static void pty_special(Backend *be, Telnet_Special code) +static void pty_special(Backend *be, SessionSpecialCode code, int arg) { /* Pty pty = FROMFIELD(be, struct pty_tag, backend); */ /* Do nothing! */ @@ -1170,7 +1170,7 @@ static void pty_special(Backend *be, Telnet_Special code) * Return a list of the special codes that make sense in this * protocol. */ -static const struct telnet_special *pty_get_specials(Backend *be) +static const SessionSpecial *pty_get_specials(Backend *be) { /* Pty pty = FROMFIELD(be, struct pty_tag, backend); */ /* diff --git a/unix/uxser.c b/unix/uxser.c index b02eb320..f2064680 100644 --- a/unix/uxser.c +++ b/unix/uxser.c @@ -496,11 +496,11 @@ static void serial_size(Backend *be, int width, int height) /* * Send serial special codes. */ -static void serial_special(Backend *be, Telnet_Special code) +static void serial_special(Backend *be, SessionSpecialCode code, int arg) { Serial serial = FROMFIELD(be, struct serial_backend_data, backend); - if (serial->fd >= 0 && code == TS_BRK) { + if (serial->fd >= 0 && code == SS_BRK) { tcsendbreak(serial->fd, 0); logevent(serial->frontend, "Sending serial break at user request"); } @@ -512,11 +512,11 @@ static void serial_special(Backend *be, Telnet_Special code) * Return a list of the special codes that make sense in this * protocol. */ -static const struct telnet_special *serial_get_specials(Backend *be) +static const SessionSpecial *serial_get_specials(Backend *be) { - static const struct telnet_special specials[] = { - {"Break", TS_BRK}, - {NULL, TS_EXITMENU} + static const struct SessionSpecial specials[] = { + {"Break", SS_BRK}, + {NULL, SS_EXITMENU} }; return specials; } diff --git a/windows/window.c b/windows/window.c index b73de782..40836435 100644 --- a/windows/window.c +++ b/windows/window.c @@ -132,7 +132,7 @@ static struct unicode_data ucsdata; static int session_closed; static int reconfiguring = FALSE; -static const struct telnet_special *specials = NULL; +static const SessionSpecial *specials = NULL; static HMENU specials_menu = NULL; static int n_specials = 0; @@ -965,10 +965,10 @@ void update_specials_menu(Frontend *frontend) for (i = 0; nesting > 0; i++) { assert(IDM_SPECIAL_MIN + 0x10 * i < IDM_SPECIAL_MAX); switch (specials[i].code) { - case TS_SEP: + case SS_SEP: AppendMenu(new_menu, MF_SEPARATOR, 0, 0); break; - case TS_SUBMENU: + case SS_SUBMENU: assert(nesting < 2); nesting++; saved_menu = new_menu; /* XXX lame stacking */ @@ -976,7 +976,7 @@ void update_specials_menu(Frontend *frontend) AppendMenu(saved_menu, MF_POPUP | MF_ENABLED, (UINT_PTR) new_menu, specials[i].name); break; - case TS_EXITMENU: + case SS_EXITMENU: nesting--; if (nesting) { new_menu = saved_menu; /* XXX lame stacking */ @@ -2415,7 +2415,8 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, if (i >= n_specials) break; if (backend) - backend_special(backend, specials[i].code); + backend_special( + backend, specials[i].code, specials[i].arg); } } break; @@ -4406,7 +4407,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, } if (wParam == VK_CANCEL && shift_state == 2) { /* Ctrl-Break */ if (backend) - backend_special(backend, TS_BRK); + backend_special(backend, SS_BRK, 0); return 0; } if (wParam == VK_PAUSE) { /* Break/Pause */ diff --git a/windows/winplink.c b/windows/winplink.c index e8da54ec..c215ec19 100644 --- a/windows/winplink.c +++ b/windows/winplink.c @@ -247,7 +247,7 @@ int stdin_gotdata(struct handle *h, void *data, int len) if (len > 0) { return backend_send(backend, data, len); } else { - backend_special(backend, TS_EOF); + backend_special(backend, SS_EOF, 0); return 0; } } else diff --git a/windows/winser.c b/windows/winser.c index 2a42ce21..e427f358 100644 --- a/windows/winser.c +++ b/windows/winser.c @@ -348,11 +348,11 @@ static void serbreak_timer(void *ctx, unsigned long now) /* * Send serial special codes. */ -static void serial_special(Backend *be, Telnet_Special code) +static void serial_special(Backend *be, SessionSpecialCode code, int arg) { Serial serial = FROMFIELD(be, struct serial_backend_data, backend); - if (serial->port && code == TS_BRK) { + if (serial->port && code == SS_BRK) { logevent(serial->frontend, "Starting serial break at user request"); SetCommBreak(serial->port); /* @@ -377,11 +377,11 @@ static void serial_special(Backend *be, Telnet_Special code) * Return a list of the special codes that make sense in this * protocol. */ -static const struct telnet_special *serial_get_specials(Backend *be) +static const SessionSpecial *serial_get_specials(Backend *be) { - static const struct telnet_special specials[] = { - {"Break", TS_BRK}, - {NULL, TS_EXITMENU} + static const SessionSpecial specials[] = { + {"Break", SS_BRK}, + {NULL, SS_EXITMENU} }; return specials; } From 8cb68390e430fc03a0d032327dec36913320e60d Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Mon, 24 Sep 2018 13:29:09 +0100 Subject: [PATCH 442/607] Move SSH packet type codes into list macros. This allows me to share just one definition of the packet types between the enum declarations in ssh.h and the string translation functions in sshcommon.c. No functional change. The style of list macro is slightly unusual; instead of the traditional 'X-macro' in which LIST(X) expands to invocations of the form X(list element), this is an 'X-y macro', where LIST(X,y) expands to invocations of the form X(y, list element). That style makes it possible to wrap the list macro up in another macro and pass a parameter through from the wrapper to the per-element macro. I'm not using that facility just yet, but I will in the next commit. --- ssh.h | 219 ++++++++++++++++++++++++++++------------------------ sshcommon.c | 114 ++++----------------------- 2 files changed, 129 insertions(+), 204 deletions(-) diff --git a/ssh.h b/ssh.h index aa6a6075..b438b35b 100644 --- a/ssh.h +++ b/ssh.h @@ -1107,49 +1107,51 @@ int platform_ssh_share(const char *name, Conf *conf, void platform_ssh_share_cleanup(const char *name); /* - * SSH-1 message type codes. + * List macro defining the SSH-1 message type codes. */ -#define SSH1_MSG_DISCONNECT 1 /* 0x1 */ -#define SSH1_SMSG_PUBLIC_KEY 2 /* 0x2 */ -#define SSH1_CMSG_SESSION_KEY 3 /* 0x3 */ -#define SSH1_CMSG_USER 4 /* 0x4 */ -#define SSH1_CMSG_AUTH_RSA 6 /* 0x6 */ -#define SSH1_SMSG_AUTH_RSA_CHALLENGE 7 /* 0x7 */ -#define SSH1_CMSG_AUTH_RSA_RESPONSE 8 /* 0x8 */ -#define SSH1_CMSG_AUTH_PASSWORD 9 /* 0x9 */ -#define SSH1_CMSG_REQUEST_PTY 10 /* 0xa */ -#define SSH1_CMSG_WINDOW_SIZE 11 /* 0xb */ -#define SSH1_CMSG_EXEC_SHELL 12 /* 0xc */ -#define SSH1_CMSG_EXEC_CMD 13 /* 0xd */ -#define SSH1_SMSG_SUCCESS 14 /* 0xe */ -#define SSH1_SMSG_FAILURE 15 /* 0xf */ -#define SSH1_CMSG_STDIN_DATA 16 /* 0x10 */ -#define SSH1_SMSG_STDOUT_DATA 17 /* 0x11 */ -#define SSH1_SMSG_STDERR_DATA 18 /* 0x12 */ -#define SSH1_CMSG_EOF 19 /* 0x13 */ -#define SSH1_SMSG_EXIT_STATUS 20 /* 0x14 */ -#define SSH1_MSG_CHANNEL_OPEN_CONFIRMATION 21 /* 0x15 */ -#define SSH1_MSG_CHANNEL_OPEN_FAILURE 22 /* 0x16 */ -#define SSH1_MSG_CHANNEL_DATA 23 /* 0x17 */ -#define SSH1_MSG_CHANNEL_CLOSE 24 /* 0x18 */ -#define SSH1_MSG_CHANNEL_CLOSE_CONFIRMATION 25 /* 0x19 */ -#define SSH1_SMSG_X11_OPEN 27 /* 0x1b */ -#define SSH1_CMSG_PORT_FORWARD_REQUEST 28 /* 0x1c */ -#define SSH1_MSG_PORT_OPEN 29 /* 0x1d */ -#define SSH1_CMSG_AGENT_REQUEST_FORWARDING 30 /* 0x1e */ -#define SSH1_SMSG_AGENT_OPEN 31 /* 0x1f */ -#define SSH1_MSG_IGNORE 32 /* 0x20 */ -#define SSH1_CMSG_EXIT_CONFIRMATION 33 /* 0x21 */ -#define SSH1_CMSG_X11_REQUEST_FORWARDING 34 /* 0x22 */ -#define SSH1_CMSG_AUTH_RHOSTS_RSA 35 /* 0x23 */ -#define SSH1_MSG_DEBUG 36 /* 0x24 */ -#define SSH1_CMSG_REQUEST_COMPRESSION 37 /* 0x25 */ -#define SSH1_CMSG_AUTH_TIS 39 /* 0x27 */ -#define SSH1_SMSG_AUTH_TIS_CHALLENGE 40 /* 0x28 */ -#define SSH1_CMSG_AUTH_TIS_RESPONSE 41 /* 0x29 */ -#define SSH1_CMSG_AUTH_CCARD 70 /* 0x46 */ -#define SSH1_SMSG_AUTH_CCARD_CHALLENGE 71 /* 0x47 */ -#define SSH1_CMSG_AUTH_CCARD_RESPONSE 72 /* 0x48 */ +#define SSH1_MESSAGE_TYPES(X, y) \ + X(y, SSH1_MSG_DISCONNECT, 1) \ + X(y, SSH1_SMSG_PUBLIC_KEY, 2) \ + X(y, SSH1_CMSG_SESSION_KEY, 3) \ + X(y, SSH1_CMSG_USER, 4) \ + X(y, SSH1_CMSG_AUTH_RSA, 6) \ + X(y, SSH1_SMSG_AUTH_RSA_CHALLENGE, 7) \ + X(y, SSH1_CMSG_AUTH_RSA_RESPONSE, 8) \ + X(y, SSH1_CMSG_AUTH_PASSWORD, 9) \ + X(y, SSH1_CMSG_REQUEST_PTY, 10) \ + X(y, SSH1_CMSG_WINDOW_SIZE, 11) \ + X(y, SSH1_CMSG_EXEC_SHELL, 12) \ + X(y, SSH1_CMSG_EXEC_CMD, 13) \ + X(y, SSH1_SMSG_SUCCESS, 14) \ + X(y, SSH1_SMSG_FAILURE, 15) \ + X(y, SSH1_CMSG_STDIN_DATA, 16) \ + X(y, SSH1_SMSG_STDOUT_DATA, 17) \ + X(y, SSH1_SMSG_STDERR_DATA, 18) \ + X(y, SSH1_CMSG_EOF, 19) \ + X(y, SSH1_SMSG_EXIT_STATUS, 20) \ + X(y, SSH1_MSG_CHANNEL_OPEN_CONFIRMATION, 21) \ + X(y, SSH1_MSG_CHANNEL_OPEN_FAILURE, 22) \ + X(y, SSH1_MSG_CHANNEL_DATA, 23) \ + X(y, SSH1_MSG_CHANNEL_CLOSE, 24) \ + X(y, SSH1_MSG_CHANNEL_CLOSE_CONFIRMATION, 25) \ + X(y, SSH1_SMSG_X11_OPEN, 27) \ + X(y, SSH1_CMSG_PORT_FORWARD_REQUEST, 28) \ + X(y, SSH1_MSG_PORT_OPEN, 29) \ + X(y, SSH1_CMSG_AGENT_REQUEST_FORWARDING, 30) \ + X(y, SSH1_SMSG_AGENT_OPEN, 31) \ + X(y, SSH1_MSG_IGNORE, 32) \ + X(y, SSH1_CMSG_EXIT_CONFIRMATION, 33) \ + X(y, SSH1_CMSG_X11_REQUEST_FORWARDING, 34) \ + X(y, SSH1_CMSG_AUTH_RHOSTS_RSA, 35) \ + X(y, SSH1_MSG_DEBUG, 36) \ + X(y, SSH1_CMSG_REQUEST_COMPRESSION, 37) \ + X(y, SSH1_CMSG_AUTH_TIS, 39) \ + X(y, SSH1_SMSG_AUTH_TIS_CHALLENGE, 40) \ + X(y, SSH1_CMSG_AUTH_TIS_RESPONSE, 41) \ + X(y, SSH1_CMSG_AUTH_CCARD, 70) \ + X(y, SSH1_SMSG_AUTH_CCARD_CHALLENGE, 71) \ + X(y, SSH1_CMSG_AUTH_CCARD_RESPONSE, 72) \ + /* end of list */ #define SSH1_AUTH_RHOSTS 1 /* 0x1 */ #define SSH1_AUTH_RSA 2 /* 0x2 */ @@ -1163,68 +1165,79 @@ void platform_ssh_share_cleanup(const char *name); #define SSH1_PROTOFLAGS_SUPPORTED 0 /* 0x1 */ /* - * SSH-2 message type codes. + * List macro defining SSH-2 message type codes. Some of these depend + * on particular contexts (i.e. a previously negotiated kex or auth + * method) */ -#define SSH2_MSG_DISCONNECT 1 /* 0x1 */ -#define SSH2_MSG_IGNORE 2 /* 0x2 */ -#define SSH2_MSG_UNIMPLEMENTED 3 /* 0x3 */ -#define SSH2_MSG_DEBUG 4 /* 0x4 */ -#define SSH2_MSG_SERVICE_REQUEST 5 /* 0x5 */ -#define SSH2_MSG_SERVICE_ACCEPT 6 /* 0x6 */ -#define SSH2_MSG_KEXINIT 20 /* 0x14 */ -#define SSH2_MSG_NEWKEYS 21 /* 0x15 */ -#define SSH2_MSG_KEXDH_INIT 30 /* 0x1e */ -#define SSH2_MSG_KEXDH_REPLY 31 /* 0x1f */ -#define SSH2_MSG_KEX_DH_GEX_REQUEST_OLD 30 /* 0x1e */ -#define SSH2_MSG_KEX_DH_GEX_REQUEST 34 /* 0x22 */ -#define SSH2_MSG_KEX_DH_GEX_GROUP 31 /* 0x1f */ -#define SSH2_MSG_KEX_DH_GEX_INIT 32 /* 0x20 */ -#define SSH2_MSG_KEX_DH_GEX_REPLY 33 /* 0x21 */ -#define SSH2_MSG_KEXGSS_INIT 30 /* 0x1e */ -#define SSH2_MSG_KEXGSS_CONTINUE 31 /* 0x1f */ -#define SSH2_MSG_KEXGSS_COMPLETE 32 /* 0x20 */ -#define SSH2_MSG_KEXGSS_HOSTKEY 33 /* 0x21 */ -#define SSH2_MSG_KEXGSS_ERROR 34 /* 0x22 */ -#define SSH2_MSG_KEXGSS_GROUPREQ 40 /* 0x28 */ -#define SSH2_MSG_KEXGSS_GROUP 41 /* 0x29 */ -#define SSH2_MSG_KEXRSA_PUBKEY 30 /* 0x1e */ -#define SSH2_MSG_KEXRSA_SECRET 31 /* 0x1f */ -#define SSH2_MSG_KEXRSA_DONE 32 /* 0x20 */ -#define SSH2_MSG_KEX_ECDH_INIT 30 /* 0x1e */ -#define SSH2_MSG_KEX_ECDH_REPLY 31 /* 0x1f */ -#define SSH2_MSG_KEX_ECMQV_INIT 30 /* 0x1e */ -#define SSH2_MSG_KEX_ECMQV_REPLY 31 /* 0x1f */ -#define SSH2_MSG_USERAUTH_REQUEST 50 /* 0x32 */ -#define SSH2_MSG_USERAUTH_FAILURE 51 /* 0x33 */ -#define SSH2_MSG_USERAUTH_SUCCESS 52 /* 0x34 */ -#define SSH2_MSG_USERAUTH_BANNER 53 /* 0x35 */ -#define SSH2_MSG_USERAUTH_PK_OK 60 /* 0x3c */ -#define SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ 60 /* 0x3c */ -#define SSH2_MSG_USERAUTH_INFO_REQUEST 60 /* 0x3c */ -#define SSH2_MSG_USERAUTH_INFO_RESPONSE 61 /* 0x3d */ -#define SSH2_MSG_GLOBAL_REQUEST 80 /* 0x50 */ -#define SSH2_MSG_REQUEST_SUCCESS 81 /* 0x51 */ -#define SSH2_MSG_REQUEST_FAILURE 82 /* 0x52 */ -#define SSH2_MSG_CHANNEL_OPEN 90 /* 0x5a */ -#define SSH2_MSG_CHANNEL_OPEN_CONFIRMATION 91 /* 0x5b */ -#define SSH2_MSG_CHANNEL_OPEN_FAILURE 92 /* 0x5c */ -#define SSH2_MSG_CHANNEL_WINDOW_ADJUST 93 /* 0x5d */ -#define SSH2_MSG_CHANNEL_DATA 94 /* 0x5e */ -#define SSH2_MSG_CHANNEL_EXTENDED_DATA 95 /* 0x5f */ -#define SSH2_MSG_CHANNEL_EOF 96 /* 0x60 */ -#define SSH2_MSG_CHANNEL_CLOSE 97 /* 0x61 */ -#define SSH2_MSG_CHANNEL_REQUEST 98 /* 0x62 */ -#define SSH2_MSG_CHANNEL_SUCCESS 99 /* 0x63 */ -#define SSH2_MSG_CHANNEL_FAILURE 100 /* 0x64 */ -#define SSH2_MSG_USERAUTH_GSSAPI_RESPONSE 60 -#define SSH2_MSG_USERAUTH_GSSAPI_TOKEN 61 -#define SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE 63 -#define SSH2_MSG_USERAUTH_GSSAPI_ERROR 64 -#define SSH2_MSG_USERAUTH_GSSAPI_ERRTOK 65 -#define SSH2_MSG_USERAUTH_GSSAPI_MIC 66 - -/* Virtual packet type, for packets too short to even have a type */ -#define SSH_MSG_NO_TYPE_CODE 0x100 +#define SSH2_MESSAGE_TYPES(X, K, A, y) \ + X(y, SSH2_MSG_DISCONNECT, 1) \ + X(y, SSH2_MSG_IGNORE, 2) \ + X(y, SSH2_MSG_UNIMPLEMENTED, 3) \ + X(y, SSH2_MSG_DEBUG, 4) \ + X(y, SSH2_MSG_SERVICE_REQUEST, 5) \ + X(y, SSH2_MSG_SERVICE_ACCEPT, 6) \ + X(y, SSH2_MSG_KEXINIT, 20) \ + X(y, SSH2_MSG_NEWKEYS, 21) \ + K(y, SSH2_MSG_KEXDH_INIT, 30, SSH2_PKTCTX_DHGROUP) \ + K(y, SSH2_MSG_KEXDH_REPLY, 31, SSH2_PKTCTX_DHGROUP) \ + K(y, SSH2_MSG_KEX_DH_GEX_REQUEST_OLD, 30, SSH2_PKTCTX_DHGEX) \ + K(y, SSH2_MSG_KEX_DH_GEX_REQUEST, 34, SSH2_PKTCTX_DHGEX) \ + K(y, SSH2_MSG_KEX_DH_GEX_GROUP, 31, SSH2_PKTCTX_DHGEX) \ + K(y, SSH2_MSG_KEX_DH_GEX_INIT, 32, SSH2_PKTCTX_DHGEX) \ + K(y, SSH2_MSG_KEX_DH_GEX_REPLY, 33, SSH2_PKTCTX_DHGEX) \ + K(y, SSH2_MSG_KEXGSS_INIT, 30, SSH2_PKTCTX_GSSKEX) \ + K(y, SSH2_MSG_KEXGSS_CONTINUE, 31, SSH2_PKTCTX_GSSKEX) \ + K(y, SSH2_MSG_KEXGSS_COMPLETE, 32, SSH2_PKTCTX_GSSKEX) \ + K(y, SSH2_MSG_KEXGSS_HOSTKEY, 33, SSH2_PKTCTX_GSSKEX) \ + K(y, SSH2_MSG_KEXGSS_ERROR, 34, SSH2_PKTCTX_GSSKEX) \ + K(y, SSH2_MSG_KEXGSS_GROUPREQ, 40, SSH2_PKTCTX_GSSKEX) \ + K(y, SSH2_MSG_KEXGSS_GROUP, 41, SSH2_PKTCTX_GSSKEX) \ + K(y, SSH2_MSG_KEXRSA_PUBKEY, 30, SSH2_PKTCTX_RSAKEX) \ + K(y, SSH2_MSG_KEXRSA_SECRET, 31, SSH2_PKTCTX_RSAKEX) \ + K(y, SSH2_MSG_KEXRSA_DONE, 32, SSH2_PKTCTX_RSAKEX) \ + K(y, SSH2_MSG_KEX_ECDH_INIT, 30, SSH2_PKTCTX_DHGEX) \ + K(y, SSH2_MSG_KEX_ECDH_REPLY, 31, SSH2_PKTCTX_DHGEX) \ + X(y, SSH2_MSG_USERAUTH_REQUEST, 50) \ + X(y, SSH2_MSG_USERAUTH_FAILURE, 51) \ + X(y, SSH2_MSG_USERAUTH_SUCCESS, 52) \ + X(y, SSH2_MSG_USERAUTH_BANNER, 53) \ + A(y, SSH2_MSG_USERAUTH_PK_OK, 60, SSH2_PKTCTX_PUBLICKEY) \ + A(y, SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ, 60, SSH2_PKTCTX_PASSWORD) \ + A(y, SSH2_MSG_USERAUTH_INFO_REQUEST, 60, SSH2_PKTCTX_KBDINTER) \ + A(y, SSH2_MSG_USERAUTH_INFO_RESPONSE, 61, SSH2_PKTCTX_KBDINTER) \ + A(y, SSH2_MSG_USERAUTH_GSSAPI_RESPONSE, 60, SSH2_PKTCTX_GSSAPI) \ + A(y, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, 61, SSH2_PKTCTX_GSSAPI) \ + A(y, SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, 63, SSH2_PKTCTX_GSSAPI) \ + A(y, SSH2_MSG_USERAUTH_GSSAPI_ERROR, 64, SSH2_PKTCTX_GSSAPI) \ + A(y, SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, 65, SSH2_PKTCTX_GSSAPI) \ + A(y, SSH2_MSG_USERAUTH_GSSAPI_MIC, 66, SSH2_PKTCTX_GSSAPI) \ + X(y, SSH2_MSG_GLOBAL_REQUEST, 80) \ + X(y, SSH2_MSG_REQUEST_SUCCESS, 81) \ + X(y, SSH2_MSG_REQUEST_FAILURE, 82) \ + X(y, SSH2_MSG_CHANNEL_OPEN, 90) \ + X(y, SSH2_MSG_CHANNEL_OPEN_CONFIRMATION, 91) \ + X(y, SSH2_MSG_CHANNEL_OPEN_FAILURE, 92) \ + X(y, SSH2_MSG_CHANNEL_WINDOW_ADJUST, 93) \ + X(y, SSH2_MSG_CHANNEL_DATA, 94) \ + X(y, SSH2_MSG_CHANNEL_EXTENDED_DATA, 95) \ + X(y, SSH2_MSG_CHANNEL_EOF, 96) \ + X(y, SSH2_MSG_CHANNEL_CLOSE, 97) \ + X(y, SSH2_MSG_CHANNEL_REQUEST, 98) \ + X(y, SSH2_MSG_CHANNEL_SUCCESS, 99) \ + X(y, SSH2_MSG_CHANNEL_FAILURE, 100) \ + /* end of list */ + +#define DEF_ENUM_UNIVERSAL(y, name, value) name = value, +#define DEF_ENUM_CONTEXTUAL(y, name, value, context) name = value, +enum { + SSH1_MESSAGE_TYPES(DEF_ENUM_UNIVERSAL, y) + SSH2_MESSAGE_TYPES(DEF_ENUM_UNIVERSAL, + DEF_ENUM_CONTEXTUAL, DEF_ENUM_CONTEXTUAL, y) + /* Virtual packet type, for packets too short to even have a type */ + SSH_MSG_NO_TYPE_CODE = 256 +}; +#undef DEF_ENUM_UNIVERSAL +#undef DEF_ENUM_CONTEXTUAL /* Given that virtual packet types exist, this is how big the dispatch * table has to be */ diff --git a/sshcommon.c b/sshcommon.c index 757580ff..3b7fc6a8 100644 --- a/sshcommon.c +++ b/sshcommon.c @@ -560,112 +560,24 @@ void add_to_commasep(strbuf *buf, const char *data) * string names. */ -#define translate(x) if (type == x) return #x -#define translatek(x,ctx) if (type == x && (pkt_kctx == ctx)) return #x -#define translatea(x,ctx) if (type == x && (pkt_actx == ctx)) return #x +#define TRANSLATE_UNIVERSAL(y, name, value) \ + if (type == value) return #name; +#define TRANSLATE_KEX(y, name, value, ctx) \ + if (type == value && pkt_kctx == ctx) return #name; +#define TRANSLATE_AUTH(y, name, value, ctx) \ + if (type == value && pkt_actx == ctx) return #name; + const char *ssh1_pkt_type(int type) { - translate(SSH1_MSG_DISCONNECT); - translate(SSH1_SMSG_PUBLIC_KEY); - translate(SSH1_CMSG_SESSION_KEY); - translate(SSH1_CMSG_USER); - translate(SSH1_CMSG_AUTH_RSA); - translate(SSH1_SMSG_AUTH_RSA_CHALLENGE); - translate(SSH1_CMSG_AUTH_RSA_RESPONSE); - translate(SSH1_CMSG_AUTH_PASSWORD); - translate(SSH1_CMSG_REQUEST_PTY); - translate(SSH1_CMSG_WINDOW_SIZE); - translate(SSH1_CMSG_EXEC_SHELL); - translate(SSH1_CMSG_EXEC_CMD); - translate(SSH1_SMSG_SUCCESS); - translate(SSH1_SMSG_FAILURE); - translate(SSH1_CMSG_STDIN_DATA); - translate(SSH1_SMSG_STDOUT_DATA); - translate(SSH1_SMSG_STDERR_DATA); - translate(SSH1_CMSG_EOF); - translate(SSH1_SMSG_EXIT_STATUS); - translate(SSH1_MSG_CHANNEL_OPEN_CONFIRMATION); - translate(SSH1_MSG_CHANNEL_OPEN_FAILURE); - translate(SSH1_MSG_CHANNEL_DATA); - translate(SSH1_MSG_CHANNEL_CLOSE); - translate(SSH1_MSG_CHANNEL_CLOSE_CONFIRMATION); - translate(SSH1_SMSG_X11_OPEN); - translate(SSH1_CMSG_PORT_FORWARD_REQUEST); - translate(SSH1_MSG_PORT_OPEN); - translate(SSH1_CMSG_AGENT_REQUEST_FORWARDING); - translate(SSH1_SMSG_AGENT_OPEN); - translate(SSH1_MSG_IGNORE); - translate(SSH1_CMSG_EXIT_CONFIRMATION); - translate(SSH1_CMSG_X11_REQUEST_FORWARDING); - translate(SSH1_CMSG_AUTH_RHOSTS_RSA); - translate(SSH1_MSG_DEBUG); - translate(SSH1_CMSG_REQUEST_COMPRESSION); - translate(SSH1_CMSG_AUTH_TIS); - translate(SSH1_SMSG_AUTH_TIS_CHALLENGE); - translate(SSH1_CMSG_AUTH_TIS_RESPONSE); - translate(SSH1_CMSG_AUTH_CCARD); - translate(SSH1_SMSG_AUTH_CCARD_CHALLENGE); - translate(SSH1_CMSG_AUTH_CCARD_RESPONSE); + SSH1_MESSAGE_TYPES(TRANSLATE_UNIVERSAL, y); return "unknown"; } const char *ssh2_pkt_type(Pkt_KCtx pkt_kctx, Pkt_ACtx pkt_actx, int type) { - translatea(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE,SSH2_PKTCTX_GSSAPI); - translatea(SSH2_MSG_USERAUTH_GSSAPI_TOKEN,SSH2_PKTCTX_GSSAPI); - translatea(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE,SSH2_PKTCTX_GSSAPI); - translatea(SSH2_MSG_USERAUTH_GSSAPI_ERROR,SSH2_PKTCTX_GSSAPI); - translatea(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK,SSH2_PKTCTX_GSSAPI); - translatea(SSH2_MSG_USERAUTH_GSSAPI_MIC, SSH2_PKTCTX_GSSAPI); - translate(SSH2_MSG_DISCONNECT); - translate(SSH2_MSG_IGNORE); - translate(SSH2_MSG_UNIMPLEMENTED); - translate(SSH2_MSG_DEBUG); - translate(SSH2_MSG_SERVICE_REQUEST); - translate(SSH2_MSG_SERVICE_ACCEPT); - translate(SSH2_MSG_KEXINIT); - translate(SSH2_MSG_NEWKEYS); - translatek(SSH2_MSG_KEXDH_INIT, SSH2_PKTCTX_DHGROUP); - translatek(SSH2_MSG_KEXDH_REPLY, SSH2_PKTCTX_DHGROUP); - translatek(SSH2_MSG_KEX_DH_GEX_REQUEST_OLD, SSH2_PKTCTX_DHGEX); - translatek(SSH2_MSG_KEX_DH_GEX_REQUEST, SSH2_PKTCTX_DHGEX); - translatek(SSH2_MSG_KEX_DH_GEX_GROUP, SSH2_PKTCTX_DHGEX); - translatek(SSH2_MSG_KEX_DH_GEX_INIT, SSH2_PKTCTX_DHGEX); - translatek(SSH2_MSG_KEX_DH_GEX_REPLY, SSH2_PKTCTX_DHGEX); - translatek(SSH2_MSG_KEXRSA_PUBKEY, SSH2_PKTCTX_RSAKEX); - translatek(SSH2_MSG_KEXRSA_SECRET, SSH2_PKTCTX_RSAKEX); - translatek(SSH2_MSG_KEXRSA_DONE, SSH2_PKTCTX_RSAKEX); - translatek(SSH2_MSG_KEX_ECDH_INIT, SSH2_PKTCTX_ECDHKEX); - translatek(SSH2_MSG_KEX_ECDH_REPLY, SSH2_PKTCTX_ECDHKEX); - translatek(SSH2_MSG_KEXGSS_INIT, SSH2_PKTCTX_GSSKEX); - translatek(SSH2_MSG_KEXGSS_CONTINUE, SSH2_PKTCTX_GSSKEX); - translatek(SSH2_MSG_KEXGSS_COMPLETE, SSH2_PKTCTX_GSSKEX); - translatek(SSH2_MSG_KEXGSS_HOSTKEY, SSH2_PKTCTX_GSSKEX); - translatek(SSH2_MSG_KEXGSS_ERROR, SSH2_PKTCTX_GSSKEX); - translatek(SSH2_MSG_KEXGSS_GROUPREQ, SSH2_PKTCTX_GSSKEX); - translatek(SSH2_MSG_KEXGSS_GROUP, SSH2_PKTCTX_GSSKEX); - translate(SSH2_MSG_USERAUTH_REQUEST); - translate(SSH2_MSG_USERAUTH_FAILURE); - translate(SSH2_MSG_USERAUTH_SUCCESS); - translate(SSH2_MSG_USERAUTH_BANNER); - translatea(SSH2_MSG_USERAUTH_PK_OK, SSH2_PKTCTX_PUBLICKEY); - translatea(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ, SSH2_PKTCTX_PASSWORD); - translatea(SSH2_MSG_USERAUTH_INFO_REQUEST, SSH2_PKTCTX_KBDINTER); - translatea(SSH2_MSG_USERAUTH_INFO_RESPONSE, SSH2_PKTCTX_KBDINTER); - translate(SSH2_MSG_GLOBAL_REQUEST); - translate(SSH2_MSG_REQUEST_SUCCESS); - translate(SSH2_MSG_REQUEST_FAILURE); - translate(SSH2_MSG_CHANNEL_OPEN); - translate(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION); - translate(SSH2_MSG_CHANNEL_OPEN_FAILURE); - translate(SSH2_MSG_CHANNEL_WINDOW_ADJUST); - translate(SSH2_MSG_CHANNEL_DATA); - translate(SSH2_MSG_CHANNEL_EXTENDED_DATA); - translate(SSH2_MSG_CHANNEL_EOF); - translate(SSH2_MSG_CHANNEL_CLOSE); - translate(SSH2_MSG_CHANNEL_REQUEST); - translate(SSH2_MSG_CHANNEL_SUCCESS); - translate(SSH2_MSG_CHANNEL_FAILURE); + SSH2_MESSAGE_TYPES(TRANSLATE_UNIVERSAL, TRANSLATE_KEX, TRANSLATE_AUTH, y); return "unknown"; } -#undef translate -#undef translatec + +#undef TRANSLATE_UNIVERSAL +#undef TRANSLATE_KEX +#undef TRANSLATE_AUTH From 09c3439b5ab3be150cfaa1565968e797fa4133b8 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Mon, 24 Sep 2018 13:45:10 +0100 Subject: [PATCH 443/607] Move SSH_MSG_UNEXPECTED generation into the BPP. Now I've got a list macro defining all the packet types we recognise, I can use it to write a test for 'is this a recognised code?', and use that in turn to centralise detection of completely unrecognised codes into the binary packet protocol, where any such messages will be handled entirely internally and never even be seen by the next level up. This lets me remove another big pile of boilerplate in ssh.c. --- ssh.c | 81 +++++++------------------------------------------- ssh.h | 1 + ssh2bpp-bare.c | 6 ++++ ssh2bpp.c | 6 ++++ sshbpp.h | 3 ++ sshcommon.c | 41 +++++++++++++++++++++++++ 6 files changed, 67 insertions(+), 71 deletions(-) diff --git a/ssh.c b/ssh.c index bc153887..1d7580cb 100644 --- a/ssh.c +++ b/ssh.c @@ -75,7 +75,6 @@ static void ssh2_channel_check_close(struct ssh_channel *c); static void ssh_channel_close_local(struct ssh_channel *c, char const *reason); static void ssh_channel_destroy(struct ssh_channel *c); static void ssh_channel_unthrottle(struct ssh_channel *c, int bufsize); -static void ssh2_msg_something_unimplemented(Ssh ssh, PktIn *pktin); static void ssh2_general_packet_processing(Ssh ssh, PktIn *pktin); static void ssh1_login_input(Ssh ssh); static void ssh2_userauth_input(Ssh ssh); @@ -8630,18 +8629,6 @@ static void ssh2_msg_unexpected(Ssh ssh, PktIn *pktin) sfree(buf); } -static void ssh2_msg_something_unimplemented(Ssh ssh, PktIn *pktin) -{ - PktOut *pktout; - pktout = ssh_bpp_new_pktout(ssh->bpp, SSH2_MSG_UNIMPLEMENTED); - put_uint32(pktout, pktin->sequence); - /* - * UNIMPLEMENTED messages MUST appear in the same order as the - * messages they respond to. Hence, never queue them. - */ - ssh_pkt_write(ssh, pktout); -} - /* * Handle the top-level SSH-2 protocol. */ @@ -8680,20 +8667,17 @@ static void ssh2_protocol_setup(Ssh ssh) #endif /* - * Most messages cause SSH2_MSG_UNIMPLEMENTED. + * All message types we don't set explicitly will dispatch to + * ssh2_msg_unexpected. */ for (i = 0; i < SSH_MAX_MSG; i++) - ssh->packet_dispatch[i] = ssh2_msg_something_unimplemented; + ssh->packet_dispatch[i] = ssh2_msg_unexpected; /* * Initially, we only accept transport messages (and a few generic * ones). do_ssh2_userauth and do_ssh2_connection will each add - * more when they start. Messages that are understood but not - * currently acceptable go to ssh2_msg_unexpected. + * more when they start. */ - ssh->packet_dispatch[SSH2_MSG_UNIMPLEMENTED] = ssh2_msg_unexpected; - ssh->packet_dispatch[SSH2_MSG_SERVICE_REQUEST] = ssh2_msg_unexpected; - ssh->packet_dispatch[SSH2_MSG_SERVICE_ACCEPT] = ssh2_msg_unexpected; ssh->packet_dispatch[SSH2_MSG_KEXINIT] = ssh2_msg_transport; ssh->packet_dispatch[SSH2_MSG_NEWKEYS] = ssh2_msg_transport; ssh->packet_dispatch[SSH2_MSG_KEXDH_INIT] = ssh2_msg_transport; @@ -8703,28 +8687,6 @@ static void ssh2_protocol_setup(Ssh ssh) ssh->packet_dispatch[SSH2_MSG_KEX_DH_GEX_INIT] = ssh2_msg_transport; ssh->packet_dispatch[SSH2_MSG_KEX_DH_GEX_REPLY] = ssh2_msg_transport; ssh->packet_dispatch[SSH2_MSG_KEXGSS_GROUP] = ssh2_msg_transport; - ssh->packet_dispatch[SSH2_MSG_USERAUTH_REQUEST] = ssh2_msg_unexpected; - ssh->packet_dispatch[SSH2_MSG_USERAUTH_FAILURE] = ssh2_msg_unexpected; - ssh->packet_dispatch[SSH2_MSG_USERAUTH_SUCCESS] = ssh2_msg_unexpected; - ssh->packet_dispatch[SSH2_MSG_USERAUTH_BANNER] = ssh2_msg_unexpected; - ssh->packet_dispatch[SSH2_MSG_USERAUTH_PK_OK] = ssh2_msg_unexpected; - /* ssh->packet_dispatch[SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ] = ssh2_msg_unexpected; duplicate case value */ - /* ssh->packet_dispatch[SSH2_MSG_USERAUTH_INFO_REQUEST] = ssh2_msg_unexpected; duplicate case value */ - ssh->packet_dispatch[SSH2_MSG_USERAUTH_INFO_RESPONSE] = ssh2_msg_unexpected; - ssh->packet_dispatch[SSH2_MSG_GLOBAL_REQUEST] = ssh2_msg_unexpected; - ssh->packet_dispatch[SSH2_MSG_REQUEST_SUCCESS] = ssh2_msg_unexpected; - ssh->packet_dispatch[SSH2_MSG_REQUEST_FAILURE] = ssh2_msg_unexpected; - ssh->packet_dispatch[SSH2_MSG_CHANNEL_OPEN] = ssh2_msg_unexpected; - ssh->packet_dispatch[SSH2_MSG_CHANNEL_OPEN_CONFIRMATION] = ssh2_msg_unexpected; - ssh->packet_dispatch[SSH2_MSG_CHANNEL_OPEN_FAILURE] = ssh2_msg_unexpected; - ssh->packet_dispatch[SSH2_MSG_CHANNEL_WINDOW_ADJUST] = ssh2_msg_unexpected; - ssh->packet_dispatch[SSH2_MSG_CHANNEL_DATA] = ssh2_msg_unexpected; - ssh->packet_dispatch[SSH2_MSG_CHANNEL_EXTENDED_DATA] = ssh2_msg_unexpected; - ssh->packet_dispatch[SSH2_MSG_CHANNEL_EOF] = ssh2_msg_unexpected; - ssh->packet_dispatch[SSH2_MSG_CHANNEL_CLOSE] = ssh2_msg_unexpected; - ssh->packet_dispatch[SSH2_MSG_CHANNEL_REQUEST] = ssh2_msg_unexpected; - ssh->packet_dispatch[SSH2_MSG_CHANNEL_SUCCESS] = ssh2_msg_unexpected; - ssh->packet_dispatch[SSH2_MSG_CHANNEL_FAILURE] = ssh2_msg_unexpected; /* * These messages have a special handler from the start. @@ -8741,38 +8703,15 @@ static void ssh2_bare_connection_protocol_setup(Ssh ssh) ssh->bpp = ssh2_bare_bpp_new(); /* - * Most messages cause SSH2_MSG_UNIMPLEMENTED. - */ - for (i = 0; i < SSH_MAX_MSG; i++) - ssh->packet_dispatch[i] = ssh2_msg_something_unimplemented; - - /* - * Initially, we set all ssh-connection messages to 'unexpected'; - * do_ssh2_connection will fill things in properly. We also handle - * a couple of messages from the transport protocol which aren't - * related to key exchange (UNIMPLEMENTED, IGNORE, DEBUG, + * Everything defaults to ssh2_msg_unexpected for the moment; + * do_ssh2_connection will fill things in properly. But we do + * handle a couple of messages from the transport protocol which + * aren't related to key exchange (UNIMPLEMENTED, IGNORE, DEBUG, * DISCONNECT). */ - ssh->packet_dispatch[SSH2_MSG_GLOBAL_REQUEST] = ssh2_msg_unexpected; - ssh->packet_dispatch[SSH2_MSG_REQUEST_SUCCESS] = ssh2_msg_unexpected; - ssh->packet_dispatch[SSH2_MSG_REQUEST_FAILURE] = ssh2_msg_unexpected; - ssh->packet_dispatch[SSH2_MSG_CHANNEL_OPEN] = ssh2_msg_unexpected; - ssh->packet_dispatch[SSH2_MSG_CHANNEL_OPEN_CONFIRMATION] = ssh2_msg_unexpected; - ssh->packet_dispatch[SSH2_MSG_CHANNEL_OPEN_FAILURE] = ssh2_msg_unexpected; - ssh->packet_dispatch[SSH2_MSG_CHANNEL_WINDOW_ADJUST] = ssh2_msg_unexpected; - ssh->packet_dispatch[SSH2_MSG_CHANNEL_DATA] = ssh2_msg_unexpected; - ssh->packet_dispatch[SSH2_MSG_CHANNEL_EXTENDED_DATA] = ssh2_msg_unexpected; - ssh->packet_dispatch[SSH2_MSG_CHANNEL_EOF] = ssh2_msg_unexpected; - ssh->packet_dispatch[SSH2_MSG_CHANNEL_CLOSE] = ssh2_msg_unexpected; - ssh->packet_dispatch[SSH2_MSG_CHANNEL_REQUEST] = ssh2_msg_unexpected; - ssh->packet_dispatch[SSH2_MSG_CHANNEL_SUCCESS] = ssh2_msg_unexpected; - ssh->packet_dispatch[SSH2_MSG_CHANNEL_FAILURE] = ssh2_msg_unexpected; - - ssh->packet_dispatch[SSH2_MSG_UNIMPLEMENTED] = ssh2_msg_unexpected; + for (i = 0; i < SSH_MAX_MSG; i++) + ssh->packet_dispatch[i] = ssh2_msg_unexpected; - /* - * These messages have a special handler from the start. - */ ssh->packet_dispatch[SSH2_MSG_DISCONNECT] = ssh2_msg_disconnect; ssh->packet_dispatch[SSH2_MSG_IGNORE] = ssh_msg_ignore; ssh->packet_dispatch[SSH2_MSG_DEBUG] = ssh2_msg_debug; diff --git a/ssh.h b/ssh.h index b438b35b..200a5407 100644 --- a/ssh.h +++ b/ssh.h @@ -1299,6 +1299,7 @@ enum { const char *ssh1_pkt_type(int type); const char *ssh2_pkt_type(Pkt_KCtx pkt_kctx, Pkt_ACtx pkt_actx, int type); +int ssh2_pkt_type_code_valid(unsigned type); /* * Need this to warn about support for the original SSH-2 keyfile diff --git a/ssh2bpp-bare.c b/ssh2bpp-bare.c index 45f757f6..c818e218 100644 --- a/ssh2bpp-bare.c +++ b/ssh2bpp-bare.c @@ -111,6 +111,12 @@ static void ssh2_bare_bpp_handle_input(BinaryPacketProtocol *bpp) &s->pktin->sequence, 0, NULL); } + if (ssh2_bpp_check_unimplemented(&s->bpp, s->pktin)) { + sfree(s->pktin); + s->pktin = NULL; + continue; + } + pq_push(s->bpp.in_pq, s->pktin); { diff --git a/ssh2bpp.c b/ssh2bpp.c index 49ab8cfd..b0dd2ea7 100644 --- a/ssh2bpp.c +++ b/ssh2bpp.c @@ -476,6 +476,12 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp) &s->pktin->sequence, 0, NULL); } + if (ssh2_bpp_check_unimplemented(&s->bpp, s->pktin)) { + sfree(s->pktin); + s->pktin = NULL; + continue; + } + pq_push(s->bpp.in_pq, s->pktin); { diff --git a/sshbpp.h b/sshbpp.h index 8fc02960..61f4fe7f 100644 --- a/sshbpp.h +++ b/sshbpp.h @@ -40,6 +40,9 @@ void ssh1_bpp_new_cipher(BinaryPacketProtocol *bpp, * up zlib compression if it was SUCCESS. */ void ssh1_bpp_requested_compression(BinaryPacketProtocol *bpp); +/* Common helper function between the SSH-2 full and bare BPPs */ +int ssh2_bpp_check_unimplemented(BinaryPacketProtocol *bpp, PktIn *pktin); + /* * Structure that tracks how much data is sent and received, for * purposes of triggering an SSH-2 rekey when either one gets over a diff --git a/sshcommon.c b/sshcommon.c index 3b7fc6a8..ac23e791 100644 --- a/sshcommon.c +++ b/sshcommon.c @@ -8,6 +8,7 @@ #include "putty.h" #include "ssh.h" +#include "sshbpp.h" #include "sshchan.h" /* ---------------------------------------------------------------------- @@ -581,3 +582,43 @@ const char *ssh2_pkt_type(Pkt_KCtx pkt_kctx, Pkt_ACtx pkt_actx, int type) #undef TRANSLATE_UNIVERSAL #undef TRANSLATE_KEX #undef TRANSLATE_AUTH + +/* ---------------------------------------------------------------------- + * Common helper function for implementations of BinaryPacketProtocol. + */ + +#define BITMAP_UNIVERSAL(y, name, value) \ + | (value >= y && value < y+32 ? 1UL << (value-y) : 0) +#define BITMAP_CONDITIONAL(y, name, value, ctx) \ + BITMAP_UNIVERSAL(y, name, value) +#define SSH2_BITMAP_WORD(y) \ + (0 SSH2_MESSAGE_TYPES(BITMAP_UNIVERSAL, BITMAP_CONDITIONAL, \ + BITMAP_CONDITIONAL, (32*y))) + +int ssh2_bpp_check_unimplemented(BinaryPacketProtocol *bpp, PktIn *pktin) +{ + static const unsigned valid_bitmap[] = { + SSH2_BITMAP_WORD(0), + SSH2_BITMAP_WORD(1), + SSH2_BITMAP_WORD(2), + SSH2_BITMAP_WORD(3), + SSH2_BITMAP_WORD(4), + SSH2_BITMAP_WORD(5), + SSH2_BITMAP_WORD(6), + SSH2_BITMAP_WORD(7), + }; + + if (pktin->type < 0x100 && + !((valid_bitmap[pktin->type >> 5] >> (pktin->type & 0x1F)) & 1)) { + PktOut *pkt = ssh_bpp_new_pktout(bpp, SSH2_MSG_UNIMPLEMENTED); + put_uint32(pkt, pktin->sequence); + ssh_bpp_format_packet(bpp, pkt); + return TRUE; + } + + return FALSE; +} + +#undef BITMAP_UNIVERSAL +#undef BITMAP_CONDITIONAL +#undef SSH1_BITMAP_WORD From f6f8219a3dcb1a144f4ccbff1dbf12c776affdaa Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 23 Sep 2018 16:35:29 +0100 Subject: [PATCH 444/607] Replace PktIn reference count with a 'free queue'. This is a new idea I've had to make memory-management of PktIn even easier. The idea is that a PktIn is essentially _always_ an element of some linked-list queue: if it's not one of the queues by which packets move through ssh.c, then it's a special 'free queue' which holds packets that are unowned and due to be freed. pq_pop() on a PktInQueue automatically relinks the packet to the free queue, and also triggers an idempotent callback which will empty the queue and really free all the packets on it. Hence, you can pop a packet off a real queue, parse it, handle it, and then just assume it'll get tidied up at some point - the only constraint being that you have to finish with it before returning to the application's main loop. The exception is that it's OK to pq_push() the packet back on to some other PktInQueue, because a side effect of that will be to _remove_ it from the free queue again. (And if _all_ the incoming packets get that treatment, then when the free-queue handler eventually runs, it may find it has nothing to do - which is harmless.) --- defs.h | 2 ++ ssh.c | 6 ----- ssh.h | 3 +-- ssh1bpp.c | 5 ++--- ssh2bpp-bare.c | 5 ++--- ssh2bpp.c | 9 ++++---- sshcommon.c | 59 +++++++++++++++++++++++++++++++++++++++----------- 7 files changed, 57 insertions(+), 32 deletions(-) diff --git a/defs.h b/defs.h index f45abfec..61ada0b3 100644 --- a/defs.h +++ b/defs.h @@ -38,6 +38,8 @@ typedef uint32_t uint32; typedef struct BinarySink BinarySink; typedef struct BinarySource BinarySource; +typedef struct IdempotentCallback IdempotentCallback; + typedef struct SockAddr_tag *SockAddr; typedef struct Socket_vtable Socket_vtable; diff --git a/ssh.c b/ssh.c index 1d7580cb..b4c873d8 100644 --- a/ssh.c +++ b/ssh.c @@ -1043,7 +1043,6 @@ static void ssh_process_pq_full(void *ctx) if (ssh->general_packet_processing) ssh->general_packet_processing(ssh, pktin); ssh->packet_dispatch[pktin->type](ssh, pktin); - ssh_unref_packet(pktin); } } @@ -3316,14 +3315,12 @@ static void ssh1_connection_input(Ssh ssh) static void ssh1_coro_wrapper_initial(Ssh ssh, PktIn *pktin) { - pktin->refcount++; /* avoid packet being freed when we return */ pq_push(&ssh->pq_ssh1_login, pktin); queue_idempotent_callback(&ssh->ssh1_login_icb); } static void ssh1_coro_wrapper_session(Ssh ssh, PktIn *pktin) { - pktin->refcount++; /* avoid packet being freed when we return */ pq_push(&ssh->pq_ssh1_connection, pktin); queue_idempotent_callback(&ssh->ssh1_connection_icb); } @@ -6661,7 +6658,6 @@ static void ssh2_setup_env(struct ssh_channel *c, PktIn *pktin, */ static void ssh2_msg_userauth(Ssh ssh, PktIn *pktin) { - pktin->refcount++; /* avoid packet being freed when we return */ pq_push(&ssh->pq_ssh2_userauth, pktin); if (pktin->type == SSH2_MSG_USERAUTH_SUCCESS) { /* @@ -8136,7 +8132,6 @@ static void ssh2_userauth_input(Ssh ssh) */ static void ssh2_msg_connection(Ssh ssh, PktIn *pktin) { - pktin->refcount++; /* avoid packet being freed when we return */ pq_push(&ssh->pq_ssh2_connection, pktin); queue_idempotent_callback(&ssh->ssh2_connection_icb); } @@ -8610,7 +8605,6 @@ static void ssh2_msg_debug(Ssh ssh, PktIn *pktin) static void ssh2_msg_transport(Ssh ssh, PktIn *pktin) { - pktin->refcount++; /* avoid packet being freed when we return */ pq_push(&ssh->pq_ssh2_transport, pktin); queue_idempotent_callback(&ssh->ssh2_transport_icb); } diff --git a/ssh.h b/ssh.h index 200a5407..36bd90de 100644 --- a/ssh.h +++ b/ssh.h @@ -53,10 +53,10 @@ struct ssh_channel; typedef struct PacketQueueNode PacketQueueNode; struct PacketQueueNode { PacketQueueNode *next, *prev; + int on_free_queue; /* is this packet scheduled for freeing? */ }; typedef struct PktIn { - int refcount; int type; unsigned long sequence; /* SSH-2 incoming sequence number */ PacketQueueNode qnode; /* for linking this packet on to a queue */ @@ -157,7 +157,6 @@ int ssh2_censor_packet( ptrlen pkt, logblank_t *blanks); PktOut *ssh_new_packet(void); -void ssh_unref_packet(PktIn *pkt); void ssh_free_pktout(PktOut *pkt); extern Socket ssh_connection_sharing_init( diff --git a/ssh1bpp.c b/ssh1bpp.c index 90942587..92c89435 100644 --- a/ssh1bpp.c +++ b/ssh1bpp.c @@ -59,8 +59,7 @@ static void ssh1_bpp_free(BinaryPacketProtocol *bpp) ssh_decompressor_free(s->decompctx); if (s->crcda_ctx) crcda_free_context(s->crcda_ctx); - if (s->pktin) - ssh_unref_packet(s->pktin); + sfree(s->pktin); sfree(s); } @@ -125,7 +124,7 @@ static void ssh1_bpp_handle_input(BinaryPacketProtocol *bpp) */ s->pktin = snew_plus(PktIn, s->biglen); s->pktin->qnode.prev = s->pktin->qnode.next = NULL; - s->pktin->refcount = 1; + s->pktin->qnode.on_free_queue = FALSE; s->pktin->type = 0; s->maxlen = s->biglen; diff --git a/ssh2bpp-bare.c b/ssh2bpp-bare.c index c818e218..db645e2f 100644 --- a/ssh2bpp-bare.c +++ b/ssh2bpp-bare.c @@ -44,8 +44,7 @@ static void ssh2_bare_bpp_free(BinaryPacketProtocol *bpp) { struct ssh2_bare_bpp_state *s = FROMFIELD(bpp, struct ssh2_bare_bpp_state, bpp); - if (s->pktin) - ssh_unref_packet(s->pktin); + sfree(s->pktin); sfree(s); } @@ -75,8 +74,8 @@ static void ssh2_bare_bpp_handle_input(BinaryPacketProtocol *bpp) */ s->pktin = snew_plus(PktIn, s->packetlen); s->pktin->qnode.prev = s->pktin->qnode.next = NULL; + s->pktin->qnode.on_free_queue = FALSE; s->maxlen = 0; - s->pktin->refcount = 1; s->data = snew_plus_get_aux(s->pktin); s->pktin->sequence = s->incoming_sequence++; diff --git a/ssh2bpp.c b/ssh2bpp.c index b0dd2ea7..272e1711 100644 --- a/ssh2bpp.c +++ b/ssh2bpp.c @@ -74,8 +74,7 @@ static void ssh2_bpp_free(BinaryPacketProtocol *bpp) ssh2_mac_free(s->in.mac); if (s->in_decomp) ssh_decompressor_free(s->in_decomp); - if (s->pktin) - ssh_unref_packet(s->pktin); + sfree(s->pktin); sfree(s); } @@ -249,8 +248,8 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp) */ s->pktin = snew_plus(PktIn, s->maxlen); s->pktin->qnode.prev = s->pktin->qnode.next = NULL; - s->pktin->refcount = 1; s->pktin->type = 0; + s->pktin->qnode.on_free_queue = FALSE; s->data = snew_plus_get_aux(s->pktin); memcpy(s->data, s->buf, s->maxlen); } else if (s->in.mac && s->in.etm_mode) { @@ -300,8 +299,8 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp) */ s->pktin = snew_plus(PktIn, OUR_V2_PACKETLIMIT + s->maclen); s->pktin->qnode.prev = s->pktin->qnode.next = NULL; - s->pktin->refcount = 1; s->pktin->type = 0; + s->pktin->qnode.on_free_queue = FALSE; s->data = snew_plus_get_aux(s->pktin); memcpy(s->data, s->buf, 4); @@ -369,8 +368,8 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp) s->maxlen = s->packetlen + s->maclen; s->pktin = snew_plus(PktIn, s->maxlen); s->pktin->qnode.prev = s->pktin->qnode.next = NULL; - s->pktin->refcount = 1; s->pktin->type = 0; + s->pktin->qnode.on_free_queue = FALSE; s->data = snew_plus_get_aux(s->pktin); memcpy(s->data, s->buf, s->cipherblk); diff --git a/sshcommon.c b/sshcommon.c index ac23e791..4090f9c6 100644 --- a/sshcommon.c +++ b/sshcommon.c @@ -15,10 +15,20 @@ * Implementation of PacketQueue. */ +static void pq_ensure_unlinked(PacketQueueNode *node) +{ + if (node->on_free_queue) { + node->next->prev = node->prev; + node->prev->next = node->next; + } else { + assert(!node->next); + assert(!node->prev); + } +} + void pq_base_push(PacketQueueBase *pqb, PacketQueueNode *node) { - assert(!node->next); - assert(!node->prev); + pq_ensure_unlinked(node); node->next = &pqb->end; node->prev = pqb->end.prev; node->next->prev = node; @@ -27,14 +37,33 @@ void pq_base_push(PacketQueueBase *pqb, PacketQueueNode *node) void pq_base_push_front(PacketQueueBase *pqb, PacketQueueNode *node) { - assert(!node->next); - assert(!node->prev); + pq_ensure_unlinked(node); node->prev = &pqb->end; node->next = pqb->end.next; node->next->prev = node; node->prev->next = node; } +static PacketQueueNode pktin_freeq_head = { + &pktin_freeq_head, &pktin_freeq_head, TRUE +}; + +static void pktin_free_queue_callback(void *vctx) +{ + while (pktin_freeq_head.next != &pktin_freeq_head) { + PacketQueueNode *node = pktin_freeq_head.next; + PktIn *pktin = FROMFIELD(node, PktIn, qnode); + pktin_freeq_head.next = node->next; + sfree(pktin); + } + + pktin_freeq_head.prev = &pktin_freeq_head; +} + +static IdempotentCallback ic_pktin_free = { + pktin_free_queue_callback, NULL, FALSE +}; + static PktIn *pq_in_get(PacketQueueBase *pqb, int pop) { PacketQueueNode *node = pqb->end.next; @@ -44,7 +73,13 @@ static PktIn *pq_in_get(PacketQueueBase *pqb, int pop) if (pop) { node->next->prev = node->prev; node->prev->next = node->next; - node->prev = node->next = NULL; + + node->prev = pktin_freeq_head.prev; + node->next = &pktin_freeq_head; + node->next->prev = node; + node->prev->next = node; + node->on_free_queue = TRUE; + queue_idempotent_callback(&ic_pktin_free); } return FROMFIELD(node, PktIn, qnode); @@ -80,8 +115,11 @@ void pq_out_init(PktOutQueue *pq) void pq_in_clear(PktInQueue *pq) { PktIn *pkt; - while ((pkt = pq_pop(pq)) != NULL) - ssh_unref_packet(pkt); + while ((pkt = pq_pop(pq)) != NULL) { + /* No need to actually free these packets: pq_pop on a + * PktInQueue will automatically move them to the free + * queue. */ + } } void pq_out_clear(PktOutQueue *pq) @@ -170,6 +208,7 @@ PktOut *ssh_new_packet(void) pkt->downstream_id = 0; pkt->additional_log_text = NULL; pkt->qnode.next = pkt->qnode.prev = NULL; + pkt->qnode.on_free_queue = FALSE; return pkt; } @@ -195,12 +234,6 @@ static void ssh_pkt_BinarySink_write(BinarySink *bs, ssh_pkt_adddata(pkt, data, len); } -void ssh_unref_packet(PktIn *pkt) -{ - if (--pkt->refcount <= 0) - sfree(pkt); -} - void ssh_free_pktout(PktOut *pkt) { sfree(pkt->data); From 43767fff045bf1c705230d639663ba086825b608 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Mon, 24 Sep 2018 14:01:06 +0100 Subject: [PATCH 445/607] Add a missing include to putty.h. We define a macro in terms of INT_MAX, so we ought to include to ensure INT_MAX is defined, rather than depending on every call site to have remembered to do that themselves. --- putty.h | 1 + 1 file changed, 1 insertion(+) diff --git a/putty.h b/putty.h index db39f2aa..3963e48e 100644 --- a/putty.h +++ b/putty.h @@ -2,6 +2,7 @@ #define PUTTY_PUTTY_H #include /* for wchar_t */ +#include /* for INT_MAX */ /* * Global variables. Most modules declare these `extern', but From 96622d17a37376e260b86482a4658ecd4fdc3d0c Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Mon, 24 Sep 2018 14:15:32 +0100 Subject: [PATCH 446/607] Move verify_ssh_manual_host_key into sshcommon.c This is essentially trivial, because the only thing it needed from the Ssh structure was the Conf. So the version in sshcommon.c just takes an actual Conf as an argument, and now it doesn't need access to the big structure definition any more. --- ssh.c | 58 +++-------------------------------------------------- ssh.h | 3 +++ sshcommon.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+), 55 deletions(-) diff --git a/ssh.c b/ssh.c index b4c873d8..8dd8ee6c 100644 --- a/ssh.c +++ b/ssh.c @@ -1464,59 +1464,6 @@ static void ssh_disconnect(Ssh ssh, const char *client_reason, sfree(error); } -int verify_ssh_manual_host_key(Ssh ssh, const char *fingerprint, ssh_key *key) -{ - if (!conf_get_str_nthstrkey(ssh->conf, CONF_ssh_manual_hostkeys, 0)) { - return -1; /* no manual keys configured */ - } - - if (fingerprint) { - /* - * The fingerprint string we've been given will have things - * like 'ssh-rsa 2048' at the front of it. Strip those off and - * narrow down to just the colon-separated hex block at the - * end of the string. - */ - const char *p = strrchr(fingerprint, ' '); - fingerprint = p ? p+1 : fingerprint; - /* Quick sanity checks, including making sure it's in lowercase */ - assert(strlen(fingerprint) == 16*3 - 1); - assert(fingerprint[2] == ':'); - assert(fingerprint[strspn(fingerprint, "0123456789abcdef:")] == 0); - - if (conf_get_str_str_opt(ssh->conf, CONF_ssh_manual_hostkeys, - fingerprint)) - return 1; /* success */ - } - - if (key) { - /* - * Construct the base64-encoded public key blob and see if - * that's listed. - */ - strbuf *binblob; - char *base64blob; - int atoms, i; - binblob = strbuf_new(); - ssh_key_public_blob(key, BinarySink_UPCAST(binblob)); - atoms = (binblob->len + 2) / 3; - base64blob = snewn(atoms * 4 + 1, char); - for (i = 0; i < atoms; i++) - base64_encode_atom(binblob->u + 3*i, - binblob->len - 3*i, base64blob + 4*i); - base64blob[atoms * 4] = '\0'; - strbuf_free(binblob); - if (conf_get_str_str_opt(ssh->conf, CONF_ssh_manual_hostkeys, - base64blob)) { - sfree(base64blob); - return 1; /* success */ - } - sfree(base64blob); - } - - return 0; -} - static void ssh1_coro_wrapper_initial(Ssh ssh, PktIn *pktin); static void ssh1_coro_wrapper_session(Ssh ssh, PktIn *pktin); static void ssh1_connection_input(Ssh ssh); @@ -1650,7 +1597,7 @@ static void do_ssh1_login(void *vctx) fingerprint = rsa_ssh1_fingerprint(&s->hostkey); /* First check against manually configured host keys. */ - s->dlgret = verify_ssh_manual_host_key(ssh, fingerprint, NULL); + s->dlgret = verify_ssh_manual_host_key(ssh->conf, fingerprint, NULL); sfree(fingerprint); if (s->dlgret == 0) { /* did not match */ bombout(("Host key did not appear in manually configured list")); @@ -5038,7 +4985,8 @@ static void do_ssh2_transport(void *vctx) logevent("Host key fingerprint is:"); logevent(s->fingerprint); /* First check against manually configured host keys. */ - s->dlgret = verify_ssh_manual_host_key(ssh, s->fingerprint, s->hkey); + s->dlgret = verify_ssh_manual_host_key(ssh->conf, + s->fingerprint, s->hkey); if (s->dlgret == 0) { /* did not match */ bombout(("Host key did not appear in manually configured list")); crStopV; diff --git a/ssh.h b/ssh.h index 36bd90de..a69a24af 100644 --- a/ssh.h +++ b/ssh.h @@ -1349,3 +1349,6 @@ int first_in_commasep_string(char const *needle, char const *haystack, int haylen); int in_commasep_string(char const *needle, char const *haystack, int haylen); void add_to_commasep(strbuf *buf, const char *data); + +int verify_ssh_manual_host_key( + Conf *conf, const char *fingerprint, ssh_key *key); diff --git a/sshcommon.c b/sshcommon.c index 4090f9c6..087dc081 100644 --- a/sshcommon.c +++ b/sshcommon.c @@ -655,3 +655,58 @@ int ssh2_bpp_check_unimplemented(BinaryPacketProtocol *bpp, PktIn *pktin) #undef BITMAP_UNIVERSAL #undef BITMAP_CONDITIONAL #undef SSH1_BITMAP_WORD + +/* ---------------------------------------------------------------------- + * Function to check a host key against any manually configured in Conf. + */ + +int verify_ssh_manual_host_key( + Conf *conf, const char *fingerprint, ssh_key *key) +{ + if (!conf_get_str_nthstrkey(conf, CONF_ssh_manual_hostkeys, 0)) + return -1; /* no manual keys configured */ + + if (fingerprint) { + /* + * The fingerprint string we've been given will have things + * like 'ssh-rsa 2048' at the front of it. Strip those off and + * narrow down to just the colon-separated hex block at the + * end of the string. + */ + const char *p = strrchr(fingerprint, ' '); + fingerprint = p ? p+1 : fingerprint; + /* Quick sanity checks, including making sure it's in lowercase */ + assert(strlen(fingerprint) == 16*3 - 1); + assert(fingerprint[2] == ':'); + assert(fingerprint[strspn(fingerprint, "0123456789abcdef:")] == 0); + + if (conf_get_str_str_opt(conf, CONF_ssh_manual_hostkeys, fingerprint)) + return 1; /* success */ + } + + if (key) { + /* + * Construct the base64-encoded public key blob and see if + * that's listed. + */ + strbuf *binblob; + char *base64blob; + int atoms, i; + binblob = strbuf_new(); + ssh_key_public_blob(key, BinarySink_UPCAST(binblob)); + atoms = (binblob->len + 2) / 3; + base64blob = snewn(atoms * 4 + 1, char); + for (i = 0; i < atoms; i++) + base64_encode_atom(binblob->u + 3*i, + binblob->len - 3*i, base64blob + 4*i); + base64blob[atoms * 4] = '\0'; + strbuf_free(binblob); + if (conf_get_str_str_opt(conf, CONF_ssh_manual_hostkeys, base64blob)) { + sfree(base64blob); + return 1; /* success */ + } + sfree(base64blob); + } + + return 0; +} From d77b95cb425972dcfcabad63e0a5b42ff9f2d9dd Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Mon, 24 Sep 2018 14:23:52 +0100 Subject: [PATCH 447/607] Macroise the cumbersome read idioms in the BPPs. Now the three 'proper' BPPs each have a BPP_READ() macro that wraps up the fiddly combination of crMaybeWaitUntilV and bufchainery they use to read a fixed-length amount of input data. The sshverstring 'BPP' doesn't read fixed-length data in quite the same way, but it has a similar BPP_WAITFOR macro. No functional change. Mostly this is just a cleanup to make the code more legible, but also, the new macros will be a good place to centralise anything else that needs doing on every read, such as EOF checking. --- ssh1bpp.c | 12 ++++++++---- ssh2bpp-bare.c | 12 ++++++++---- ssh2bpp.c | 29 +++++++++++++---------------- sshverstring.c | 13 ++++++++++--- 4 files changed, 39 insertions(+), 27 deletions(-) diff --git a/ssh1bpp.c b/ssh1bpp.c index 92c89435..9640d35d 100644 --- a/ssh1bpp.c +++ b/ssh1bpp.c @@ -91,6 +91,12 @@ void ssh1_bpp_requested_compression(BinaryPacketProtocol *bpp) s->pending_compression_request = TRUE; } +#define BPP_READ(ptr, len) do \ + { \ + crMaybeWaitUntilV(bufchain_try_fetch_consume( \ + s->bpp.in_raw, ptr, len)); \ + } while (0) + static void ssh1_bpp_handle_input(BinaryPacketProtocol *bpp) { struct ssh1_bpp_state *s = FROMFIELD(bpp, struct ssh1_bpp_state, bpp); @@ -103,8 +109,7 @@ static void ssh1_bpp_handle_input(BinaryPacketProtocol *bpp) { unsigned char lenbuf[4]; - crMaybeWaitUntilV(bufchain_try_fetch_consume( - bpp->in_raw, lenbuf, 4)); + BPP_READ(lenbuf, 4); s->len = toint(GET_32BIT_MSB_FIRST(lenbuf)); } @@ -130,8 +135,7 @@ static void ssh1_bpp_handle_input(BinaryPacketProtocol *bpp) s->maxlen = s->biglen; s->data = snew_plus_get_aux(s->pktin); - crMaybeWaitUntilV(bufchain_try_fetch_consume( - bpp->in_raw, s->data, s->biglen)); + BPP_READ(s->data, s->biglen); if (s->cipher && detect_attack(s->crcda_ctx, s->data, s->biglen, NULL)) { diff --git a/ssh2bpp-bare.c b/ssh2bpp-bare.c index db645e2f..58e6ae32 100644 --- a/ssh2bpp-bare.c +++ b/ssh2bpp-bare.c @@ -48,6 +48,12 @@ static void ssh2_bare_bpp_free(BinaryPacketProtocol *bpp) sfree(s); } +#define BPP_READ(ptr, len) do \ + { \ + crMaybeWaitUntilV(bufchain_try_fetch_consume( \ + s->bpp.in_raw, ptr, len)); \ + } while (0) + static void ssh2_bare_bpp_handle_input(BinaryPacketProtocol *bpp) { struct ssh2_bare_bpp_state *s = @@ -59,8 +65,7 @@ static void ssh2_bare_bpp_handle_input(BinaryPacketProtocol *bpp) /* Read the length field. */ { unsigned char lenbuf[4]; - crMaybeWaitUntilV(bufchain_try_fetch_consume( - s->bpp.in_raw, lenbuf, 4)); + BPP_READ(lenbuf, 4); s->packetlen = toint(GET_32BIT_MSB_FIRST(lenbuf)); } @@ -83,8 +88,7 @@ static void ssh2_bare_bpp_handle_input(BinaryPacketProtocol *bpp) /* * Read the remainder of the packet. */ - crMaybeWaitUntilV(bufchain_try_fetch_consume( - s->bpp.in_raw, s->data, s->packetlen)); + BPP_READ(s->data, s->packetlen); /* * The data we just read is precisely the initial type byte diff --git a/ssh2bpp.c b/ssh2bpp.c index 272e1711..21ea2401 100644 --- a/ssh2bpp.c +++ b/ssh2bpp.c @@ -158,6 +158,12 @@ void ssh2_bpp_new_incoming_crypto( s->pending_newkeys = FALSE; } +#define BPP_READ(ptr, len) do \ + { \ + crMaybeWaitUntilV(bufchain_try_fetch_consume( \ + s->bpp.in_raw, ptr, len)); \ + } while (0) + static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp) { struct ssh2_bpp_state *s = FROMFIELD(bpp, struct ssh2_bpp_state, bpp); @@ -206,8 +212,7 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp) } /* Read an amount corresponding to the MAC. */ - crMaybeWaitUntilV(bufchain_try_fetch_consume( - s->bpp.in_raw, s->buf, s->maclen)); + BPP_READ(s->buf, s->maclen); s->packetlen = 0; ssh2_mac_start(s->in.mac); @@ -216,10 +221,7 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp) for (;;) { /* Once around this loop per cipher block. */ /* Read another cipher-block's worth, and tack it on to * the end. */ - crMaybeWaitUntilV(bufchain_try_fetch_consume( - s->bpp.in_raw, - s->buf + (s->packetlen + s->maclen), - s->cipherblk)); + BPP_READ(s->buf + (s->packetlen + s->maclen), s->cipherblk); /* Decrypt one more block (a little further back in * the stream). */ ssh2_cipher_decrypt(s->in.cipher, @@ -262,8 +264,7 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp) * OpenSSH encrypt-then-MAC mode: the packet length is * unencrypted, unless the cipher supports length encryption. */ - crMaybeWaitUntilV(bufchain_try_fetch_consume( - s->bpp.in_raw, s->buf, 4)); + BPP_READ(s->buf, 4); /* Cipher supports length decryption, so do it */ if (s->in.cipher && (ssh2_cipher_alg(s->in.cipher)->flags & @@ -307,9 +308,7 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp) /* * Read the remainder of the packet. */ - crMaybeWaitUntilV(bufchain_try_fetch_consume( - s->bpp.in_raw, s->data + 4, - s->packetlen + s->maclen - 4)); + BPP_READ(s->data + 4, s->packetlen + s->maclen - 4); /* * Check the MAC. @@ -334,8 +333,7 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp) * Acquire and decrypt the first block of the packet. This will * contain the length and padding details. */ - crMaybeWaitUntilV(bufchain_try_fetch_consume( - s->bpp.in_raw, s->buf, s->cipherblk)); + BPP_READ(s->buf, s->cipherblk); if (s->in.cipher) ssh2_cipher_decrypt( @@ -376,9 +374,8 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp) /* * Read and decrypt the remainder of the packet. */ - crMaybeWaitUntilV(bufchain_try_fetch_consume( - s->bpp.in_raw, s->data + s->cipherblk, - s->packetlen + s->maclen - s->cipherblk)); + BPP_READ(s->data + s->cipherblk, + s->packetlen + s->maclen - s->cipherblk); /* Decrypt everything _except_ the MAC. */ if (s->in.cipher) diff --git a/sshverstring.c b/sshverstring.c index 37644276..029b140c 100644 --- a/sshverstring.c +++ b/sshverstring.c @@ -197,6 +197,12 @@ static void ssh_verstring_send(struct ssh_verstring_state *s) vs_logevent(("We claim version: %s", s->our_vstring)); } +#define BPP_WAITFOR(minlen) do \ + { \ + crMaybeWaitUntilV( \ + bufchain_size(s->bpp.in_raw) >= (minlen)); \ + } while (0) + void ssh_verstring_handle_input(BinaryPacketProtocol *bpp) { struct ssh_verstring_state *s = @@ -221,8 +227,7 @@ void ssh_verstring_handle_input(BinaryPacketProtocol *bpp) * Every time round this loop, we're at the start of a new * line, so look for the prefix. */ - crMaybeWaitUntilV(bufchain_size(s->bpp.in_raw) >= - s->prefix_wanted.len); + BPP_WAITFOR(s->prefix_wanted.len); bufchain_fetch(s->bpp.in_raw, s->prefix, s->prefix_wanted.len); if (!memcmp(s->prefix, s->prefix_wanted.ptr, s->prefix_wanted.len)) { bufchain_consume(s->bpp.in_raw, s->prefix_wanted.len); @@ -237,7 +242,9 @@ void ssh_verstring_handle_input(BinaryPacketProtocol *bpp) void *data; char *nl; - crMaybeWaitUntilV(bufchain_size(s->bpp.in_raw) > 0); + /* Wait to receive at least 1 byte, but then consume more + * than that if it's there. */ + BPP_WAITFOR(1); bufchain_prefix(s->bpp.in_raw, &data, &len); if ((nl = memchr(data, '\012', len)) != NULL) { bufchain_consume(s->bpp.in_raw, nl - (char *)data + 1); From 56bf65ef841c8c1aeba15ed5aaac50dfffba4f84 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Mon, 24 Sep 2018 14:40:35 +0100 Subject: [PATCH 448/607] Fix spurious EOF in agent forwarding! Commit 6a8b9d381, which created the Channel vtable and moved the agent forwarding implementation of it out into agentf.c, managed to set the rcvd_eof flag to TRUE in agentf_new(), meaning that we behave exactly as if the first agent request was followed by an incoming EOF. --- agentf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/agentf.c b/agentf.c index dbc1e4af..2c869fe5 100644 --- a/agentf.c +++ b/agentf.c @@ -164,7 +164,7 @@ Channel *agentf_new(SshChannel *c) af->c = c; af->chan.vt = &agentf_channelvt; af->chan.initial_fixed_window_size = 0; - af->rcvd_eof = TRUE; + af->rcvd_eof = FALSE; bufchain_init(&af->inbuffer); af->pending = NULL; af->input_wanted = TRUE; From 54b300f1547266feded4ef56bfc4692f6324850d Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Mon, 24 Sep 2018 14:59:22 +0100 Subject: [PATCH 449/607] pscp: try not to print error message on statistics line. If an error happens in mid-file-copy, we now try to move the terminal cursor to the start of the next line before printing the error message. --- pscp.c | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/pscp.c b/pscp.c index 2ae32826..d99c8d83 100644 --- a/pscp.c +++ b/pscp.c @@ -42,6 +42,7 @@ static int main_cmd_is_sftp = 0; static int fallback_cmd_is_sftp = 0; static int using_sftp = 0; static int uploading = 0; +static int progress_bar_displayed = FALSE; static Backend *backend; static Conf *conf; @@ -74,6 +75,21 @@ static void tell_str(FILE *stream, const char *str) tell_char(stream, str[i]); } +static void abandon_progress_bar(void) +{ + /* + * Output a \n to stdout (which is where we've been sending + * progress bars) so that the cursor will move to the next line. + * We should do this before displaying any other kind of output + * like an error message. + */ + if (progress_bar_displayed) { + putchar('\n'); + fflush(stdout); + progress_bar_displayed = FALSE; + } +} + static void tell_user(FILE *stream, const char *fmt, ...) { char *str, *str2; @@ -83,6 +99,7 @@ static void tell_user(FILE *stream, const char *fmt, ...) va_end(ap); str2 = dupcat(str, "\n", NULL); sfree(str); + abandon_progress_bar(); tell_str(stream, str2); sfree(str2); } @@ -99,6 +116,7 @@ void modalfatalbox(const char *fmt, ...) str2 = dupcat("Fatal: ", str, "\n", NULL); sfree(str); va_end(ap); + abandon_progress_bar(); tell_str(stderr, str2); sfree(str2); errs++; @@ -114,6 +132,7 @@ void nonfatal(const char *fmt, ...) str2 = dupcat("Error: ", str, "\n", NULL); sfree(str); va_end(ap); + abandon_progress_bar(); tell_str(stderr, str2); sfree(str2); errs++; @@ -127,6 +146,7 @@ void connection_fatal(Frontend *frontend, const char *fmt, ...) str2 = dupcat("Fatal: ", str, "\n", NULL); sfree(str); va_end(ap); + abandon_progress_bar(); tell_str(stderr, str2); sfree(str2); errs++; @@ -287,6 +307,7 @@ static void bump(const char *fmt, ...) va_end(ap); str2 = dupcat(str, "\n", NULL); sfree(str); + abandon_progress_bar(); tell_str(stderr, str2); sfree(str2); errs++; @@ -556,7 +577,9 @@ static void print_stats(const char *name, uint64 size, uint64 done, prev_stats_len = len; if (uint64_compare(done, size) == 0) - printf("\n"); + abandon_progress_bar(); + + progress_bar_displayed = TRUE; fflush(stdout); } @@ -1615,6 +1638,7 @@ static void run_err(const char *fmt, ...) str2 = dupcat("pscp: ", str, "\n", NULL); sfree(str); scp_send_errmsg(str2); + abandon_progress_bar(); tell_user(stderr, "%s", str2); va_end(ap); sfree(str2); @@ -1711,8 +1735,6 @@ static void source(const char *src) if (uint64_compare(uint64_add32(i, k),size) > 0) /* i + k > size */ k = (uint64_subtract(size, i)).lo; /* k = size - i; */ if ((j = read_from_file(f, transbuf, k)) != k) { - if (statistics) - printf("\n"); bump("%s: Read error", src); } if (scp_send_filedata(transbuf, k)) From a703f86731befdaaed00c968b21fc5e8261dbc53 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Fri, 21 Sep 2018 17:00:36 +0100 Subject: [PATCH 450/607] Defer passing a ConnectionLayer to sshshare.c. This paves the way for me to reorganise ssh.c in a way that will mean I don't have a ConnectionLayer available yet at the time I have to create the connshare. The constructor function now takes a mere Frontend, for generating setup-time Event Log messages, and there's a separate ssh_connshare_provide_connlayer() function I can call later once I have the ConnectionLayer to provide. NFC for the moment: the new provide_connlayer function is called immediately after ssh_connection_sharing_init. --- ssh.c | 7 +++++-- ssh.h | 4 +++- sshshare.c | 20 +++++++++++++------- 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/ssh.c b/ssh.c index 8dd8ee6c..92a93e27 100644 --- a/ssh.c +++ b/ssh.c @@ -1249,8 +1249,11 @@ static const char *connect_to_host(Ssh ssh, const char *host, int port, ssh->connshare = NULL; ssh->attempting_connshare = TRUE; /* affects socket logging behaviour */ ssh->s = ssh_connection_sharing_init( - ssh->savedhost, ssh->savedport, ssh->conf, &ssh->cl, &ssh->plugvt, - &ssh->connshare); + ssh->savedhost, ssh->savedport, ssh->conf, ssh->frontend, + &ssh->plugvt, &ssh->connshare); + if (ssh->connshare) + ssh_connshare_provide_connlayer(ssh->connshare, &ssh->cl); + ssh->attempting_connshare = FALSE; if (ssh->s != NULL) { /* diff --git a/ssh.h b/ssh.h index a69a24af..40d2b762 100644 --- a/ssh.h +++ b/ssh.h @@ -160,8 +160,10 @@ PktOut *ssh_new_packet(void); void ssh_free_pktout(PktOut *pkt); extern Socket ssh_connection_sharing_init( - const char *host, int port, Conf *conf, ConnectionLayer *cl, + const char *host, int port, Conf *conf, Frontend *frontend, Plug sshplug, ssh_sharing_state **state); +void ssh_connshare_provide_connlayer(ssh_sharing_state *sharestate, + ConnectionLayer *cl); int ssh_share_test_for_upstream(const char *host, int port, Conf *conf); void share_got_pkt_from_server(ssh_sharing_connstate *ctx, int type, const void *pkt, int pktlen); diff --git a/sshshare.c b/sshshare.c index 7515d117..937b4da6 100644 --- a/sshshare.c +++ b/sshshare.c @@ -2052,6 +2052,12 @@ static const Plug_vtable ssh_sharing_listen_plugvt = { share_listen_accepting }; +void ssh_connshare_provide_connlayer(ssh_sharing_state *sharestate, + ConnectionLayer *cl) +{ + sharestate->cl = cl; +} + /* * Init function for connection sharing. We either open a listening * socket and become an upstream, or connect to an existing one and @@ -2063,7 +2069,7 @@ static const Plug_vtable ssh_sharing_listen_plugvt = { * upstream) we return NULL. */ Socket ssh_connection_sharing_init( - const char *host, int port, Conf *conf, ConnectionLayer *cl, + const char *host, int port, Conf *conf, Frontend *frontend, Plug sshplug, ssh_sharing_state **state) { int result, can_upstream, can_downstream; @@ -2090,6 +2096,7 @@ Socket ssh_connection_sharing_init( sharestate = snew(struct ssh_sharing_state); sharestate->plugvt = &ssh_sharing_listen_plugvt; sharestate->listensock = NULL; + sharestate->cl = NULL; /* * Now hand off to a per-platform routine that either connects to @@ -2115,16 +2122,16 @@ Socket ssh_connection_sharing_init( /* For this result, if 'logtext' is not NULL then it is an * error message indicating a reason why connection sharing * couldn't be set up _at all_ */ - logeventf(cl->frontend, + logeventf(frontend, "Could not set up connection sharing: %s", logtext); } else { /* Failing that, ds_err and us_err indicate why we * couldn't be a downstream and an upstream respectively */ if (ds_err) - logeventf(cl->frontend, "Could not set up connection sharing" + logeventf(frontend, "Could not set up connection sharing" " as downstream: %s", ds_err); if (us_err) - logeventf(cl->frontend, "Could not set up connection sharing" + logeventf(frontend, "Could not set up connection sharing" " as upstream: %s", us_err); } @@ -2142,7 +2149,7 @@ Socket ssh_connection_sharing_init( */ /* 'logtext' is a local endpoint address */ - logeventf(cl->frontend, + logeventf(frontend, "Using existing shared connection at %s", logtext); *state = NULL; @@ -2159,12 +2166,11 @@ Socket ssh_connection_sharing_init( */ /* 'logtext' is a local endpoint address */ - logeventf(cl->frontend, "Sharing this connection at %s", logtext); + logeventf(frontend, "Sharing this connection at %s", logtext); *state = sharestate; sharestate->listensock = sock; sharestate->connections = newtree234(share_connstate_cmp); - sharestate->cl = cl; sharestate->server_verstring = NULL; sharestate->sockname = sockname; sharestate->nextid = 1; From 623c7b720c731ce3c94cf65dc9607351b29a70a7 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Fri, 21 Sep 2018 13:16:38 +0100 Subject: [PATCH 451/607] Put an optional IdempotentCallback in packet queues. This means that someone putting things on a packet queue doesn't need to separately hold a pointer to someone who needs notifying about it, or remember to call the notification function every time they push things on the queue. It's all taken care of automatically, without having to put extra stuff at the call sites. The precise semantics are that the callback will be scheduled whenever _new_ packets appear on the queue, but not when packets are removed. (Because the expectation is that the callback is notifying whoever is consuming the queue.) --- ssh.h | 1 + sshcommon.c | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/ssh.h b/ssh.h index 40d2b762..e9db3219 100644 --- a/ssh.h +++ b/ssh.h @@ -85,6 +85,7 @@ typedef struct PktOut { typedef struct PacketQueueBase { PacketQueueNode end; + struct IdempotentCallback *ic; } PacketQueueBase; typedef struct PktInQueue { diff --git a/sshcommon.c b/sshcommon.c index 087dc081..932e6c46 100644 --- a/sshcommon.c +++ b/sshcommon.c @@ -33,6 +33,9 @@ void pq_base_push(PacketQueueBase *pqb, PacketQueueNode *node) node->prev = pqb->end.prev; node->next->prev = node; node->prev->next = node; + + if (pqb->ic) + queue_idempotent_callback(pqb->ic); } void pq_base_push_front(PacketQueueBase *pqb, PacketQueueNode *node) @@ -42,6 +45,9 @@ void pq_base_push_front(PacketQueueBase *pqb, PacketQueueNode *node) node->next = pqb->end.next; node->next->prev = node; node->prev->next = node; + + if (pqb->ic) + queue_idempotent_callback(pqb->ic); } static PacketQueueNode pktin_freeq_head = { @@ -102,12 +108,14 @@ static PktOut *pq_out_get(PacketQueueBase *pqb, int pop) void pq_in_init(PktInQueue *pq) { + pq->pqb.ic = NULL; pq->pqb.end.next = pq->pqb.end.prev = &pq->pqb.end; pq->get = pq_in_get; } void pq_out_init(PktOutQueue *pq) { + pq->pqb.ic = NULL; pq->pqb.end.next = pq->pqb.end.prev = &pq->pqb.end; pq->get = pq_out_get; } @@ -115,6 +123,7 @@ void pq_out_init(PktOutQueue *pq) void pq_in_clear(PktInQueue *pq) { PktIn *pkt; + pq->pqb.ic = NULL; while ((pkt = pq_pop(pq)) != NULL) { /* No need to actually free these packets: pq_pop on a * PktInQueue will automatically move them to the free @@ -125,6 +134,7 @@ void pq_in_clear(PktInQueue *pq) void pq_out_clear(PktOutQueue *pq) { PktOut *pkt; + pq->pqb.ic = NULL; while ((pkt = pq_pop(pq)) != NULL) ssh_free_pktout(pkt); } @@ -188,6 +198,9 @@ void pq_base_concatenate(PacketQueueBase *qdest, qdest->end.prev = tail2; head1->prev = &qdest->end; tail2->next = &qdest->end; + + if (qdest->ic) + queue_idempotent_callback(qdest->ic); } } From 06b721ca0366db434095edf672ea1610c5b0bcb9 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 22 Sep 2018 08:13:41 +0100 Subject: [PATCH 452/607] Put an optional IdempotentCallback in bufchains. The callback has the same semantics as for packet queues: it triggers automatically when data is added to a bufchain, not when it's removed. --- cmdgen.c | 4 ++++ misc.c | 4 ++++ misc.h | 1 + testbn.c | 1 + windows/winpgen.c | 3 ++- windows/winpgnt.c | 3 ++- 6 files changed, 14 insertions(+), 2 deletions(-) diff --git a/cmdgen.c b/cmdgen.c index 610a8c4a..fe083a0c 100644 --- a/cmdgen.c +++ b/cmdgen.c @@ -126,6 +126,10 @@ char *x_get_default(const char *key) void sk_cleanup(void) { } +void queue_idempotent_callback(IdempotentCallback *ic) +{ + assert(0); +} void showversion(void) { diff --git a/misc.c b/misc.c index 42a4a228..efb83579 100644 --- a/misc.c +++ b/misc.c @@ -707,6 +707,7 @@ void bufchain_init(bufchain *ch) { ch->head = ch->tail = NULL; ch->buffersize = 0; + ch->ic = NULL; } void bufchain_clear(bufchain *ch) @@ -758,6 +759,9 @@ void bufchain_add(bufchain *ch, const void *data, int len) ch->tail = newbuf; } } + + if (ch->ic) + queue_idempotent_callback(ch->ic); } void bufchain_consume(bufchain *ch, int len) diff --git a/misc.h b/misc.h index b63df049..0977050b 100644 --- a/misc.h +++ b/misc.h @@ -78,6 +78,7 @@ struct bufchain_granule; struct bufchain_tag { struct bufchain_granule *head, *tail; int buffersize; /* current amount of buffered data */ + IdempotentCallback *ic; }; void bufchain_init(bufchain *ch); diff --git a/testbn.c b/testbn.c index 16529e27..0abe4690 100644 --- a/testbn.c +++ b/testbn.c @@ -33,6 +33,7 @@ int random_byte(void) } void logevent(Frontend *frontend, const char *msg) { assert(0); } +void queue_idempotent_callback(IdempotentCallback *ic) { assert(0); } #define fromxdigit(c) ( (c)>'9' ? ((c)&0xDF) - 'A' + 10 : (c) - '0' ) diff --git a/windows/winpgen.c b/windows/winpgen.c index d951fa6b..ecb28ac4 100644 --- a/windows/winpgen.c +++ b/windows/winpgen.c @@ -60,8 +60,9 @@ void nonfatal(const char *fmt, ...) sfree(stuff); } -/* Stub needed to link against misc.c */ +/* Stubs needed to link against misc.c */ void logevent(Frontend *frontend, const char *msg) { assert(0); } +void queue_idempotent_callback(IdempotentCallback *ic) { assert(0); } /* ---------------------------------------------------------------------- * Progress report code. This is really horrible :-) diff --git a/windows/winpgnt.c b/windows/winpgnt.c index 0f89b810..2fa53654 100644 --- a/windows/winpgnt.c +++ b/windows/winpgnt.c @@ -113,8 +113,9 @@ static void unmungestr(char *in, char *out, int outlen) return; } -/* Stub needed to link against misc.c */ +/* Stubs needed to link against misc.c */ void logevent(Frontend *frontend, const char *msg) { assert(0); } +void queue_idempotent_callback(IdempotentCallback *ic) { assert(0); } static int has_security; From 60d95b6a62e7db689ca9c74dfb0efdb82d000289 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Mon, 24 Sep 2018 14:02:44 +0100 Subject: [PATCH 453/607] Tweak crWaitUntil macros for greater robustness. I've rewritten these macros so that they don't keep rewriting the same value into the crLine variable. They now write it just once, before ever testing the condition. The point isn't the extra efficiency (which is surely negligible); it's to make it safe to abort a coroutine and free its entire state at unexpected moments. If you use one of these macros with a condition that has side effects, say crWaitUntil(func()), and one of the side effects can be to free the entire object that holds the coroutine state, then the write to crLine after testing the condition would previously have caused a stale-pointer dereference. But now that only happened once, _before_ the condition was first evaluated; so as long as func() returns false in the event that it frees the coroutine state, it's safe - crWaitUntil will see the false condition and return without touching the state object, and then it'll never be called again because the whole object will have gone away. --- sshcr.h | 39 +++++++++++++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/sshcr.h b/sshcr.h index 18a31ff5..5abf4c17 100644 --- a/sshcr.h +++ b/sshcr.h @@ -46,9 +46,40 @@ } while (0) #define crStop(z) do{ *crLine = 0; return (z); }while(0) #define crStopV do{ *crLine = 0; return; }while(0) -#define crWaitUntil(c) do { crReturn(0); } while (!(c)) -#define crWaitUntilV(c) do { crReturnV; } while (!(c)) -#define crMaybeWaitUntil(c) do { while (!(c)) crReturn(0); } while (0) -#define crMaybeWaitUntilV(c) do { while (!(c)) crReturnV; } while (0) + +/* + * The crMaybeWaitUntil macros could have been more easily written in + * terms of the simple crReturn above, by writing things like + * + * while (!condition) { crReturn(whatever); } + * + * (or do-while in the case of crWaitUntil). But it's better to do it + * directly by writing _once_ to crLine before first testing the + * condition, because this way it's robust against the condition check + * potentially freeing the entire coroutine state structure as a side + * effect (as long as it also evaluates false if it does that), + * because we don't write into crLine between the condition evaluating + * to false and the 'return' statement. + */ +#define crMaybeWaitUntil(c) \ + do { \ + *crLine =__LINE__; \ + case __LINE__: if (!(c)) return 0; \ + } while (0) +#define crMaybeWaitUntilV(c) \ + do { \ + *crLine =__LINE__; \ + case __LINE__: if (!(c)) return; \ + } while (0) +#define crWaitUntil(c) \ + do { \ + *crLine =__LINE__; return; \ + case __LINE__: if (!(c)) return 0; \ + } while (0) +#define crWaitUntilV(c) \ + do { \ + *crLine =__LINE__; return; \ + case __LINE__: if (!(c)) return; \ + } while (0) #endif /* PUTTY_SSHCR_H */ From 6bb847738bf3aa6f56f93cc9e8cedc9f0207663a Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Mon, 24 Sep 2018 18:08:09 +0100 Subject: [PATCH 454/607] Give the BPP an input and output packet queue. Now, instead of writing each packet straight on to the raw output bufchain by calling the BPP's format_packet function, the higher protocol layers will put the packets on to a queue, which will automatically trigger a callback (using the new mechanism for embedding a callback in any packet queue) to make the BPP format its queue on to the raw-output bufchain. That in turn triggers a second callback which moves the data to the socket. This means in particular that the CBC ignore-message workaround can be moved into the new BPP routine to process the output queue, which is a good place for it because then it can easily arrange to only put an ignore message at the start of any sequence of packets that are being formatted as a single output blob. --- ssh.c | 68 +++++++++++++++++++++++--------------------------- ssh1bpp.c | 21 +++++++++++----- ssh2bpp-bare.c | 25 +++++++++++++------ ssh2bpp.c | 53 +++++++++++++++++++++++++++++++++------ sshbpp.h | 30 +++++++++++++++++----- sshcommon.c | 35 ++++++++++++++++++++++++-- sshverstring.c | 7 +++--- 7 files changed, 170 insertions(+), 69 deletions(-) diff --git a/ssh.c b/ssh.c index 92a93e27..b4ad1a76 100644 --- a/ssh.c +++ b/ssh.c @@ -474,8 +474,7 @@ struct ssh_tag { int incoming_data_seen_eof; char *incoming_data_eof_message; - PktInQueue pq_full; - struct IdempotentCallback pq_full_consumer; + struct IdempotentCallback incoming_pkt_consumer; PktInQueue pq_ssh1_login; struct IdempotentCallback ssh1_login_icb; @@ -725,22 +724,7 @@ static int s_write(Ssh ssh, const void *data, int len) static void ssh_pkt_write(Ssh ssh, PktOut *pkt) { - if (ssh->version == 2 && ssh->v2_cbc_ignore_workaround && - bufchain_size(&ssh->outgoing_data) != 0) { - /* - * When using a CBC-mode cipher in SSH-2, it's necessary to - * ensure that an attacker can't provide data to be encrypted - * using an IV that they know. We ensure this by prefixing - * each packet that might contain user data with an - * SSH_MSG_IGNORE. - */ - PktOut *ipkt = ssh_bpp_new_pktout(ssh->bpp, SSH2_MSG_IGNORE); - put_stringz(ipkt, ""); - ssh_bpp_format_packet(ssh->bpp, ipkt); - } - - ssh_bpp_format_packet(ssh->bpp, pkt); - queue_idempotent_callback(&ssh->outgoing_data_sender); + pq_push(&ssh->bpp->out_pq, pkt); } /* @@ -881,8 +865,6 @@ static void ssh2_add_sigblob(Ssh ssh, PktOut *pkt, static void ssh_feed_to_bpp(Ssh ssh) { - PacketQueueNode *prev_tail = ssh->pq_full.pqb.end.prev; - assert(ssh->bpp); ssh_bpp_handle_input(ssh->bpp); @@ -904,9 +886,6 @@ static void ssh_feed_to_bpp(Ssh ssh) ssh->close_expected = TRUE; ssh->disconnect_message_seen = TRUE; } - - if (ssh->pq_full.pqb.end.prev != prev_tail) - queue_idempotent_callback(&ssh->pq_full_consumer); } static void ssh_got_ssh_version(struct ssh_version_receiver *rcv, @@ -976,12 +955,14 @@ static void ssh_got_ssh_version(struct ssh_version_receiver *rcv, } ssh->bpp->out_raw = &ssh->outgoing_data; + ssh->bpp->out_raw->ic = &ssh->outgoing_data_sender; ssh->bpp->in_raw = &ssh->incoming_data; - ssh->bpp->in_pq = &ssh->pq_full; + ssh->bpp->in_pq.pqb.ic = &ssh->incoming_pkt_consumer; ssh->bpp->pls = &ssh->pls; ssh->bpp->logctx = ssh->logctx; + ssh->bpp->remote_bugs = ssh->remote_bugs; - queue_idempotent_callback(&ssh->incoming_data_consumer); + queue_idempotent_callback(&ssh->bpp->ic_in_raw); queue_idempotent_callback(&ssh->user_input_consumer); update_specials_menu(ssh->frontend); @@ -1034,12 +1015,12 @@ static void ssh_process_incoming_data(void *ctx) } } -static void ssh_process_pq_full(void *ctx) +static void ssh_process_incoming_pkts(void *ctx) { Ssh ssh = (Ssh)ctx; PktIn *pktin; - while ((pktin = pq_pop(&ssh->pq_full)) != NULL) { + while ((pktin = pq_pop(&ssh->bpp->in_pq)) != NULL) { if (ssh->general_packet_processing) ssh->general_packet_processing(ssh, pktin); ssh->packet_dispatch[pktin->type](ssh, pktin); @@ -1730,6 +1711,13 @@ static void do_ssh1_login(void *vctx) sfree(s->rsabuf); + /* + * Force the BPP to synchronously marshal all packets up to and + * including the SESSION_KEY into wire format, before we turn on + * crypto. + */ + ssh_bpp_handle_output(ssh->bpp); + { const struct ssh1_cipheralg *cipher = (s->cipher_type == SSH_CIPHER_BLOWFISH ? &ssh1_blowfish : @@ -5077,6 +5065,13 @@ static void do_ssh2_transport(void *vctx) ssh->stats.out.running = TRUE; ssh->stats.out.remaining = ssh->max_data_size; + /* + * Force the BPP to synchronously marshal all packets up to and + * including that NEWKEYS into wire format, before we switch over + * to new crypto. + */ + ssh_bpp_handle_output(ssh->bpp); + /* * We've sent client NEWKEYS, so create and initialise * client-to-server session keys. @@ -6616,10 +6611,10 @@ static void ssh2_msg_userauth(Ssh ssh, PktIn *pktin) * protocol has officially started, which means we must * install the dispatch-table entries for all the * connection-layer messages. In particular, we must do this - * _before_ we return to the loop in ssh_process_pq_full + * _before_ we return to the loop in ssh_process_incoming_pkts * that's processing the currently queued packets through the * dispatch table, because if (say) an SSH_MSG_GLOBAL_REQUEST - * is already pending in pq_full, we can't afford to delay + * is already pending in in_pq, we can't afford to delay * installing its dispatch table entry until after that queue * run is done. */ @@ -8331,14 +8326,15 @@ static void do_ssh2_connection(void *vctx) /* * Put our current pending packet queue back to the front of - * pq_full, and then schedule a callback to re-process those + * the main pq, and then schedule a callback to re-process those * packets (if any). That way, anything already in our queue that * matches any of the table entries we've just modified will go to * the right handler function, and won't come here to confuse us. */ if (pq_peek(&ssh->pq_ssh2_connection)) { - pq_concatenate(&ssh->pq_full, &ssh->pq_ssh2_connection, &ssh->pq_full); - queue_idempotent_callback(&ssh->pq_full_consumer); + pq_concatenate(&ssh->bpp->in_pq, + &ssh->pq_ssh2_connection, &ssh->bpp->in_pq); + queue_idempotent_callback(ssh->bpp->in_pq.pqb.ic); } /* @@ -9005,10 +9001,9 @@ static const char *ssh_init(Frontend *frontend, Backend **backend_handle, ssh->incoming_data_consumer.fn = ssh_process_incoming_data; ssh->incoming_data_consumer.ctx = ssh; ssh->incoming_data_consumer.queued = FALSE; - pq_in_init(&ssh->pq_full); - ssh->pq_full_consumer.fn = ssh_process_pq_full; - ssh->pq_full_consumer.ctx = ssh; - ssh->pq_full_consumer.queued = FALSE; + ssh->incoming_pkt_consumer.fn = ssh_process_incoming_pkts; + ssh->incoming_pkt_consumer.ctx = ssh; + ssh->incoming_pkt_consumer.queued = FALSE; pq_in_init(&ssh->pq_ssh1_login); ssh->ssh1_login_icb.fn = do_ssh1_login; ssh->ssh1_login_icb.ctx = ssh; @@ -9191,7 +9186,6 @@ static void ssh_free(Backend *be) bufchain_clear(&ssh->incoming_data); bufchain_clear(&ssh->outgoing_data); sfree(ssh->incoming_data_eof_message); - pq_in_clear(&ssh->pq_full); pq_in_clear(&ssh->pq_ssh1_login); pq_in_clear(&ssh->pq_ssh1_connection); pq_in_clear(&ssh->pq_ssh2_transport); diff --git a/ssh1bpp.c b/ssh1bpp.c index 9640d35d..24eaeab4 100644 --- a/ssh1bpp.c +++ b/ssh1bpp.c @@ -30,14 +30,14 @@ struct ssh1_bpp_state { static void ssh1_bpp_free(BinaryPacketProtocol *bpp); static void ssh1_bpp_handle_input(BinaryPacketProtocol *bpp); +static void ssh1_bpp_handle_output(BinaryPacketProtocol *bpp); static PktOut *ssh1_bpp_new_pktout(int type); -static void ssh1_bpp_format_packet(BinaryPacketProtocol *bpp, PktOut *pkt); static const struct BinaryPacketProtocolVtable ssh1_bpp_vtable = { ssh1_bpp_free, ssh1_bpp_handle_input, + ssh1_bpp_handle_output, ssh1_bpp_new_pktout, - ssh1_bpp_format_packet, }; BinaryPacketProtocol *ssh1_bpp_new(void) @@ -45,6 +45,7 @@ BinaryPacketProtocol *ssh1_bpp_new(void) struct ssh1_bpp_state *s = snew(struct ssh1_bpp_state); memset(s, 0, sizeof(*s)); s->bpp.vt = &ssh1_bpp_vtable; + ssh_bpp_common_setup(&s->bpp); return &s->bpp; } @@ -202,7 +203,7 @@ static void ssh1_bpp_handle_input(BinaryPacketProtocol *bpp) NULL, 0, NULL); } - pq_push(s->bpp.in_pq, s->pktin); + pq_push(&s->bpp.in_pq, s->pktin); { int type = s->pktin->type; @@ -241,9 +242,8 @@ static PktOut *ssh1_bpp_new_pktout(int pkt_type) return pkt; } -static void ssh1_bpp_format_packet(BinaryPacketProtocol *bpp, PktOut *pkt) +static void ssh1_bpp_format_packet(struct ssh1_bpp_state *s, PktOut *pkt) { - struct ssh1_bpp_state *s = FROMFIELD(bpp, struct ssh1_bpp_state, bpp); int pad, biglen, i, pktoffs; unsigned long crc; int len; @@ -290,6 +290,15 @@ static void ssh1_bpp_format_packet(BinaryPacketProtocol *bpp, PktOut *pkt) bufchain_add(s->bpp.out_raw, pkt->data + pktoffs, biglen + 4); /* len(length+padding+type+data+CRC) */ +} + +static void ssh1_bpp_handle_output(BinaryPacketProtocol *bpp) +{ + struct ssh1_bpp_state *s = FROMFIELD(bpp, struct ssh1_bpp_state, bpp); + PktOut *pkt; - ssh_free_pktout(pkt); + while ((pkt = pq_pop(&s->bpp.out_pq)) != NULL) { + ssh1_bpp_format_packet(s, pkt); + ssh_free_pktout(pkt); + } } diff --git a/ssh2bpp-bare.c b/ssh2bpp-bare.c index 58e6ae32..1c838303 100644 --- a/ssh2bpp-bare.c +++ b/ssh2bpp-bare.c @@ -22,14 +22,14 @@ struct ssh2_bare_bpp_state { static void ssh2_bare_bpp_free(BinaryPacketProtocol *bpp); static void ssh2_bare_bpp_handle_input(BinaryPacketProtocol *bpp); +static void ssh2_bare_bpp_handle_output(BinaryPacketProtocol *bpp); static PktOut *ssh2_bare_bpp_new_pktout(int type); -static void ssh2_bare_bpp_format_packet(BinaryPacketProtocol *bpp, PktOut *); static const struct BinaryPacketProtocolVtable ssh2_bare_bpp_vtable = { ssh2_bare_bpp_free, ssh2_bare_bpp_handle_input, + ssh2_bare_bpp_handle_output, ssh2_bare_bpp_new_pktout, - ssh2_bare_bpp_format_packet, }; BinaryPacketProtocol *ssh2_bare_bpp_new(void) @@ -37,6 +37,7 @@ BinaryPacketProtocol *ssh2_bare_bpp_new(void) struct ssh2_bare_bpp_state *s = snew(struct ssh2_bare_bpp_state); memset(s, 0, sizeof(*s)); s->bpp.vt = &ssh2_bare_bpp_vtable; + ssh_bpp_common_setup(&s->bpp); return &s->bpp; } @@ -120,7 +121,7 @@ static void ssh2_bare_bpp_handle_input(BinaryPacketProtocol *bpp) continue; } - pq_push(s->bpp.in_pq, s->pktin); + pq_push(&s->bpp.in_pq, s->pktin); { int type = s->pktin->type; @@ -142,11 +143,9 @@ static PktOut *ssh2_bare_bpp_new_pktout(int pkt_type) return pkt; } -static void ssh2_bare_bpp_format_packet(BinaryPacketProtocol *bpp, PktOut *pkt) +static void ssh2_bare_bpp_format_packet(struct ssh2_bare_bpp_state *s, + PktOut *pkt) { - struct ssh2_bare_bpp_state *s = - FROMFIELD(bpp, struct ssh2_bare_bpp_state, bpp); - if (s->bpp.logctx) { ptrlen pktdata = make_ptrlen(pkt->data + 5, pkt->length - 5); logblank_t blanks[MAX_BLANKS]; @@ -164,6 +163,16 @@ static void ssh2_bare_bpp_format_packet(BinaryPacketProtocol *bpp, PktOut *pkt) PUT_32BIT(pkt->data, pkt->length - 4); bufchain_add(s->bpp.out_raw, pkt->data, pkt->length); +} - ssh_free_pktout(pkt); +static void ssh2_bare_bpp_handle_output(BinaryPacketProtocol *bpp) +{ + struct ssh2_bare_bpp_state *s = + FROMFIELD(bpp, struct ssh2_bare_bpp_state, bpp); + PktOut *pkt; + + while ((pkt = pq_pop(&s->bpp.out_pq)) != NULL) { + ssh2_bare_bpp_format_packet(s, pkt); + ssh_free_pktout(pkt); + } } diff --git a/ssh2bpp.c b/ssh2bpp.c index 21ea2401..1bc27340 100644 --- a/ssh2bpp.c +++ b/ssh2bpp.c @@ -25,6 +25,7 @@ struct ssh2_bpp_state { unsigned cipherblk; PktIn *pktin; struct DataTransferStats *stats; + int cbc_ignore_workaround; struct ssh2_bpp_direction in, out; /* comp and decomp logically belong in the per-direction @@ -39,14 +40,14 @@ struct ssh2_bpp_state { static void ssh2_bpp_free(BinaryPacketProtocol *bpp); static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp); +static void ssh2_bpp_handle_output(BinaryPacketProtocol *bpp); static PktOut *ssh2_bpp_new_pktout(int type); -static void ssh2_bpp_format_packet(BinaryPacketProtocol *bpp, PktOut *pkt); static const struct BinaryPacketProtocolVtable ssh2_bpp_vtable = { ssh2_bpp_free, ssh2_bpp_handle_input, + ssh2_bpp_handle_output, ssh2_bpp_new_pktout, - ssh2_bpp_format_packet, }; BinaryPacketProtocol *ssh2_bpp_new(struct DataTransferStats *stats) @@ -55,6 +56,7 @@ BinaryPacketProtocol *ssh2_bpp_new(struct DataTransferStats *stats) memset(s, 0, sizeof(*s)); s->bpp.vt = &ssh2_bpp_vtable; s->stats = stats; + ssh_bpp_common_setup(&s->bpp); return &s->bpp; } @@ -99,8 +101,13 @@ void ssh2_bpp_new_outgoing_crypto( s->out.cipher = ssh2_cipher_new(cipher); ssh2_cipher_setkey(s->out.cipher, ckey); ssh2_cipher_setiv(s->out.cipher, iv); + + s->cbc_ignore_workaround = ( + (ssh2_cipher_alg(s->out.cipher)->flags & SSH_CIPHER_IS_CBC) && + !(s->bpp.remote_bugs & BUG_CHOKES_ON_SSH2_IGNORE)); } else { s->out.cipher = NULL; + s->cbc_ignore_workaround = FALSE; } s->out.etm_mode = etm_mode; if (mac) { @@ -478,7 +485,7 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp) continue; } - pq_push(s->bpp.in_pq, s->pktin); + pq_push(&s->bpp.in_pq, s->pktin); { int type = s->pktin->type; @@ -611,10 +618,8 @@ static void ssh2_bpp_format_packet_inner(struct ssh2_bpp_state *s, PktOut *pkt) } -static void ssh2_bpp_format_packet(BinaryPacketProtocol *bpp, PktOut *pkt) +static void ssh2_bpp_format_packet(struct ssh2_bpp_state *s, PktOut *pkt) { - struct ssh2_bpp_state *s = FROMFIELD(bpp, struct ssh2_bpp_state, bpp); - if (pkt->minlen > 0 && !s->out_comp) { /* * If we've been told to pad the packet out to a given minimum @@ -678,6 +683,40 @@ static void ssh2_bpp_format_packet(BinaryPacketProtocol *bpp, PktOut *pkt) ssh2_bpp_format_packet_inner(s, pkt); bufchain_add(s->bpp.out_raw, pkt->data, pkt->length); +} - ssh_free_pktout(pkt); +static void ssh2_bpp_handle_output(BinaryPacketProtocol *bpp) +{ + struct ssh2_bpp_state *s = FROMFIELD(bpp, struct ssh2_bpp_state, bpp); + PktOut *pkt; + + if (s->cbc_ignore_workaround) { + /* + * When using a CBC-mode cipher in SSH-2, it's necessary to + * ensure that an attacker can't provide data to be encrypted + * using an IV that they know. We ensure this by inserting an + * SSH_MSG_IGNORE if the last cipher block of the previous + * packet has already been sent to the network (which we + * approximate conservatively by checking if it's vanished + * from out_raw). + */ + if (bufchain_size(s->bpp.out_raw) < + (ssh2_cipher_alg(s->out.cipher)->blksize + + ssh2_mac_alg(s->out.mac)->len)) { + /* + * There's less data in out_raw than the MAC size plus the + * cipher block size, which means at least one byte of + * that cipher block must already have left. Add an + * IGNORE. + */ + pkt = ssh_bpp_new_pktout(&s->bpp, SSH2_MSG_IGNORE); + put_stringz(pkt, ""); + ssh2_bpp_format_packet(s, pkt); + } + } + + while ((pkt = pq_pop(&s->bpp.out_pq)) != NULL) { + ssh2_bpp_format_packet(s, pkt); + ssh_free_pktout(pkt); + } } diff --git a/sshbpp.h b/sshbpp.h index 61f4fe7f..c3f26728 100644 --- a/sshbpp.h +++ b/sshbpp.h @@ -5,30 +5,44 @@ #ifndef PUTTY_SSHBPP_H #define PUTTY_SSHBPP_H -typedef struct BinaryPacketProtocol BinaryPacketProtocol; - struct BinaryPacketProtocolVtable { void (*free)(BinaryPacketProtocol *); void (*handle_input)(BinaryPacketProtocol *); + void (*handle_output)(BinaryPacketProtocol *); PktOut *(*new_pktout)(int type); - void (*format_packet)(BinaryPacketProtocol *, PktOut *); }; struct BinaryPacketProtocol { const struct BinaryPacketProtocolVtable *vt; bufchain *in_raw, *out_raw; - PktInQueue *in_pq; + PktInQueue in_pq; + PktOutQueue out_pq; PacketLogSettings *pls; LogContext *logctx; + Ssh ssh; + + /* ic_in_raw is filled in by the BPP (probably by calling + * ssh_bpp_common_setup). The BPP's owner triggers it when data is + * added to in_raw, and also when the BPP is newly created. */ + IdempotentCallback ic_in_raw; + + /* ic_out_pq is entirely internal to the BPP itself; it's used as + * the callback on out_pq. */ + IdempotentCallback ic_out_pq; + + int remote_bugs; int seen_disconnect; char *error; }; -#define ssh_bpp_free(bpp) ((bpp)->vt->free(bpp)) #define ssh_bpp_handle_input(bpp) ((bpp)->vt->handle_input(bpp)) +#define ssh_bpp_handle_output(bpp) ((bpp)->vt->handle_output(bpp)) #define ssh_bpp_new_pktout(bpp, type) ((bpp)->vt->new_pktout(type)) -#define ssh_bpp_format_packet(bpp, pkt) ((bpp)->vt->format_packet(bpp, pkt)) + +/* ssh_bpp_free is more than just a macro wrapper on the vtable; it + * does centralised parts of the freeing too. */ +void ssh_bpp_free(BinaryPacketProtocol *bpp); BinaryPacketProtocol *ssh1_bpp_new(void); void ssh1_bpp_new_cipher(BinaryPacketProtocol *bpp, @@ -40,6 +54,10 @@ void ssh1_bpp_new_cipher(BinaryPacketProtocol *bpp, * up zlib compression if it was SUCCESS. */ void ssh1_bpp_requested_compression(BinaryPacketProtocol *bpp); +/* Helper routine which does common BPP initialisation, e.g. setting + * up in_pq and out_pq, and initialising input_consumer. */ +void ssh_bpp_common_setup(BinaryPacketProtocol *); + /* Common helper function between the SSH-2 full and bare BPPs */ int ssh2_bpp_check_unimplemented(BinaryPacketProtocol *bpp, PktIn *pktin); diff --git a/sshcommon.c b/sshcommon.c index 932e6c46..088e1c88 100644 --- a/sshcommon.c +++ b/sshcommon.c @@ -252,6 +252,7 @@ void ssh_free_pktout(PktOut *pkt) sfree(pkt->data); sfree(pkt); } + /* ---------------------------------------------------------------------- * Implement zombiechan_new() and its trivial vtable. */ @@ -630,9 +631,39 @@ const char *ssh2_pkt_type(Pkt_KCtx pkt_kctx, Pkt_ACtx pkt_actx, int type) #undef TRANSLATE_AUTH /* ---------------------------------------------------------------------- - * Common helper function for implementations of BinaryPacketProtocol. + * Common helper functions for clients and implementations of + * BinaryPacketProtocol. */ +static void ssh_bpp_input_raw_data_callback(void *context) +{ + BinaryPacketProtocol *bpp = (BinaryPacketProtocol *)context; + ssh_bpp_handle_input(bpp); +} + +static void ssh_bpp_output_packet_callback(void *context) +{ + BinaryPacketProtocol *bpp = (BinaryPacketProtocol *)context; + ssh_bpp_handle_output(bpp); +} + +void ssh_bpp_common_setup(BinaryPacketProtocol *bpp) +{ + pq_in_init(&bpp->in_pq); + pq_out_init(&bpp->out_pq); + bpp->ic_in_raw.fn = ssh_bpp_input_raw_data_callback; + bpp->ic_in_raw.ctx = bpp; + bpp->ic_out_pq.fn = ssh_bpp_output_packet_callback; + bpp->ic_out_pq.ctx = bpp; + bpp->out_pq.pqb.ic = &bpp->ic_out_pq; +} + +void ssh_bpp_free(BinaryPacketProtocol *bpp) +{ + delete_callbacks_for_context(bpp); + bpp->vt->free(bpp); +} + #define BITMAP_UNIVERSAL(y, name, value) \ | (value >= y && value < y+32 ? 1UL << (value-y) : 0) #define BITMAP_CONDITIONAL(y, name, value, ctx) \ @@ -658,7 +689,7 @@ int ssh2_bpp_check_unimplemented(BinaryPacketProtocol *bpp, PktIn *pktin) !((valid_bitmap[pktin->type >> 5] >> (pktin->type & 0x1F)) & 1)) { PktOut *pkt = ssh_bpp_new_pktout(bpp, SSH2_MSG_UNIMPLEMENTED); put_uint32(pkt, pktin->sequence); - ssh_bpp_format_packet(bpp, pkt); + pq_push(&bpp->out_pq, pkt); return TRUE; } diff --git a/sshverstring.c b/sshverstring.c index 029b140c..f02b0e9b 100644 --- a/sshverstring.c +++ b/sshverstring.c @@ -41,14 +41,14 @@ struct ssh_verstring_state { static void ssh_verstring_free(BinaryPacketProtocol *bpp); static void ssh_verstring_handle_input(BinaryPacketProtocol *bpp); +static void ssh_verstring_handle_output(BinaryPacketProtocol *bpp); static PktOut *ssh_verstring_new_pktout(int type); -static void ssh_verstring_format_packet(BinaryPacketProtocol *bpp, PktOut *); static const struct BinaryPacketProtocolVtable ssh_verstring_vtable = { ssh_verstring_free, ssh_verstring_handle_input, + ssh_verstring_handle_output, ssh_verstring_new_pktout, - ssh_verstring_format_packet, }; static void ssh_detect_bugs(struct ssh_verstring_state *s); @@ -97,6 +97,7 @@ BinaryPacketProtocol *ssh_verstring_new( s->send_early = !ssh_version_includes_v1(protoversion); s->bpp.vt = &ssh_verstring_vtable; + ssh_bpp_common_setup(&s->bpp); return &s->bpp; } @@ -394,7 +395,7 @@ static PktOut *ssh_verstring_new_pktout(int type) return NULL; } -static void ssh_verstring_format_packet(BinaryPacketProtocol *bpp, PktOut *pkg) +static void ssh_verstring_handle_output(BinaryPacketProtocol *bpp) { assert(0 && "Should never try to send packets during SSH version " "string exchange"); From 30744400405512d5c46f9e24b422a018b41bebcd Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Mon, 24 Sep 2018 18:14:33 +0100 Subject: [PATCH 455/607] Move SSH_MSG_DISCONNECT construction into the BPP. This is a convenient place for it because it abstracts away the difference in disconnect packet formats between SSH-1 and -2, so when I start restructuring, I'll be able to call it even from places that don't know which version of SSH they're running. --- ssh.c | 15 ++------------- ssh1bpp.c | 11 +++++++++++ ssh2bpp-bare.c | 1 + ssh2bpp.c | 1 + sshbpp.h | 8 +++++++- sshcommon.c | 10 ++++++++++ sshverstring.c | 9 +++++++++ 7 files changed, 41 insertions(+), 14 deletions(-) diff --git a/ssh.c b/ssh.c index b4ad1a76..605c8e8a 100644 --- a/ssh.c +++ b/ssh.c @@ -1429,19 +1429,8 @@ static void ssh_disconnect(Ssh ssh, const char *client_reason, error = dupprintf("Disconnected: %s", client_reason); else error = dupstr("Disconnected"); - if (wire_reason) { - if (ssh->version == 1) { - PktOut *pktout = ssh_bpp_new_pktout(ssh->bpp, SSH1_MSG_DISCONNECT); - put_stringz(pktout, wire_reason); - ssh_pkt_write(ssh, pktout); - } else if (ssh->version == 2) { - PktOut *pktout = ssh_bpp_new_pktout(ssh->bpp, SSH2_MSG_DISCONNECT); - put_uint32(pktout, code); - put_stringz(pktout, wire_reason); - put_stringz(pktout, "en"); /* language tag */ - ssh_pkt_write(ssh, pktout); - } - } + if (wire_reason) + ssh_bpp_queue_disconnect(ssh->bpp, wire_reason, code); ssh->close_expected = TRUE; ssh->clean_exit = clean_exit; ssh_closing(&ssh->plugvt, error, 0, 0); diff --git a/ssh1bpp.c b/ssh1bpp.c index 24eaeab4..36e03b5d 100644 --- a/ssh1bpp.c +++ b/ssh1bpp.c @@ -31,6 +31,8 @@ struct ssh1_bpp_state { static void ssh1_bpp_free(BinaryPacketProtocol *bpp); static void ssh1_bpp_handle_input(BinaryPacketProtocol *bpp); static void ssh1_bpp_handle_output(BinaryPacketProtocol *bpp); +static void ssh1_bpp_queue_disconnect(BinaryPacketProtocol *bpp, + const char *msg, int category); static PktOut *ssh1_bpp_new_pktout(int type); static const struct BinaryPacketProtocolVtable ssh1_bpp_vtable = { @@ -38,6 +40,7 @@ static const struct BinaryPacketProtocolVtable ssh1_bpp_vtable = { ssh1_bpp_handle_input, ssh1_bpp_handle_output, ssh1_bpp_new_pktout, + ssh1_bpp_queue_disconnect, }; BinaryPacketProtocol *ssh1_bpp_new(void) @@ -302,3 +305,11 @@ static void ssh1_bpp_handle_output(BinaryPacketProtocol *bpp) ssh_free_pktout(pkt); } } + +static void ssh1_bpp_queue_disconnect(BinaryPacketProtocol *bpp, + const char *msg, int category) +{ + PktOut *pkt = ssh_bpp_new_pktout(bpp, SSH1_MSG_DISCONNECT); + put_stringz(pkt, msg); + pq_push(&bpp->out_pq, pkt); +} diff --git a/ssh2bpp-bare.c b/ssh2bpp-bare.c index 1c838303..5b58a3c7 100644 --- a/ssh2bpp-bare.c +++ b/ssh2bpp-bare.c @@ -30,6 +30,7 @@ static const struct BinaryPacketProtocolVtable ssh2_bare_bpp_vtable = { ssh2_bare_bpp_handle_input, ssh2_bare_bpp_handle_output, ssh2_bare_bpp_new_pktout, + ssh2_bpp_queue_disconnect, /* in sshcommon.c */ }; BinaryPacketProtocol *ssh2_bare_bpp_new(void) diff --git a/ssh2bpp.c b/ssh2bpp.c index 1bc27340..b476f33b 100644 --- a/ssh2bpp.c +++ b/ssh2bpp.c @@ -48,6 +48,7 @@ static const struct BinaryPacketProtocolVtable ssh2_bpp_vtable = { ssh2_bpp_handle_input, ssh2_bpp_handle_output, ssh2_bpp_new_pktout, + ssh2_bpp_queue_disconnect, /* in sshcommon.c */ }; BinaryPacketProtocol *ssh2_bpp_new(struct DataTransferStats *stats) diff --git a/sshbpp.h b/sshbpp.h index c3f26728..b3eb9985 100644 --- a/sshbpp.h +++ b/sshbpp.h @@ -10,6 +10,8 @@ struct BinaryPacketProtocolVtable { void (*handle_input)(BinaryPacketProtocol *); void (*handle_output)(BinaryPacketProtocol *); PktOut *(*new_pktout)(int type); + void (*queue_disconnect)(BinaryPacketProtocol *, + const char *msg, int category); }; struct BinaryPacketProtocol { @@ -39,6 +41,8 @@ struct BinaryPacketProtocol { #define ssh_bpp_handle_input(bpp) ((bpp)->vt->handle_input(bpp)) #define ssh_bpp_handle_output(bpp) ((bpp)->vt->handle_output(bpp)) #define ssh_bpp_new_pktout(bpp, type) ((bpp)->vt->new_pktout(type)) +#define ssh_bpp_queue_disconnect(bpp, msg, cat) \ + ((bpp)->vt->queue_disconnect(bpp, msg, cat)) /* ssh_bpp_free is more than just a macro wrapper on the vtable; it * does centralised parts of the freeing too. */ @@ -58,7 +62,9 @@ void ssh1_bpp_requested_compression(BinaryPacketProtocol *bpp); * up in_pq and out_pq, and initialising input_consumer. */ void ssh_bpp_common_setup(BinaryPacketProtocol *); -/* Common helper function between the SSH-2 full and bare BPPs */ +/* Common helper functions between the SSH-2 full and bare BPPs */ +void ssh2_bpp_queue_disconnect(BinaryPacketProtocol *bpp, + const char *msg, int category); int ssh2_bpp_check_unimplemented(BinaryPacketProtocol *bpp, PktIn *pktin); /* diff --git a/sshcommon.c b/sshcommon.c index 088e1c88..5a2270b4 100644 --- a/sshcommon.c +++ b/sshcommon.c @@ -664,6 +664,16 @@ void ssh_bpp_free(BinaryPacketProtocol *bpp) bpp->vt->free(bpp); } +void ssh2_bpp_queue_disconnect(BinaryPacketProtocol *bpp, + const char *msg, int category) +{ + PktOut *pkt = ssh_bpp_new_pktout(bpp, SSH2_MSG_DISCONNECT); + put_uint32(pkt, category); + put_stringz(pkt, msg); + put_stringz(pkt, "en"); /* language tag */ + pq_push(&bpp->out_pq, pkt); +} + #define BITMAP_UNIVERSAL(y, name, value) \ | (value >= y && value < y+32 ? 1UL << (value-y) : 0) #define BITMAP_CONDITIONAL(y, name, value, ctx) \ diff --git a/sshverstring.c b/sshverstring.c index f02b0e9b..ffead60c 100644 --- a/sshverstring.c +++ b/sshverstring.c @@ -43,12 +43,15 @@ static void ssh_verstring_free(BinaryPacketProtocol *bpp); static void ssh_verstring_handle_input(BinaryPacketProtocol *bpp); static void ssh_verstring_handle_output(BinaryPacketProtocol *bpp); static PktOut *ssh_verstring_new_pktout(int type); +static void ssh_verstring_queue_disconnect(BinaryPacketProtocol *bpp, + const char *msg, int category); static const struct BinaryPacketProtocolVtable ssh_verstring_vtable = { ssh_verstring_free, ssh_verstring_handle_input, ssh_verstring_handle_output, ssh_verstring_new_pktout, + ssh_verstring_queue_disconnect, }; static void ssh_detect_bugs(struct ssh_verstring_state *s); @@ -608,3 +611,9 @@ int ssh_verstring_get_bugs(BinaryPacketProtocol *bpp) FROMFIELD(bpp, struct ssh_verstring_state, bpp); return s->remote_bugs; } + +static void ssh_verstring_queue_disconnect(BinaryPacketProtocol *bpp, + const char *msg, int category) +{ + /* No way to send disconnect messages at this stage of the protocol! */ +} From 344ec3aec5d8d32a1e6d6ccc8028c6951ebce5d1 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 22 Sep 2018 11:09:15 +0100 Subject: [PATCH 456/607] Restructure SSH-1 compression again. Having redesigned it a few days ago in commit 562cdd4df, I'm changing it again, this time to fix a potential race condition on the _output_ side: the last change was intended to cope with a server sending an asynchronous message like IGNORE immediately after enabling compression, and this one fixes the case in which _we_ happen to decide to send an IGNORE while a compression request is still pending. I couldn't fix this until after the BPP was reorganised to have an explicit output queue of packets, but now it does, I can simply defer processing that queue on to the output raw-data bufchain if we're waiting for a compression request to be answered. Once it is answered, the BPP can release any pending packets. --- ssh.c | 9 ++++++- ssh1bpp.c | 77 ++++++++++++++++++++++++++++++++++++++----------------- 2 files changed, 62 insertions(+), 24 deletions(-) diff --git a/ssh.c b/ssh.c index 605c8e8a..94dbb064 100644 --- a/ssh.c +++ b/ssh.c @@ -3125,7 +3125,6 @@ static void do_ssh1_connection(void *vctx) pkt = ssh_bpp_new_pktout(ssh->bpp, SSH1_CMSG_REQUEST_COMPRESSION); put_uint32(pkt, 6); /* gzip compression level */ ssh_pkt_write(ssh, pkt); - ssh1_bpp_requested_compression(ssh->bpp); crMaybeWaitUntilV((pktin = pq_pop(&ssh->pq_ssh1_connection)) != NULL); if (pktin->type != SSH1_SMSG_SUCCESS && pktin->type != SSH1_SMSG_FAILURE) { @@ -3134,6 +3133,14 @@ static void do_ssh1_connection(void *vctx) } else if (pktin->type == SSH1_SMSG_FAILURE) { c_write_str(ssh, "Server refused to compress\r\n"); } else { + /* + * We don't have to actually do anything here: the SSH-1 + * BPP will take care of automatically starting the + * compression, by recognising our outgoing request packet + * and the success response. (Horrible, but it's the + * easiest way to avoid race conditions if other packets + * cross in transit.) + */ logevent("Started zlib (RFC1950) compression"); } } diff --git a/ssh1bpp.c b/ssh1bpp.c index 36e03b5d..4b775929 100644 --- a/ssh1bpp.c +++ b/ssh1bpp.c @@ -86,15 +86,6 @@ void ssh1_bpp_new_cipher(BinaryPacketProtocol *bpp, } } -void ssh1_bpp_requested_compression(BinaryPacketProtocol *bpp) -{ - struct ssh1_bpp_state *s; - assert(bpp->vt == &ssh1_bpp_vtable); - s = FROMFIELD(bpp, struct ssh1_bpp_state, bpp); - - s->pending_compression_request = TRUE; -} - #define BPP_READ(ptr, len) do \ { \ crMaybeWaitUntilV(bufchain_try_fetch_consume( \ @@ -212,21 +203,39 @@ static void ssh1_bpp_handle_input(BinaryPacketProtocol *bpp) int type = s->pktin->type; s->pktin = NULL; - if (type == SSH1_MSG_DISCONNECT) + switch (type) { + case SSH1_MSG_DISCONNECT: s->bpp.seen_disconnect = TRUE; - - if (type == SSH1_SMSG_SUCCESS && s->pending_compression_request) { - assert(!s->compctx); - assert(!s->decompctx); - - s->compctx = ssh_compressor_new(&ssh_zlib); - s->decompctx = ssh_decompressor_new(&ssh_zlib); - - s->pending_compression_request = FALSE; - } - - if (type == SSH1_SMSG_FAILURE && s->pending_compression_request) { - s->pending_compression_request = FALSE; + break; + + case SSH1_SMSG_SUCCESS: + case SSH1_SMSG_FAILURE: + if (s->pending_compression_request) { + /* + * This is the response to + * SSH1_CMSG_REQUEST_COMPRESSION. + */ + if (type == SSH1_SMSG_SUCCESS) { + /* + * If the response was positive, start + * compression. + */ + assert(!s->compctx); + assert(!s->decompctx); + + s->compctx = ssh_compressor_new(&ssh_zlib); + s->decompctx = ssh_decompressor_new(&ssh_zlib); + } + + /* + * Either way, cancel the pending flag, and + * schedule a run of our output side in case we + * had any packets queued up in the meantime. + */ + s->pending_compression_request = FALSE; + queue_idempotent_callback(&s->bpp.ic_out_pq); + } + break; } } } @@ -300,9 +309,31 @@ static void ssh1_bpp_handle_output(BinaryPacketProtocol *bpp) struct ssh1_bpp_state *s = FROMFIELD(bpp, struct ssh1_bpp_state, bpp); PktOut *pkt; + if (s->pending_compression_request) { + /* + * Don't send any output packets while we're awaiting a + * response to SSH1_CMSG_REQUEST_COMPRESSION, because if they + * cross over in transit with the responding SSH1_CMSG_SUCCESS + * then the other end could decode them with the wrong + * compression settings. + */ + return; + } + while ((pkt = pq_pop(&s->bpp.out_pq)) != NULL) { + int type = pkt->type; ssh1_bpp_format_packet(s, pkt); ssh_free_pktout(pkt); + + if (type == SSH1_CMSG_REQUEST_COMPRESSION) { + /* + * When we see the actual compression request go past, set + * the pending flag, and stop processing packets this + * time. + */ + s->pending_compression_request = TRUE; + break; + } } } From 2ca0070f891c464d4274bdc1c69709fd6b694bd7 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Mon, 24 Sep 2018 18:28:16 +0100 Subject: [PATCH 457/607] Move most of ssh.c out into separate source files. I've tried to separate out as many individually coherent changes from this work as I could into their own commits, but here's where I run out and have to commit the rest of this major refactoring as a big-bang change. Most of ssh.c is now no longer in ssh.c: all five of the main coroutines that handle layers of the SSH-1 and SSH-2 protocols now each have their own source file to live in, and a lot of the supporting functions have moved into the appropriate one of those too. The new abstraction is a vtable called 'PacketProtocolLayer', which has an input and output packet queue. Each layer's main coroutine is invoked from the method ssh_ppl_process_queue(), which is usually (though not exclusively) triggered automatically when things are pushed on the input queue. In SSH-2, the base layer is the transport protocol, and it contains a pair of subsidiary queues by which it passes some of its packets to the higher SSH-2 layers - first userauth and then connection, which are peers at the same level, with the former abdicating in favour of the latter at the appropriate moment. SSH-1 is simpler: the whole login phase of the protocol (crypto setup and authentication) is all in one module, and since SSH-1 has no repeat key exchange, that setup layer abdicates in favour of the connection phase when it's done. ssh.c itself is now about a tenth of its old size (which all by itself is cause for celebration!). Its main job is to set up all the layers, hook them up to each other and to the BPP, and to funnel data back and forth between that collection of modules and external things such as the network and the terminal. Once it's set up a collection of packet protocol layers, it communicates with them partly by calling methods of the base layer (and if that's ssh2transport then it will delegate some functionality to the corresponding methods of its higher layer), and partly by talking directly to the connection layer no matter where it is in the stack by means of the separate ConnectionLayer vtable which I introduced in commit 8001dd4cb, and to which I've now added quite a few extra methods replacing services that used to be internal function calls within ssh.c. (One effect of this is that the SSH-1 and SSH-2 channel storage is now no longer shared - there are distinct struct types ssh1_channel and ssh2_channel. That means a bit more code duplication, but on the plus side, a lot fewer confusing conditionals in the middle of half-shared functions, and less risk of a piece of SSH-1 escaping into SSH-2 or vice versa, which I remember has happened at least once in the past.) The bulk of this commit introduces the five new source files, their common header sshppl.h and some shared supporting routines in sshcommon.c, and rewrites nearly all of ssh.c itself. But it also includes a couple of other changes that I couldn't separate easily enough: Firstly, there's a new handling for socket EOF, in which ssh.c sets an 'input_eof' flag in the BPP, and that responds by checking a flag that tells it whether to report the EOF as an error or not. (This is the main reason for those new BPP_READ / BPP_WAITFOR macros - they can check the EOF flag every time the coroutine is resumed.) Secondly, the error reporting itself is changed around again. I'd expected to put some data fields in the public PacketProtocolLayer structure that it could set to report errors in the same way as the BPPs have been doing, but in the end, I decided propagating all those data fields around was a pain and that even the BPPs shouldn't have been doing it that way. So I've reverted to a system where everything calls back to functions in ssh.c itself to report any connection- ending condition. But there's a new family of those functions, categorising the possible such conditions by semantics, and each one has a different set of detailed effects (e.g. how rudely to close the network connection, what exit status should be passed back to the whole application, whether to send a disconnect message and/or display a GUI error box). I don't expect this to be immediately perfect: of course, the code has been through a big upheaval, new bugs are expected, and I haven't been able to do a full job of testing (e.g. I haven't tested every auth or kex method). But I've checked that it _basically_ works - both SSH protocols, all the different kinds of forwarding channel, more than one auth method, Windows and Linux, connection sharing - and I think it's now at the point where the easiest way to find further bugs is to let it out into the wild and see what users can spot. --- Recipe | 1 + defs.h | 1 + ssh.c | 9942 +++------------------------------------------- ssh.h | 56 +- ssh1bpp.c | 35 +- ssh1connection.c | 1211 ++++++ ssh1login.c | 1206 ++++++ ssh2bpp-bare.c | 23 +- ssh2bpp.c | 36 +- ssh2connection.c | 2501 ++++++++++++ ssh2transport.c | 2967 ++++++++++++++ ssh2userauth.c | 1673 ++++++++ sshbpp.h | 8 +- sshcommon.c | 102 + sshgss.h | 12 + sshppl.h | 144 + sshverstring.c | 21 +- 17 files changed, 10575 insertions(+), 9364 deletions(-) create mode 100644 ssh1connection.c create mode 100644 ssh1login.c create mode 100644 ssh2connection.c create mode 100644 ssh2transport.c create mode 100644 ssh2userauth.c create mode 100644 sshppl.h diff --git a/Recipe b/Recipe index 87fc0b67..10366fe0 100644 --- a/Recipe +++ b/Recipe @@ -251,6 +251,7 @@ NONSSH = telnet raw rlogin ldisc pinger # SSH back end (putty, plink, pscp, psftp). SSH = ssh sshcommon ssh1bpp ssh2bpp ssh2bpp-bare ssh1censor ssh2censor + + ssh1login ssh1connection ssh2transport ssh2userauth ssh2connection + sshverstring sshcrc sshdes sshmd5 sshrsa sshrand sshsha sshblowf + sshdh sshcrcda sshpubk sshzlib sshdss x11fwd portfwd + sshaes sshccp sshsh256 sshsh512 sshbn wildcard pinger ssharcf diff --git a/defs.h b/defs.h index 61ada0b3..28020964 100644 --- a/defs.h +++ b/defs.h @@ -95,6 +95,7 @@ typedef struct ptrlen { typedef struct logblank_t logblank_t; typedef struct BinaryPacketProtocol BinaryPacketProtocol; +typedef struct PacketProtocolLayer PacketProtocolLayer; /* Do a compile-time type-check of 'to_check' (without evaluating it), * as a side effect of returning the value 'to_return'. Note that diff --git a/ssh.c b/ssh.c index 94dbb064..033c236a 100644 --- a/ssh.c +++ b/ssh.c @@ -17,6 +17,7 @@ #include "ssh.h" #include "sshcr.h" #include "sshbpp.h" +#include "sshppl.h" #include "sshchan.h" #ifndef NO_GSSAPI #include "sshgssc.h" @@ -28,353 +29,13 @@ #define GSS_CTXT_MAYFAIL (1<<3) /* Context may expire during handshake */ #endif -static const char *const ssh2_disconnect_reasons[] = { - NULL, - "host not allowed to connect", - "protocol error", - "key exchange failed", - "host authentication failed", - "MAC error", - "compression error", - "service not available", - "protocol version not supported", - "host key not verifiable", - "connection lost", - "by application", - "too many connections", - "auth cancelled by user", - "no more auth methods available", - "illegal user name", -}; - -#define DH_MIN_SIZE 1024 -#define DH_MAX_SIZE 8192 - -/* Safely convert rekey_time to unsigned long minutes */ -static unsigned long rekey_mins(int rekey_time, unsigned long def) -{ - if (rekey_time < 0 || rekey_time > MAX_TICK_MINS) - rekey_time = def; - return (unsigned long)rekey_time; -} - -/* Enumeration values for fields in SSH-1 packets */ -enum { - PKT_END, PKT_INT, PKT_CHAR, PKT_DATA, PKT_STR, PKT_BIGNUM, -}; - -static void ssh2_pkt_send(Ssh, struct PktOut *); -static void do_ssh1_login(void *vctx); -static void do_ssh2_userauth(void *vctx); -static void ssh2_connection_setup(Ssh ssh); -static void do_ssh2_connection(void *vctx); -static void ssh_channel_init(struct ssh_channel *c); -static struct ssh_channel *ssh_channel_msg(Ssh ssh, PktIn *pktin); -static void ssh_channel_got_eof(struct ssh_channel *c); -static void ssh2_channel_check_close(struct ssh_channel *c); -static void ssh_channel_close_local(struct ssh_channel *c, char const *reason); -static void ssh_channel_destroy(struct ssh_channel *c); -static void ssh_channel_unthrottle(struct ssh_channel *c, int bufsize); -static void ssh2_general_packet_processing(Ssh ssh, PktIn *pktin); -static void ssh1_login_input(Ssh ssh); -static void ssh2_userauth_input(Ssh ssh); -static void ssh2_connection_input(Ssh ssh); - -struct ssh_signkey_with_user_pref_id { - const ssh_keyalg *alg; - int id; -}; -const static struct ssh_signkey_with_user_pref_id hostkey_algs[] = { - { &ssh_ecdsa_ed25519, HK_ED25519 }, - { &ssh_ecdsa_nistp256, HK_ECDSA }, - { &ssh_ecdsa_nistp384, HK_ECDSA }, - { &ssh_ecdsa_nistp521, HK_ECDSA }, - { &ssh_dss, HK_DSA }, - { &ssh_rsa, HK_RSA }, -}; - -const static struct ssh2_macalg *const macs[] = { - &ssh_hmac_sha256, &ssh_hmac_sha1, &ssh_hmac_sha1_96, &ssh_hmac_md5 -}; -const static struct ssh2_macalg *const buggymacs[] = { - &ssh_hmac_sha1_buggy, &ssh_hmac_sha1_96_buggy, &ssh_hmac_md5 -}; - -static ssh_compressor *ssh_comp_none_init(void) -{ - return NULL; -} -static void ssh_comp_none_cleanup(ssh_compressor *handle) -{ -} -static ssh_decompressor *ssh_decomp_none_init(void) -{ - return NULL; -} -static void ssh_decomp_none_cleanup(ssh_decompressor *handle) -{ -} -static void ssh_comp_none_block(ssh_compressor *handle, - unsigned char *block, int len, - unsigned char **outblock, int *outlen, - int minlen) -{ -} -static int ssh_decomp_none_block(ssh_decompressor *handle, - unsigned char *block, int len, - unsigned char **outblock, int *outlen) -{ - return 0; -} -const static struct ssh_compression_alg ssh_comp_none = { - "none", NULL, - ssh_comp_none_init, ssh_comp_none_cleanup, ssh_comp_none_block, - ssh_decomp_none_init, ssh_decomp_none_cleanup, ssh_decomp_none_block, - NULL -}; -const static struct ssh_compression_alg *const compressions[] = { - &ssh_zlib, &ssh_comp_none -}; - -typedef void (*handler_fn_t)(Ssh ssh, PktIn *pktin); -typedef void (*chandler_fn_t)(Ssh ssh, PktIn *pktin, void *ctx); -typedef void (*cchandler_fn_t)(struct ssh_channel *, PktIn *, void *); - -/* - * Each channel has a queue of outstanding CHANNEL_REQUESTS and their - * handlers. - */ -struct outstanding_channel_request { - cchandler_fn_t handler; - void *ctx; - struct outstanding_channel_request *next; -}; - -/* - * 2-3-4 tree storing channels. - */ -struct ssh_channel { - Ssh ssh; /* pointer back to main context */ - unsigned remoteid, localid; - int type; - /* True if we opened this channel but server hasn't confirmed. */ - int halfopen; - /* - * In SSH-1, this value contains four bits: - * - * 1 We have sent SSH1_MSG_CHANNEL_CLOSE. - * 2 We have sent SSH1_MSG_CHANNEL_CLOSE_CONFIRMATION. - * 4 We have received SSH1_MSG_CHANNEL_CLOSE. - * 8 We have received SSH1_MSG_CHANNEL_CLOSE_CONFIRMATION. - * - * A channel is completely finished with when all four bits are set. - * - * In SSH-2, the four bits mean: - * - * 1 We have sent SSH2_MSG_CHANNEL_EOF. - * 2 We have sent SSH2_MSG_CHANNEL_CLOSE. - * 4 We have received SSH2_MSG_CHANNEL_EOF. - * 8 We have received SSH2_MSG_CHANNEL_CLOSE. - * - * A channel is completely finished with when we have both sent - * and received CLOSE. - * - * The symbolic constants below use the SSH-2 terminology, which - * is a bit confusing in SSH-1, but we have to use _something_. - */ -#define CLOSES_SENT_EOF 1 -#define CLOSES_SENT_CLOSE 2 -#define CLOSES_RCVD_EOF 4 -#define CLOSES_RCVD_CLOSE 8 - int closes; - - /* - * This flag indicates that an EOF is pending on the outgoing side - * of the channel: that is, wherever we're getting the data for - * this channel has sent us some data followed by EOF. We can't - * actually send the EOF until we've finished sending the data, so - * we set this flag instead to remind us to do so once our buffer - * is clear. - */ - int pending_eof; - - /* - * True if this channel is causing the underlying connection to be - * throttled. - */ - int throttling_conn; - - /* - * True if we currently have backed-up data on the direction of - * this channel pointing out of the SSH connection, and therefore - * would prefer the 'Channel' implementation not to read further - * local input if possible. - */ - int throttled_by_backlog; - - union { - struct ssh2_data_channel { - bufchain outbuffer; - unsigned remwindow, remmaxpkt; - /* locwindow is signed so we can cope with excess data. */ - int locwindow, locmaxwin; - /* - * remlocwin is the amount of local window that we think - * the remote end had available to it after it sent the - * last data packet or window adjust ack. - */ - int remlocwin; - /* - * These store the list of channel requests that haven't - * been acked. - */ - struct outstanding_channel_request *chanreq_head, *chanreq_tail; - enum { THROTTLED, UNTHROTTLING, UNTHROTTLED } throttle_state; - } v2; - } v; - - ssh_sharing_connstate *sharectx; /* sharing context, if this is a - * downstream channel */ - Channel *chan; /* handle the client side of this channel, if not */ - SshChannel sc; /* entry point for chan to talk back to */ -}; - -static int sshchannel_write(SshChannel *c, const void *buf, int len); -static void sshchannel_write_eof(SshChannel *c); -static void sshchannel_unclean_close(SshChannel *c, const char *err); -static void sshchannel_unthrottle(SshChannel *c, int bufsize); -static Conf *sshchannel_get_conf(SshChannel *c); -static void sshchannel_window_override_removed(SshChannel *c); -static void sshchannel_x11_sharing_handover( - SshChannel *c, ssh_sharing_connstate *share_cs, share_channel *share_chan, - const char *peer_addr, int peer_port, int endian, - int protomajor, int protominor, const void *initial_data, int initial_len); - -const struct SshChannelVtable sshchannel_vtable = { - sshchannel_write, - sshchannel_write_eof, - sshchannel_unclean_close, - sshchannel_unthrottle, - sshchannel_get_conf, - sshchannel_window_override_removed, - sshchannel_x11_sharing_handover, -}; - -/* - * 2-3-4 tree storing remote->local port forwardings. SSH-1 and SSH-2 - * use this structure in different ways, reflecting SSH-2's - * altogether saner approach to port forwarding. - * - * In SSH-1, you arrange a remote forwarding by sending the server - * the remote port number, and the local destination host:port. - * When a connection comes in, the server sends you back that - * host:port pair, and you connect to it. This is a ready-made - * security hole if you're not on the ball: a malicious server - * could send you back _any_ host:port pair, so if you trustingly - * connect to the address it gives you then you've just opened the - * entire inside of your corporate network just by connecting - * through it to a dodgy SSH server. Hence, we must store a list of - * host:port pairs we _are_ trying to forward to, and reject a - * connection request from the server if it's not in the list. - * - * In SSH-2, each side of the connection minds its own business and - * doesn't send unnecessary information to the other. You arrange a - * remote forwarding by sending the server just the remote port - * number. When a connection comes in, the server tells you which - * of its ports was connected to; and _you_ have to remember what - * local host:port pair went with that port number. - * - * Hence, in SSH-1 this structure is indexed by destination - * host:port pair, whereas in SSH-2 it is indexed by source port. - */ -struct ssh_portfwd; /* forward declaration */ - -struct ssh_rportfwd { - unsigned sport, dport; - char *shost, *dhost; - int addressfamily; - char *log_description; /* name of remote listening port, for logging */ - ssh_sharing_connstate *share_ctx; - PortFwdRecord *pfr; -}; - -static void free_rportfwd(struct ssh_rportfwd *pf) -{ - if (pf) { - sfree(pf->log_description); - sfree(pf->shost); - sfree(pf->dhost); - sfree(pf); - } -} - -static void ssh1_protocol_setup(Ssh ssh); -static void ssh2_protocol_setup(Ssh ssh); -static void ssh2_bare_connection_protocol_setup(Ssh ssh); -static void ssh_size(Backend *be, int width, int height); -static void ssh_special(Backend *be, SessionSpecialCode, int arg); -static int ssh2_try_send(struct ssh_channel *c); -static int ssh_send_channel_data(struct ssh_channel *c, - const char *buf, int len); -static void ssh_throttle_all(Ssh ssh, int enable, int bufsize); -static void ssh2_set_window(struct ssh_channel *c, int newwin); -static int ssh_sendbuffer(Backend *be); -static int ssh_do_close(Ssh ssh, int notify_exit); -static void ssh2_timer(void *ctx, unsigned long now); -static int ssh2_timer_update(Ssh ssh, unsigned long rekey_time); -#ifndef NO_GSSAPI -static void ssh2_gss_update(Ssh ssh, int definitely_rekeying); -static PktOut *ssh2_gss_authpacket(Ssh ssh, Ssh_gss_ctx gss_ctx, - const char *authtype); -#endif -static void ssh2_msg_unexpected(Ssh ssh, PktIn *pktin); - -struct queued_handler; -struct queued_handler { - int msg1, msg2; - chandler_fn_t handler; - void *ctx; - struct queued_handler *next; -}; - -/* - * Enumeration of high-level classes of reason why we might need to do - * a repeat key exchange. The full detailed reason in human-readable - * form for the Event Log is kept in ssh->rekey_reason, but - * ssh->rekey_class is a variable with this enum type which is used to - * discriminate between classes of reason that the code needs to treat - * differently. - * - * RK_NONE == 0 is the value indicating that no rekey is currently - * needed at all. RK_INITIAL indicates that we haven't even done the - * _first_ key exchange yet. RK_NORMAL is the usual case. - * RK_GSS_UPDATE indicates that we're rekeying because we've just got - * new GSSAPI credentials (hence there's no point in doing a - * preliminary check for new GSS creds, because we already know the - * answer); RK_POST_USERAUTH indicates that _if_ we're going to need a - * post-userauth immediate rekey for any reason, this is the moment to - * do it. - * - * So RK_POST_USERAUTH only tells the transport layer to _consider_ - * rekeying, not to definitely do it. Also, that one enum value is - * special in that do_ssh2_transport fills in the reason text after it - * decides whether it needs a rekey at all. In the other cases, - * rekey_reason is set up at the same time as rekey_class. - */ -enum RekeyClass { - RK_NONE = 0, - RK_INITIAL, - RK_NORMAL, - RK_POST_USERAUTH, - RK_GSS_UPDATE -}; - struct ssh_tag { - char *v_c, *v_s; - struct ssh_version_receiver version_receiver; - ssh_hash *exhash; - Socket s; + Frontend *frontend; + Conf *conf; + + struct ssh_version_receiver version_receiver; + int remote_bugs; const Plug_vtable *plugvt; Backend backend; @@ -382,8561 +43,724 @@ struct ssh_tag { Ldisc *ldisc; LogContext *logctx; - unsigned char session_key[32]; - int v1_remote_protoflags; - int v1_local_protoflags; - int agentfwd_enabled; - int X11_fwd_enabled; - int remote_bugs; - const struct ssh_kex *kex; - const ssh_keyalg *hostkey_alg; - char *hostkey_str; /* string representation, for easy checking in rekeys */ - unsigned char v2_session_id[SSH2_KEX_MAX_HASH_LEN]; - int v2_session_id_len; - int v2_cbc_ignore_workaround; - int v2_out_cipherblksize; - struct dh_ctx *dh_ctx; + /* The last list returned from get_specials. */ + SessionSpecial *specials; int bare_connection; - int attempting_connshare; ssh_sharing_state *connshare; + int attempting_connshare; + + struct ssh_connection_shared_gss_state gss_state; char *savedhost; int savedport; - int send_ok; - int echoing, editing; - - int session_started; - Frontend *frontend; - - int ospeed, ispeed; /* temporaries */ - int term_width, term_height; - - tree234 *channels; /* indexed by local id */ - struct ssh_channel *mainchan; /* primary session channel */ - int ncmode; /* is primary channel direct-tcpip? */ - int exitcode; - int close_expected; - int clean_exit; - int disconnect_message_seen; - - tree234 *rportfwds; - PortFwdManager *portfwdmgr; - - ConnectionLayer cl; - - enum { - SSH_STATE_PREPACKET, - SSH_STATE_BEFORE_SIZE, - SSH_STATE_INTERMED, - SSH_STATE_SESSION, - SSH_STATE_CLOSED - } state; - - int size_needed, eof_needed; - int sent_console_eof; - int got_pty; /* affects EOF behaviour on main channel */ - - PktOutQueue outq; - int queueing; + char *fullhostname; - /* - * Gross hack: pscp will try to start SFTP but fall back to - * scp1 if that fails. This variable is the means by which - * scp.c can reach into the SSH code and find out which one it - * got. - */ int fallback_cmd; - - bufchain banner; /* accumulates banners during do_ssh2_userauth */ - - struct X11Display *x11disp; - struct X11FakeAuth *x11auth; - tree234 *x11authtree; + int exitcode; int version; int conn_throttle_count; int overall_bufsize; int throttled_all; - int v1_stdout_throttling; - - int do_ssh1_connection_crstate; - - void *do_ssh_init_state; - void *do_ssh1_login_state; - void *do_ssh2_transport_state; - void *do_ssh2_userauth_state; - void *do_ssh2_connection_state; - void *do_ssh_connection_init_state; - - bufchain incoming_data; - struct IdempotentCallback incoming_data_consumer; - int incoming_data_seen_eof; - char *incoming_data_eof_message; - - struct IdempotentCallback incoming_pkt_consumer; - - PktInQueue pq_ssh1_login; - struct IdempotentCallback ssh1_login_icb; - - PktInQueue pq_ssh1_connection; - struct IdempotentCallback ssh1_connection_icb; - - PktInQueue pq_ssh2_transport; - struct IdempotentCallback ssh2_transport_icb; - - PktInQueue pq_ssh2_userauth; - struct IdempotentCallback ssh2_userauth_icb; - - PktInQueue pq_ssh2_connection; - struct IdempotentCallback ssh2_connection_icb; - - bufchain user_input; - struct IdempotentCallback user_input_consumer; - - bufchain outgoing_data; - struct IdempotentCallback outgoing_data_sender; - - const char *rekey_reason; - enum RekeyClass rekey_class; - - PacketLogSettings pls; - BinaryPacketProtocol *bpp; - - void (*general_packet_processing)(Ssh ssh, PktIn *pkt); - void (*current_user_input_fn) (Ssh ssh); - - /* - * We maintain our own copy of a Conf structure here. That way, - * when we're passed a new one for reconfiguration, we can check - * the differences and potentially reconfigure port forwardings - * etc in mid-session. - */ - Conf *conf; - - /* - * Dynamically allocated username string created during SSH - * login. Stored in here rather than in the coroutine state so - * that it'll be reliably freed if we shut down the SSH session - * at some unexpected moment. - */ - char *username; - - /* - * Used to transfer data back from async callbacks. - */ - void *agent_response; - int agent_response_len; - int user_response; - - /* - * The SSH connection can be set as `frozen', meaning we are - * not currently accepting incoming data from the network. - */ int frozen; - /* - * Dispatch table for packet types that we may have to deal - * with at any time. - */ - handler_fn_t packet_dispatch[SSH_MAX_MSG]; - - /* - * Queues of one-off handler functions for success/failure - * indications from a request. - */ - struct queued_handler *qhead, *qtail; - handler_fn_t q_saved_handler1, q_saved_handler2; + /* in case we find these out before we have a ConnectionLayer to tell */ + int term_width, term_height; - /* - * This module deals with sending keepalives. - */ - Pinger pinger; + bufchain in_raw, out_raw, user_input; + int send_outgoing_eof; + IdempotentCallback ic_out_raw; - /* - * Track incoming and outgoing data sizes and time, for - * size-based rekeys. - */ - unsigned long max_data_size; + PacketLogSettings pls; struct DataTransferStats stats; - int kex_in_progress; - unsigned long next_rekey, last_rekey; - const char *deferred_rekey_reason; - /* - * Fully qualified host name, which we need if doing GSSAPI. - */ - char *fullhostname; - -#ifndef NO_GSSAPI - /* - * GSSAPI libraries for this session. We need them at key exchange - * and userauth time. - * - * And the gss_ctx we setup at initial key exchange will be used - * during gssapi-keyex userauth time as well. - */ - struct ssh_gss_liblist *gsslibs; - struct ssh_gss_library *gsslib; - int gss_status; - time_t gss_cred_expiry; /* Re-delegate if newer */ - unsigned long gss_ctxt_lifetime; /* Re-delegate when short */ - Ssh_gss_name gss_srv_name; /* Cached for KEXGSS */ - Ssh_gss_ctx gss_ctx; /* Saved for gssapi-keyex */ - tree234 *transient_hostkey_cache; -#endif - int gss_kex_used; /* outside ifdef; always FALSE if NO_GSSAPI */ + BinaryPacketProtocol *bpp; /* - * The last list returned from get_specials. + * base_layer identifies the bottommost packet protocol layer, the + * one connected directly to the BPP's packet queues. Any + * operation that needs to talk to all layers (e.g. free, or + * get_specials) will do it by talking to this, which will + * recursively propagate it if necessary. */ - SessionSpecial *specials; + PacketProtocolLayer *base_layer; /* - * List of host key algorithms for which we _don't_ have a stored - * host key. These are indices into the main hostkey_algs[] array + * The ConnectionLayer vtable from our connection layer. */ - int uncert_hostkeys[lenof(hostkey_algs)]; - int n_uncert_hostkeys; + ConnectionLayer *cl; /* - * Flag indicating that the current rekey is intended to finish - * with a newly cross-certified host key. + * session_started is FALSE until we initialise the main protocol + * layers. So it distinguishes between base_layer==NULL meaning + * that the SSH protocol hasn't been set up _yet_, and + * base_layer==NULL meaning the SSH protocol has run and finished. + * It's also used to mark the point where we stop counting proxy + * command diagnostics as pre-session-startup. */ - int cross_certifying; + int session_started; - /* - * Any asynchronous query to our SSH agent that we might have in - * flight from the main authentication loop. (Queries from - * agent-forwarding channels live in their channel structure.) - */ - agent_pending_query *auth_agent_query; + Pinger pinger; int need_random_unref; }; -static const char *ssh_pkt_type(Ssh ssh, int type) -{ - if (ssh->version == 1) - return ssh1_pkt_type(type); - else - return ssh2_pkt_type(ssh->pls.kctx, ssh->pls.actx, type); -} +#define ssh_logevent(params) ( \ + logevent_and_free((ssh)->frontend, dupprintf params)) + +static void ssh_shutdown(Ssh ssh); +static void ssh_throttle_all(Ssh ssh, int enable, int bufsize); +static void ssh_bpp_output_raw_data_callback(void *vctx); Frontend *ssh_get_frontend(Ssh ssh) { return ssh->frontend; } -#define logevent(s) logevent(ssh->frontend, s) - -/* logevent, only printf-formatted. */ -static void logeventf(Ssh ssh, const char *fmt, ...) -{ - va_list ap; - char *buf; - - va_start(ap, fmt); - buf = dupvprintf(fmt, ap); - va_end(ap); - logevent(buf); - sfree(buf); -} - -static void bomb_out(Ssh ssh, char *text) -{ - ssh_do_close(ssh, FALSE); - logevent(text); - connection_fatal(ssh->frontend, "%s", text); - sfree(text); -} - -#define bombout(msg) bomb_out(ssh, dupprintf msg) - -static int ssh_channelcmp(void *av, void *bv) -{ - struct ssh_channel *a = (struct ssh_channel *) av; - struct ssh_channel *b = (struct ssh_channel *) bv; - if (a->localid < b->localid) - return -1; - if (a->localid > b->localid) - return +1; - return 0; -} -static int ssh_channelfind(void *av, void *bv) -{ - unsigned *a = (unsigned *) av; - struct ssh_channel *b = (struct ssh_channel *) bv; - if (*a < b->localid) - return -1; - if (*a > b->localid) - return +1; - return 0; -} - -static int ssh_rportcmp_ssh1(void *av, void *bv) -{ - struct ssh_rportfwd *a = (struct ssh_rportfwd *) av; - struct ssh_rportfwd *b = (struct ssh_rportfwd *) bv; - int i; - if ( (i = strcmp(a->dhost, b->dhost)) != 0) - return i < 0 ? -1 : +1; - if (a->dport > b->dport) - return +1; - if (a->dport < b->dport) - return -1; - return 0; -} - -static int ssh_rportcmp_ssh2(void *av, void *bv) -{ - struct ssh_rportfwd *a = (struct ssh_rportfwd *) av; - struct ssh_rportfwd *b = (struct ssh_rportfwd *) bv; - int i; - if ( (i = strcmp(a->shost, b->shost)) != 0) - return i < 0 ? -1 : +1; - if (a->sport > b->sport) - return +1; - if (a->sport < b->sport) - return -1; - return 0; -} - -static void c_write(Ssh ssh, const void *buf, int len) -{ - from_backend(ssh->frontend, 1, buf, len); -} - -static void c_write_str(Ssh ssh, const char *buf) -{ - c_write(ssh, buf, strlen(buf)); -} - -static int s_write(Ssh ssh, const void *data, int len) +static void ssh_connect_bpp(Ssh ssh) { - if (len && ssh->logctx) - log_packet(ssh->logctx, PKT_OUTGOING, -1, NULL, data, len, - 0, NULL, NULL, 0, NULL); - if (!ssh->s) - return 0; - return sk_write(ssh->s, data, len); + ssh->bpp->ssh = ssh; + ssh->bpp->in_raw = &ssh->in_raw; + ssh->bpp->out_raw = &ssh->out_raw; + ssh->bpp->out_raw->ic = &ssh->ic_out_raw; + ssh->bpp->pls = &ssh->pls; + ssh->bpp->logctx = ssh->logctx; + ssh->bpp->remote_bugs = ssh->remote_bugs; } -static void ssh_pkt_write(Ssh ssh, PktOut *pkt) +static void ssh_connect_ppl(Ssh ssh, PacketProtocolLayer *ppl) { - pq_push(&ssh->bpp->out_pq, pkt); + ppl->bpp = ssh->bpp; + ppl->user_input = &ssh->user_input; + ppl->frontend = ssh->frontend; + ppl->ssh = ssh; + ppl->remote_bugs = ssh->remote_bugs; } -/* - * Either queue or send a packet, depending on whether queueing is - * set. - */ -static void ssh2_pkt_send(Ssh ssh, PktOut *pkt) +static void ssh_got_ssh_version(struct ssh_version_receiver *rcv, + int major_version) { - if (ssh->queueing) { - pq_push(&ssh->outq, pkt); - } else { - ssh_pkt_write(ssh, pkt); - } -} + Ssh ssh = FROMFIELD(rcv, struct ssh_tag, version_receiver); + BinaryPacketProtocol *old_bpp; + PacketProtocolLayer *connection_layer; -static void ssh_send_outgoing_data(void *ctx) -{ - Ssh ssh = (Ssh)ctx; + ssh->session_started = TRUE; - while (bufchain_size(&ssh->outgoing_data) > 0) { - void *data; - int len, backlog; + /* + * We don't support choosing a major protocol version dynamically, + * so this should always be the same value we set up in + * connect_to_host(). + */ + assert(ssh->version == major_version); - bufchain_prefix(&ssh->outgoing_data, &data, &len); - backlog = s_write(ssh, data, len); - bufchain_consume(&ssh->outgoing_data, len); + old_bpp = ssh->bpp; + ssh->remote_bugs = ssh_verstring_get_bugs(old_bpp); - if (ssh->version == 2 && !ssh->kex_in_progress && - ssh->state != SSH_STATE_PREPACKET && - !ssh->bare_connection && !ssh->stats.out.running) { - ssh->rekey_reason = "too much data sent"; - ssh->rekey_class = RK_NORMAL; - queue_idempotent_callback(&ssh->ssh2_transport_icb); - } + if (!ssh->bare_connection) { + if (ssh->version == 2) { + PacketProtocolLayer *userauth_layer, *transport_child_layer; - if (backlog > SSH_MAX_BACKLOG) { - ssh_throttle_all(ssh, 1, backlog); - return; - } - } -} + /* + * We use the 'simple' variant of the SSH protocol if + * we're asked to, except not if we're also doing + * connection-sharing (either tunnelling our packets over + * an upstream or expecting to be tunnelled over + * ourselves), since then the assumption that we have only + * one channel to worry about is not true after all. + */ + int is_simple = + (conf_get_int(ssh->conf, CONF_ssh_simple) && !ssh->connshare); -/* - * Send all queued SSH-2 packets. - */ -static void ssh2_pkt_queuesend(Ssh ssh) -{ - PktOut *pkt; + ssh->bpp = ssh2_bpp_new(&ssh->stats); + ssh_connect_bpp(ssh); - assert(!ssh->queueing); +#ifndef NO_GSSAPI + /* Load and pick the highest GSS library on the preference + * list. */ + if (!ssh->gss_state.libs) + ssh->gss_state.libs = ssh_gss_setup(ssh->conf); + ssh->gss_state.lib = NULL; + if (ssh->gss_state.libs->nlibraries > 0) { + int i, j; + for (i = 0; i < ngsslibs; i++) { + int want_id = conf_get_int_int(ssh->conf, + CONF_ssh_gsslist, i); + for (j = 0; j < ssh->gss_state.libs->nlibraries; j++) + if (ssh->gss_state.libs->libraries[j].id == want_id) { + ssh->gss_state.lib = + &ssh->gss_state.libs->libraries[j]; + goto got_gsslib; /* double break */ + } + } + got_gsslib: + /* + * We always expect to have found something in + * the above loop: we only came here if there + * was at least one viable GSS library, and the + * preference list should always mention + * everything and only change the order. + */ + assert(ssh->gss_state.lib); + } +#endif - while ((pkt = pq_pop(&ssh->outq)) != NULL) - ssh_pkt_write(ssh, pkt); -} + connection_layer = ssh2_connection_new( + ssh, ssh->connshare, is_simple, ssh->conf, + ssh_verstring_get_remote(old_bpp), &ssh->cl); + ssh_connect_ppl(ssh, connection_layer); -#if 0 -void bndebug(char *string, Bignum b) -{ - unsigned char *p; - int i, len; - p = ssh2_mpint_fmt(b, &len); - debug(("%s", string)); - for (i = 0; i < len; i++) - debug((" %02x", p[i])); - debug(("\n")); - sfree(p); -} -#endif + if (conf_get_int(ssh->conf, CONF_ssh_no_userauth)) { + userauth_layer = NULL; + transport_child_layer = connection_layer; + } else { + char *username = get_remote_username(ssh->conf); + + userauth_layer = ssh2_userauth_new( + connection_layer, ssh->savedhost, ssh->fullhostname, + conf_get_filename(ssh->conf, CONF_keyfile), + conf_get_int(ssh->conf, CONF_tryagent), username, + conf_get_int(ssh->conf, CONF_change_username), + conf_get_int(ssh->conf, CONF_try_ki_auth), + conf_get_int(ssh->conf, CONF_try_gssapi_auth), + conf_get_int(ssh->conf, CONF_try_gssapi_kex), + conf_get_int(ssh->conf, CONF_gssapifwd), + &ssh->gss_state); + ssh_connect_ppl(ssh, userauth_layer); + transport_child_layer = userauth_layer; + + sfree(username); + } -/* - * Helper function to add an SSH-2 signature blob to a packet. Expects - * to be shown the public key blob as well as the signature blob. - * Normally just appends the sig blob unmodified as a string, except - * that it optionally breaks it open and fiddle with it to work around - * BUG_SSH2_RSA_PADDING. - */ -static void ssh2_add_sigblob(Ssh ssh, PktOut *pkt, - const void *pkblob, int pkblob_len, - const void *sigblob, int sigblob_len) -{ - BinarySource pk[1], sig[1]; - BinarySource_BARE_INIT(pk, pkblob, pkblob_len); - BinarySource_BARE_INIT(sig, sigblob, sigblob_len); + ssh->base_layer = ssh2_transport_new( + ssh->conf, ssh->savedhost, ssh->savedport, + ssh->fullhostname, + ssh_verstring_get_local(old_bpp), + ssh_verstring_get_remote(old_bpp), + &ssh->gss_state, + &ssh->stats, transport_child_layer); + ssh_connect_ppl(ssh, ssh->base_layer); - /* dmemdump(pkblob, pkblob_len); */ - /* dmemdump(sigblob, sigblob_len); */ + if (userauth_layer) + ssh2_userauth_set_transport_layer(userauth_layer, + ssh->base_layer); - /* - * See if this is in fact an ssh-rsa signature and a buggy - * server; otherwise we can just do this the easy way. - */ - if ((ssh->remote_bugs & BUG_SSH2_RSA_PADDING) && - ptrlen_eq_string(get_string(pk), "ssh-rsa") && - ptrlen_eq_string(get_string(sig), "ssh-rsa")) { - ptrlen mod_mp, sig_mp; - size_t sig_prefix_len; + } else { - /* - * Find the modulus and signature integers. - */ - get_string(pk); /* skip over exponent */ - mod_mp = get_string(pk); /* remember modulus */ - sig_prefix_len = sig->pos; - sig_mp = get_string(sig); - if (get_err(pk) || get_err(sig)) - goto give_up; + ssh->bpp = ssh1_bpp_new(); + ssh_connect_bpp(ssh); - /* - * Find the byte length of the modulus, not counting leading - * zeroes. - */ - while (mod_mp.len > 0 && *(const char *)mod_mp.ptr == 0) { - mod_mp.len--; - mod_mp.ptr = (const char *)mod_mp.ptr + 1; - } - - /* debug(("modulus length is %d\n", len)); */ - /* debug(("signature length is %d\n", siglen)); */ - - if (mod_mp.len != sig_mp.len) { - strbuf *substr = strbuf_new(); - put_data(substr, sigblob, sig_prefix_len); - put_uint32(substr, mod_mp.len); - put_padding(substr, mod_mp.len - sig_mp.len, 0); - put_data(substr, sig_mp.ptr, sig_mp.len); - put_stringsb(pkt, substr); - return; - } - - /* Otherwise fall through and do it the easy way. We also come - * here as a fallback if we discover above that the key blob - * is misformatted in some way. */ - give_up:; - } - - put_string(pkt, sigblob, sigblob_len); -} - -static void ssh_feed_to_bpp(Ssh ssh) -{ - assert(ssh->bpp); - ssh_bpp_handle_input(ssh->bpp); - - if (ssh->bpp->error) { - bomb_out(ssh, ssh->bpp->error); /* also frees the error string */ - return; - } - - if (ssh->bpp->seen_disconnect) { - /* - * If we've seen a DISCONNECT message, we should unset the - * close_expected flag, because now we _do_ expect the server - * to close the network connection afterwards. That way, the - * more informative connection_fatal message for the - * disconnect itself won't fight with 'Server unexpectedly - * closed network connection'. - */ - ssh->clean_exit = FALSE; - ssh->close_expected = TRUE; - ssh->disconnect_message_seen = TRUE; - } -} - -static void ssh_got_ssh_version(struct ssh_version_receiver *rcv, - int major_version) -{ - Ssh ssh = FROMFIELD(rcv, struct ssh_tag, version_receiver); - BinaryPacketProtocol *old_bpp; - - /* - * This is as good a time as any to stop printing proxy-command - * diagnostics in the terminal window, on the assumption that the - * proxy command must by now have made a sensible connection and - * the real session output will start shortly. - */ - ssh->session_started = TRUE; - - /* - * Queue an outgoing-data run: if the version string has been sent - * late rather than early, it'll still be sitting on our output - * raw data queue. - */ - queue_idempotent_callback(&ssh->outgoing_data_sender); - - /* - * We don't support choosing a major protocol version dynamically, - * so this should always be the same value we set up in - * connect_to_host(). - */ - assert(ssh->version == major_version); - - old_bpp = ssh->bpp; - ssh->remote_bugs = ssh_verstring_get_bugs(old_bpp); - - if (!ssh->bare_connection) { - if (ssh->version == 2) { - /* - * Retrieve both version strings from the old BPP before - * we free it. - */ - ssh->v_s = dupstr(ssh_verstring_get_remote(old_bpp)); - ssh->v_c = dupstr(ssh_verstring_get_local(old_bpp)); - - /* - * Initialise SSH-2 protocol. - */ - ssh2_protocol_setup(ssh); - ssh->general_packet_processing = ssh2_general_packet_processing; - ssh->current_user_input_fn = NULL; - } else { - /* - * Initialise SSH-1 protocol. - */ - ssh1_protocol_setup(ssh); - ssh->current_user_input_fn = ssh1_login_input; - } - - if (ssh->version == 2) - queue_idempotent_callback(&ssh->ssh2_transport_icb); - - } else { - assert(ssh->version == 2); /* can't do SSH-1 bare connection! */ - logeventf(ssh, "Using bare ssh-connection protocol"); - - ssh2_bare_connection_protocol_setup(ssh); - ssh->current_user_input_fn = ssh2_connection_input; - - } - - ssh->bpp->out_raw = &ssh->outgoing_data; - ssh->bpp->out_raw->ic = &ssh->outgoing_data_sender; - ssh->bpp->in_raw = &ssh->incoming_data; - ssh->bpp->in_pq.pqb.ic = &ssh->incoming_pkt_consumer; - ssh->bpp->pls = &ssh->pls; - ssh->bpp->logctx = ssh->logctx; - ssh->bpp->remote_bugs = ssh->remote_bugs; - - queue_idempotent_callback(&ssh->bpp->ic_in_raw); - queue_idempotent_callback(&ssh->user_input_consumer); - - update_specials_menu(ssh->frontend); - ssh->state = SSH_STATE_BEFORE_SIZE; - ssh->pinger = pinger_new(ssh->conf, &ssh->backend); - - if (ssh->bare_connection) { - /* - * Get connection protocol under way. - */ - do_ssh2_connection(ssh); - } -} - -static void ssh_process_incoming_data(void *ctx) -{ - Ssh ssh = (Ssh)ctx; - - if (ssh->state == SSH_STATE_CLOSED) - return; - - if (!ssh->frozen) - ssh_feed_to_bpp(ssh); - - if (ssh->state == SSH_STATE_CLOSED) /* yes, check _again_ */ - return; - - if (ssh->incoming_data_seen_eof) { - int need_notify = ssh_do_close(ssh, FALSE); - const char *error_msg = ssh->incoming_data_eof_message; - - if (!error_msg) { - if (!ssh->close_expected) - error_msg = "Server unexpectedly closed network connection"; - else - error_msg = "Server closed network connection"; - } - - if (ssh->close_expected && ssh->clean_exit && ssh->exitcode < 0) - ssh->exitcode = 0; - - if (need_notify) - notify_remote_exit(ssh->frontend); - - if (error_msg) - logevent(error_msg); - if ((!ssh->close_expected || !ssh->clean_exit) && - !ssh->disconnect_message_seen) - connection_fatal(ssh->frontend, "%s", error_msg); - } -} - -static void ssh_process_incoming_pkts(void *ctx) -{ - Ssh ssh = (Ssh)ctx; - PktIn *pktin; - - while ((pktin = pq_pop(&ssh->bpp->in_pq)) != NULL) { - if (ssh->general_packet_processing) - ssh->general_packet_processing(ssh, pktin); - ssh->packet_dispatch[pktin->type](ssh, pktin); - } -} - -static void ssh_process_user_input(void *ctx) -{ - Ssh ssh = (Ssh)ctx; - if (ssh->current_user_input_fn) - ssh->current_user_input_fn(ssh); -} - -static int ssh_do_close(Ssh ssh, int notify_exit) -{ - int ret = 0; - struct ssh_channel *c; - - ssh->state = SSH_STATE_CLOSED; - expire_timer_context(ssh); - if (ssh->s) { - sk_close(ssh->s); - ssh->s = NULL; - if (notify_exit) - notify_remote_exit(ssh->frontend); - else - ret = 1; - } - /* - * Now we must shut down any port- and X-forwarded channels going - * through this connection. - */ - if (ssh->channels) { - while (NULL != (c = index234(ssh->channels, 0))) { - ssh_channel_close_local(c, NULL); - del234(ssh->channels, c); /* moving next one to index 0 */ - if (ssh->version == 2) - bufchain_clear(&c->v.v2.outbuffer); - sfree(c); - } - } - /* - * Go through port-forwardings, and close any associated - * listening sockets. - */ - portfwdmgr_close_all(ssh->portfwdmgr); - - /* - * Also stop attempting to connection-share. - */ - if (ssh->connshare) { - sharestate_free(ssh->connshare); - ssh->connshare = NULL; - } - - return ret; -} - -static void ssh_socket_log(Plug plug, int type, SockAddr addr, int port, - const char *error_msg, int error_code) -{ - Ssh ssh = FROMFIELD(plug, struct ssh_tag, plugvt); - - /* - * While we're attempting connection sharing, don't loudly log - * everything that happens. Real TCP connections need to be logged - * when we _start_ trying to connect, because it might be ages - * before they respond if something goes wrong; but connection - * sharing is local and quick to respond, and it's sufficient to - * simply wait and see whether it worked afterwards. - */ - - if (!ssh->attempting_connshare) - backend_socket_log(ssh->frontend, type, addr, port, - error_msg, error_code, ssh->conf, - ssh->session_started); -} - -static void ssh_closing(Plug plug, const char *error_msg, int error_code, - int calling_back) -{ - Ssh ssh = FROMFIELD(plug, struct ssh_tag, plugvt); - ssh->incoming_data_seen_eof = TRUE; - ssh->incoming_data_eof_message = dupstr(error_msg); - queue_idempotent_callback(&ssh->incoming_data_consumer); -} - -static void ssh_receive(Plug plug, int urgent, char *data, int len) -{ - Ssh ssh = FROMFIELD(plug, struct ssh_tag, plugvt); - - /* Log raw data, if we're in that mode. */ - if (ssh->logctx) - log_packet(ssh->logctx, PKT_INCOMING, -1, NULL, data, len, - 0, NULL, NULL, 0, NULL); - - bufchain_add(&ssh->incoming_data, data, len); - queue_idempotent_callback(&ssh->incoming_data_consumer); - - if (ssh->state == SSH_STATE_CLOSED) { - ssh_do_close(ssh, TRUE); - } -} - -static void ssh_sent(Plug plug, int bufsize) -{ - Ssh ssh = FROMFIELD(plug, struct ssh_tag, plugvt); - /* - * If the send backlog on the SSH socket itself clears, we should - * unthrottle the whole world if it was throttled, and also resume - * sending our bufchain of queued wire data. - */ - if (bufsize < SSH_MAX_BACKLOG) { - ssh_throttle_all(ssh, 0, bufsize); - queue_idempotent_callback(&ssh->outgoing_data_sender); - } -} - -static void ssh_hostport_setup(const char *host, int port, Conf *conf, - char **savedhost, int *savedport, - char **loghost_ret) -{ - char *loghost = conf_get_str(conf, CONF_loghost); - if (loghost_ret) - *loghost_ret = loghost; - - if (*loghost) { - char *tmphost; - char *colon; - - tmphost = dupstr(loghost); - *savedport = 22; /* default ssh port */ - - /* - * A colon suffix on the hostname string also lets us affect - * savedport. (Unless there are multiple colons, in which case - * we assume this is an unbracketed IPv6 literal.) - */ - colon = host_strrchr(tmphost, ':'); - if (colon && colon == host_strchr(tmphost, ':')) { - *colon++ = '\0'; - if (*colon) - *savedport = atoi(colon); - } - - *savedhost = host_strduptrim(tmphost); - sfree(tmphost); - } else { - *savedhost = host_strduptrim(host); - if (port < 0) - port = 22; /* default ssh port */ - *savedport = port; - } -} - -static int ssh_test_for_upstream(const char *host, int port, Conf *conf) -{ - char *savedhost; - int savedport; - int ret; - - random_ref(); /* platform may need this to determine share socket name */ - ssh_hostport_setup(host, port, conf, &savedhost, &savedport, NULL); - ret = ssh_share_test_for_upstream(savedhost, savedport, conf); - sfree(savedhost); - random_unref(); - - return ret; -} - -static const Plug_vtable Ssh_plugvt = { - ssh_socket_log, - ssh_closing, - ssh_receive, - ssh_sent, - NULL -}; - -/* - * Connect to specified host and port. - * Returns an error message, or NULL on success. - * Also places the canonical host name into `realhost'. It must be - * freed by the caller. - */ -static const char *connect_to_host(Ssh ssh, const char *host, int port, - char **realhost, int nodelay, int keepalive) -{ - SockAddr addr; - const char *err; - char *loghost; - int addressfamily, sshprot; - - ssh_hostport_setup(host, port, ssh->conf, - &ssh->savedhost, &ssh->savedport, &loghost); - - ssh->plugvt = &Ssh_plugvt; - - /* - * Try connection-sharing, in case that means we don't open a - * socket after all. ssh_connection_sharing_init will connect to a - * previously established upstream if it can, and failing that, - * establish a listening socket for _us_ to be the upstream. In - * the latter case it will return NULL just as if it had done - * nothing, because here we only need to care if we're a - * downstream and need to do our connection setup differently. - */ - ssh->connshare = NULL; - ssh->attempting_connshare = TRUE; /* affects socket logging behaviour */ - ssh->s = ssh_connection_sharing_init( - ssh->savedhost, ssh->savedport, ssh->conf, ssh->frontend, - &ssh->plugvt, &ssh->connshare); - if (ssh->connshare) - ssh_connshare_provide_connlayer(ssh->connshare, &ssh->cl); - - ssh->attempting_connshare = FALSE; - if (ssh->s != NULL) { - /* - * We are a downstream. - */ - ssh->bare_connection = TRUE; - ssh->fullhostname = NULL; - *realhost = dupstr(host); /* best we can do */ - - if ((flags & FLAG_VERBOSE) || (flags & FLAG_INTERACTIVE)) { - /* In an interactive session, or in verbose mode, announce - * in the console window that we're a sharing downstream, - * to avoid confusing users as to why this session doesn't - * behave in quite the usual way. */ - c_write_str(ssh,"Reusing a shared connection to this server.\r\n"); - } - } else { - /* - * We're not a downstream, so open a normal socket. - */ - - /* - * Try to find host. - */ - addressfamily = conf_get_int(ssh->conf, CONF_addressfamily); - addr = name_lookup(host, port, realhost, ssh->conf, addressfamily, - ssh->frontend, "SSH connection"); - if ((err = sk_addr_error(addr)) != NULL) { - sk_addr_free(addr); - return err; - } - ssh->fullhostname = dupstr(*realhost); /* save in case of GSSAPI */ - - ssh->s = new_connection(addr, *realhost, port, - 0, 1, nodelay, keepalive, - &ssh->plugvt, ssh->conf); - if ((err = sk_socket_error(ssh->s)) != NULL) { - ssh->s = NULL; - notify_remote_exit(ssh->frontend); - return err; - } - } - - /* - * The SSH version number is always fixed (since we no longer support - * fallback between versions), so set it now. - */ - sshprot = conf_get_int(ssh->conf, CONF_sshprot); - assert(sshprot == 0 || sshprot == 3); - if (sshprot == 0) - /* SSH-1 only */ - ssh->version = 1; - if (sshprot == 3 || ssh->bare_connection) { - /* SSH-2 only */ - ssh->version = 2; - } - - /* - * Set up the initial BPP that will do the version string - * exchange. - */ - ssh->version_receiver.got_ssh_version = ssh_got_ssh_version; - ssh->bpp = ssh_verstring_new( - ssh->conf, ssh->frontend, ssh->bare_connection, - ssh->version == 1 ? "1.5" : "2.0", &ssh->version_receiver); - ssh->bpp->out_raw = &ssh->outgoing_data; - ssh->bpp->in_raw = &ssh->incoming_data; - /* - * And call its handle_input method right now, in case it wants to - * send the outgoing version string immediately. - */ - ssh_bpp_handle_input(ssh->bpp); - queue_idempotent_callback(&ssh->outgoing_data_sender); - - /* - * loghost, if configured, overrides realhost. - */ - if (*loghost) { - sfree(*realhost); - *realhost = dupstr(loghost); - } - - return NULL; -} - -/* - * Throttle or unthrottle the SSH connection. - */ -static void ssh_throttle_conn(Ssh ssh, int adjust) -{ - int old_count = ssh->conn_throttle_count; - int frozen; - - ssh->conn_throttle_count += adjust; - assert(ssh->conn_throttle_count >= 0); - - if (ssh->conn_throttle_count && !old_count) { - frozen = TRUE; - } else if (!ssh->conn_throttle_count && old_count) { - frozen = FALSE; - } else { - return; /* don't change current frozen state */ - } - - ssh->frozen = frozen; - - if (ssh->s) - sk_set_frozen(ssh->s, frozen); -} - -static void ssh_channel_check_throttle(struct ssh_channel *c) -{ - /* - * We don't want this channel to read further input if this - * particular channel has a backed-up SSH window, or if the - * outgoing side of the whole SSH connection is currently - * throttled, or if this channel already has an outgoing EOF - * either sent or pending. - */ - chan_set_input_wanted(c->chan, - !c->throttled_by_backlog && - !c->ssh->throttled_all && - !c->pending_eof && - !(c->closes & CLOSES_SENT_EOF)); -} - -/* - * Throttle or unthrottle _all_ local data streams (for when sends - * on the SSH connection itself back up). - */ -static void ssh_throttle_all(Ssh ssh, int enable, int bufsize) -{ - int i; - struct ssh_channel *c; - - if (enable == ssh->throttled_all) - return; - ssh->throttled_all = enable; - ssh->overall_bufsize = bufsize; - if (!ssh->channels) - return; - for (i = 0; NULL != (c = index234(ssh->channels, i)); i++) - ssh_channel_check_throttle(c); -} - -static void ssh_agent_callback(void *sshv, void *reply, int replylen) -{ - Ssh ssh = (Ssh) sshv; - - ssh->auth_agent_query = NULL; - - ssh->agent_response = reply; - ssh->agent_response_len = replylen; - - if (ssh->version == 1) - do_ssh1_login(ssh); - else - do_ssh2_userauth(ssh); -} - -static void ssh_dialog_callback(void *sshv, int ret) -{ - Ssh ssh = (Ssh) sshv; - - ssh->user_response = ret; - - if (ssh->version == 1) - do_ssh1_login(ssh); - else - queue_idempotent_callback(&ssh->ssh2_transport_icb); - - /* - * This may have unfrozen the SSH connection. - */ - if (!ssh->frozen) - queue_idempotent_callback(&ssh->incoming_data_consumer); -} - -/* - * Client-initiated disconnection. Send a DISCONNECT if `wire_reason' - * non-NULL, otherwise just close the connection. `client_reason' == NULL - * => log `wire_reason'. - */ -static void ssh_disconnect(Ssh ssh, const char *client_reason, - const char *wire_reason, - int code, int clean_exit) -{ - char *error; - if (!client_reason) - client_reason = wire_reason; - if (client_reason) - error = dupprintf("Disconnected: %s", client_reason); - else - error = dupstr("Disconnected"); - if (wire_reason) - ssh_bpp_queue_disconnect(ssh->bpp, wire_reason, code); - ssh->close_expected = TRUE; - ssh->clean_exit = clean_exit; - ssh_closing(&ssh->plugvt, error, 0, 0); - sfree(error); -} - -static void ssh1_coro_wrapper_initial(Ssh ssh, PktIn *pktin); -static void ssh1_coro_wrapper_session(Ssh ssh, PktIn *pktin); -static void ssh1_connection_input(Ssh ssh); - -/* - * Handle the key exchange and user authentication phases. - */ -static void do_ssh1_login(void *vctx) -{ - Ssh ssh = (Ssh)vctx; - PktIn *pktin; - PktOut *pkt; - - int i, j, ret; - ptrlen pl; - struct MD5Context md5c; - struct do_ssh1_login_state { - int crLine; - int len; - unsigned char *rsabuf; - unsigned long supported_ciphers_mask, supported_auths_mask; - int tried_publickey, tried_agent; - int tis_auth_refused, ccard_auth_refused; - unsigned char cookie[8]; - unsigned char session_id[16]; - int cipher_type; - strbuf *publickey_blob; - char *publickey_comment; - int privatekey_available, privatekey_encrypted; - prompts_t *cur_prompt; - int userpass_ret; - char c; - int pwpkt_type; - unsigned char *agent_response; - BinarySource asrc[1]; /* response from SSH agent */ - int keyi, nkeys; - int authed; - struct RSAKey key; - Bignum challenge; - ptrlen comment; - int dlgret; - Filename *keyfile; - struct RSAKey servkey, hostkey; - }; - crState(do_ssh1_login_state); - - crBeginState; - - crMaybeWaitUntilV((pktin = pq_pop(&ssh->pq_ssh1_login)) != NULL); - - if (pktin->type != SSH1_SMSG_PUBLIC_KEY) { - bombout(("Public key packet not received")); - crStopV; - } - - logevent("Received public keys"); - - pl = get_data(pktin, 8); - memcpy(s->cookie, pl.ptr, pl.len); - - get_rsa_ssh1_pub(pktin, &s->servkey, RSA_SSH1_EXPONENT_FIRST); - get_rsa_ssh1_pub(pktin, &s->hostkey, RSA_SSH1_EXPONENT_FIRST); - - s->hostkey.comment = NULL; /* avoid confusing rsa_ssh1_fingerprint */ - - /* - * Log the host key fingerprint. - */ - if (!get_err(pktin)) { - char *fingerprint = rsa_ssh1_fingerprint(&s->hostkey); - logevent("Host key fingerprint is:"); - logeventf(ssh, " %s", fingerprint); - sfree(fingerprint); - } - - ssh->v1_remote_protoflags = get_uint32(pktin); - s->supported_ciphers_mask = get_uint32(pktin); - s->supported_auths_mask = get_uint32(pktin); - - if (get_err(pktin)) { - bombout(("Bad SSH-1 public key packet")); - crStopV; - } - - if ((ssh->remote_bugs & BUG_CHOKES_ON_RSA)) - s->supported_auths_mask &= ~(1 << SSH1_AUTH_RSA); - - ssh->v1_local_protoflags = - ssh->v1_remote_protoflags & SSH1_PROTOFLAGS_SUPPORTED; - ssh->v1_local_protoflags |= SSH1_PROTOFLAG_SCREEN_NUMBER; - - MD5Init(&md5c); - { - int i; - for (i = (bignum_bitcount(s->hostkey.modulus) + 7) / 8; i-- ;) - put_byte(&md5c, bignum_byte(s->hostkey.modulus, i)); - for (i = (bignum_bitcount(s->servkey.modulus) + 7) / 8; i-- ;) - put_byte(&md5c, bignum_byte(s->servkey.modulus, i)); - } - put_data(&md5c, s->cookie, 8); - MD5Final(s->session_id, &md5c); - - for (i = 0; i < 32; i++) - ssh->session_key[i] = random_byte(); - - /* - * Verify that the `bits' and `bytes' parameters match. - */ - if (s->hostkey.bits > s->hostkey.bytes * 8 || - s->servkey.bits > s->servkey.bytes * 8) { - bombout(("SSH-1 public keys were badly formatted")); - crStopV; - } - - s->len = (s->hostkey.bytes > s->servkey.bytes ? - s->hostkey.bytes : s->servkey.bytes); - - s->rsabuf = snewn(s->len, unsigned char); - - /* - * Verify the host key. - */ - { - /* - * First format the key into a string. - */ - int len = rsastr_len(&s->hostkey); - char *fingerprint; - char *keystr = snewn(len, char); - rsastr_fmt(keystr, &s->hostkey); - fingerprint = rsa_ssh1_fingerprint(&s->hostkey); - - /* First check against manually configured host keys. */ - s->dlgret = verify_ssh_manual_host_key(ssh->conf, fingerprint, NULL); - sfree(fingerprint); - if (s->dlgret == 0) { /* did not match */ - bombout(("Host key did not appear in manually configured list")); - sfree(keystr); - crStopV; - } else if (s->dlgret < 0) { /* none configured; use standard handling */ - s->dlgret = verify_ssh_host_key(ssh->frontend, - ssh->savedhost, ssh->savedport, - "rsa", keystr, fingerprint, - ssh_dialog_callback, ssh); - sfree(keystr); -#ifdef FUZZING - s->dlgret = 1; -#endif - if (s->dlgret < 0) { - ssh->user_response = -1; - crWaitUntilV(ssh->user_response >= 0); - s->dlgret = ssh->user_response; - } - - if (s->dlgret == 0) { - ssh_disconnect(ssh, "User aborted at host key verification", - NULL, 0, TRUE); - crStopV; - } - } else { - sfree(keystr); - } - } - - for (i = 0; i < 32; i++) { - s->rsabuf[i] = ssh->session_key[i]; - if (i < 16) - s->rsabuf[i] ^= s->session_id[i]; - } - - if (s->hostkey.bytes > s->servkey.bytes) { - ret = rsa_ssh1_encrypt(s->rsabuf, 32, &s->servkey); - if (ret) - ret = rsa_ssh1_encrypt(s->rsabuf, s->servkey.bytes, &s->hostkey); - } else { - ret = rsa_ssh1_encrypt(s->rsabuf, 32, &s->hostkey); - if (ret) - ret = rsa_ssh1_encrypt(s->rsabuf, s->hostkey.bytes, &s->servkey); - } - if (!ret) { - bombout(("SSH-1 public key encryptions failed due to bad formatting")); - crStopV; - } - - logevent("Encrypted session key"); - - { - int cipher_chosen = 0, warn = 0; - const char *cipher_string = NULL; - int i; - for (i = 0; !cipher_chosen && i < CIPHER_MAX; i++) { - int next_cipher = conf_get_int_int(ssh->conf, - CONF_ssh_cipherlist, i); - if (next_cipher == CIPHER_WARN) { - /* If/when we choose a cipher, warn about it */ - warn = 1; - } else if (next_cipher == CIPHER_AES) { - /* XXX Probably don't need to mention this. */ - logevent("AES not supported in SSH-1, skipping"); - } else { - switch (next_cipher) { - case CIPHER_3DES: s->cipher_type = SSH_CIPHER_3DES; - cipher_string = "3DES"; break; - case CIPHER_BLOWFISH: s->cipher_type = SSH_CIPHER_BLOWFISH; - cipher_string = "Blowfish"; break; - case CIPHER_DES: s->cipher_type = SSH_CIPHER_DES; - cipher_string = "single-DES"; break; - } - if (s->supported_ciphers_mask & (1 << s->cipher_type)) - cipher_chosen = 1; - } - } - if (!cipher_chosen) { - if ((s->supported_ciphers_mask & (1 << SSH_CIPHER_3DES)) == 0) - bombout(("Server violates SSH-1 protocol by not " - "supporting 3DES encryption")); - else - /* shouldn't happen */ - bombout(("No supported ciphers found")); - crStopV; - } - - /* Warn about chosen cipher if necessary. */ - if (warn) { - s->dlgret = askalg(ssh->frontend, "cipher", cipher_string, - ssh_dialog_callback, ssh); - if (s->dlgret < 0) { - ssh->user_response = -1; - crWaitUntilV(ssh->user_response >= 0); - s->dlgret = ssh->user_response; - } - if (s->dlgret == 0) { - ssh_disconnect(ssh, "User aborted at cipher warning", NULL, - 0, TRUE); - crStopV; - } - } - } - - switch (s->cipher_type) { - case SSH_CIPHER_3DES: - logevent("Using 3DES encryption"); - break; - case SSH_CIPHER_DES: - logevent("Using single-DES encryption"); - break; - case SSH_CIPHER_BLOWFISH: - logevent("Using Blowfish encryption"); - break; - } - - pkt = ssh_bpp_new_pktout(ssh->bpp, SSH1_CMSG_SESSION_KEY); - put_byte(pkt, s->cipher_type); - put_data(pkt, s->cookie, 8); - put_uint16(pkt, s->len * 8); - put_data(pkt, s->rsabuf, s->len); - put_uint32(pkt, ssh->v1_local_protoflags); - ssh_pkt_write(ssh, pkt); - - logevent("Trying to enable encryption..."); - - sfree(s->rsabuf); - - /* - * Force the BPP to synchronously marshal all packets up to and - * including the SESSION_KEY into wire format, before we turn on - * crypto. - */ - ssh_bpp_handle_output(ssh->bpp); - - { - const struct ssh1_cipheralg *cipher = - (s->cipher_type == SSH_CIPHER_BLOWFISH ? &ssh1_blowfish : - s->cipher_type == SSH_CIPHER_DES ? &ssh1_des : &ssh1_3des); - ssh1_bpp_new_cipher(ssh->bpp, cipher, ssh->session_key); - logeventf(ssh, "Initialised %s encryption", cipher->text_name); - } - - if (s->servkey.modulus) { - sfree(s->servkey.modulus); - s->servkey.modulus = NULL; - } - if (s->servkey.exponent) { - sfree(s->servkey.exponent); - s->servkey.exponent = NULL; - } - if (s->hostkey.modulus) { - sfree(s->hostkey.modulus); - s->hostkey.modulus = NULL; - } - if (s->hostkey.exponent) { - sfree(s->hostkey.exponent); - s->hostkey.exponent = NULL; - } - crMaybeWaitUntilV((pktin = pq_pop(&ssh->pq_ssh1_login)) != NULL); - - if (pktin->type != SSH1_SMSG_SUCCESS) { - bombout(("Encryption not successfully enabled")); - crStopV; - } - - logevent("Successfully started encryption"); - - fflush(stdout); /* FIXME eh? */ - if ((ssh->username = get_remote_username(ssh->conf)) == NULL) { - s->cur_prompt = new_prompts(ssh->frontend); - s->cur_prompt->to_server = TRUE; - s->cur_prompt->name = dupstr("SSH login name"); - add_prompt(s->cur_prompt, dupstr("login as: "), TRUE); - s->userpass_ret = get_userpass_input(s->cur_prompt, NULL); - while (1) { - while (s->userpass_ret < 0 && - bufchain_size(&ssh->user_input) > 0) - s->userpass_ret = get_userpass_input( - s->cur_prompt, &ssh->user_input); - - if (s->userpass_ret >= 0) - break; - - ssh->send_ok = 1; - crReturnV; - ssh->send_ok = 0; - } - if (!s->userpass_ret) { - /* - * Failed to get a username. Terminate. - */ - free_prompts(s->cur_prompt); - ssh_disconnect(ssh, "No username provided", NULL, 0, TRUE); - crStopV; - } - ssh->username = dupstr(s->cur_prompt->prompts[0]->result); - free_prompts(s->cur_prompt); - } - - pkt = ssh_bpp_new_pktout(ssh->bpp, SSH1_CMSG_USER); - put_stringz(pkt, ssh->username); - ssh_pkt_write(ssh, pkt); - - { - char *userlog = dupprintf("Sent username \"%s\"", ssh->username); - logevent(userlog); - if ((flags & FLAG_VERBOSE) || (flags & FLAG_INTERACTIVE)) { - c_write_str(ssh, userlog); - c_write_str(ssh, "\r\n"); - } - sfree(userlog); - } - - crMaybeWaitUntilV((pktin = pq_pop(&ssh->pq_ssh1_login)) != NULL); - - if ((s->supported_auths_mask & (1 << SSH1_AUTH_RSA)) == 0) { - /* We must not attempt PK auth. Pretend we've already tried it. */ - s->tried_publickey = s->tried_agent = 1; - } else { - s->tried_publickey = s->tried_agent = 0; - } - s->tis_auth_refused = s->ccard_auth_refused = 0; - /* - * Load the public half of any configured keyfile for later use. - */ - s->keyfile = conf_get_filename(ssh->conf, CONF_keyfile); - if (!filename_is_null(s->keyfile)) { - int keytype; - logeventf(ssh, "Reading key file \"%.150s\"", - filename_to_str(s->keyfile)); - keytype = key_type(s->keyfile); - if (keytype == SSH_KEYTYPE_SSH1 || - keytype == SSH_KEYTYPE_SSH1_PUBLIC) { - const char *error; - s->publickey_blob = strbuf_new(); - if (rsa_ssh1_loadpub(s->keyfile, - BinarySink_UPCAST(s->publickey_blob), - &s->publickey_comment, &error)) { - s->privatekey_available = (keytype == SSH_KEYTYPE_SSH1); - if (!s->privatekey_available) - logeventf(ssh, "Key file contains public key only"); - s->privatekey_encrypted = rsa_ssh1_encrypted(s->keyfile, NULL); - } else { - char *msgbuf; - logeventf(ssh, "Unable to load key (%s)", error); - msgbuf = dupprintf("Unable to load key file " - "\"%.150s\" (%s)\r\n", - filename_to_str(s->keyfile), - error); - c_write_str(ssh, msgbuf); - sfree(msgbuf); - strbuf_free(s->publickey_blob); - s->publickey_blob = NULL; - } - } else { - char *msgbuf; - logeventf(ssh, "Unable to use this key file (%s)", - key_type_to_str(keytype)); - msgbuf = dupprintf("Unable to use key file \"%.150s\"" - " (%s)\r\n", - filename_to_str(s->keyfile), - key_type_to_str(keytype)); - c_write_str(ssh, msgbuf); - sfree(msgbuf); - s->publickey_blob = NULL; - } - } else - s->publickey_blob = NULL; - - while (pktin->type == SSH1_SMSG_FAILURE) { - s->pwpkt_type = SSH1_CMSG_AUTH_PASSWORD; - - if (conf_get_int(ssh->conf, CONF_tryagent) && agent_exists() && !s->tried_agent) { - /* - * Attempt RSA authentication using Pageant. - */ - void *r; - int rlen; - strbuf *request; - - s->authed = FALSE; - s->tried_agent = 1; - logevent("Pageant is running. Requesting keys."); - - /* Request the keys held by the agent. */ - request = strbuf_new_for_agent_query(); - put_byte(request, SSH1_AGENTC_REQUEST_RSA_IDENTITIES); - ssh->auth_agent_query = agent_query( - request, &r, &rlen, ssh_agent_callback, ssh); - strbuf_free(request); - if (ssh->auth_agent_query) { - ssh->agent_response = NULL; - crWaitUntilV(ssh->agent_response); - r = ssh->agent_response; - rlen = ssh->agent_response_len; - } - s->agent_response = r; - BinarySource_BARE_INIT(s->asrc, r, rlen); - get_uint32(s->asrc); /* skip length field */ - if (get_byte(s->asrc) == SSH1_AGENT_RSA_IDENTITIES_ANSWER) { - s->nkeys = toint(get_uint32(s->asrc)); - if (s->nkeys < 0) { - logeventf(ssh, "Pageant reported negative key count %d", - s->nkeys); - s->nkeys = 0; - } - logeventf(ssh, "Pageant has %d SSH-1 keys", s->nkeys); - for (s->keyi = 0; s->keyi < s->nkeys; s->keyi++) { - size_t start, end; - start = s->asrc->pos; - get_rsa_ssh1_pub(s->asrc, &s->key, - RSA_SSH1_EXPONENT_FIRST); - end = s->asrc->pos; - s->comment = get_string(s->asrc); - if (get_err(s->asrc)) { - logevent("Pageant key list packet was truncated"); - break; - } - if (s->publickey_blob) { - ptrlen keystr = make_ptrlen( - (const char *)s->asrc->data + start, end - start); - - if (keystr.len == s->publickey_blob->len && - !memcmp(keystr.ptr, s->publickey_blob->s, - s->publickey_blob->len)) { - logeventf(ssh, "Pageant key #%d matches " - "configured key file", s->keyi); - s->tried_publickey = 1; - } else - /* Skip non-configured key */ - continue; - } - logeventf(ssh, "Trying Pageant key #%d", s->keyi); - pkt = ssh_bpp_new_pktout(ssh->bpp, SSH1_CMSG_AUTH_RSA); - put_mp_ssh1(pkt, s->key.modulus); - ssh_pkt_write(ssh, pkt); - crMaybeWaitUntilV((pktin = pq_pop(&ssh->pq_ssh1_login)) - != NULL); - if (pktin->type != SSH1_SMSG_AUTH_RSA_CHALLENGE) { - logevent("Key refused"); - continue; - } - logevent("Received RSA challenge"); - s->challenge = get_mp_ssh1(pktin); - if (get_err(pktin)) { - freebn(s->challenge); - bombout(("Server's RSA challenge was badly formatted")); - crStopV; - } - - { - strbuf *agentreq; - char *ret; - void *vret; - int retlen; - - agentreq = strbuf_new_for_agent_query(); - put_byte(agentreq, SSH1_AGENTC_RSA_CHALLENGE); - put_uint32(agentreq, bignum_bitcount(s->key.modulus)); - put_mp_ssh1(agentreq, s->key.exponent); - put_mp_ssh1(agentreq, s->key.modulus); - put_mp_ssh1(agentreq, s->challenge); - put_data(agentreq, s->session_id, 16); - put_uint32(agentreq, 1); /* response format */ - ssh->auth_agent_query = agent_query( - agentreq, &vret, &retlen, - ssh_agent_callback, ssh); - strbuf_free(agentreq); - - if (ssh->auth_agent_query) { - ssh->agent_response = NULL; - crWaitUntilV(ssh->agent_response); - vret = ssh->agent_response; - retlen = ssh->agent_response_len; - } - - ret = vret; - if (ret) { - if (ret[4] == SSH1_AGENT_RSA_RESPONSE) { - logevent("Sending Pageant's response"); - pkt = ssh_bpp_new_pktout(ssh->bpp, - SSH1_CMSG_AUTH_RSA_RESPONSE); - put_data(pkt, ret + 5, 16); - ssh_pkt_write(ssh, pkt); - sfree(ret); - crMaybeWaitUntilV( - (pktin = pq_pop(&ssh->pq_ssh1_login)) - != NULL); - if (pktin->type == SSH1_SMSG_SUCCESS) { - logevent - ("Pageant's response accepted"); - if (flags & FLAG_VERBOSE) { - c_write_str(ssh, "Authenticated using" - " RSA key \""); - c_write(ssh, s->comment.ptr, - s->comment.len); - c_write_str(ssh, "\" from agent\r\n"); - } - s->authed = TRUE; - } else - logevent - ("Pageant's response not accepted"); - } else { - logevent - ("Pageant failed to answer challenge"); - sfree(ret); - } - } else { - logevent("No reply received from Pageant"); - } - } - freebn(s->key.exponent); - freebn(s->key.modulus); - freebn(s->challenge); - if (s->authed) - break; - } - sfree(s->agent_response); - if (s->publickey_blob && !s->tried_publickey) - logevent("Configured key file not in Pageant"); - } else { - logevent("Failed to get reply from Pageant"); - } - if (s->authed) - break; - } - if (s->publickey_blob && s->privatekey_available && - !s->tried_publickey) { - /* - * Try public key authentication with the specified - * key file. - */ - int got_passphrase; /* need not be kept over crReturn */ - if (flags & FLAG_VERBOSE) - c_write_str(ssh, "Trying public key authentication.\r\n"); - s->keyfile = conf_get_filename(ssh->conf, CONF_keyfile); - logeventf(ssh, "Trying public key \"%s\"", - filename_to_str(s->keyfile)); - s->tried_publickey = 1; - got_passphrase = FALSE; - while (!got_passphrase) { - /* - * Get a passphrase, if necessary. - */ - char *passphrase = NULL; /* only written after crReturn */ - const char *error; - if (!s->privatekey_encrypted) { - if (flags & FLAG_VERBOSE) - c_write_str(ssh, "No passphrase required.\r\n"); - passphrase = NULL; - } else { - s->cur_prompt = new_prompts(ssh->frontend); - s->cur_prompt->to_server = FALSE; - s->cur_prompt->name = dupstr("SSH key passphrase"); - add_prompt(s->cur_prompt, - dupprintf("Passphrase for key \"%.100s\": ", - s->publickey_comment), FALSE); - s->userpass_ret = get_userpass_input(s->cur_prompt, NULL); - while (1) { - while (s->userpass_ret < 0 && - bufchain_size(&ssh->user_input) > 0) - s->userpass_ret = get_userpass_input( - s->cur_prompt, &ssh->user_input); - - if (s->userpass_ret >= 0) - break; - - ssh->send_ok = 1; - crReturnV; - ssh->send_ok = 0; - } - if (!s->userpass_ret) { - /* Failed to get a passphrase. Terminate. */ - free_prompts(s->cur_prompt); - ssh_disconnect(ssh, NULL, "Unable to authenticate", - 0, TRUE); - crStopV; - } - passphrase = dupstr(s->cur_prompt->prompts[0]->result); - free_prompts(s->cur_prompt); - } - /* - * Try decrypting key with passphrase. - */ - s->keyfile = conf_get_filename(ssh->conf, CONF_keyfile); - ret = rsa_ssh1_loadkey( - s->keyfile, &s->key, passphrase, &error); - if (passphrase) { - smemclr(passphrase, strlen(passphrase)); - sfree(passphrase); - } - if (ret == 1) { - /* Correct passphrase. */ - got_passphrase = TRUE; - } else if (ret == 0) { - c_write_str(ssh, "Couldn't load private key from "); - c_write_str(ssh, filename_to_str(s->keyfile)); - c_write_str(ssh, " ("); - c_write_str(ssh, error); - c_write_str(ssh, ").\r\n"); - got_passphrase = FALSE; - break; /* go and try something else */ - } else if (ret == -1) { - c_write_str(ssh, "Wrong passphrase.\r\n"); /* FIXME */ - got_passphrase = FALSE; - /* and try again */ - } else { - assert(0 && "unexpected return from rsa_ssh1_loadkey()"); - got_passphrase = FALSE; /* placate optimisers */ - } - } - - if (got_passphrase) { - - /* - * Send a public key attempt. - */ - pkt = ssh_bpp_new_pktout(ssh->bpp, SSH1_CMSG_AUTH_RSA); - put_mp_ssh1(pkt, s->key.modulus); - ssh_pkt_write(ssh, pkt); - - crMaybeWaitUntilV((pktin = pq_pop(&ssh->pq_ssh1_login)) - != NULL); - if (pktin->type == SSH1_SMSG_FAILURE) { - c_write_str(ssh, "Server refused our public key.\r\n"); - continue; /* go and try something else */ - } - if (pktin->type != SSH1_SMSG_AUTH_RSA_CHALLENGE) { - bombout(("Bizarre response to offer of public key")); - crStopV; - } - - { - int i; - unsigned char buffer[32]; - Bignum challenge, response; - - challenge = get_mp_ssh1(pktin); - if (get_err(pktin)) { - freebn(challenge); - bombout(("Server's RSA challenge was badly formatted")); - crStopV; - } - response = rsa_ssh1_decrypt(challenge, &s->key); - freebn(s->key.private_exponent);/* burn the evidence */ - - for (i = 0; i < 32; i++) { - buffer[i] = bignum_byte(response, 31 - i); - } - - MD5Init(&md5c); - put_data(&md5c, buffer, 32); - put_data(&md5c, s->session_id, 16); - MD5Final(buffer, &md5c); - - pkt = ssh_bpp_new_pktout( - ssh->bpp, SSH1_CMSG_AUTH_RSA_RESPONSE); - put_data(pkt, buffer, 16); - ssh_pkt_write(ssh, pkt); - - freebn(challenge); - freebn(response); - } - - crMaybeWaitUntilV((pktin = pq_pop(&ssh->pq_ssh1_login)) - != NULL); - if (pktin->type == SSH1_SMSG_FAILURE) { - if (flags & FLAG_VERBOSE) - c_write_str(ssh, "Failed to authenticate with" - " our public key.\r\n"); - continue; /* go and try something else */ - } else if (pktin->type != SSH1_SMSG_SUCCESS) { - bombout(("Bizarre response to RSA authentication response")); - crStopV; - } - - break; /* we're through! */ - } - - } - - /* - * Otherwise, try various forms of password-like authentication. - */ - s->cur_prompt = new_prompts(ssh->frontend); - - if (conf_get_int(ssh->conf, CONF_try_tis_auth) && - (s->supported_auths_mask & (1 << SSH1_AUTH_TIS)) && - !s->tis_auth_refused) { - s->pwpkt_type = SSH1_CMSG_AUTH_TIS_RESPONSE; - logevent("Requested TIS authentication"); - pkt = ssh_bpp_new_pktout(ssh->bpp, SSH1_CMSG_AUTH_TIS); - ssh_pkt_write(ssh, pkt); - crMaybeWaitUntilV((pktin = pq_pop(&ssh->pq_ssh1_login)) != NULL); - if (pktin->type != SSH1_SMSG_AUTH_TIS_CHALLENGE) { - logevent("TIS authentication declined"); - if (flags & FLAG_INTERACTIVE) - c_write_str(ssh, "TIS authentication refused.\r\n"); - s->tis_auth_refused = 1; - continue; - } else { - ptrlen challenge; - char *instr_suf, *prompt; - - challenge = get_string(pktin); - if (get_err(pktin)) { - bombout(("TIS challenge packet was badly formed")); - crStopV; - } - logevent("Received TIS challenge"); - s->cur_prompt->to_server = TRUE; - s->cur_prompt->name = dupstr("SSH TIS authentication"); - /* Prompt heuristic comes from OpenSSH */ - if (memchr(challenge.ptr, '\n', challenge.len)) { - instr_suf = dupstr(""); - prompt = mkstr(challenge); - } else { - instr_suf = mkstr(challenge); - prompt = dupstr("Response: "); - } - s->cur_prompt->instruction = - dupprintf("Using TIS authentication.%s%s", - (*instr_suf) ? "\n" : "", - instr_suf); - s->cur_prompt->instr_reqd = TRUE; - add_prompt(s->cur_prompt, prompt, FALSE); - sfree(instr_suf); - } - } - if (conf_get_int(ssh->conf, CONF_try_tis_auth) && - (s->supported_auths_mask & (1 << SSH1_AUTH_CCARD)) && - !s->ccard_auth_refused) { - s->pwpkt_type = SSH1_CMSG_AUTH_CCARD_RESPONSE; - logevent("Requested CryptoCard authentication"); - pkt = ssh_bpp_new_pktout(ssh->bpp, SSH1_CMSG_AUTH_CCARD); - ssh_pkt_write(ssh, pkt); - crMaybeWaitUntilV((pktin = pq_pop(&ssh->pq_ssh1_login)) != NULL); - if (pktin->type != SSH1_SMSG_AUTH_CCARD_CHALLENGE) { - logevent("CryptoCard authentication declined"); - c_write_str(ssh, "CryptoCard authentication refused.\r\n"); - s->ccard_auth_refused = 1; - continue; - } else { - ptrlen challenge; - char *instr_suf, *prompt; - - challenge = get_string(pktin); - if (get_err(pktin)) { - bombout(("CryptoCard challenge packet was badly formed")); - crStopV; - } - logevent("Received CryptoCard challenge"); - s->cur_prompt->to_server = TRUE; - s->cur_prompt->name = dupstr("SSH CryptoCard authentication"); - s->cur_prompt->name_reqd = FALSE; - /* Prompt heuristic comes from OpenSSH */ - if (memchr(challenge.ptr, '\n', challenge.len)) { - instr_suf = dupstr(""); - prompt = mkstr(challenge); - } else { - instr_suf = mkstr(challenge); - prompt = dupstr("Response: "); - } - s->cur_prompt->instruction = - dupprintf("Using CryptoCard authentication.%s%s", - (*instr_suf) ? "\n" : "", - instr_suf); - s->cur_prompt->instr_reqd = TRUE; - add_prompt(s->cur_prompt, prompt, FALSE); - sfree(instr_suf); - } - } - if (s->pwpkt_type == SSH1_CMSG_AUTH_PASSWORD) { - if ((s->supported_auths_mask & (1 << SSH1_AUTH_PASSWORD)) == 0) { - bombout(("No supported authentication methods available")); - crStopV; - } - s->cur_prompt->to_server = TRUE; - s->cur_prompt->name = dupstr("SSH password"); - add_prompt(s->cur_prompt, dupprintf("%s@%s's password: ", - ssh->username, ssh->savedhost), - FALSE); - } - - /* - * Show password prompt, having first obtained it via a TIS - * or CryptoCard exchange if we're doing TIS or CryptoCard - * authentication. - */ - s->userpass_ret = get_userpass_input(s->cur_prompt, NULL); - while (1) { - while (s->userpass_ret < 0 && - bufchain_size(&ssh->user_input) > 0) - s->userpass_ret = get_userpass_input( - s->cur_prompt, &ssh->user_input); - - if (s->userpass_ret >= 0) - break; - - ssh->send_ok = 1; - crReturnV; - ssh->send_ok = 0; - } - if (!s->userpass_ret) { - /* - * Failed to get a password (for example - * because one was supplied on the command line - * which has already failed to work). Terminate. - */ - free_prompts(s->cur_prompt); - ssh_disconnect(ssh, NULL, "Unable to authenticate", 0, TRUE); - crStopV; - } - - if (s->pwpkt_type == SSH1_CMSG_AUTH_PASSWORD) { - /* - * Defence against traffic analysis: we send a - * whole bunch of packets containing strings of - * different lengths. One of these strings is the - * password, in a SSH1_CMSG_AUTH_PASSWORD packet. - * The others are all random data in - * SSH1_MSG_IGNORE packets. This way a passive - * listener can't tell which is the password, and - * hence can't deduce the password length. - * - * Anybody with a password length greater than 16 - * bytes is going to have enough entropy in their - * password that a listener won't find it _that_ - * much help to know how long it is. So what we'll - * do is: - * - * - if password length < 16, we send 15 packets - * containing string lengths 1 through 15 - * - * - otherwise, we let N be the nearest multiple - * of 8 below the password length, and send 8 - * packets containing string lengths N through - * N+7. This won't obscure the order of - * magnitude of the password length, but it will - * introduce a bit of extra uncertainty. - * - * A few servers can't deal with SSH1_MSG_IGNORE, at - * least in this context. For these servers, we need - * an alternative defence. We make use of the fact - * that the password is interpreted as a C string: - * so we can append a NUL, then some random data. - * - * A few servers can deal with neither SSH1_MSG_IGNORE - * here _nor_ a padded password string. - * For these servers we are left with no defences - * against password length sniffing. - */ - if (!(ssh->remote_bugs & BUG_CHOKES_ON_SSH1_IGNORE) && - !(ssh->remote_bugs & BUG_NEEDS_SSH1_PLAIN_PASSWORD)) { - /* - * The server can deal with SSH1_MSG_IGNORE, so - * we can use the primary defence. - */ - int bottom, top, pwlen, i; - - pwlen = strlen(s->cur_prompt->prompts[0]->result); - if (pwlen < 16) { - bottom = 0; /* zero length passwords are OK! :-) */ - top = 15; - } else { - bottom = pwlen & ~7; - top = bottom + 7; - } - - assert(pwlen >= bottom && pwlen <= top); - - for (i = bottom; i <= top; i++) { - if (i == pwlen) { - pkt = ssh_bpp_new_pktout(ssh->bpp, s->pwpkt_type); - put_stringz(pkt, s->cur_prompt->prompts[0]->result); - ssh_pkt_write(ssh, pkt); - } else { - strbuf *random_data = strbuf_new(); - for (j = 0; j < i; j++) - put_byte(random_data, random_byte()); - - pkt = ssh_bpp_new_pktout(ssh->bpp, SSH1_MSG_IGNORE); - put_stringsb(pkt, random_data); - ssh_pkt_write(ssh, pkt); - } - } - logevent("Sending password with camouflage packets"); - } - else if (!(ssh->remote_bugs & BUG_NEEDS_SSH1_PLAIN_PASSWORD)) { - /* - * The server can't deal with SSH1_MSG_IGNORE - * but can deal with padded passwords, so we - * can use the secondary defence. - */ - strbuf *padded_pw = strbuf_new(); - - logevent("Sending length-padded password"); - pkt = ssh_bpp_new_pktout(ssh->bpp, s->pwpkt_type); - put_asciz(padded_pw, s->cur_prompt->prompts[0]->result); - do { - put_byte(padded_pw, random_byte()); - } while (padded_pw->len % 64 != 0); - put_stringsb(pkt, padded_pw); - ssh_pkt_write(ssh, pkt); - } else { - /* - * The server is believed unable to cope with - * any of our password camouflage methods. - */ - logevent("Sending unpadded password"); - pkt = ssh_bpp_new_pktout(ssh->bpp, s->pwpkt_type); - put_stringz(pkt, s->cur_prompt->prompts[0]->result); - ssh_pkt_write(ssh, pkt); - } - } else { - pkt = ssh_bpp_new_pktout(ssh->bpp, s->pwpkt_type); - put_stringz(pkt, s->cur_prompt->prompts[0]->result); - ssh_pkt_write(ssh, pkt); - } - logevent("Sent password"); - free_prompts(s->cur_prompt); - crMaybeWaitUntilV((pktin = pq_pop(&ssh->pq_ssh1_login)) != NULL); - if (pktin->type == SSH1_SMSG_FAILURE) { - if (flags & FLAG_VERBOSE) - c_write_str(ssh, "Access denied\r\n"); - logevent("Authentication refused"); - } else if (pktin->type != SSH1_SMSG_SUCCESS) { - bombout(("Strange packet received, type %d", pktin->type)); - crStopV; - } - } - - /* Clear up */ - if (s->publickey_blob) { - strbuf_free(s->publickey_blob); - sfree(s->publickey_comment); - } - - logevent("Authentication successful"); - - /* Set up for the next phase */ - { - int i; - for (i = 0; i < SSH_MAX_MSG; i++) - if (ssh->packet_dispatch[i] == ssh1_coro_wrapper_initial) - ssh->packet_dispatch[i] = ssh1_coro_wrapper_session; - ssh->current_user_input_fn = ssh1_connection_input; - queue_idempotent_callback(&ssh->user_input_consumer); - } - - crFinishV; -} - -static void ssh_channel_try_eof(struct ssh_channel *c) -{ - Ssh ssh = c->ssh; - PktOut *pktout; - assert(c->pending_eof); /* precondition for calling us */ - if (c->halfopen) - return; /* can't close: not even opened yet */ - if (ssh->version == 2 && bufchain_size(&c->v.v2.outbuffer) > 0) - return; /* can't send EOF: pending outgoing data */ - - c->pending_eof = FALSE; /* we're about to send it */ - if (ssh->version == 1) { - pktout = ssh_bpp_new_pktout(ssh->bpp, SSH1_MSG_CHANNEL_CLOSE); - put_uint32(pktout, c->remoteid); - ssh_pkt_write(ssh, pktout); - c->closes |= CLOSES_SENT_EOF; - } else { - pktout = ssh_bpp_new_pktout(ssh->bpp, SSH2_MSG_CHANNEL_EOF); - put_uint32(pktout, c->remoteid); - ssh2_pkt_send(ssh, pktout); - c->closes |= CLOSES_SENT_EOF; - ssh2_channel_check_close(c); - } -} - -static Conf *sshchannel_get_conf(SshChannel *sc) -{ - struct ssh_channel *c = FROMFIELD(sc, struct ssh_channel, sc); - Ssh ssh = c->ssh; - return ssh->conf; -} - -static void sshchannel_write_eof(SshChannel *sc) -{ - struct ssh_channel *c = FROMFIELD(sc, struct ssh_channel, sc); - Ssh ssh = c->ssh; - - if (ssh->state == SSH_STATE_CLOSED) - return; - - if (c->closes & CLOSES_SENT_EOF) - return; - - c->pending_eof = TRUE; - ssh_channel_try_eof(c); -} - -static void sshchannel_unclean_close(SshChannel *sc, const char *err) -{ - struct ssh_channel *c = FROMFIELD(sc, struct ssh_channel, sc); - Ssh ssh = c->ssh; - char *reason; - - if (ssh->state == SSH_STATE_CLOSED) - return; - - reason = dupprintf("due to local error: %s", err); - ssh_channel_close_local(c, reason); - sfree(reason); - c->pending_eof = FALSE; /* this will confuse a zombie channel */ - - ssh2_channel_check_close(c); -} - -static int sshchannel_write(SshChannel *sc, const void *buf, int len) -{ - struct ssh_channel *c = FROMFIELD(sc, struct ssh_channel, sc); - Ssh ssh = c->ssh; - - if (ssh->state == SSH_STATE_CLOSED) - return 0; - - return ssh_send_channel_data(c, buf, len); -} - -static void sshchannel_unthrottle(SshChannel *sc, int bufsize) -{ - struct ssh_channel *c = FROMFIELD(sc, struct ssh_channel, sc); - Ssh ssh = c->ssh; - - if (ssh->state == SSH_STATE_CLOSED) - return; - - ssh_channel_unthrottle(c, bufsize); -} - -static void ssh_queueing_handler(Ssh ssh, PktIn *pktin) -{ - struct queued_handler *qh = ssh->qhead; - - assert(qh != NULL); - - assert(pktin->type == qh->msg1 || pktin->type == qh->msg2); - - if (qh->msg1 > 0) { - assert(ssh->packet_dispatch[qh->msg1] == ssh_queueing_handler); - ssh->packet_dispatch[qh->msg1] = ssh->q_saved_handler1; - } - if (qh->msg2 > 0) { - assert(ssh->packet_dispatch[qh->msg2] == ssh_queueing_handler); - ssh->packet_dispatch[qh->msg2] = ssh->q_saved_handler2; - } - - if (qh->next) { - ssh->qhead = qh->next; - - if (ssh->qhead->msg1 > 0) { - ssh->q_saved_handler1 = ssh->packet_dispatch[ssh->qhead->msg1]; - ssh->packet_dispatch[ssh->qhead->msg1] = ssh_queueing_handler; - } - if (ssh->qhead->msg2 > 0) { - ssh->q_saved_handler2 = ssh->packet_dispatch[ssh->qhead->msg2]; - ssh->packet_dispatch[ssh->qhead->msg2] = ssh_queueing_handler; - } - } else { - ssh->qhead = ssh->qtail = NULL; - } - - qh->handler(ssh, pktin, qh->ctx); - - sfree(qh); -} - -static void ssh_queue_handler(Ssh ssh, int msg1, int msg2, - chandler_fn_t handler, void *ctx) -{ - struct queued_handler *qh; - - qh = snew(struct queued_handler); - qh->msg1 = msg1; - qh->msg2 = msg2; - qh->handler = handler; - qh->ctx = ctx; - qh->next = NULL; - - if (ssh->qtail == NULL) { - ssh->qhead = qh; - - if (qh->msg1 > 0) { - ssh->q_saved_handler1 = ssh->packet_dispatch[ssh->qhead->msg1]; - ssh->packet_dispatch[qh->msg1] = ssh_queueing_handler; - } - if (qh->msg2 > 0) { - ssh->q_saved_handler2 = ssh->packet_dispatch[ssh->qhead->msg2]; - ssh->packet_dispatch[qh->msg2] = ssh_queueing_handler; - } - } else { - ssh->qtail->next = qh; - } - ssh->qtail = qh; -} - -static void ssh_rportfwd_succfail(Ssh ssh, PktIn *pktin, void *ctx) -{ - struct ssh_rportfwd *rpf = (struct ssh_rportfwd *)ctx; - - if (pktin->type == (ssh->version == 1 ? SSH1_SMSG_SUCCESS : - SSH2_MSG_REQUEST_SUCCESS)) { - logeventf(ssh, "Remote port forwarding from %s enabled", - rpf->log_description); - } else { - logeventf(ssh, "Remote port forwarding from %s refused", - rpf->log_description); - - struct ssh_rportfwd *realpf = del234(ssh->rportfwds, rpf); - assert(realpf == rpf); - portfwdmgr_close(ssh->portfwdmgr, rpf->pfr); - free_rportfwd(rpf); - } -} - -/* Many of these vtable methods have the same names as wrapper macros - * in ssh.h, so parenthesise the names to inhibit macro expansion */ - -static struct ssh_rportfwd *(ssh_rportfwd_alloc)( - ConnectionLayer *cl, - const char *shost, int sport, const char *dhost, int dport, - int addressfamily, const char *log_description, PortFwdRecord *pfr, - ssh_sharing_connstate *share_ctx); -static void (ssh_rportfwd_remove)( - ConnectionLayer *cl, struct ssh_rportfwd *rpf); -static SshChannel *(ssh_lportfwd_open)( - ConnectionLayer *cl, const char *hostname, int port, - const char *org, Channel *chan); -static struct X11FakeAuth *(ssh_add_sharing_x11_display)( - ConnectionLayer *cl, int authtype, ssh_sharing_connstate *share_cs, - share_channel *share_chan); -static void (ssh_remove_sharing_x11_display)(ConnectionLayer *cl, - struct X11FakeAuth *auth); -static void (ssh_send_packet_from_downstream)( - ConnectionLayer *cl, unsigned id, int type, - const void *pkt, int pktlen, const char *additional_log_text); -static unsigned (ssh_alloc_sharing_channel)( - ConnectionLayer *cl, ssh_sharing_connstate *connstate); -static void (ssh_delete_sharing_channel)( - ConnectionLayer *cl, unsigned localid); -static void (ssh_sharing_queue_global_request)( - ConnectionLayer *cl, ssh_sharing_connstate *share_ctx); -static int (ssh_agent_forwarding_permitted)(ConnectionLayer *cl); - -const struct ConnectionLayerVtable ssh_connlayer_vtable = { - ssh_rportfwd_alloc, - ssh_rportfwd_remove, - ssh_lportfwd_open, - ssh_add_sharing_x11_display, - ssh_remove_sharing_x11_display, - ssh_send_packet_from_downstream, - ssh_alloc_sharing_channel, - ssh_delete_sharing_channel, - ssh_sharing_queue_global_request, - ssh_agent_forwarding_permitted, -}; - -static struct ssh_rportfwd *(ssh_rportfwd_alloc)( - ConnectionLayer *cl, - const char *shost, int sport, const char *dhost, int dport, - int addressfamily, const char *log_description, PortFwdRecord *pfr, - ssh_sharing_connstate *share_ctx) -{ - Ssh ssh = FROMFIELD(cl, struct ssh_tag, cl); - - /* - * Ensure the remote port forwardings tree exists. - */ - if (!ssh->rportfwds) { - if (ssh->version == 1) - ssh->rportfwds = newtree234(ssh_rportcmp_ssh1); - else - ssh->rportfwds = newtree234(ssh_rportcmp_ssh2); - } - - struct ssh_rportfwd *rpf = snew(struct ssh_rportfwd); - - rpf->shost = dupstr(shost); - rpf->sport = sport; - rpf->dhost = dupstr(dhost); - rpf->dport = dport; - rpf->addressfamily = addressfamily; - rpf->log_description = dupstr(log_description); - rpf->pfr = pfr; - rpf->share_ctx = share_ctx; - - if (add234(ssh->rportfwds, rpf) != rpf) { - free_rportfwd(rpf); - return NULL; - } - - if (!rpf->share_ctx) { - PktOut *pktout; - - if (ssh->version == 1) { - pktout = ssh_bpp_new_pktout( - ssh->bpp, SSH1_CMSG_PORT_FORWARD_REQUEST); - put_uint32(pktout, rpf->sport); - put_stringz(pktout, rpf->dhost); - put_uint32(pktout, rpf->dport); - ssh_pkt_write(ssh, pktout); - ssh_queue_handler(ssh, SSH1_SMSG_SUCCESS, - SSH1_SMSG_FAILURE, - ssh_rportfwd_succfail, rpf); - } else { - pktout = ssh_bpp_new_pktout(ssh->bpp, SSH2_MSG_GLOBAL_REQUEST); - put_stringz(pktout, "tcpip-forward"); - put_bool(pktout, 1); /* want reply */ - put_stringz(pktout, rpf->shost); - put_uint32(pktout, rpf->sport); - ssh2_pkt_send(ssh, pktout); - - ssh_queue_handler(ssh, SSH2_MSG_REQUEST_SUCCESS, - SSH2_MSG_REQUEST_FAILURE, - ssh_rportfwd_succfail, rpf); - } - } - - return rpf; -} - -static void (ssh_rportfwd_remove)( - ConnectionLayer *cl, struct ssh_rportfwd *rpf) -{ - Ssh ssh = FROMFIELD(cl, struct ssh_tag, cl); - if (ssh->version == 1) { - /* - * We cannot cancel listening ports on the server side in - * SSH-1! There's no message to support it. - */ - } else if (rpf->share_ctx) { - /* - * We don't manufacture a cancel-tcpip-forward message for - * remote port forwardings being removed on behalf of a - * downstream; we just pass through the one the downstream - * sent to us. - */ - } else { - PktOut *pktout = ssh_bpp_new_pktout(ssh->bpp, SSH2_MSG_GLOBAL_REQUEST); - put_stringz(pktout, "cancel-tcpip-forward"); - put_bool(pktout, 0); /* _don't_ want reply */ - put_stringz(pktout, rpf->shost); - put_uint32(pktout, rpf->sport); - ssh2_pkt_send(ssh, pktout); - } - - struct ssh_rportfwd *realpf = del234(ssh->rportfwds, rpf); - assert(realpf == rpf); - free_rportfwd(rpf); -} - -static void ssh_sharing_global_request_response(Ssh ssh, PktIn *pktin, - void *ctx) -{ - share_got_pkt_from_server(ctx, pktin->type, - BinarySource_UPCAST(pktin)->data, - BinarySource_UPCAST(pktin)->len); -} - -static void (ssh_sharing_queue_global_request)( - ConnectionLayer *cl, ssh_sharing_connstate *share_ctx) -{ - Ssh ssh = FROMFIELD(cl, struct ssh_tag, cl); - ssh_queue_handler(ssh, SSH2_MSG_REQUEST_SUCCESS, SSH2_MSG_REQUEST_FAILURE, - ssh_sharing_global_request_response, share_ctx); -} - -static void ssh1_smsg_stdout_stderr_data(Ssh ssh, PktIn *pktin) -{ - ptrlen string; - int bufsize; - - string = get_string(pktin); - if (get_err(pktin)) { - bombout(("Incoming terminal data packet was badly formed")); - return; - } - - bufsize = from_backend(ssh->frontend, pktin->type == SSH1_SMSG_STDERR_DATA, - string.ptr, string.len); - if (!ssh->v1_stdout_throttling && bufsize > SSH1_BUFFER_LIMIT) { - ssh->v1_stdout_throttling = 1; - ssh_throttle_conn(ssh, +1); - } -} - -static void ssh1_smsg_x11_open(Ssh ssh, PktIn *pktin) -{ - /* Remote side is trying to open a channel to talk to our - * X-Server. Give them back a local channel number. */ - struct ssh_channel *c; - PktOut *pkt; - int remoteid = get_uint32(pktin); - - logevent("Received X11 connect request"); - /* Refuse if X11 forwarding is disabled. */ - if (!ssh->X11_fwd_enabled) { - pkt = ssh_bpp_new_pktout(ssh->bpp, SSH1_MSG_CHANNEL_OPEN_FAILURE); - put_uint32(pkt, remoteid); - ssh_pkt_write(ssh, pkt); - logevent("Rejected X11 connect request"); - } else { - c = snew(struct ssh_channel); - c->ssh = ssh; - - ssh_channel_init(c); - c->chan = x11_new_channel(ssh->x11authtree, &c->sc, NULL, -1, FALSE); - c->remoteid = remoteid; - c->halfopen = FALSE; - pkt = ssh_bpp_new_pktout(ssh->bpp, SSH1_MSG_CHANNEL_OPEN_CONFIRMATION); - put_uint32(pkt, c->remoteid); - put_uint32(pkt, c->localid); - ssh_pkt_write(ssh, pkt); - logevent("Opened X11 forward channel"); - } -} - -static void ssh1_smsg_agent_open(Ssh ssh, PktIn *pktin) -{ - /* Remote side is trying to open a channel to talk to our - * agent. Give them back a local channel number. */ - struct ssh_channel *c; - PktOut *pkt; - int remoteid = toint(get_uint32(pktin)); - - /* Refuse if agent forwarding is disabled. */ - if (!ssh->agentfwd_enabled) { - pkt = ssh_bpp_new_pktout(ssh->bpp, SSH1_MSG_CHANNEL_OPEN_FAILURE); - put_uint32(pkt, remoteid); - ssh_pkt_write(ssh, pkt); - } else { - c = snew(struct ssh_channel); - c->ssh = ssh; - ssh_channel_init(c); - c->remoteid = remoteid; - c->halfopen = FALSE; - c->chan = agentf_new(&c->sc); - pkt = ssh_bpp_new_pktout(ssh->bpp, SSH1_MSG_CHANNEL_OPEN_CONFIRMATION); - put_uint32(pkt, c->remoteid); - put_uint32(pkt, c->localid); - ssh_pkt_write(ssh, pkt); - } -} - -static void ssh1_msg_port_open(Ssh ssh, PktIn *pktin) -{ - /* Remote side is trying to open a channel to talk to a - * forwarded port. Give them back a local channel number. */ - struct ssh_rportfwd pf, *pfp; - PktOut *pkt; - int remoteid; - int port; - ptrlen host; - char *err; - - remoteid = toint(get_uint32(pktin)); - host = get_string(pktin); - port = toint(get_uint32(pktin)); - - pf.dhost = mkstr(host); - pf.dport = port; - pfp = find234(ssh->rportfwds, &pf, NULL); - - if (pfp == NULL) { - logeventf(ssh, "Rejected remote port open request for %s:%d", - pf.dhost, port); - pkt = ssh_bpp_new_pktout(ssh->bpp, SSH1_MSG_CHANNEL_OPEN_FAILURE); - put_uint32(pkt, remoteid); - ssh_pkt_write(ssh, pkt); - } else { - struct ssh_channel *c = snew(struct ssh_channel); - c->ssh = ssh; - - logeventf(ssh, "Received remote port open request for %s:%d", - pf.dhost, port); - err = portfwdmgr_connect(ssh->portfwdmgr, &c->chan, pf.dhost, port, - &c->sc, pfp->addressfamily); - if (err != NULL) { - logeventf(ssh, "Port open failed: %s", err); - sfree(err); - sfree(c); - pkt = ssh_bpp_new_pktout(ssh->bpp, SSH1_MSG_CHANNEL_OPEN_FAILURE); - put_uint32(pkt, remoteid); - ssh_pkt_write(ssh, pkt); - } else { - ssh_channel_init(c); - c->remoteid = remoteid; - c->halfopen = FALSE; - pkt = ssh_bpp_new_pktout( - ssh->bpp, SSH1_MSG_CHANNEL_OPEN_CONFIRMATION); - put_uint32(pkt, c->remoteid); - put_uint32(pkt, c->localid); - ssh_pkt_write(ssh, pkt); - logevent("Forwarded port opened successfully"); - } - } - - sfree(pf.dhost); -} - -static void ssh1_msg_channel_open_confirmation(Ssh ssh, PktIn *pktin) -{ - struct ssh_channel *c; - - c = ssh_channel_msg(ssh, pktin); - chan_open_confirmation(c->chan); - c->remoteid = get_uint32(pktin); - c->halfopen = FALSE; - c->throttling_conn = 0; - - if (c && c->pending_eof) { - /* - * We have a pending close on this channel, - * which we decided on before the server acked - * the channel open. So now we know the - * remoteid, we can close it again. - */ - ssh_channel_try_eof(c); - } -} - -static void ssh1_msg_channel_open_failure(Ssh ssh, PktIn *pktin) -{ - struct ssh_channel *c; - - c = ssh_channel_msg(ssh, pktin); - chan_open_failed(c->chan, NULL); - chan_free(c->chan); - - del234(ssh->channels, c); - sfree(c); -} - -static void ssh1_msg_channel_close(Ssh ssh, PktIn *pktin) -{ - /* Remote side closes a channel. */ - struct ssh_channel *c; - - c = ssh_channel_msg(ssh, pktin); - if (c) { - - if (pktin->type == SSH1_MSG_CHANNEL_CLOSE) { - /* - * Received CHANNEL_CLOSE, which we translate into - * outgoing EOF. - */ - ssh_channel_got_eof(c); - } - - if (pktin->type == SSH1_MSG_CHANNEL_CLOSE_CONFIRMATION && - !(c->closes & CLOSES_RCVD_CLOSE)) { - - if (!(c->closes & CLOSES_SENT_EOF)) { - bombout(("Received CHANNEL_CLOSE_CONFIRMATION for channel %u" - " for which we never sent CHANNEL_CLOSE\n", - c->localid)); - } - - c->closes |= CLOSES_RCVD_CLOSE; - } - - if (!((CLOSES_SENT_EOF | CLOSES_RCVD_EOF) & ~c->closes) && - !(c->closes & CLOSES_SENT_CLOSE)) { - PktOut *pkt = ssh_bpp_new_pktout( - ssh->bpp, SSH1_MSG_CHANNEL_CLOSE_CONFIRMATION); - put_uint32(pkt, c->remoteid); - ssh_pkt_write(ssh, pkt); - c->closes |= CLOSES_SENT_CLOSE; - } - - if (!((CLOSES_SENT_CLOSE | CLOSES_RCVD_CLOSE) & ~c->closes)) - ssh_channel_destroy(c); - } -} - -static int ssh_channel_data(struct ssh_channel *c, int is_stderr, - const void *data, int length) -{ - if (c->chan) - chan_send(c->chan, is_stderr, data, length); - return 0; -} - -static void ssh1_msg_channel_data(Ssh ssh, PktIn *pktin) -{ - /* Data sent down one of our channels. */ - ptrlen data; - struct ssh_channel *c; - - c = ssh_channel_msg(ssh, pktin); - data = get_string(pktin); - - if (c) { - int bufsize = ssh_channel_data(c, FALSE, data.ptr, data.len); - if (!c->throttling_conn && bufsize > SSH1_BUFFER_LIMIT) { - c->throttling_conn = 1; - ssh_throttle_conn(ssh, +1); - } - } -} - -static void ssh1_smsg_exit_status(Ssh ssh, PktIn *pktin) -{ - PktOut *pkt; - ssh->exitcode = get_uint32(pktin); - logeventf(ssh, "Server sent command exit status %d", ssh->exitcode); - pkt = ssh_bpp_new_pktout(ssh->bpp, SSH1_CMSG_EXIT_CONFIRMATION); - ssh_pkt_write(ssh, pkt); - /* - * In case `helpful' firewalls or proxies tack - * extra human-readable text on the end of the - * session which we might mistake for another - * encrypted packet, we close the session once - * we've sent EXIT_CONFIRMATION. - */ - ssh_disconnect(ssh, NULL, NULL, 0, TRUE); -} - -static int (ssh_agent_forwarding_permitted)(ConnectionLayer *cl) -{ - Ssh ssh = FROMFIELD(cl, struct ssh_tag, cl); - return conf_get_int(ssh->conf, CONF_agentfwd) && agent_exists(); -} - -static void do_ssh1_connection(void *vctx) -{ - Ssh ssh = (Ssh)vctx; - PktIn *pktin; - PktOut *pkt; - - crBegin(ssh->do_ssh1_connection_crstate); - - ssh->packet_dispatch[SSH1_SMSG_STDOUT_DATA] = - ssh->packet_dispatch[SSH1_SMSG_STDERR_DATA] = - ssh1_smsg_stdout_stderr_data; - - ssh->packet_dispatch[SSH1_MSG_CHANNEL_OPEN_CONFIRMATION] = - ssh1_msg_channel_open_confirmation; - ssh->packet_dispatch[SSH1_MSG_CHANNEL_OPEN_FAILURE] = - ssh1_msg_channel_open_failure; - ssh->packet_dispatch[SSH1_MSG_CHANNEL_CLOSE] = - ssh->packet_dispatch[SSH1_MSG_CHANNEL_CLOSE_CONFIRMATION] = - ssh1_msg_channel_close; - ssh->packet_dispatch[SSH1_MSG_CHANNEL_DATA] = ssh1_msg_channel_data; - ssh->packet_dispatch[SSH1_SMSG_EXIT_STATUS] = ssh1_smsg_exit_status; - - if (ssh_agent_forwarding_permitted(&ssh->cl)) { - logevent("Requesting agent forwarding"); - pkt = ssh_bpp_new_pktout(ssh->bpp, SSH1_CMSG_AGENT_REQUEST_FORWARDING); - ssh_pkt_write(ssh, pkt); - crMaybeWaitUntilV((pktin = pq_pop(&ssh->pq_ssh1_connection)) != NULL); - if (pktin->type != SSH1_SMSG_SUCCESS - && pktin->type != SSH1_SMSG_FAILURE) { - bombout(("Protocol confusion")); - crStopV; - } else if (pktin->type == SSH1_SMSG_FAILURE) { - logevent("Agent forwarding refused"); - } else { - logevent("Agent forwarding enabled"); - ssh->agentfwd_enabled = TRUE; - ssh->packet_dispatch[SSH1_SMSG_AGENT_OPEN] = ssh1_smsg_agent_open; - } - } - - if (conf_get_int(ssh->conf, CONF_x11_forward)) { - ssh->x11disp = - x11_setup_display(conf_get_str(ssh->conf, CONF_x11_display), - ssh->conf); - if (!ssh->x11disp) { - /* FIXME: return an error message from x11_setup_display */ - logevent("X11 forwarding not enabled: unable to" - " initialise X display"); - } else { - ssh->x11auth = x11_invent_fake_auth - (ssh->x11authtree, conf_get_int(ssh->conf, CONF_x11_auth)); - ssh->x11auth->disp = ssh->x11disp; - - logevent("Requesting X11 forwarding"); - pkt = ssh_bpp_new_pktout( - ssh->bpp, SSH1_CMSG_X11_REQUEST_FORWARDING); - put_stringz(pkt, ssh->x11auth->protoname); - put_stringz(pkt, ssh->x11auth->datastring); - if (ssh->v1_local_protoflags & SSH1_PROTOFLAG_SCREEN_NUMBER) - put_uint32(pkt, ssh->x11disp->screennum); - ssh_pkt_write(ssh, pkt); - crMaybeWaitUntilV((pktin = pq_pop(&ssh->pq_ssh1_connection)) - != NULL); - if (pktin->type != SSH1_SMSG_SUCCESS - && pktin->type != SSH1_SMSG_FAILURE) { - bombout(("Protocol confusion")); - crStopV; - } else if (pktin->type == SSH1_SMSG_FAILURE) { - logevent("X11 forwarding refused"); - } else { - logevent("X11 forwarding enabled"); - ssh->X11_fwd_enabled = TRUE; - ssh->packet_dispatch[SSH1_SMSG_X11_OPEN] = ssh1_smsg_x11_open; - } - } - } - - portfwdmgr_config(ssh->portfwdmgr, ssh->conf); - ssh->packet_dispatch[SSH1_MSG_PORT_OPEN] = ssh1_msg_port_open; - - if (!conf_get_int(ssh->conf, CONF_nopty)) { - PktOut *pkt; - /* Unpick the terminal-speed string. */ - /* XXX perhaps we should allow no speeds to be sent. */ - ssh->ospeed = 38400; ssh->ispeed = 38400; /* last-resort defaults */ - sscanf(conf_get_str(ssh->conf, CONF_termspeed), "%d,%d", &ssh->ospeed, &ssh->ispeed); - /* Send the pty request. */ - pkt = ssh_bpp_new_pktout(ssh->bpp, SSH1_CMSG_REQUEST_PTY); - put_stringz(pkt, conf_get_str(ssh->conf, CONF_termtype)); - put_uint32(pkt, ssh->term_height); - put_uint32(pkt, ssh->term_width); - put_uint32(pkt, 0); /* width in pixels */ - put_uint32(pkt, 0); /* height in pixels */ - write_ttymodes_to_packet_from_conf( - BinarySink_UPCAST(pkt), ssh->frontend, ssh->conf, - 1, ssh->ospeed, ssh->ispeed); - ssh_pkt_write(ssh, pkt); - ssh->state = SSH_STATE_INTERMED; - crMaybeWaitUntilV((pktin = pq_pop(&ssh->pq_ssh1_connection)) != NULL); - if (pktin->type != SSH1_SMSG_SUCCESS - && pktin->type != SSH1_SMSG_FAILURE) { - bombout(("Protocol confusion")); - crStopV; - } else if (pktin->type == SSH1_SMSG_FAILURE) { - c_write_str(ssh, "Server refused to allocate pty\r\n"); - ssh->editing = ssh->echoing = 1; - } else { - logeventf(ssh, "Allocated pty (ospeed %dbps, ispeed %dbps)", - ssh->ospeed, ssh->ispeed); - ssh->got_pty = TRUE; - } - } else { - ssh->editing = ssh->echoing = 1; - } - - if (conf_get_int(ssh->conf, CONF_compression)) { - pkt = ssh_bpp_new_pktout(ssh->bpp, SSH1_CMSG_REQUEST_COMPRESSION); - put_uint32(pkt, 6); /* gzip compression level */ - ssh_pkt_write(ssh, pkt); - crMaybeWaitUntilV((pktin = pq_pop(&ssh->pq_ssh1_connection)) != NULL); - if (pktin->type != SSH1_SMSG_SUCCESS - && pktin->type != SSH1_SMSG_FAILURE) { - bombout(("Protocol confusion")); - crStopV; - } else if (pktin->type == SSH1_SMSG_FAILURE) { - c_write_str(ssh, "Server refused to compress\r\n"); - } else { - /* - * We don't have to actually do anything here: the SSH-1 - * BPP will take care of automatically starting the - * compression, by recognising our outgoing request packet - * and the success response. (Horrible, but it's the - * easiest way to avoid race conditions if other packets - * cross in transit.) - */ - logevent("Started zlib (RFC1950) compression"); - } - } - - /* - * Start the shell or command. - * - * Special case: if the first-choice command is an SSH-2 - * subsystem (hence not usable here) and the second choice - * exists, we fall straight back to that. - */ - { - char *cmd = conf_get_str(ssh->conf, CONF_remote_cmd); - - if (conf_get_int(ssh->conf, CONF_ssh_subsys) && - conf_get_str(ssh->conf, CONF_remote_cmd2)) { - cmd = conf_get_str(ssh->conf, CONF_remote_cmd2); - ssh->fallback_cmd = TRUE; - } - if (*cmd) { - pkt = ssh_bpp_new_pktout(ssh->bpp, SSH1_CMSG_EXEC_CMD); - put_stringz(pkt, cmd); - ssh_pkt_write(ssh, pkt); - } else { - pkt = ssh_bpp_new_pktout(ssh->bpp, SSH1_CMSG_EXEC_SHELL); - ssh_pkt_write(ssh, pkt); - } - logevent("Started session"); - } - - ssh->state = SSH_STATE_SESSION; - if (ssh->size_needed) - backend_size(&ssh->backend, ssh->term_width, ssh->term_height); - if (ssh->eof_needed) - backend_special(&ssh->backend, SS_EOF, 0); - - if (ssh->ldisc) - ldisc_echoedit_update(ssh->ldisc); /* cause ldisc to notice changes */ - ssh->send_ok = 1; - ssh->channels = newtree234(ssh_channelcmp); - while (1) { - - /* - * By this point, most incoming packets are already being - * handled by the dispatch table, and we need only pay - * attention to the unusual ones. - */ - - while ((pktin = pq_pop(&ssh->pq_ssh1_connection)) != NULL) { - if (pktin->type == SSH1_SMSG_SUCCESS) { - /* may be from EXEC_SHELL on some servers */ - } else if (pktin->type == SSH1_SMSG_FAILURE) { - /* may be from EXEC_SHELL on some servers - * if no pty is available or in other odd cases. Ignore */ - } else { - bombout(("Strange packet received: type %d", pktin->type)); - crStopV; - } - } - while (bufchain_size(&ssh->user_input) > 0) { - void *data; - int len; - bufchain_prefix(&ssh->user_input, &data, &len); - if (len > 512) - len = 512; - pkt = ssh_bpp_new_pktout(ssh->bpp, SSH1_CMSG_STDIN_DATA); - put_string(pkt, data, len); - ssh_pkt_write(ssh, pkt); - bufchain_consume(&ssh->user_input, len); - } - crReturnV; - } - - crFinishV; -} - -/* - * Handle the top-level SSH-2 protocol. - */ -static void ssh1_msg_debug(Ssh ssh, PktIn *pktin) -{ - ptrlen msg = get_string(pktin); - logeventf(ssh, "Remote debug message: %.*s", PTRLEN_PRINTF(msg)); -} - -static void ssh1_msg_disconnect(Ssh ssh, PktIn *pktin) -{ - ptrlen msg = get_string(pktin); - bombout(("Server sent disconnect message:\n\"%.*s\"", PTRLEN_PRINTF(msg))); -} - -static void ssh_msg_ignore(Ssh ssh, PktIn *pktin) -{ - /* Do nothing, because we're ignoring it! Duhh. */ -} - -static void ssh1_login_input(Ssh ssh) -{ - do_ssh1_login(ssh); -} - -static void ssh1_connection_input(Ssh ssh) -{ - do_ssh1_connection(ssh); -} - -static void ssh1_coro_wrapper_initial(Ssh ssh, PktIn *pktin) -{ - pq_push(&ssh->pq_ssh1_login, pktin); - queue_idempotent_callback(&ssh->ssh1_login_icb); -} - -static void ssh1_coro_wrapper_session(Ssh ssh, PktIn *pktin) -{ - pq_push(&ssh->pq_ssh1_connection, pktin); - queue_idempotent_callback(&ssh->ssh1_connection_icb); -} - -static void ssh1_protocol_setup(Ssh ssh) -{ - int i; - - ssh->bpp = ssh1_bpp_new(); - - /* - * Most messages are handled by the main protocol routine. - */ - for (i = 0; i < SSH_MAX_MSG; i++) - ssh->packet_dispatch[i] = ssh1_coro_wrapper_initial; - - /* - * These special message types we install handlers for. - */ - ssh->packet_dispatch[SSH1_MSG_DISCONNECT] = ssh1_msg_disconnect; - ssh->packet_dispatch[SSH1_MSG_IGNORE] = ssh_msg_ignore; - ssh->packet_dispatch[SSH1_MSG_DEBUG] = ssh1_msg_debug; -} - -/* - * SSH-2 key derivation (RFC 4253 section 7.2). - */ -static void ssh2_mkkey(Ssh ssh, strbuf *out, Bignum K, unsigned char *H, - char chr, int keylen) -{ - const struct ssh_hashalg *h = ssh->kex->hash; - int keylen_padded; - unsigned char *key; - ssh_hash *s, *s2; - - if (keylen == 0) - return; - - /* - * Round the requested amount of key material up to a multiple of - * the length of the hash we're using to make it. This makes life - * simpler because then we can just write each hash output block - * straight into the output buffer without fiddling about - * truncating the last one. Since it's going into a strbuf, and - * strbufs are always smemclr()ed on free, there's no need to - * worry about leaving extra potentially-sensitive data in memory - * that the caller didn't ask for. - */ - keylen_padded = ((keylen + h->hlen - 1) / h->hlen) * h->hlen; - - out->len = 0; - key = strbuf_append(out, keylen_padded); - - /* First hlen bytes. */ - s = ssh_hash_new(h); - if (!(ssh->remote_bugs & BUG_SSH2_DERIVEKEY)) - put_mp_ssh2(s, K); - put_data(s, H, h->hlen); - put_byte(s, chr); - put_data(s, ssh->v2_session_id, ssh->v2_session_id_len); - ssh_hash_final(s, key); - - /* Subsequent blocks of hlen bytes. */ - if (keylen_padded > h->hlen) { - int offset; - - s = ssh_hash_new(h); - if (!(ssh->remote_bugs & BUG_SSH2_DERIVEKEY)) - put_mp_ssh2(s, K); - put_data(s, H, h->hlen); - - for (offset = h->hlen; offset < keylen_padded; offset += h->hlen) { - put_data(s, key + offset - h->hlen, h->hlen); - s2 = ssh_hash_copy(s); - ssh_hash_final(s2, key + offset); - } - - ssh_hash_free(s); - } -} - -/* - * Structure for constructing KEXINIT algorithm lists. - */ -#define MAXKEXLIST 16 -struct kexinit_algorithm { - const char *name; - union { - struct { - const struct ssh_kex *kex; - int warn; - } kex; - struct { - const ssh_keyalg *hostkey; - int warn; - } hk; - struct { - const struct ssh2_cipheralg *cipher; - int warn; - } cipher; - struct { - const struct ssh2_macalg *mac; - int etm; - } mac; - const struct ssh_compression_alg *comp; - } u; -}; - -/* - * Find a slot in a KEXINIT algorithm list to use for a new algorithm. - * If the algorithm is already in the list, return a pointer to its - * entry, otherwise return an entry from the end of the list. - * This assumes that every time a particular name is passed in, it - * comes from the same string constant. If this isn't true, this - * function may need to be rewritten to use strcmp() instead. - */ -static struct kexinit_algorithm *ssh2_kexinit_addalg(struct kexinit_algorithm - *list, const char *name) -{ - int i; - - for (i = 0; i < MAXKEXLIST; i++) - if (list[i].name == NULL || list[i].name == name) { - list[i].name = name; - return &list[i]; - } - assert(!"No space in KEXINIT list"); - return NULL; -} - -#ifndef NO_GSSAPI -/* - * Data structure managing host keys in sessions based on GSSAPI KEX. - * - * In a session we started with a GSSAPI key exchange, the concept of - * 'host key' has completely different lifetime and security semantics - * from the usual ones. Per RFC 4462 section 2.1, we assume that any - * host key delivered to us in the course of a GSSAPI key exchange is - * _solely_ there to use as a transient fallback within the same - * session, if at the time of a subsequent rekey the GSS credentials - * are temporarily invalid and so a non-GSS KEX method has to be used. - * - * In particular, in a GSS-based SSH deployment, host keys may not - * even _be_ persistent identities for the server; it would be - * legitimate for a server to generate a fresh one routinely if it - * wanted to, like SSH-1 server keys. - * - * So, in this mode, we never touch the persistent host key cache at - * all, either to check keys against it _or_ to store keys in it. - * Instead, we maintain an in-memory cache of host keys that have been - * mentioned in GSS key exchanges within this particular session, and - * we permit precisely those host keys in non-GSS rekeys. - */ -struct ssh_transient_hostkey_cache_entry { - const ssh_keyalg *alg; - strbuf *pub_blob; -}; - -static int ssh_transient_hostkey_cache_cmp(void *av, void *bv) -{ - const struct ssh_transient_hostkey_cache_entry - *a = (const struct ssh_transient_hostkey_cache_entry *)av, - *b = (const struct ssh_transient_hostkey_cache_entry *)bv; - return strcmp(a->alg->ssh_id, b->alg->ssh_id); -} - -static int ssh_transient_hostkey_cache_find(void *av, void *bv) -{ - const ssh_keyalg *aalg = (const ssh_keyalg *)av; - const struct ssh_transient_hostkey_cache_entry - *b = (const struct ssh_transient_hostkey_cache_entry *)bv; - return strcmp(aalg->ssh_id, b->alg->ssh_id); -} - -static void ssh_init_transient_hostkey_store(Ssh ssh) -{ - ssh->transient_hostkey_cache = - newtree234(ssh_transient_hostkey_cache_cmp); -} - -static void ssh_cleanup_transient_hostkey_store(Ssh ssh) -{ - struct ssh_transient_hostkey_cache_entry *ent; - while ((ent = delpos234(ssh->transient_hostkey_cache, 0)) != NULL) { - strbuf_free(ent->pub_blob); - sfree(ent); - } - freetree234(ssh->transient_hostkey_cache); -} - -static void ssh_store_transient_hostkey(Ssh ssh, ssh_key *key) -{ - struct ssh_transient_hostkey_cache_entry *ent, *retd; - - if ((ent = find234(ssh->transient_hostkey_cache, (void *)ssh_key_alg(key), - ssh_transient_hostkey_cache_find)) != NULL) { - strbuf_free(ent->pub_blob); - sfree(ent); - } - - ent = snew(struct ssh_transient_hostkey_cache_entry); - ent->alg = ssh_key_alg(key); - ent->pub_blob = strbuf_new(); - ssh_key_public_blob(key, BinarySink_UPCAST(ent->pub_blob)); - retd = add234(ssh->transient_hostkey_cache, ent); - assert(retd == ent); -} - -static int ssh_verify_transient_hostkey(Ssh ssh, ssh_key *key) -{ - struct ssh_transient_hostkey_cache_entry *ent; - int toret = FALSE; - - if ((ent = find234(ssh->transient_hostkey_cache, (void *)ssh_key_alg(key), - ssh_transient_hostkey_cache_find)) != NULL) { - strbuf *this_blob = strbuf_new(); - ssh_key_public_blob(key, BinarySink_UPCAST(this_blob)); - - if (this_blob->len == ent->pub_blob->len && - !memcmp(this_blob->s, ent->pub_blob->s, - this_blob->len)) - toret = TRUE; - - strbuf_free(this_blob); - } - - return toret; -} - -static int ssh_have_transient_hostkey(Ssh ssh, const ssh_keyalg *alg) -{ - struct ssh_transient_hostkey_cache_entry *ent = - find234(ssh->transient_hostkey_cache, (void *)alg, - ssh_transient_hostkey_cache_find); - return ent != NULL; -} - -static int ssh_have_any_transient_hostkey(Ssh ssh) -{ - return count234(ssh->transient_hostkey_cache) > 0; -} - -#endif /* NO_GSSAPI */ - -/* - * Handle the SSH-2 transport layer. - */ -static void do_ssh2_transport(void *vctx) -{ - Ssh ssh = (Ssh)vctx; - PktIn *pktin; - - enum kexlist { - KEXLIST_KEX, KEXLIST_HOSTKEY, KEXLIST_CSCIPHER, KEXLIST_SCCIPHER, - KEXLIST_CSMAC, KEXLIST_SCMAC, KEXLIST_CSCOMP, KEXLIST_SCCOMP, - NKEXLIST - }; - const char * kexlist_descr[NKEXLIST] = { - "key exchange algorithm", "host key algorithm", - "client-to-server cipher", "server-to-client cipher", - "client-to-server MAC", "server-to-client MAC", - "client-to-server compression method", - "server-to-client compression method" }; - struct do_ssh2_transport_state { - int crLine; - int nbits, pbits, warn_kex, warn_hk, warn_cscipher, warn_sccipher; - Bignum p, g, e, f, K; - void *our_kexinit; - int our_kexinitlen; - int kex_init_value, kex_reply_value; - const struct ssh2_macalg *const *maclist; - int nmacs; - struct { - const struct ssh2_cipheralg *cipher; - const struct ssh2_macalg *mac; - int etm_mode; - const struct ssh_compression_alg *comp; - } in, out; - ptrlen hostkeydata, sigdata; - char *keystr, *fingerprint; - ssh_key *hkey; /* actual host key */ - struct RSAKey *rsakey; /* for RSA kex */ - struct ec_key *eckey; /* for ECDH kex */ - unsigned char exchange_hash[SSH2_KEX_MAX_HASH_LEN]; - int n_preferred_kex; - int can_gssapi_keyex; - int need_gss_transient_hostkey; - int warned_about_no_gss_transient_hostkey; - const struct ssh_kexes *preferred_kex[KEX_MAX + 1]; /* +1 for GSSAPI */ - int n_preferred_hk; - int preferred_hk[HK_MAX]; - int n_preferred_ciphers; - const struct ssh2_ciphers *preferred_ciphers[CIPHER_MAX]; - const struct ssh_compression_alg *preferred_comp; - int userauth_succeeded; /* for delayed compression */ - int pending_compression; - int got_session_id; - PktOut *pktout; - int dlgret; - int guessok; - int ignorepkt; - struct kexinit_algorithm kexlists[NKEXLIST][MAXKEXLIST]; -#ifndef NO_GSSAPI - Ssh_gss_buf gss_buf; - Ssh_gss_buf gss_rcvtok, gss_sndtok; - Ssh_gss_stat gss_stat; - Ssh_gss_ctx gss_ctx; - Ssh_gss_buf mic; - int init_token_sent; - int complete_rcvd; - int gss_delegate; - time_t gss_cred_expiry; -#endif - }; - crState(do_ssh2_transport_state); - - assert(!ssh->bare_connection); - assert(ssh->version == 2); - - crBeginState; - - s->in.cipher = s->out.cipher = NULL; - s->in.mac = s->out.mac = NULL; - s->in.comp = s->out.comp = NULL; - - s->got_session_id = FALSE; - s->userauth_succeeded = FALSE; - s->pending_compression = FALSE; - s->need_gss_transient_hostkey = FALSE; - s->warned_about_no_gss_transient_hostkey = FALSE; - - /* - * Be prepared to work around the buggy MAC problem. - */ - if (ssh->remote_bugs & BUG_SSH2_HMAC) - s->maclist = buggymacs, s->nmacs = lenof(buggymacs); - else - s->maclist = macs, s->nmacs = lenof(macs); - - begin_key_exchange: - -#ifndef NO_GSSAPI - if (s->need_gss_transient_hostkey) { - /* - * This flag indicates a special case in which we must not do - * GSS key exchange even if we could. (See comments below, - * where the flag was set on the previous key exchange.) - */ - s->can_gssapi_keyex = FALSE; - } else if (conf_get_int(ssh->conf, CONF_try_gssapi_kex)) { - /* - * We always check if we have GSS creds before we come up with - * the kex algorithm list, otherwise future rekeys will fail - * when creds expire. To make this so, this code section must - * follow the begin_key_exchange label above, otherwise this - * section would execute just once per-connection. - * - * Update GSS state unless the reason we're here is that a - * timer just checked the GSS state and decided that we should - * rekey to update delegated credentials. In that case, the - * state is "fresh". - */ - if (ssh->rekey_class != RK_GSS_UPDATE) - ssh2_gss_update(ssh, TRUE); - - /* Do GSSAPI KEX when capable */ - s->can_gssapi_keyex = ssh->gss_status & GSS_KEX_CAPABLE; - - /* - * But not when failure is likely. [ GSS implementations may - * attempt (and fail) to use a ticket that is almost expired - * when retrieved from the ccache that actually expires by the - * time the server receives it. ] - * - * Note: The first time always try KEXGSS if we can, failures - * will be very rare, and disabling the initial GSS KEX is - * worse. Some day GSS libraries will ignore cached tickets - * whose lifetime is critically short, and will instead use - * fresh ones. - */ - if (!s->got_session_id && (ssh->gss_status & GSS_CTXT_MAYFAIL) != 0) - s->can_gssapi_keyex = 0; - s->gss_delegate = conf_get_int(ssh->conf, CONF_gssapifwd); - } else { - s->can_gssapi_keyex = FALSE; - } -#endif - - ssh->pls.kctx = SSH2_PKTCTX_NOKEX; - { - int i, j, k, warn; - struct kexinit_algorithm *alg; - - /* - * Set up the preferred key exchange. (NULL => warn below here) - */ - s->n_preferred_kex = 0; - if (s->can_gssapi_keyex) - s->preferred_kex[s->n_preferred_kex++] = &ssh_gssk5_sha1_kex; - for (i = 0; i < KEX_MAX; i++) { - switch (conf_get_int_int(ssh->conf, CONF_ssh_kexlist, i)) { - case KEX_DHGEX: - s->preferred_kex[s->n_preferred_kex++] = - &ssh_diffiehellman_gex; - break; - case KEX_DHGROUP14: - s->preferred_kex[s->n_preferred_kex++] = - &ssh_diffiehellman_group14; - break; - case KEX_DHGROUP1: - s->preferred_kex[s->n_preferred_kex++] = - &ssh_diffiehellman_group1; - break; - case KEX_RSA: - s->preferred_kex[s->n_preferred_kex++] = - &ssh_rsa_kex; - break; - case KEX_ECDH: - s->preferred_kex[s->n_preferred_kex++] = - &ssh_ecdh_kex; - break; - case KEX_WARN: - /* Flag for later. Don't bother if it's the last in - * the list. */ - if (i < KEX_MAX - 1) { - s->preferred_kex[s->n_preferred_kex++] = NULL; - } - break; - } - } - - /* - * Set up the preferred host key types. These are just the ids - * in the enum in putty.h, so 'warn below here' is indicated - * by HK_WARN. - */ - s->n_preferred_hk = 0; - for (i = 0; i < HK_MAX; i++) { - int id = conf_get_int_int(ssh->conf, CONF_ssh_hklist, i); - /* As above, don't bother with HK_WARN if it's last in the - * list */ - if (id != HK_WARN || i < HK_MAX - 1) - s->preferred_hk[s->n_preferred_hk++] = id; - } - - /* - * Set up the preferred ciphers. (NULL => warn below here) - */ - s->n_preferred_ciphers = 0; - for (i = 0; i < CIPHER_MAX; i++) { - switch (conf_get_int_int(ssh->conf, CONF_ssh_cipherlist, i)) { - case CIPHER_BLOWFISH: - s->preferred_ciphers[s->n_preferred_ciphers++] = &ssh2_blowfish; - break; - case CIPHER_DES: - if (conf_get_int(ssh->conf, CONF_ssh2_des_cbc)) { - s->preferred_ciphers[s->n_preferred_ciphers++] = &ssh2_des; - } - break; - case CIPHER_3DES: - s->preferred_ciphers[s->n_preferred_ciphers++] = &ssh2_3des; - break; - case CIPHER_AES: - s->preferred_ciphers[s->n_preferred_ciphers++] = &ssh2_aes; - break; - case CIPHER_ARCFOUR: - s->preferred_ciphers[s->n_preferred_ciphers++] = &ssh2_arcfour; - break; - case CIPHER_CHACHA20: - s->preferred_ciphers[s->n_preferred_ciphers++] = &ssh2_ccp; - break; - case CIPHER_WARN: - /* Flag for later. Don't bother if it's the last in - * the list. */ - if (i < CIPHER_MAX - 1) { - s->preferred_ciphers[s->n_preferred_ciphers++] = NULL; - } - break; - } - } - - /* - * Set up preferred compression. - */ - if (conf_get_int(ssh->conf, CONF_compression)) - s->preferred_comp = &ssh_zlib; - else - s->preferred_comp = &ssh_comp_none; - - /* - * Enable queueing of outgoing auth- or connection-layer - * packets while we are in the middle of a key exchange. - */ - ssh->queueing = TRUE; - - /* - * Flag that KEX is in progress. - */ - ssh->kex_in_progress = TRUE; - - for (i = 0; i < NKEXLIST; i++) - for (j = 0; j < MAXKEXLIST; j++) - s->kexlists[i][j].name = NULL; - /* List key exchange algorithms. */ - warn = FALSE; - for (i = 0; i < s->n_preferred_kex; i++) { - const struct ssh_kexes *k = s->preferred_kex[i]; - if (!k) warn = TRUE; - else for (j = 0; j < k->nkexes; j++) { - alg = ssh2_kexinit_addalg(s->kexlists[KEXLIST_KEX], - k->list[j]->name); - alg->u.kex.kex = k->list[j]; - alg->u.kex.warn = warn; - } - } - /* List server host key algorithms. */ - if (!s->got_session_id) { - /* - * In the first key exchange, we list all the algorithms - * we're prepared to cope with, but prefer those algorithms - * for which we have a host key for this host. - * - * If the host key algorithm is below the warning - * threshold, we warn even if we did already have a key - * for it, on the basis that if the user has just - * reconfigured that host key type to be warned about, - * they surely _do_ want to be alerted that a server - * they're actually connecting to is using it. - */ - warn = FALSE; - for (i = 0; i < s->n_preferred_hk; i++) { - if (s->preferred_hk[i] == HK_WARN) - warn = TRUE; - for (j = 0; j < lenof(hostkey_algs); j++) { - if (hostkey_algs[j].id != s->preferred_hk[i]) - continue; - if (have_ssh_host_key(ssh->savedhost, ssh->savedport, - hostkey_algs[j].alg->cache_id)) { - alg = ssh2_kexinit_addalg(s->kexlists[KEXLIST_HOSTKEY], - hostkey_algs[j].alg->ssh_id); - alg->u.hk.hostkey = hostkey_algs[j].alg; - alg->u.hk.warn = warn; - } - } - } - warn = FALSE; - for (i = 0; i < s->n_preferred_hk; i++) { - if (s->preferred_hk[i] == HK_WARN) - warn = TRUE; - for (j = 0; j < lenof(hostkey_algs); j++) { - if (hostkey_algs[j].id != s->preferred_hk[i]) - continue; - alg = ssh2_kexinit_addalg(s->kexlists[KEXLIST_HOSTKEY], - hostkey_algs[j].alg->ssh_id); - alg->u.hk.hostkey = hostkey_algs[j].alg; - alg->u.hk.warn = warn; - } - } -#ifndef NO_GSSAPI - } else if (ssh->gss_kex_used && !s->need_gss_transient_hostkey) { - /* - * If we've previously done a GSSAPI KEX, then we list - * precisely the algorithms for which a previous GSS key - * exchange has delivered us a host key, because we expect - * one of exactly those keys to be used in any subsequent - * non-GSS-based rekey. - * - * An exception is if this is the key exchange we - * triggered for the purposes of populating that cache - - * in which case the cache will currently be empty, which - * isn't helpful! - */ - warn = FALSE; - for (i = 0; i < s->n_preferred_hk; i++) { - if (s->preferred_hk[i] == HK_WARN) - warn = TRUE; - for (j = 0; j < lenof(hostkey_algs); j++) { - if (hostkey_algs[j].id != s->preferred_hk[i]) - continue; - if (ssh_have_transient_hostkey(ssh, hostkey_algs[j].alg)) { - alg = ssh2_kexinit_addalg(s->kexlists[KEXLIST_HOSTKEY], - hostkey_algs[j].alg->ssh_id); - alg->u.hk.hostkey = hostkey_algs[j].alg; - alg->u.hk.warn = warn; - } - } - } -#endif - } else { - /* - * In subsequent key exchanges, we list only the kex - * algorithm that was selected in the first key exchange, - * so that we keep getting the same host key and hence - * don't have to interrupt the user's session to ask for - * reverification. - */ - assert(ssh->kex); - alg = ssh2_kexinit_addalg(s->kexlists[KEXLIST_HOSTKEY], - ssh->hostkey_alg->ssh_id); - alg->u.hk.hostkey = ssh->hostkey_alg; - alg->u.hk.warn = FALSE; - } - if (s->can_gssapi_keyex) { - alg = ssh2_kexinit_addalg(s->kexlists[KEXLIST_HOSTKEY], "null"); - alg->u.hk.hostkey = NULL; - } - /* List encryption algorithms (client->server then server->client). */ - for (k = KEXLIST_CSCIPHER; k <= KEXLIST_SCCIPHER; k++) { - warn = FALSE; -#ifdef FUZZING - alg = ssh2_kexinit_addalg(s->kexlists[k], "none"); - alg->u.cipher.cipher = NULL; - alg->u.cipher.warn = warn; -#endif /* FUZZING */ - for (i = 0; i < s->n_preferred_ciphers; i++) { - const struct ssh2_ciphers *c = s->preferred_ciphers[i]; - if (!c) warn = TRUE; - else for (j = 0; j < c->nciphers; j++) { - alg = ssh2_kexinit_addalg(s->kexlists[k], - c->list[j]->name); - alg->u.cipher.cipher = c->list[j]; - alg->u.cipher.warn = warn; - } - } - } - /* List MAC algorithms (client->server then server->client). */ - for (j = KEXLIST_CSMAC; j <= KEXLIST_SCMAC; j++) { -#ifdef FUZZING - alg = ssh2_kexinit_addalg(s->kexlists[j], "none"); - alg->u.mac.mac = NULL; - alg->u.mac.etm = FALSE; -#endif /* FUZZING */ - for (i = 0; i < s->nmacs; i++) { - alg = ssh2_kexinit_addalg(s->kexlists[j], s->maclist[i]->name); - alg->u.mac.mac = s->maclist[i]; - alg->u.mac.etm = FALSE; - } - for (i = 0; i < s->nmacs; i++) - /* For each MAC, there may also be an ETM version, - * which we list second. */ - if (s->maclist[i]->etm_name) { - alg = ssh2_kexinit_addalg(s->kexlists[j], - s->maclist[i]->etm_name); - alg->u.mac.mac = s->maclist[i]; - alg->u.mac.etm = TRUE; - } - } - /* List client->server compression algorithms, - * then server->client compression algorithms. (We use the - * same set twice.) */ - for (j = KEXLIST_CSCOMP; j <= KEXLIST_SCCOMP; j++) { - assert(lenof(compressions) > 1); - /* Prefer non-delayed versions */ - alg = ssh2_kexinit_addalg(s->kexlists[j], s->preferred_comp->name); - alg->u.comp = s->preferred_comp; - /* We don't even list delayed versions of algorithms until - * they're allowed to be used, to avoid a race. See the end of - * this function. */ - if (s->userauth_succeeded && s->preferred_comp->delayed_name) { - alg = ssh2_kexinit_addalg(s->kexlists[j], - s->preferred_comp->delayed_name); - alg->u.comp = s->preferred_comp; - } - for (i = 0; i < lenof(compressions); i++) { - const struct ssh_compression_alg *c = compressions[i]; - alg = ssh2_kexinit_addalg(s->kexlists[j], c->name); - alg->u.comp = c; - if (s->userauth_succeeded && c->delayed_name) { - alg = ssh2_kexinit_addalg(s->kexlists[j], c->delayed_name); - alg->u.comp = c; - } - } - } - /* - * Construct and send our key exchange packet. - */ - s->pktout = ssh_bpp_new_pktout(ssh->bpp, SSH2_MSG_KEXINIT); - for (i = 0; i < 16; i++) - put_byte(s->pktout, (unsigned char) random_byte()); - for (i = 0; i < NKEXLIST; i++) { - strbuf *list = strbuf_new(); - for (j = 0; j < MAXKEXLIST; j++) { - if (s->kexlists[i][j].name == NULL) break; - add_to_commasep(list, s->kexlists[i][j].name); - } - put_stringsb(s->pktout, list); - } - /* List client->server languages. Empty list. */ - put_stringz(s->pktout, ""); - /* List server->client languages. Empty list. */ - put_stringz(s->pktout, ""); - /* First KEX packet does _not_ follow, because we're not that brave. */ - put_bool(s->pktout, FALSE); - /* Reserved. */ - put_uint32(s->pktout, 0); - } - - s->our_kexinitlen = s->pktout->length - 5; - s->our_kexinit = snewn(s->our_kexinitlen, unsigned char); - memcpy(s->our_kexinit, s->pktout->data + 5, s->our_kexinitlen); - - ssh_pkt_write(ssh, s->pktout); - - crMaybeWaitUntilV((pktin = pq_pop(&ssh->pq_ssh2_transport)) != NULL); - - /* - * Now examine the other side's KEXINIT to see what we're up - * to. - */ - { - ptrlen str; - int i, j; - - if (pktin->type != SSH2_MSG_KEXINIT) { - bombout(("expected key exchange packet from server")); - crStopV; - } - ssh->kex = NULL; - ssh->hostkey_alg = NULL; - s->in.cipher = s->out.cipher = NULL; - s->in.mac = s->out.mac = NULL; - s->in.comp = s->out.comp = NULL; - s->warn_kex = s->warn_hk = FALSE; - s->warn_cscipher = s->warn_sccipher = FALSE; - - get_data(pktin, 16); /* skip garbage cookie */ - - s->guessok = FALSE; - for (i = 0; i < NKEXLIST; i++) { - str = get_string(pktin); - if (get_err(pktin)) { - bombout(("KEXINIT packet was incomplete")); - crStopV; - } - - /* If we've already selected a cipher which requires a - * particular MAC, then just select that, and don't even - * bother looking through the server's KEXINIT string for - * MACs. */ - if (i == KEXLIST_CSMAC && s->out.cipher && - s->out.cipher->required_mac) { - s->out.mac = s->out.cipher->required_mac; - s->out.etm_mode = !!(s->out.mac->etm_name); - goto matched; - } - if (i == KEXLIST_SCMAC && s->in.cipher && - s->in.cipher->required_mac) { - s->in.mac = s->in.cipher->required_mac; - s->in.etm_mode = !!(s->in.mac->etm_name); - goto matched; - } - - for (j = 0; j < MAXKEXLIST; j++) { - struct kexinit_algorithm *alg = &s->kexlists[i][j]; - if (alg->name == NULL) break; - if (in_commasep_string(alg->name, str.ptr, str.len)) { - /* We've found a matching algorithm. */ - if (i == KEXLIST_KEX || i == KEXLIST_HOSTKEY) { - /* Check if we might need to ignore first kex pkt */ - if (j != 0 || - !first_in_commasep_string(alg->name, - str.ptr, str.len)) - s->guessok = FALSE; - } - if (i == KEXLIST_KEX) { - ssh->kex = alg->u.kex.kex; - s->warn_kex = alg->u.kex.warn; - } else if (i == KEXLIST_HOSTKEY) { - /* - * Ignore an unexpected/inappropriate offer of "null", - * we offer "null" when we're willing to use GSS KEX, - * but it is only acceptable when GSSKEX is actually - * selected. - */ - if (alg->u.hk.hostkey == NULL && - ssh->kex->main_type != KEXTYPE_GSS) - continue; - ssh->hostkey_alg = alg->u.hk.hostkey; - s->warn_hk = alg->u.hk.warn; - } else if (i == KEXLIST_CSCIPHER) { - s->out.cipher = alg->u.cipher.cipher; - s->warn_cscipher = alg->u.cipher.warn; - } else if (i == KEXLIST_SCCIPHER) { - s->in.cipher = alg->u.cipher.cipher; - s->warn_sccipher = alg->u.cipher.warn; - } else if (i == KEXLIST_CSMAC) { - s->out.mac = alg->u.mac.mac; - s->out.etm_mode = alg->u.mac.etm; - } else if (i == KEXLIST_SCMAC) { - s->in.mac = alg->u.mac.mac; - s->in.etm_mode = alg->u.mac.etm; - } else if (i == KEXLIST_CSCOMP) { - s->out.comp = alg->u.comp; - } else if (i == KEXLIST_SCCOMP) { - s->in.comp = alg->u.comp; - } - goto matched; - } - if ((i == KEXLIST_CSCOMP || i == KEXLIST_SCCOMP) && - in_commasep_string(alg->u.comp->delayed_name, - str.ptr, str.len) && - !s->userauth_succeeded) - s->pending_compression = TRUE; /* try this later */ - } - bombout(("Couldn't agree a %s (available: %.*s)", - kexlist_descr[i], PTRLEN_PRINTF(str))); - crStopV; - matched:; - - if (i == KEXLIST_HOSTKEY && - !ssh->gss_kex_used && - ssh->kex->main_type != KEXTYPE_GSS) { - int j; - - /* - * In addition to deciding which host key we're - * actually going to use, we should make a list of the - * host keys offered by the server which we _don't_ - * have cached. These will be offered as cross- - * certification options by ssh_get_specials. - * - * We also count the key we're currently using for KEX - * as one we've already got, because by the time this - * menu becomes visible, it will be. - */ - ssh->n_uncert_hostkeys = 0; - - for (j = 0; j < lenof(hostkey_algs); j++) { - if (hostkey_algs[j].alg != ssh->hostkey_alg && - in_commasep_string(hostkey_algs[j].alg->ssh_id, - str.ptr, str.len) && - !have_ssh_host_key(ssh->savedhost, ssh->savedport, - hostkey_algs[j].alg->cache_id)) { - ssh->uncert_hostkeys[ssh->n_uncert_hostkeys++] = j; - } - } - } - } - - if (s->pending_compression) { - logevent("Server supports delayed compression; " - "will try this later"); - } - get_string(pktin); /* client->server language */ - get_string(pktin); /* server->client language */ - s->ignorepkt = get_bool(pktin) && !s->guessok; - - ssh->exhash = ssh_hash_new(ssh->kex->hash); - put_stringz(ssh->exhash, ssh->v_c); - put_stringz(ssh->exhash, ssh->v_s); - put_string(ssh->exhash, s->our_kexinit, s->our_kexinitlen); - sfree(s->our_kexinit); - /* Include the type byte in the hash of server's KEXINIT */ - put_string(ssh->exhash, - (const char *)BinarySource_UPCAST(pktin)->data - 1, - BinarySource_UPCAST(pktin)->len + 1); - - if (s->warn_kex) { - s->dlgret = askalg(ssh->frontend, "key-exchange algorithm", - ssh->kex->name, - ssh_dialog_callback, ssh); - if (s->dlgret < 0) { - ssh->user_response = -1; - crWaitUntilV(ssh->user_response >= 0); - s->dlgret = ssh->user_response; - } - if (s->dlgret == 0) { - ssh_disconnect(ssh, "User aborted at kex warning", NULL, - 0, TRUE); - crStopV; - } - } - - if (s->warn_hk) { - int j, k; - char *betteralgs; - - /* - * Change warning box wording depending on why we chose a - * warning-level host key algorithm. If it's because - * that's all we have *cached*, use the askhk mechanism, - * and list the host keys we could usefully cross-certify. - * Otherwise, use askalg for the standard wording. - */ - betteralgs = NULL; - for (j = 0; j < ssh->n_uncert_hostkeys; j++) { - const struct ssh_signkey_with_user_pref_id *hktype = - &hostkey_algs[ssh->uncert_hostkeys[j]]; - int better = FALSE; - for (k = 0; k < HK_MAX; k++) { - int id = conf_get_int_int(ssh->conf, CONF_ssh_hklist, k); - if (id == HK_WARN) { - break; - } else if (id == hktype->id) { - better = TRUE; - break; - } - } - if (better) { - if (betteralgs) { - char *old_ba = betteralgs; - betteralgs = dupcat(betteralgs, ",", - hktype->alg->ssh_id, - (const char *)NULL); - sfree(old_ba); - } else { - betteralgs = dupstr(hktype->alg->ssh_id); - } - } - } - if (betteralgs) { - s->dlgret = askhk(ssh->frontend, ssh->hostkey_alg->ssh_id, - betteralgs, ssh_dialog_callback, ssh); - sfree(betteralgs); - } else { - s->dlgret = askalg(ssh->frontend, "host key type", - ssh->hostkey_alg->ssh_id, - ssh_dialog_callback, ssh); - } - if (s->dlgret < 0) { - ssh->user_response = -1; - crWaitUntilV(ssh->user_response >= 0); - s->dlgret = ssh->user_response; - } - if (s->dlgret == 0) { - ssh_disconnect(ssh, "User aborted at host key warning", NULL, - 0, TRUE); - crStopV; - } - } - - if (s->warn_cscipher) { - s->dlgret = askalg(ssh->frontend, - "client-to-server cipher", - s->out.cipher->name, - ssh_dialog_callback, ssh); - if (s->dlgret < 0) { - ssh->user_response = -1; - crWaitUntilV(ssh->user_response >= 0); - s->dlgret = ssh->user_response; - } - if (s->dlgret == 0) { - ssh_disconnect(ssh, "User aborted at cipher warning", NULL, - 0, TRUE); - crStopV; - } - } - - if (s->warn_sccipher) { - s->dlgret = askalg(ssh->frontend, - "server-to-client cipher", - s->in.cipher->name, - ssh_dialog_callback, ssh); - if (s->dlgret < 0) { - ssh->user_response = -1; - crWaitUntilV(ssh->user_response >= 0); - s->dlgret = ssh->user_response; - } - if (s->dlgret == 0) { - ssh_disconnect(ssh, "User aborted at cipher warning", NULL, - 0, TRUE); - crStopV; - } - } - - if (s->ignorepkt) /* first_kex_packet_follows */ - crMaybeWaitUntilV((pktin = pq_pop(&ssh->pq_ssh2_transport)) != NULL); - } - - if (ssh->kex->main_type == KEXTYPE_DH) { - /* - * Work out the number of bits of key we will need from the - * key exchange. We start with the maximum key length of - * either cipher... - */ - { - int csbits, scbits; - - csbits = s->out.cipher ? s->out.cipher->real_keybits : 0; - scbits = s->in.cipher ? s->in.cipher->real_keybits : 0; - s->nbits = (csbits > scbits ? csbits : scbits); - } - /* The keys only have hlen-bit entropy, since they're based on - * a hash. So cap the key size at hlen bits. */ - if (s->nbits > ssh->kex->hash->hlen * 8) - s->nbits = ssh->kex->hash->hlen * 8; - - /* - * If we're doing Diffie-Hellman group exchange, start by - * requesting a group. - */ - if (dh_is_gex(ssh->kex)) { - logevent("Doing Diffie-Hellman group exchange"); - ssh->pls.kctx = SSH2_PKTCTX_DHGEX; - /* - * Work out how big a DH group we will need to allow that - * much data. - */ - s->pbits = 512 << ((s->nbits - 1) / 64); - if (s->pbits < DH_MIN_SIZE) - s->pbits = DH_MIN_SIZE; - if (s->pbits > DH_MAX_SIZE) - s->pbits = DH_MAX_SIZE; - if ((ssh->remote_bugs & BUG_SSH2_OLDGEX)) { - s->pktout = ssh_bpp_new_pktout( - ssh->bpp, SSH2_MSG_KEX_DH_GEX_REQUEST_OLD); - put_uint32(s->pktout, s->pbits); - } else { - s->pktout = ssh_bpp_new_pktout( - ssh->bpp, SSH2_MSG_KEX_DH_GEX_REQUEST); - put_uint32(s->pktout, DH_MIN_SIZE); - put_uint32(s->pktout, s->pbits); - put_uint32(s->pktout, DH_MAX_SIZE); - } - ssh_pkt_write(ssh, s->pktout); - - crMaybeWaitUntilV((pktin = pq_pop(&ssh->pq_ssh2_transport)) != NULL); - if (pktin->type != SSH2_MSG_KEX_DH_GEX_GROUP) { - bombout(("expected key exchange group packet from server")); - crStopV; - } - s->p = get_mp_ssh2(pktin); - s->g = get_mp_ssh2(pktin); - if (get_err(pktin)) { - freebn(s->p); - freebn(s->g); - bombout(("unable to read mp-ints from incoming group packet")); - crStopV; - } - ssh->dh_ctx = dh_setup_gex(s->p, s->g); - s->kex_init_value = SSH2_MSG_KEX_DH_GEX_INIT; - s->kex_reply_value = SSH2_MSG_KEX_DH_GEX_REPLY; - } else { - ssh->pls.kctx = SSH2_PKTCTX_DHGROUP; - ssh->dh_ctx = dh_setup_group(ssh->kex); - s->kex_init_value = SSH2_MSG_KEXDH_INIT; - s->kex_reply_value = SSH2_MSG_KEXDH_REPLY; - logeventf(ssh, "Using Diffie-Hellman with standard group \"%s\"", - ssh->kex->groupname); - } - - logeventf(ssh, "Doing Diffie-Hellman key exchange with hash %s", - ssh->kex->hash->text_name); - /* - * Now generate and send e for Diffie-Hellman. - */ - set_busy_status(ssh->frontend, BUSY_CPU); /* this can take a while */ - s->e = dh_create_e(ssh->dh_ctx, s->nbits * 2); - s->pktout = ssh_bpp_new_pktout(ssh->bpp, s->kex_init_value); - put_mp_ssh2(s->pktout, s->e); - ssh_pkt_write(ssh, s->pktout); - - set_busy_status(ssh->frontend, BUSY_WAITING); /* wait for server */ - crMaybeWaitUntilV((pktin = pq_pop(&ssh->pq_ssh2_transport)) != NULL); - if (pktin->type != s->kex_reply_value) { - bombout(("expected key exchange reply packet from server")); - crStopV; - } - set_busy_status(ssh->frontend, BUSY_CPU); /* cogitate */ - s->hostkeydata = get_string(pktin); - s->hkey = ssh_key_new_pub(ssh->hostkey_alg, s->hostkeydata); - s->f = get_mp_ssh2(pktin); - s->sigdata = get_string(pktin); - if (get_err(pktin)) { - bombout(("unable to parse key exchange reply packet")); - crStopV; - } - - { - const char *err = dh_validate_f(ssh->dh_ctx, s->f); - if (err) { - bombout(("key exchange reply failed validation: %s", err)); - crStopV; - } - } - s->K = dh_find_K(ssh->dh_ctx, s->f); - - /* We assume everything from now on will be quick, and it might - * involve user interaction. */ - set_busy_status(ssh->frontend, BUSY_NOT); - - put_stringpl(ssh->exhash, s->hostkeydata); - if (dh_is_gex(ssh->kex)) { - if (!(ssh->remote_bugs & BUG_SSH2_OLDGEX)) - put_uint32(ssh->exhash, DH_MIN_SIZE); - put_uint32(ssh->exhash, s->pbits); - if (!(ssh->remote_bugs & BUG_SSH2_OLDGEX)) - put_uint32(ssh->exhash, DH_MAX_SIZE); - put_mp_ssh2(ssh->exhash, s->p); - put_mp_ssh2(ssh->exhash, s->g); - } - put_mp_ssh2(ssh->exhash, s->e); - put_mp_ssh2(ssh->exhash, s->f); - - dh_cleanup(ssh->dh_ctx); - freebn(s->f); - if (dh_is_gex(ssh->kex)) { - freebn(s->g); - freebn(s->p); - } - } else if (ssh->kex->main_type == KEXTYPE_ECDH) { - - logeventf(ssh, "Doing ECDH key exchange with curve %s and hash %s", - ssh_ecdhkex_curve_textname(ssh->kex), - ssh->kex->hash->text_name); - ssh->pls.kctx = SSH2_PKTCTX_ECDHKEX; - - s->eckey = ssh_ecdhkex_newkey(ssh->kex); - if (!s->eckey) { - bombout(("Unable to generate key for ECDH")); - crStopV; - } - - s->pktout = ssh_bpp_new_pktout(ssh->bpp, SSH2_MSG_KEX_ECDH_INIT); - { - strbuf *pubpoint = strbuf_new(); - ssh_ecdhkex_getpublic(s->eckey, BinarySink_UPCAST(pubpoint)); - put_stringsb(s->pktout, pubpoint); - } - - ssh_pkt_write(ssh, s->pktout); - - crMaybeWaitUntilV((pktin = pq_pop(&ssh->pq_ssh2_transport)) != NULL); - if (pktin->type != SSH2_MSG_KEX_ECDH_REPLY) { - ssh_ecdhkex_freekey(s->eckey); - bombout(("expected ECDH reply packet from server")); - crStopV; - } - - s->hostkeydata = get_string(pktin); - put_stringpl(ssh->exhash, s->hostkeydata); - s->hkey = ssh_key_new_pub(ssh->hostkey_alg, s->hostkeydata); - - { - strbuf *pubpoint = strbuf_new(); - ssh_ecdhkex_getpublic(s->eckey, BinarySink_UPCAST(pubpoint)); - put_string(ssh->exhash, pubpoint->u, pubpoint->len); - strbuf_free(pubpoint); - } - - { - ptrlen keydata = get_string(pktin); - put_stringpl(ssh->exhash, keydata); - s->K = ssh_ecdhkex_getkey(s->eckey, keydata.ptr, keydata.len); - if (!get_err(pktin) && !s->K) { - ssh_ecdhkex_freekey(s->eckey); - bombout(("point received in ECDH was not valid")); - crStopV; - } - } - - s->sigdata = get_string(pktin); - if (get_err(pktin)) { - bombout(("unable to parse key exchange reply packet")); - crStopV; - } - - ssh_ecdhkex_freekey(s->eckey); -#ifndef NO_GSSAPI - } else if (ssh->kex->main_type == KEXTYPE_GSS) { - ptrlen data; - - ssh->pls.kctx = SSH2_PKTCTX_GSSKEX; - s->init_token_sent = 0; - s->complete_rcvd = 0; - s->hkey = NULL; - s->fingerprint = NULL; - s->keystr = NULL; - - /* - * Work out the number of bits of key we will need from the - * key exchange. We start with the maximum key length of - * either cipher... - * - * This is rote from the KEXTYPE_DH section above. - */ - { - int csbits, scbits; - - csbits = s->out.cipher->real_keybits; - scbits = s->in.cipher->real_keybits; - s->nbits = (csbits > scbits ? csbits : scbits); - } - /* The keys only have hlen-bit entropy, since they're based on - * a hash. So cap the key size at hlen bits. */ - if (s->nbits > ssh->kex->hash->hlen * 8) - s->nbits = ssh->kex->hash->hlen * 8; - - if (dh_is_gex(ssh->kex)) { - /* - * Work out how big a DH group we will need to allow that - * much data. - */ - s->pbits = 512 << ((s->nbits - 1) / 64); - logeventf(ssh, "Doing GSSAPI (with Kerberos V5) Diffie-Hellman " - "group exchange, with minimum %d bits", s->pbits); - s->pktout = ssh_bpp_new_pktout(ssh->bpp, SSH2_MSG_KEXGSS_GROUPREQ); - put_uint32(s->pktout, s->pbits); /* min */ - put_uint32(s->pktout, s->pbits); /* preferred */ - put_uint32(s->pktout, s->pbits * 2); /* max */ - ssh_pkt_write(ssh, s->pktout); - - crMaybeWaitUntilV( - (pktin = pq_pop(&ssh->pq_ssh2_transport)) != NULL); - if (pktin->type != SSH2_MSG_KEXGSS_GROUP) { - bombout(("expected key exchange group packet from server")); - crStopV; - } - s->p = get_mp_ssh2(pktin); - s->g = get_mp_ssh2(pktin); - if (get_err(pktin)) { - bombout(("unable to read mp-ints from incoming group packet")); - crStopV; - } - ssh->dh_ctx = dh_setup_gex(s->p, s->g); - } else { - ssh->dh_ctx = dh_setup_group(ssh->kex); - logeventf(ssh, "Using GSSAPI (with Kerberos V5) Diffie-Hellman with standard group \"%s\"", - ssh->kex->groupname); - } - - logeventf(ssh, "Doing GSSAPI (with Kerberos V5) Diffie-Hellman key exchange with hash %s", - ssh->kex->hash->text_name); - /* Now generate e for Diffie-Hellman. */ - set_busy_status(ssh->frontend, BUSY_CPU); /* this can take a while */ - s->e = dh_create_e(ssh->dh_ctx, s->nbits * 2); - - if (ssh->gsslib->gsslogmsg) - logevent(ssh->gsslib->gsslogmsg); - - /* initial tokens are empty */ - SSH_GSS_CLEAR_BUF(&s->gss_rcvtok); - SSH_GSS_CLEAR_BUF(&s->gss_sndtok); - SSH_GSS_CLEAR_BUF(&s->mic); - s->gss_stat = ssh->gsslib->acquire_cred(ssh->gsslib, &s->gss_ctx, - &s->gss_cred_expiry); - if (s->gss_stat != SSH_GSS_OK) { - bombout(("GSSAPI key exchange failed to initialize")); - crStopV; - } - - /* now enter the loop */ - assert(ssh->gss_srv_name); - do { - /* - * When acquire_cred yields no useful expiration, go with the - * service ticket expiration. - */ - s->gss_stat = ssh->gsslib->init_sec_context - (ssh->gsslib, - &s->gss_ctx, - ssh->gss_srv_name, - s->gss_delegate, - &s->gss_rcvtok, - &s->gss_sndtok, - (s->gss_cred_expiry == GSS_NO_EXPIRATION ? - &s->gss_cred_expiry : NULL), - NULL); - SSH_GSS_CLEAR_BUF(&s->gss_rcvtok); - - if (s->gss_stat == SSH_GSS_S_COMPLETE && s->complete_rcvd) - break; /* MIC is verified after the loop */ - - if (s->gss_stat != SSH_GSS_S_COMPLETE && - s->gss_stat != SSH_GSS_S_CONTINUE_NEEDED) { - if (ssh->gsslib->display_status(ssh->gsslib, s->gss_ctx, - &s->gss_buf) == SSH_GSS_OK) { - bombout(("GSSAPI key exchange failed to initialize" - " context: %s", (char *)s->gss_buf.value)); - sfree(s->gss_buf.value); - crStopV; - } else { - bombout(("GSSAPI key exchange failed to initialize" - " context")); - crStopV; - } - } - assert(s->gss_stat == SSH_GSS_S_COMPLETE || - s->gss_stat == SSH_GSS_S_CONTINUE_NEEDED); - - if (!s->init_token_sent) { - s->init_token_sent = 1; - s->pktout = ssh_bpp_new_pktout(ssh->bpp, SSH2_MSG_KEXGSS_INIT); - if (s->gss_sndtok.length == 0) { - bombout(("GSSAPI key exchange failed:" - " no initial context token")); - crStopV; - } - put_string(s->pktout, - s->gss_sndtok.value, s->gss_sndtok.length); - put_mp_ssh2(s->pktout, s->e); - ssh_pkt_write(ssh, s->pktout); - ssh->gsslib->free_tok(ssh->gsslib, &s->gss_sndtok); - logevent("GSSAPI key exchange initialised"); - } else if (s->gss_sndtok.length != 0) { - s->pktout = ssh_bpp_new_pktout( - ssh->bpp, SSH2_MSG_KEXGSS_CONTINUE); - put_string(s->pktout, - s->gss_sndtok.value, s->gss_sndtok.length); - ssh_pkt_write(ssh, s->pktout); - ssh->gsslib->free_tok(ssh->gsslib, &s->gss_sndtok); - } - - if (s->gss_stat == SSH_GSS_S_COMPLETE && s->complete_rcvd) - break; - - wait_for_gss_token: - crMaybeWaitUntilV( - (pktin = pq_pop(&ssh->pq_ssh2_transport)) != NULL); - switch (pktin->type) { - case SSH2_MSG_KEXGSS_CONTINUE: - data = get_string(pktin); - s->gss_rcvtok.value = (char *)data.ptr; - s->gss_rcvtok.length = data.len; - continue; - case SSH2_MSG_KEXGSS_COMPLETE: - s->complete_rcvd = 1; - s->f = get_mp_ssh2(pktin); - data = get_string(pktin); - s->mic.value = (char *)data.ptr; - s->mic.length = data.len; - /* Save expiration time of cred when delegating */ - if (s->gss_delegate && s->gss_cred_expiry != GSS_NO_EXPIRATION) - ssh->gss_cred_expiry = s->gss_cred_expiry; - /* If there's a final token we loop to consume it */ - if (get_bool(pktin)) { - data = get_string(pktin); - s->gss_rcvtok.value = (char *)data.ptr; - s->gss_rcvtok.length = data.len; - continue; - } - break; - case SSH2_MSG_KEXGSS_HOSTKEY: - s->hostkeydata = get_string(pktin); - if (ssh->hostkey_alg) { - s->hkey = ssh_key_new_pub(ssh->hostkey_alg, - s->hostkeydata); - put_string(ssh->exhash, - s->hostkeydata.ptr, s->hostkeydata.len); - } - /* - * Can't loop as we have no token to pass to - * init_sec_context. - */ - goto wait_for_gss_token; - case SSH2_MSG_KEXGSS_ERROR: - /* - * We have no use for the server's major and minor - * status. The minor status is really only - * meaningful to the server, and with luck the major - * status means something to us (but not really all - * that much). The string is more meaningful, and - * hopefully the server sends any error tokens, as - * that will produce the most useful information for - * us. - */ - get_uint32(pktin); /* server's major status */ - get_uint32(pktin); /* server's minor status */ - data = get_string(pktin); - logeventf(ssh, "GSSAPI key exchange failed; " - "server's message: %.*s", PTRLEN_PRINTF(data)); - /* Language tag, but we have no use for it */ - get_string(pktin); - /* - * Wait for an error token, if there is one, or the - * server's disconnect. The error token, if there - * is one, must follow the SSH2_MSG_KEXGSS_ERROR - * message, per the RFC. - */ - goto wait_for_gss_token; - default: - bombout(("unexpected message type during gss kex")); - crStopV; - break; - } - } while (s->gss_rcvtok.length || - s->gss_stat == SSH_GSS_S_CONTINUE_NEEDED || - !s->complete_rcvd); - - s->K = dh_find_K(ssh->dh_ctx, s->f); - - /* We assume everything from now on will be quick, and it might - * involve user interaction. */ - set_busy_status(ssh->frontend, BUSY_NOT); - - if (!s->hkey) - put_stringz(ssh->exhash, ""); - if (dh_is_gex(ssh->kex)) { - /* min, preferred, max */ - put_uint32(ssh->exhash, s->pbits); - put_uint32(ssh->exhash, s->pbits); - put_uint32(ssh->exhash, s->pbits * 2); - - put_mp_ssh2(ssh->exhash, s->p); - put_mp_ssh2(ssh->exhash, s->g); - } - put_mp_ssh2(ssh->exhash, s->e); - put_mp_ssh2(ssh->exhash, s->f); - - /* - * MIC verification is done below, after we compute the hash - * used as the MIC input. - */ - - dh_cleanup(ssh->dh_ctx); - freebn(s->f); - if (dh_is_gex(ssh->kex)) { - freebn(s->g); - freebn(s->p); - } -#endif - } else { - ptrlen rsakeydata; - - assert(ssh->kex->main_type == KEXTYPE_RSA); - logeventf(ssh, "Doing RSA key exchange with hash %s", - ssh->kex->hash->text_name); - ssh->pls.kctx = SSH2_PKTCTX_RSAKEX; - /* - * RSA key exchange. First expect a KEXRSA_PUBKEY packet - * from the server. - */ - crMaybeWaitUntilV((pktin = pq_pop(&ssh->pq_ssh2_transport)) != NULL); - if (pktin->type != SSH2_MSG_KEXRSA_PUBKEY) { - bombout(("expected RSA public key packet from server")); - crStopV; - } - - s->hostkeydata = get_string(pktin); - put_stringpl(ssh->exhash, s->hostkeydata); - s->hkey = ssh_key_new_pub(ssh->hostkey_alg, s->hostkeydata); - - rsakeydata = get_string(pktin); - - s->rsakey = ssh_rsakex_newkey(rsakeydata.ptr, rsakeydata.len); - if (!s->rsakey) { - bombout(("unable to parse RSA public key from server")); - crStopV; - } - - put_stringpl(ssh->exhash, rsakeydata); - - /* - * Next, set up a shared secret K, of precisely KLEN - - * 2*HLEN - 49 bits, where KLEN is the bit length of the - * RSA key modulus and HLEN is the bit length of the hash - * we're using. - */ - { - int klen = ssh_rsakex_klen(s->rsakey); - int nbits = klen - (2*ssh->kex->hash->hlen*8 + 49); - int i, byte = 0; - strbuf *buf; - unsigned char *outstr; - int outstrlen; - - s->K = bn_power_2(nbits - 1); - - for (i = 0; i < nbits; i++) { - if ((i & 7) == 0) { - byte = random_byte(); - } - bignum_set_bit(s->K, i, (byte >> (i & 7)) & 1); - } - - /* - * Encode this as an mpint. - */ - buf = strbuf_new(); - put_mp_ssh2(buf, s->K); - - /* - * Encrypt it with the given RSA key. - */ - outstrlen = (klen + 7) / 8; - outstr = snewn(outstrlen, unsigned char); - ssh_rsakex_encrypt(ssh->kex->hash, buf->u, buf->len, - outstr, outstrlen, s->rsakey); - - /* - * And send it off in a return packet. - */ - s->pktout = ssh_bpp_new_pktout(ssh->bpp, SSH2_MSG_KEXRSA_SECRET); - put_string(s->pktout, outstr, outstrlen); - ssh_pkt_write(ssh, s->pktout); - - put_string(ssh->exhash, outstr, outstrlen); - - strbuf_free(buf); - sfree(outstr); - } - - ssh_rsakex_freekey(s->rsakey); - - crMaybeWaitUntilV((pktin = pq_pop(&ssh->pq_ssh2_transport)) != NULL); - if (pktin->type != SSH2_MSG_KEXRSA_DONE) { - bombout(("expected signature packet from server")); - crStopV; - } - - s->sigdata = get_string(pktin); - if (get_err(pktin)) { - bombout(("unable to parse signature packet")); - crStopV; - } - } - - put_mp_ssh2(ssh->exhash, s->K); - assert(ssh_hash_alg(ssh->exhash)->hlen <= sizeof(s->exchange_hash)); - ssh_hash_final(ssh->exhash, s->exchange_hash); - -#ifndef NO_GSSAPI - if (ssh->kex->main_type == KEXTYPE_GSS) { - Ssh_gss_buf gss_buf; - SSH_GSS_CLEAR_BUF(&s->gss_buf); - - gss_buf.value = s->exchange_hash; - gss_buf.length = ssh->kex->hash->hlen; - s->gss_stat = ssh->gsslib->verify_mic(ssh->gsslib, s->gss_ctx, &gss_buf, &s->mic); - if (s->gss_stat != SSH_GSS_OK) { - if (ssh->gsslib->display_status(ssh->gsslib, s->gss_ctx, - &s->gss_buf) == SSH_GSS_OK) { - bombout(("GSSAPI Key Exchange MIC was not valid: %s", - (char *)s->gss_buf.value)); - sfree(s->gss_buf.value); - } else { - bombout(("GSSAPI Key Exchange MIC was not valid")); - } - crStopV; - } - - ssh->gss_kex_used = TRUE; - - /*- - * If this the first KEX, save the GSS context for "gssapi-keyex" - * authentication. - * - * http://tools.ietf.org/html/rfc4462#section-4 - * - * This method may be used only if the initial key exchange was - * performed using a GSS-API-based key exchange method defined in - * accordance with Section 2. The GSS-API context used with this - * method is always that established during an initial GSS-API-based - * key exchange. Any context established during key exchange for the - * purpose of rekeying MUST NOT be used with this method. - */ - if (!s->got_session_id) { - ssh->gss_ctx = s->gss_ctx; - } else { - ssh->gsslib->release_cred(ssh->gsslib, &s->gss_ctx); - } - logeventf(ssh, "GSSAPI Key Exchange complete!"); - } -#endif - - ssh->dh_ctx = NULL; - -#if 0 - debug(("Exchange hash is:\n")); - dmemdump(s->exchange_hash, ssh->kex->hash->hlen); -#endif - - /* In GSS keyex there's no hostkey signature to verify */ - if (ssh->kex->main_type != KEXTYPE_GSS) { - if (!s->hkey) { - bombout(("Server's host key is invalid")); - crStopV; - } - - if (!ssh_key_verify( - s->hkey, s->sigdata, - make_ptrlen(s->exchange_hash, ssh->kex->hash->hlen))) { -#ifndef FUZZING - bombout(("Server's host key did not match the signature " - "supplied")); - crStopV; -#endif - } - } - - s->keystr = (s->hkey ? ssh_key_cache_str(s->hkey) : NULL); -#ifndef NO_GSSAPI - if (ssh->gss_kex_used) { - /* - * In a GSS-based session, check the host key (if any) against - * the transient host key cache. See comment above, at the - * definition of ssh_transient_hostkey_cache_entry. - */ - if (ssh->kex->main_type == KEXTYPE_GSS) { - - /* - * We've just done a GSS key exchange. If it gave us a - * host key, store it. - */ - if (s->hkey) { - s->fingerprint = ssh2_fingerprint(s->hkey); - logevent("GSS kex provided fallback host key:"); - logevent(s->fingerprint); - sfree(s->fingerprint); - s->fingerprint = NULL; - ssh_store_transient_hostkey(ssh, s->hkey); - } else if (!ssh_have_any_transient_hostkey(ssh)) { - /* - * But if it didn't, then we currently have no - * fallback host key to use in subsequent non-GSS - * rekeys. So we should immediately trigger a non-GSS - * rekey of our own, to set one up, before the session - * keys have been used for anything else. - * - * This is similar to the cross-certification done at - * user request in the permanent host key cache, but - * here we do it automatically, once, at session - * startup, and only add the key to the transient - * cache. - */ - if (ssh->hostkey_alg) { - s->need_gss_transient_hostkey = TRUE; - } else { - /* - * If we negotiated the "null" host key algorithm - * in the key exchange, that's an indication that - * no host key at all is available from the server - * (both because we listed "null" last, and - * because RFC 4462 section 5 says that a server - * MUST NOT offer "null" as a host key algorithm - * unless that is the only algorithm it provides - * at all). - * - * In that case we actually _can't_ perform a - * non-GSSAPI key exchange, so it's pointless to - * attempt one proactively. This is also likely to - * cause trouble later if a rekey is required at a - * moment whne GSS credentials are not available, - * but someone setting up a server in this - * configuration presumably accepts that as a - * consequence. - */ - if (!s->warned_about_no_gss_transient_hostkey) { - logevent("No fallback host key available"); - s->warned_about_no_gss_transient_hostkey = TRUE; - } - } - } - } else { - /* - * We've just done a fallback key exchange, so make - * sure the host key it used is in the cache of keys - * we previously received in GSS kexes. - * - * An exception is if this was the non-GSS key exchange we - * triggered on purpose to populate the transient cache. - */ - assert(s->hkey); /* only KEXTYPE_GSS lets this be null */ - s->fingerprint = ssh2_fingerprint(s->hkey); - - if (s->need_gss_transient_hostkey) { - logevent("Post-GSS rekey provided fallback host key:"); - logevent(s->fingerprint); - ssh_store_transient_hostkey(ssh, s->hkey); - s->need_gss_transient_hostkey = FALSE; - } else if (!ssh_verify_transient_hostkey(ssh, s->hkey)) { - logevent("Non-GSS rekey after initial GSS kex " - "used host key:"); - logevent(s->fingerprint); - bombout(("Host key was not previously sent via GSS kex")); - } - - sfree(s->fingerprint); - s->fingerprint = NULL; - } - } else -#endif /* NO_GSSAPI */ - if (!s->got_session_id) { - /* - * Make a note of any other host key formats that are available. - */ - { - int i, j, nkeys = 0; - char *list = NULL; - for (i = 0; i < lenof(hostkey_algs); i++) { - if (hostkey_algs[i].alg == ssh->hostkey_alg) - continue; - - for (j = 0; j < ssh->n_uncert_hostkeys; j++) - if (ssh->uncert_hostkeys[j] == i) - break; - - if (j < ssh->n_uncert_hostkeys) { - char *newlist; - if (list) - newlist = dupprintf("%s/%s", list, - hostkey_algs[i].alg->ssh_id); - else - newlist = dupprintf("%s", hostkey_algs[i].alg->ssh_id); - sfree(list); - list = newlist; - nkeys++; - } - } - if (list) { - logeventf(ssh, - "Server also has %s host key%s, but we " - "don't know %s", list, - nkeys > 1 ? "s" : "", - nkeys > 1 ? "any of them" : "it"); - sfree(list); - } - } - - /* - * Authenticate remote host: verify host key. (We've already - * checked the signature of the exchange hash.) - */ - s->fingerprint = ssh2_fingerprint(s->hkey); - logevent("Host key fingerprint is:"); - logevent(s->fingerprint); - /* First check against manually configured host keys. */ - s->dlgret = verify_ssh_manual_host_key(ssh->conf, - s->fingerprint, s->hkey); - if (s->dlgret == 0) { /* did not match */ - bombout(("Host key did not appear in manually configured list")); - crStopV; - } else if (s->dlgret < 0) { /* none configured; use standard handling */ - s->dlgret = verify_ssh_host_key(ssh->frontend, - ssh->savedhost, ssh->savedport, - ssh_key_cache_id(s->hkey), - s->keystr, s->fingerprint, - ssh_dialog_callback, ssh); -#ifdef FUZZING - s->dlgret = 1; -#endif - if (s->dlgret < 0) { - ssh->user_response = -1; - crWaitUntilV(ssh->user_response >= 0); - s->dlgret = ssh->user_response; - } - if (s->dlgret == 0) { - ssh_disconnect(ssh, "Aborted at host key verification", NULL, - 0, TRUE); - crStopV; - } - } - sfree(s->fingerprint); - /* - * Save this host key, to check against the one presented in - * subsequent rekeys. - */ - ssh->hostkey_str = s->keystr; - s->keystr = NULL; - } else if (ssh->cross_certifying) { - s->fingerprint = ssh2_fingerprint(s->hkey); - logevent("Storing additional host key for this host:"); - logevent(s->fingerprint); - sfree(s->fingerprint); - store_host_key(ssh->savedhost, ssh->savedport, - ssh_key_cache_id(s->hkey), s->keystr); - ssh->cross_certifying = FALSE; - /* - * Don't forget to store the new key as the one we'll be - * re-checking in future normal rekeys. - */ - ssh->hostkey_str = s->keystr; - s->keystr = NULL; - } else { - /* - * In a rekey, we never present an interactive host key - * verification request to the user. Instead, we simply - * enforce that the key we're seeing this time is identical to - * the one we saw before. - */ - if (strcmp(ssh->hostkey_str, s->keystr)) { -#ifndef FUZZING - bombout(("Host key was different in repeat key exchange")); - crStopV; -#endif - } - } - sfree(s->keystr); - if (s->hkey) { - ssh_key_free(s->hkey); - s->hkey = NULL; - } - - /* - * The exchange hash from the very first key exchange is also - * the session id, used in session key construction and - * authentication. - */ - if (!s->got_session_id) { - assert(sizeof(s->exchange_hash) <= sizeof(ssh->v2_session_id)); - memcpy(ssh->v2_session_id, s->exchange_hash, - sizeof(s->exchange_hash)); - ssh->v2_session_id_len = ssh->kex->hash->hlen; - assert(ssh->v2_session_id_len <= sizeof(ssh->v2_session_id)); - s->got_session_id = TRUE; - } - - /* - * Send SSH2_MSG_NEWKEYS. - */ - s->pktout = ssh_bpp_new_pktout(ssh->bpp, SSH2_MSG_NEWKEYS); - ssh_pkt_write(ssh, s->pktout); - /* Start counting down the outgoing-data limit for these cipher keys. */ - ssh->stats.out.running = TRUE; - ssh->stats.out.remaining = ssh->max_data_size; - - /* - * Force the BPP to synchronously marshal all packets up to and - * including that NEWKEYS into wire format, before we switch over - * to new crypto. - */ - ssh_bpp_handle_output(ssh->bpp); - - /* - * We've sent client NEWKEYS, so create and initialise - * client-to-server session keys. - */ - { - strbuf *cipher_key = strbuf_new(); - strbuf *cipher_iv = strbuf_new(); - strbuf *mac_key = strbuf_new(); - - if (s->out.cipher) { - ssh2_mkkey(ssh, cipher_iv, s->K, s->exchange_hash, 'A', - s->out.cipher->blksize); - ssh2_mkkey(ssh, cipher_key, s->K, s->exchange_hash, 'C', - s->out.cipher->padded_keybytes); - } - if (s->out.mac) { - ssh2_mkkey(ssh, mac_key, s->K, s->exchange_hash, 'E', - s->out.mac->keylen); - } - - ssh2_bpp_new_outgoing_crypto( - ssh->bpp, - s->out.cipher, cipher_key->u, cipher_iv->u, - s->out.mac, s->out.etm_mode, mac_key->u, - s->out.comp); - - /* - * Remember some details we'll need later for making other - * policy decisions based on the crypto we've just - * initialised. - */ - ssh->v2_cbc_ignore_workaround = ( - s->out.cipher && - (s->out.cipher->flags & SSH_CIPHER_IS_CBC) && - !(ssh->remote_bugs & BUG_CHOKES_ON_SSH2_IGNORE)); - ssh->v2_out_cipherblksize = s->out.cipher->blksize; - - strbuf_free(cipher_key); - strbuf_free(cipher_iv); - strbuf_free(mac_key); - } - - if (s->out.cipher) - logeventf(ssh, "Initialised %.200s client->server encryption", - s->out.cipher->text_name); - if (s->out.mac) - logeventf(ssh, "Initialised %.200s client->server" - " MAC algorithm%s%s", - s->out.mac->text_name, - s->out.etm_mode ? " (in ETM mode)" : "", - (s->out.cipher->required_mac ? - " (required by cipher)" : "")); - if (s->out.comp->text_name) - logeventf(ssh, "Initialised %s compression", - s->out.comp->text_name); - - /* - * Now our end of the key exchange is complete, we can send all - * our queued higher-layer packets. - */ - ssh->queueing = FALSE; - ssh2_pkt_queuesend(ssh); - - /* - * Expect SSH2_MSG_NEWKEYS from server. - */ - crMaybeWaitUntilV((pktin = pq_pop(&ssh->pq_ssh2_transport)) != NULL); - if (pktin->type != SSH2_MSG_NEWKEYS) { - bombout(("expected new-keys packet from server")); - crStopV; - } - /* Start counting down the incoming-data limit for these cipher keys. */ - ssh->stats.in.running = TRUE; - ssh->stats.in.remaining = ssh->max_data_size; - - /* - * We've seen server NEWKEYS, so create and initialise - * server-to-client session keys. - */ - { - strbuf *cipher_key = strbuf_new(); - strbuf *cipher_iv = strbuf_new(); - strbuf *mac_key = strbuf_new(); - - if (s->in.cipher) { - ssh2_mkkey(ssh, cipher_iv, s->K, s->exchange_hash, 'B', - s->in.cipher->blksize); - ssh2_mkkey(ssh, cipher_key, s->K, s->exchange_hash, 'D', - s->in.cipher->padded_keybytes); - } - if (s->in.mac) { - ssh2_mkkey(ssh, mac_key, s->K, s->exchange_hash, 'F', - s->in.mac->keylen); - } - - ssh2_bpp_new_incoming_crypto( - ssh->bpp, - s->in.cipher, cipher_key->u, cipher_iv->u, - s->in.mac, s->in.etm_mode, mac_key->u, - s->in.comp); - - strbuf_free(cipher_key); - strbuf_free(cipher_iv); - strbuf_free(mac_key); - } - - if (s->in.cipher) - logeventf(ssh, "Initialised %.200s server->client encryption", - s->in.cipher->text_name); - if (s->in.mac) - logeventf(ssh, "Initialised %.200s server->client" - " MAC algorithm%s%s", - s->in.mac->text_name, - s->in.etm_mode ? " (in ETM mode)" : "", - (s->in.cipher->required_mac ? - " (required by cipher)" : "")); - if (s->in.comp->text_name) - logeventf(ssh, "Initialised %s decompression", - s->in.comp->text_name); - - /* - * Free shared secret. - */ - freebn(s->K); - - /* - * Update the specials menu to list the remaining uncertified host - * keys. - */ - update_specials_menu(ssh->frontend); - - /* - * Key exchange is over. Loop straight back round if we have a - * deferred rekey reason. - */ - if (ssh->deferred_rekey_reason) { - logevent(ssh->deferred_rekey_reason); - pktin = NULL; - ssh->deferred_rekey_reason = NULL; - goto begin_key_exchange; - } - - /* - * Otherwise, schedule a timer for our next rekey. - */ - ssh->kex_in_progress = FALSE; - ssh->last_rekey = GETTICKCOUNT(); - (void) ssh2_timer_update(ssh, 0); - - /* - * Now we're encrypting. Get the next-layer protocol started if it - * hasn't already, and then sit here waiting for reasons to go - * back to the start and do a repeat key exchange. One of those - * reasons is that we receive KEXINIT from the other end; the - * other is if we find ssh->rekey_reason is non-NULL, i.e. we've - * decided to initiate a rekey ourselves for some reason. - */ - ssh->rekey_class = RK_NONE; - while (!pq_peek(&ssh->pq_ssh2_transport) && !ssh->rekey_class) { - wait_for_rekey: - if (!ssh->current_user_input_fn) { - /* - * Allow userauth to initialise itself. - */ - do_ssh2_userauth(ssh); - ssh->current_user_input_fn = ssh2_userauth_input; - } - crReturnV; - } - if ((pktin = pq_pop(&ssh->pq_ssh2_transport)) != NULL) { - if (pktin->type != SSH2_MSG_KEXINIT) { - bombout(("unexpected key exchange packet, type %d", pktin->type)); - crStopV; - } - logevent("Server initiated key re-exchange"); - } else { - if (ssh->rekey_class == RK_POST_USERAUTH) { - /* - * userauth has seen a USERAUTH_SUCCEEDED. For a couple of - * reasons, this may be the moment to do an immediate - * rekey with different parameters. - * - * One is to turn on delayed compression. We do this by a - * rekey to work around a protocol design bug: - * draft-miller-secsh-compression-delayed-00 says that you - * negotiate delayed compression in the first key - * exchange, and both sides start compressing when the - * server has sent USERAUTH_SUCCESS. This has a race - * condition -- the server can't know when the client has - * seen it, and thus which incoming packets it should - * treat as compressed. - * - * Instead, we do the initial key exchange without - * offering the delayed methods, but note if the server - * offers them; when we get here, if a delayed method was - * available that was higher on our list than what we got, - * we initiate a rekey in which we _do_ list the delayed - * methods (and hopefully get it as a result). Subsequent - * rekeys will do the same. - * - * Another reason for a rekey at this point is if we've - * done a GSS key exchange and don't have anything in our - * transient hostkey cache, in which case we should make - * an attempt to populate the cache now. - */ - assert(!s->userauth_succeeded); /* should only happen once */ - s->userauth_succeeded = TRUE; - if (s->pending_compression) { - ssh->rekey_reason = "enabling delayed compression"; - } else if (s->need_gss_transient_hostkey) { - ssh->rekey_reason = "populating transient host key cache"; - } else { - /* Can't see any point rekeying. */ - goto wait_for_rekey; /* this is utterly horrid */ - } - /* else fall through to rekey... */ - - s->pending_compression = FALSE; - } - /* - * Now we've decided to rekey. - * - * Special case: if the server bug is set that doesn't - * allow rekeying, we give a different log message and - * continue waiting. (If such a server _initiates_ a rekey, - * we process it anyway!) - */ - if ((ssh->remote_bugs & BUG_SSH2_REKEY)) { - logeventf(ssh, "Server bug prevents key re-exchange (%s)", - ssh->rekey_reason); - /* Reset the counters, so that at least this message doesn't - * hit the event log _too_ often. */ - ssh->stats.in.running = ssh->stats.out.running = TRUE; - ssh->stats.in.remaining = ssh->stats.out.remaining = - ssh->max_data_size; - (void) ssh2_timer_update(ssh, 0); - goto wait_for_rekey; /* this is still utterly horrid */ - } else { - logeventf(ssh, "Initiating key re-exchange (%s)", - ssh->rekey_reason); - } - } - goto begin_key_exchange; - - crFinishV; -} - -/* - * Send data on an SSH channel. In SSH-2, this involves buffering it - * first. - */ -static int ssh_send_channel_data(struct ssh_channel *c, const char *buf, - int len) -{ - assert(!(c->closes & CLOSES_SENT_EOF)); - - if (c->ssh->version == 2) { - bufchain_add(&c->v.v2.outbuffer, buf, len); - return ssh2_try_send(c); - } else { - PktOut *pkt = ssh_bpp_new_pktout(c->ssh->bpp, SSH1_MSG_CHANNEL_DATA); - put_uint32(pkt, c->remoteid); - put_string(pkt, buf, len); - ssh_pkt_write(c->ssh, pkt); - /* - * In SSH-1 we can return 0 here - implying that channels are - * never individually throttled - because the only - * circumstance that can cause throttling will be the whole - * SSH connection backing up, in which case _everything_ will - * be throttled as a whole. - */ - return 0; - } -} - -/* - * Attempt to send data on an SSH-2 channel. - */ -static int ssh2_try_send(struct ssh_channel *c) -{ - Ssh ssh = c->ssh; - PktOut *pktout; - int ret; - - while (c->v.v2.remwindow > 0 && bufchain_size(&c->v.v2.outbuffer) > 0) { - int len; - void *data; - bufchain_prefix(&c->v.v2.outbuffer, &data, &len); - if ((unsigned)len > c->v.v2.remwindow) - len = c->v.v2.remwindow; - if ((unsigned)len > c->v.v2.remmaxpkt) - len = c->v.v2.remmaxpkt; - pktout = ssh_bpp_new_pktout(ssh->bpp, SSH2_MSG_CHANNEL_DATA); - put_uint32(pktout, c->remoteid); - put_string(pktout, data, len); - ssh2_pkt_send(ssh, pktout); - if (!ssh->s) /* a network error might have closed the socket */ - break; - bufchain_consume(&c->v.v2.outbuffer, len); - c->v.v2.remwindow -= len; - } - - /* - * After having sent as much data as we can, return the amount - * still buffered. - */ - ret = bufchain_size(&c->v.v2.outbuffer); - - /* - * And if there's no data pending but we need to send an EOF, send - * it. - */ - if (!ret && c->pending_eof) - ssh_channel_try_eof(c); - - return ret; -} - -static void ssh2_try_send_and_unthrottle(Ssh ssh, struct ssh_channel *c) -{ - int bufsize; - if (c->closes & CLOSES_SENT_EOF) - return; /* don't send on channels we've EOFed */ - bufsize = ssh2_try_send(c); - if (bufsize == 0) { - c->throttled_by_backlog = FALSE; - ssh_channel_check_throttle(c); - } -} - -static int ssh_is_simple(Ssh ssh) -{ - /* - * We use the 'simple' variant of the SSH protocol if we're asked - * to, except not if we're also doing connection-sharing (either - * tunnelling our packets over an upstream or expecting to be - * tunnelled over ourselves), since then the assumption that we - * have only one channel to worry about is not true after all. - */ - return (conf_get_int(ssh->conf, CONF_ssh_simple) && - !ssh->bare_connection && !ssh->connshare); -} - -/* - * Set up most of a new ssh_channel. Nulls out sharectx, but leaves - * chan untouched (since it will sometimes have been filled in before - * calling this). - */ -static void ssh_channel_init(struct ssh_channel *c) -{ - Ssh ssh = c->ssh; - c->localid = alloc_channel_id(ssh->channels, struct ssh_channel); - c->closes = 0; - c->pending_eof = FALSE; - c->throttling_conn = FALSE; - c->sharectx = NULL; - if (ssh->version == 2) { - c->v.v2.locwindow = c->v.v2.locmaxwin = c->v.v2.remlocwin = - ssh_is_simple(ssh) ? OUR_V2_BIGWIN : OUR_V2_WINSIZE; - c->v.v2.chanreq_head = NULL; - c->v.v2.throttle_state = UNTHROTTLED; - bufchain_init(&c->v.v2.outbuffer); - } - c->sc.vt = &sshchannel_vtable; - add234(ssh->channels, c); -} - -/* - * Construct the common parts of a CHANNEL_OPEN. - */ -static PktOut *ssh2_chanopen_init(struct ssh_channel *c, - const char *type) -{ - PktOut *pktout; - - pktout = ssh_bpp_new_pktout(c->ssh->bpp, SSH2_MSG_CHANNEL_OPEN); - put_stringz(pktout, type); - put_uint32(pktout, c->localid); - put_uint32(pktout, c->v.v2.locwindow);/* our window size */ - put_uint32(pktout, OUR_V2_MAXPKT); /* our max pkt size */ - return pktout; -} - -/* - * CHANNEL_FAILURE doesn't come with any indication of what message - * caused it, so we have to keep track of the outstanding - * CHANNEL_REQUESTs ourselves. - */ -static void ssh2_queue_chanreq_handler(struct ssh_channel *c, - cchandler_fn_t handler, void *ctx) -{ - struct outstanding_channel_request *ocr = - snew(struct outstanding_channel_request); - - assert(!(c->closes & (CLOSES_SENT_CLOSE | CLOSES_RCVD_CLOSE))); - ocr->handler = handler; - ocr->ctx = ctx; - ocr->next = NULL; - if (!c->v.v2.chanreq_head) - c->v.v2.chanreq_head = ocr; - else - c->v.v2.chanreq_tail->next = ocr; - c->v.v2.chanreq_tail = ocr; -} - -/* - * Construct the common parts of a CHANNEL_REQUEST. If handler is not - * NULL then a reply will be requested and the handler will be called - * when it arrives. The returned packet is ready to have any - * request-specific data added and be sent. Note that if a handler is - * provided, it's essential that the request actually be sent. - * - * The handler will usually be passed the response packet in pktin. If - * pktin is NULL, this means that no reply will ever be forthcoming - * (e.g. because the entire connection is being destroyed, or because - * the server initiated channel closure before we saw the response) - * and the handler should free any storage it's holding. - */ -static PktOut *ssh2_chanreq_init(struct ssh_channel *c, - const char *type, - cchandler_fn_t handler, void *ctx) -{ - PktOut *pktout; - - assert(!(c->closes & (CLOSES_SENT_CLOSE | CLOSES_RCVD_CLOSE))); - pktout = ssh_bpp_new_pktout(c->ssh->bpp, SSH2_MSG_CHANNEL_REQUEST); - put_uint32(pktout, c->remoteid); - put_stringz(pktout, type); - put_bool(pktout, handler != NULL); - if (handler != NULL) - ssh2_queue_chanreq_handler(c, handler, ctx); - return pktout; -} - -static void ssh_channel_unthrottle(struct ssh_channel *c, int bufsize) -{ - Ssh ssh = c->ssh; - int buflimit; - - if (ssh->version == 1) { - buflimit = SSH1_BUFFER_LIMIT; - } else { - if (ssh_is_simple(ssh)) - buflimit = 0; - else - buflimit = c->v.v2.locmaxwin; - if (bufsize < buflimit) - ssh2_set_window(c, buflimit - bufsize); - } - if (c->throttling_conn && bufsize <= buflimit) { - c->throttling_conn = 0; - ssh_throttle_conn(ssh, -1); - } -} - -/* - * Potentially enlarge the window on an SSH-2 channel. - */ -static void ssh2_handle_winadj_response(struct ssh_channel *, PktIn *, - void *); -static void ssh2_set_window(struct ssh_channel *c, int newwin) -{ - Ssh ssh = c->ssh; - - /* - * Never send WINDOW_ADJUST for a channel that the remote side has - * already sent EOF on; there's no point, since it won't be - * sending any more data anyway. Ditto if _we've_ already sent - * CLOSE. - */ - if (c->closes & (CLOSES_RCVD_EOF | CLOSES_SENT_CLOSE)) - return; - - /* - * If the client-side Channel is in an initial setup phase with a - * fixed window size, e.g. for an X11 channel when we're still - * waiting to see its initial auth and may yet hand it off to a - * downstream, don't send any WINDOW_ADJUST either. - */ - if (c->chan->initial_fixed_window_size) - return; - - /* - * If the remote end has a habit of ignoring maxpkt, limit the - * window so that it has no choice (assuming it doesn't ignore the - * window as well). - */ - if ((ssh->remote_bugs & BUG_SSH2_MAXPKT) && newwin > OUR_V2_MAXPKT) - newwin = OUR_V2_MAXPKT; - - /* - * Only send a WINDOW_ADJUST if there's significantly more window - * available than the other end thinks there is. This saves us - * sending a WINDOW_ADJUST for every character in a shell session. - * - * "Significant" is arbitrarily defined as half the window size. - */ - if (newwin / 2 >= c->v.v2.locwindow) { - PktOut *pktout; - unsigned *up; - - /* - * In order to keep track of how much window the client - * actually has available, we'd like it to acknowledge each - * WINDOW_ADJUST. We can't do that directly, so we accompany - * it with a CHANNEL_REQUEST that has to be acknowledged. - * - * This is only necessary if we're opening the window wide. - * If we're not, then throughput is being constrained by - * something other than the maximum window size anyway. - */ - if (newwin == c->v.v2.locmaxwin && - !(ssh->remote_bugs & BUG_CHOKES_ON_WINADJ)) { - up = snew(unsigned); - *up = newwin - c->v.v2.locwindow; - pktout = ssh2_chanreq_init(c, "winadj@putty.projects.tartarus.org", - ssh2_handle_winadj_response, up); - ssh2_pkt_send(ssh, pktout); - - if (c->v.v2.throttle_state != UNTHROTTLED) - c->v.v2.throttle_state = UNTHROTTLING; - } else { - /* Pretend the WINDOW_ADJUST was acked immediately. */ - c->v.v2.remlocwin = newwin; - c->v.v2.throttle_state = THROTTLED; - } - pktout = ssh_bpp_new_pktout(ssh->bpp, SSH2_MSG_CHANNEL_WINDOW_ADJUST); - put_uint32(pktout, c->remoteid); - put_uint32(pktout, newwin - c->v.v2.locwindow); - ssh2_pkt_send(ssh, pktout); - c->v.v2.locwindow = newwin; - } -} - -/* - * Find the channel associated with a message. If there's no channel, - * or it's not properly open, make a noise about it and return NULL. - * If the channel is shared, pass the message on to downstream and - * also return NULL (meaning the caller should ignore this message). - */ -static struct ssh_channel *ssh_channel_msg(Ssh ssh, PktIn *pktin) -{ - unsigned localid = get_uint32(pktin); - struct ssh_channel *c; - int halfopen_ok; - - /* Is this message OK on a half-open connection? */ - if (ssh->version == 1) - halfopen_ok = (pktin->type == SSH1_MSG_CHANNEL_OPEN_CONFIRMATION || - pktin->type == SSH1_MSG_CHANNEL_OPEN_FAILURE); - else - halfopen_ok = (pktin->type == SSH2_MSG_CHANNEL_OPEN_CONFIRMATION || - pktin->type == SSH2_MSG_CHANNEL_OPEN_FAILURE); - c = find234(ssh->channels, &localid, ssh_channelfind); - if (c && c->sharectx) { - share_got_pkt_from_server(c->sharectx, pktin->type, - BinarySource_UPCAST(pktin)->data, - BinarySource_UPCAST(pktin)->len); - return NULL; - } - if (!c || c->halfopen != halfopen_ok) { - char *buf = dupprintf("Received %s for %s channel %u", - ssh_pkt_type(ssh, pktin->type), - !c ? "nonexistent" : - c->halfopen ? "half-open" : "open", - localid); - ssh_disconnect(ssh, NULL, buf, SSH2_DISCONNECT_PROTOCOL_ERROR, FALSE); - sfree(buf); - return NULL; - } - return c; -} - -static void ssh2_handle_winadj_response(struct ssh_channel *c, - PktIn *pktin, void *ctx) -{ - unsigned *sizep = ctx; - - /* - * Winadj responses should always be failures. However, at least - * one server ("boks_sshd") is known to return SUCCESS for channel - * requests it's never heard of, such as "winadj@putty". Raised - * with foxt.com as bug 090916-090424, but for the sake of a quiet - * life, we don't worry about what kind of response we got. - */ - - c->v.v2.remlocwin += *sizep; - sfree(sizep); - /* - * winadj messages are only sent when the window is fully open, so - * if we get an ack of one, we know any pending unthrottle is - * complete. - */ - if (c->v.v2.throttle_state == UNTHROTTLING) - c->v.v2.throttle_state = UNTHROTTLED; -} - -static void ssh2_msg_channel_response(Ssh ssh, PktIn *pktin) -{ - struct ssh_channel *c = ssh_channel_msg(ssh, pktin); - struct outstanding_channel_request *ocr; - - if (!c) return; - ocr = c->v.v2.chanreq_head; - if (!ocr) { - ssh2_msg_unexpected(ssh, pktin); - return; - } - ocr->handler(c, pktin, ocr->ctx); - if (ssh->state == SSH_STATE_CLOSED) - return; /* in case the handler called bomb_out(), which some can */ - c->v.v2.chanreq_head = ocr->next; - sfree(ocr); - /* - * We may now initiate channel-closing procedures, if that - * CHANNEL_REQUEST was the last thing outstanding before we send - * CHANNEL_CLOSE. - */ - ssh2_channel_check_close(c); -} - -static void ssh2_msg_channel_window_adjust(Ssh ssh, PktIn *pktin) -{ - struct ssh_channel *c; - c = ssh_channel_msg(ssh, pktin); - if (!c) - return; - if (!(c->closes & CLOSES_SENT_EOF)) { - c->v.v2.remwindow += get_uint32(pktin); - ssh2_try_send_and_unthrottle(ssh, c); - } -} - -static void ssh2_msg_channel_data(Ssh ssh, PktIn *pktin) -{ - ptrlen data; - unsigned ext_type = 0; /* 0 means not extended */ - struct ssh_channel *c; - c = ssh_channel_msg(ssh, pktin); - if (!c) - return; - if (pktin->type == SSH2_MSG_CHANNEL_EXTENDED_DATA) - ext_type = get_uint32(pktin); - data = get_string(pktin); - if (!get_err(pktin)) { - int bufsize; - c->v.v2.locwindow -= data.len; - c->v.v2.remlocwin -= data.len; - if (ext_type != 0 && ext_type != SSH2_EXTENDED_DATA_STDERR) - data.len = 0; /* Don't do anything with unknown extended data. */ - bufsize = ssh_channel_data(c, ext_type == SSH2_EXTENDED_DATA_STDERR, - data.ptr, data.len); - /* - * If it looks like the remote end hit the end of its window, - * and we didn't want it to do that, think about using a - * larger window. - */ - if (c->v.v2.remlocwin <= 0 && c->v.v2.throttle_state == UNTHROTTLED && - c->v.v2.locmaxwin < 0x40000000) - c->v.v2.locmaxwin += OUR_V2_WINSIZE; - /* - * If we are not buffering too much data, - * enlarge the window again at the remote side. - * If we are buffering too much, we may still - * need to adjust the window if the server's - * sent excess data. - */ - if (bufsize < c->v.v2.locmaxwin) - ssh2_set_window(c, c->v.v2.locmaxwin - bufsize); - /* - * If we're either buffering way too much data, or if we're - * buffering anything at all and we're in "simple" mode, - * throttle the whole channel. - */ - if ((bufsize > c->v.v2.locmaxwin || (ssh_is_simple(ssh) && bufsize>0)) - && !c->throttling_conn) { - c->throttling_conn = 1; - ssh_throttle_conn(ssh, +1); - } - } -} - -static void ssh_check_termination(Ssh ssh) -{ - if (ssh->version == 2 && - !conf_get_int(ssh->conf, CONF_ssh_no_shell) && - (ssh->channels && count234(ssh->channels) == 0) && - !(ssh->connshare && share_ndownstreams(ssh->connshare) > 0)) { - /* - * We used to send SSH_MSG_DISCONNECT here, because I'd - * believed that _every_ conforming SSH-2 connection had to - * end with a disconnect being sent by at least one side; - * apparently I was wrong and it's perfectly OK to - * unceremoniously slam the connection shut when you're done, - * and indeed OpenSSH feels this is more polite than sending a - * DISCONNECT. So now we don't. - */ - ssh_disconnect(ssh, "All channels closed", NULL, 0, TRUE); - } -} - -/* - * Close any local socket and free any local resources associated with - * a channel. This converts the channel into a zombie. - */ -static void ssh_channel_close_local(struct ssh_channel *c, char const *reason) -{ - Ssh ssh = c->ssh; - const char *msg = NULL; - - if (c->sharectx) - return; - - msg = chan_log_close_msg(c->chan); - chan_free(c->chan); - c->chan = zombiechan_new(); - - if (msg != NULL) { - if (reason != NULL) - logeventf(ssh, "%s %s", msg, reason); - else - logevent(msg); - } -} - -static void ssh_channel_destroy(struct ssh_channel *c) -{ - Ssh ssh = c->ssh; - - ssh_channel_close_local(c, NULL); - - del234(ssh->channels, c); - if (ssh->version == 2) { - bufchain_clear(&c->v.v2.outbuffer); - assert(c->v.v2.chanreq_head == NULL); - } - sfree(c); - - /* - * If that was the last channel left open, we might need to - * terminate. - */ - ssh_check_termination(ssh); -} - -static void ssh2_channel_check_close(struct ssh_channel *c) -{ - Ssh ssh = c->ssh; - PktOut *pktout; - - assert(ssh->version == 2); - if (c->halfopen) { - /* - * If we've sent out our own CHANNEL_OPEN but not yet seen - * either OPEN_CONFIRMATION or OPEN_FAILURE in response, then - * it's too early to be sending close messages of any kind. - */ - return; - } - - if ((!((CLOSES_SENT_EOF | CLOSES_RCVD_EOF) & ~c->closes) || - chan_want_close(c->chan, (c->closes & CLOSES_SENT_EOF), - (c->closes & CLOSES_RCVD_EOF))) && - !c->v.v2.chanreq_head && - !(c->closes & CLOSES_SENT_CLOSE)) { - /* - * We have both sent and received EOF (or the channel is a - * zombie), and we have no outstanding channel requests, which - * means the channel is in final wind-up. But we haven't sent - * CLOSE, so let's do so now. - */ - pktout = ssh_bpp_new_pktout(ssh->bpp, SSH2_MSG_CHANNEL_CLOSE); - put_uint32(pktout, c->remoteid); - ssh2_pkt_send(ssh, pktout); - c->closes |= CLOSES_SENT_EOF | CLOSES_SENT_CLOSE; - } - - if (!((CLOSES_SENT_CLOSE | CLOSES_RCVD_CLOSE) & ~c->closes)) { - assert(c->v.v2.chanreq_head == NULL); - /* - * We have both sent and received CLOSE, which means we're - * completely done with the channel. - */ - ssh_channel_destroy(c); - } -} - -static void ssh_channel_got_eof(struct ssh_channel *c) -{ - if (c->closes & CLOSES_RCVD_EOF) - return; /* already seen EOF */ - c->closes |= CLOSES_RCVD_EOF; - - chan_send_eof(c->chan); -} - -static void ssh2_msg_channel_eof(Ssh ssh, PktIn *pktin) -{ - struct ssh_channel *c; - - c = ssh_channel_msg(ssh, pktin); - if (!c) - return; - ssh_channel_got_eof(c); - ssh2_channel_check_close(c); -} - -static void ssh2_msg_channel_close(Ssh ssh, PktIn *pktin) -{ - struct ssh_channel *c; - - c = ssh_channel_msg(ssh, pktin); - if (!c) - return; - - /* - * When we receive CLOSE on a channel, we assume it comes with an - * implied EOF if we haven't seen EOF yet. - */ - ssh_channel_got_eof(c); - - if (!(ssh->remote_bugs & BUG_SENDS_LATE_REQUEST_REPLY)) { - /* - * It also means we stop expecting to see replies to any - * outstanding channel requests, so clean those up too. - * (ssh_chanreq_init will enforce by assertion that we don't - * subsequently put anything back on this list.) - */ - while (c->v.v2.chanreq_head) { - struct outstanding_channel_request *ocr = c->v.v2.chanreq_head; - ocr->handler(c, NULL, ocr->ctx); - c->v.v2.chanreq_head = ocr->next; - sfree(ocr); - } - } - - /* - * And we also send an outgoing EOF, if we haven't already, on the - * assumption that CLOSE is a pretty forceful announcement that - * the remote side is doing away with the entire channel. (If it - * had wanted to send us EOF and continue receiving data from us, - * it would have just sent CHANNEL_EOF.) - */ - if (!(c->closes & CLOSES_SENT_EOF)) { - /* - * Abandon any buffered data we still wanted to send to this - * channel. Receiving a CHANNEL_CLOSE is an indication that - * the server really wants to get on and _destroy_ this - * channel, and it isn't going to send us any further - * WINDOW_ADJUSTs to permit us to send pending stuff. - */ - bufchain_clear(&c->v.v2.outbuffer); - - /* - * Send outgoing EOF. - */ - sshfwd_write_eof(&c->sc); - - /* - * Make sure we don't read any more from whatever our local - * data source is for this channel. (This will pick up on the - * changes made by sshfwd_write_eof.) - */ - ssh_channel_check_throttle(c); - } - - /* - * Now process the actual close. - */ - if (!(c->closes & CLOSES_RCVD_CLOSE)) { - c->closes |= CLOSES_RCVD_CLOSE; - ssh2_channel_check_close(c); - } -} - -static void ssh2_msg_channel_open_confirmation(Ssh ssh, PktIn *pktin) -{ - struct ssh_channel *c; - - c = ssh_channel_msg(ssh, pktin); - if (!c) - return; - assert(c->halfopen); /* ssh_channel_msg will have enforced this */ - c->remoteid = get_uint32(pktin); - c->halfopen = FALSE; - c->v.v2.remwindow = get_uint32(pktin); - c->v.v2.remmaxpkt = get_uint32(pktin); - - chan_open_confirmation(c->chan); - - /* - * Now that the channel is fully open, it's possible in principle - * to immediately close it. Check whether it wants us to! - * - * This can occur if a local socket error occurred between us - * sending out CHANNEL_OPEN and receiving OPEN_CONFIRMATION. If - * that happens, all we can do is immediately initiate close - * proceedings now that we know the server's id to put in the - * close message. We'll have handled that in this code by having - * already turned c->chan into a zombie, so its want_close method - * (which ssh2_channel_check_close will consult) will already be - * returning TRUE. - */ - ssh2_channel_check_close(c); - - if (c->pending_eof) - ssh_channel_try_eof(c); /* in case we had a pending EOF */ -} - -static char *ssh2_channel_open_failure_error_text(PktIn *pktin) -{ - static const char *const reasons[] = { - NULL, - "Administratively prohibited", - "Connect failed", - "Unknown channel type", - "Resource shortage", - }; - unsigned reason_code; - const char *reason_code_string; - char reason_code_buf[256]; - ptrlen reason; - - reason_code = get_uint32(pktin); - if (reason_code < lenof(reasons) && reasons[reason_code]) { - reason_code_string = reasons[reason_code]; - } else { - reason_code_string = reason_code_buf; - sprintf(reason_code_buf, "unknown reason code %#x", reason_code); - } - - reason = get_string(pktin); - - return dupprintf("%s [%.*s]", reason_code_string, PTRLEN_PRINTF(reason)); -} - -static void ssh2_msg_channel_open_failure(Ssh ssh, PktIn *pktin) -{ - struct ssh_channel *c; - - c = ssh_channel_msg(ssh, pktin); - if (!c) - return; - assert(c->halfopen); /* ssh_channel_msg will have enforced this */ - - { - char *errtext = ssh2_channel_open_failure_error_text(pktin); - chan_open_failed(c->chan, errtext); - sfree(errtext); - } - chan_free(c->chan); - - del234(ssh->channels, c); - sfree(c); -} - -static void ssh2_msg_channel_request(Ssh ssh, PktIn *pktin) -{ - ptrlen type; - int want_reply; - int reply = SSH2_MSG_CHANNEL_FAILURE; /* default */ - struct ssh_channel *c; - PktOut *pktout; - - c = ssh_channel_msg(ssh, pktin); - if (!c) - return; - type = get_string(pktin); - want_reply = get_bool(pktin); - - if (c->closes & CLOSES_SENT_CLOSE) { - /* - * We don't reply to channel requests after we've sent - * CHANNEL_CLOSE for the channel, because our reply might - * cross in the network with the other side's CHANNEL_CLOSE - * and arrive after they have wound the channel up completely. - */ - want_reply = FALSE; - } - - /* - * Having got the channel number, we now look at - * the request type string to see if it's something - * we recognise. - */ - if (c == ssh->mainchan) { - /* - * We recognise "exit-status" and "exit-signal" on - * the primary channel. - */ - if (ptrlen_eq_string(type, "exit-status")) { - - ssh->exitcode = get_uint32(pktin); - logeventf(ssh, "Server sent command exit status %d", - ssh->exitcode); - reply = SSH2_MSG_CHANNEL_SUCCESS; - - } else if (ptrlen_eq_string(type, "exit-signal")) { - char *fmt_sig = NULL, *fmt_msg = NULL; - ptrlen errmsg; - int core = FALSE; - int format, exitcode; - - /* ICK: older versions of OpenSSH (e.g. 3.4p1) - * provide an `int' for the signal, despite its - * having been a `string' in the drafts of RFC 4254 since at - * least 2001. (Fixed in session.c 1.147.) Try to - * infer which we can safely parse it as. */ - - size_t startpos = BinarySource_UPCAST(pktin)->pos; - - for (format = 0; format < 2; format++) { - BinarySource_UPCAST(pktin)->pos = startpos; - BinarySource_UPCAST(pktin)->err = BSE_NO_ERROR; - - if (format == 0) { /* standard string-based format */ - ptrlen signame = get_string(pktin); - fmt_sig = dupprintf(" \"%.*s\"", PTRLEN_PRINTF(signame)); - - /* - * Really hideous method of translating the - * signal description back into a locally - * meaningful number. - */ - - if (0) - ; -#define TRANSLATE_SIGNAL(s) \ - else if (ptrlen_eq_string(signame, #s)) \ - exitcode = 128 + SIG ## s -#ifdef SIGABRT - TRANSLATE_SIGNAL(ABRT); -#endif -#ifdef SIGALRM - TRANSLATE_SIGNAL(ALRM); -#endif -#ifdef SIGFPE - TRANSLATE_SIGNAL(FPE); -#endif -#ifdef SIGHUP - TRANSLATE_SIGNAL(HUP); -#endif -#ifdef SIGILL - TRANSLATE_SIGNAL(ILL); -#endif -#ifdef SIGINT - TRANSLATE_SIGNAL(INT); -#endif -#ifdef SIGKILL - TRANSLATE_SIGNAL(KILL); -#endif -#ifdef SIGPIPE - TRANSLATE_SIGNAL(PIPE); -#endif -#ifdef SIGQUIT - TRANSLATE_SIGNAL(QUIT); -#endif -#ifdef SIGSEGV - TRANSLATE_SIGNAL(SEGV); -#endif -#ifdef SIGTERM - TRANSLATE_SIGNAL(TERM); -#endif -#ifdef SIGUSR1 - TRANSLATE_SIGNAL(USR1); -#endif -#ifdef SIGUSR2 - TRANSLATE_SIGNAL(USR2); -#endif -#undef TRANSLATE_SIGNAL - else - exitcode = 128; - } else { /* nonstandard integer format */ - unsigned signum = get_uint32(pktin); - fmt_sig = dupprintf(" %u", signum); - exitcode = 128 + signum; - } - - core = get_bool(pktin); - errmsg = get_string(pktin); /* error message */ - get_string(pktin); /* language tag */ - if (!get_err(pktin) && get_avail(pktin) == 0) - break; /* successful parse */ - - sfree(fmt_sig); - } - - if (format == 2) { - fmt_sig = NULL; - exitcode = 128; - } - - ssh->exitcode = exitcode; - if (errmsg.len) { - fmt_msg = dupprintf(" (\"%.*s\")", PTRLEN_PRINTF(errmsg)); - } - - logeventf(ssh, "Server exited on signal%s%s%s", - fmt_sig ? fmt_sig : "", - core ? " (core dumped)" : "", - fmt_msg ? fmt_msg : ""); - sfree(fmt_sig); - sfree(fmt_msg); - reply = SSH2_MSG_CHANNEL_SUCCESS; - } - } else { - /* - * This is a channel request we don't know - * about, so we now either ignore the request - * or respond with CHANNEL_FAILURE, depending - * on want_reply. - */ - reply = SSH2_MSG_CHANNEL_FAILURE; - } - if (want_reply) { - pktout = ssh_bpp_new_pktout(ssh->bpp, reply); - put_uint32(pktout, c->remoteid); - ssh2_pkt_send(ssh, pktout); - } -} - -static void ssh2_msg_global_request(Ssh ssh, PktIn *pktin) -{ - int want_reply; - PktOut *pktout; - - get_string(pktin); /* ignore request type (see below) */ - want_reply = get_bool(pktin); - - /* - * We currently don't support any global requests - * at all, so we either ignore the request or - * respond with REQUEST_FAILURE, depending on - * want_reply. - */ - if (want_reply) { - pktout = ssh_bpp_new_pktout(ssh->bpp, SSH2_MSG_REQUEST_FAILURE); - ssh2_pkt_send(ssh, pktout); - } -} - -static struct X11FakeAuth *(ssh_add_sharing_x11_display)( - ConnectionLayer *cl, int authtype, ssh_sharing_connstate *share_cs, - share_channel *share_chan) -{ - Ssh ssh = FROMFIELD(cl, struct ssh_tag, cl); - struct X11FakeAuth *auth; - - /* - * Make up a new set of fake X11 auth data, and add it to the tree - * of currently valid ones with an indication of the sharing - * context that it's relevant to. - */ - auth = x11_invent_fake_auth(ssh->x11authtree, authtype); - auth->share_cs = share_cs; - auth->share_chan = share_chan; - - return auth; -} - -static void (ssh_remove_sharing_x11_display)( - ConnectionLayer *cl, struct X11FakeAuth *auth) -{ - Ssh ssh = FROMFIELD(cl, struct ssh_tag, cl); - del234(ssh->x11authtree, auth); - x11_free_fake_auth(auth); -} - -static void ssh2_msg_channel_open(Ssh ssh, PktIn *pktin) -{ - ptrlen type; - int peerport; - const char *error = NULL; - struct ssh_channel *c; - unsigned remid, winsize, pktsize; - PktOut *pktout; - - type = get_string(pktin); - c = snew(struct ssh_channel); - c->ssh = ssh; - - remid = get_uint32(pktin); - winsize = get_uint32(pktin); - pktsize = get_uint32(pktin); - - if (ptrlen_eq_string(type, "x11")) { - char *addrstr = mkstr(get_string(pktin)); - peerport = get_uint32(pktin); - - logeventf(ssh, "Received X11 connect request from %s:%d", - addrstr, peerport); - - if (!ssh->X11_fwd_enabled && !ssh->connshare) - error = "X11 forwarding is not enabled"; - else { - c->chan = x11_new_channel(ssh->x11authtree, &c->sc, - addrstr, peerport, - ssh->connshare != NULL); - logevent("Opened X11 forward channel"); - } - - sfree(addrstr); - } else if (ptrlen_eq_string(type, "forwarded-tcpip")) { - struct ssh_rportfwd pf, *realpf; - ptrlen peeraddr; - - pf.shost = mkstr(get_string(pktin)); - pf.sport = get_uint32(pktin); - peeraddr = get_string(pktin); - peerport = get_uint32(pktin); - realpf = find234(ssh->rportfwds, &pf, NULL); - logeventf(ssh, "Received remote port %s:%d open request " - "from %.*s:%d", pf.shost, pf.sport, - PTRLEN_PRINTF(peeraddr), peerport); - sfree(pf.shost); - - if (realpf == NULL) { - error = "Remote port is not recognised"; - } else { - char *err; - - if (realpf->share_ctx) { - /* - * This port forwarding is on behalf of a - * connection-sharing downstream, so abandon our own - * channel-open procedure and just pass the message on - * to sshshare.c. - */ - share_got_pkt_from_server(realpf->share_ctx, pktin->type, - BinarySource_UPCAST(pktin)->data, - BinarySource_UPCAST(pktin)->len); - sfree(c); - return; - } - - err = portfwdmgr_connect( - ssh->portfwdmgr, &c->chan, realpf->dhost, realpf->dport, - &c->sc, realpf->addressfamily); - logeventf(ssh, "Attempting to forward remote port to " - "%s:%d", realpf->dhost, realpf->dport); - if (err != NULL) { - logeventf(ssh, "Port open failed: %s", err); - sfree(err); - error = "Port open failed"; - } else { - logevent("Forwarded port opened successfully"); - } - } - } else if (ptrlen_eq_string(type, "auth-agent@openssh.com")) { - if (!ssh->agentfwd_enabled) - error = "Agent forwarding is not enabled"; - else - c->chan = agentf_new(&c->sc); - } else { - error = "Unsupported channel type requested"; - } - - c->remoteid = remid; - c->halfopen = FALSE; - if (error) { - pktout = ssh_bpp_new_pktout(ssh->bpp, SSH2_MSG_CHANNEL_OPEN_FAILURE); - put_uint32(pktout, c->remoteid); - put_uint32(pktout, SSH2_OPEN_CONNECT_FAILED); - put_stringz(pktout, error); - put_stringz(pktout, "en"); /* language tag */ - ssh2_pkt_send(ssh, pktout); - logeventf(ssh, "Rejected channel open: %s", error); - sfree(c); - } else { - ssh_channel_init(c); - c->v.v2.remwindow = winsize; - c->v.v2.remmaxpkt = pktsize; - if (c->chan->initial_fixed_window_size) { - c->v.v2.locwindow = c->v.v2.locmaxwin = c->v.v2.remlocwin = - c->chan->initial_fixed_window_size; - } - pktout = ssh_bpp_new_pktout( - ssh->bpp, SSH2_MSG_CHANNEL_OPEN_CONFIRMATION); - put_uint32(pktout, c->remoteid); - put_uint32(pktout, c->localid); - put_uint32(pktout, c->v.v2.locwindow); - put_uint32(pktout, OUR_V2_MAXPKT); /* our max pkt size */ - ssh2_pkt_send(ssh, pktout); - } -} - -static void sshchannel_x11_sharing_handover( - SshChannel *sc, ssh_sharing_connstate *share_cs, share_channel *share_chan, - const char *peer_addr, int peer_port, int endian, - int protomajor, int protominor, const void *initial_data, int initial_len) -{ - struct ssh_channel *c = FROMFIELD(sc, struct ssh_channel, sc); - - /* - * This function is called when we've just discovered that an X - * forwarding channel on which we'd been handling the initial auth - * ourselves turns out to be destined for a connection-sharing - * downstream. So we turn the channel into a sharing one, meaning - * that we completely stop tracking windows and buffering data and - * just pass more or less unmodified SSH messages back and forth. - */ - c->sharectx = share_cs; - share_setup_x11_channel(share_cs, share_chan, - c->localid, c->remoteid, c->v.v2.remwindow, - c->v.v2.remmaxpkt, c->v.v2.locwindow, - peer_addr, peer_port, endian, - protomajor, protominor, - initial_data, initial_len); - chan_free(c->chan); - c->chan = NULL; -} - -static void sshchannel_window_override_removed(SshChannel *sc) -{ - struct ssh_channel *c = FROMFIELD(sc, struct ssh_channel, sc); - - /* - * This function is called when a client-side Channel has just - * stopped requiring an initial fixed-size window. - */ - assert(!c->chan->initial_fixed_window_size); - if (c->ssh->version == 2) - ssh2_set_window( - c, ssh_is_simple(c->ssh) ? OUR_V2_BIGWIN : OUR_V2_WINSIZE); -} - -/* - * Buffer banner messages for later display at some convenient point, - * if we're going to display them. - */ -static void ssh2_msg_userauth_banner(Ssh ssh, PktIn *pktin) -{ - /* Arbitrary limit to prevent unbounded inflation of buffer */ - if (conf_get_int(ssh->conf, CONF_ssh_show_banner) && - bufchain_size(&ssh->banner) <= 131072) { - ptrlen banner = get_string(pktin); - if (banner.len) - sanitise_term_data(&ssh->banner, banner.ptr, banner.len); - } -} - -static void ssh2_setup_x11(struct ssh_channel *c, PktIn *pktin, - void *ctx) -{ - struct ssh2_setup_x11_state { - int crLine; - }; - Ssh ssh = c->ssh; - PktOut *pktout; - crStateP(ssh2_setup_x11_state, ctx); - - crBeginState; - - logevent("Requesting X11 forwarding"); - pktout = ssh2_chanreq_init(ssh->mainchan, "x11-req", - ssh2_setup_x11, s); - put_bool(pktout, 0); /* many connections */ - put_stringz(pktout, ssh->x11auth->protoname); - put_stringz(pktout, ssh->x11auth->datastring); - put_uint32(pktout, ssh->x11disp->screennum); - ssh2_pkt_send(ssh, pktout); - - /* Wait to be called back with either a response packet, or NULL - * meaning clean up and free our data */ - crReturnV; - - if (pktin) { - if (pktin->type == SSH2_MSG_CHANNEL_SUCCESS) { - logevent("X11 forwarding enabled"); - ssh->X11_fwd_enabled = TRUE; - } else - logevent("X11 forwarding refused"); - } - - crFinishFreeV; -} - -static void ssh2_setup_agent(struct ssh_channel *c, PktIn *pktin, - void *ctx) -{ - struct ssh2_setup_agent_state { - int crLine; - }; - Ssh ssh = c->ssh; - PktOut *pktout; - crStateP(ssh2_setup_agent_state, ctx); - - crBeginState; - - logevent("Requesting OpenSSH-style agent forwarding"); - pktout = ssh2_chanreq_init(ssh->mainchan, "auth-agent-req@openssh.com", - ssh2_setup_agent, s); - ssh2_pkt_send(ssh, pktout); - - /* Wait to be called back with either a response packet, or NULL - * meaning clean up and free our data */ - crReturnV; - - if (pktin) { - if (pktin->type == SSH2_MSG_CHANNEL_SUCCESS) { - logevent("Agent forwarding enabled"); - ssh->agentfwd_enabled = TRUE; - } else - logevent("Agent forwarding refused"); - } - - crFinishFreeV; -} - -static void ssh2_setup_pty(struct ssh_channel *c, PktIn *pktin, - void *ctx) -{ - struct ssh2_setup_pty_state { - int crLine; - }; - Ssh ssh = c->ssh; - PktOut *pktout; - crStateP(ssh2_setup_pty_state, ctx); - - crBeginState; - - /* Unpick the terminal-speed string. */ - /* XXX perhaps we should allow no speeds to be sent. */ - ssh->ospeed = 38400; ssh->ispeed = 38400; /* last-resort defaults */ - sscanf(conf_get_str(ssh->conf, CONF_termspeed), "%d,%d", &ssh->ospeed, &ssh->ispeed); - /* Build the pty request. */ - pktout = ssh2_chanreq_init(ssh->mainchan, "pty-req", - ssh2_setup_pty, s); - put_stringz(pktout, conf_get_str(ssh->conf, CONF_termtype)); - put_uint32(pktout, ssh->term_width); - put_uint32(pktout, ssh->term_height); - put_uint32(pktout, 0); /* pixel width */ - put_uint32(pktout, 0); /* pixel height */ - { - strbuf *modebuf = strbuf_new(); - write_ttymodes_to_packet_from_conf( - BinarySink_UPCAST(modebuf), ssh->frontend, ssh->conf, - 2, ssh->ospeed, ssh->ispeed); - put_stringsb(pktout, modebuf); - } - ssh2_pkt_send(ssh, pktout); - ssh->state = SSH_STATE_INTERMED; - - /* Wait to be called back with either a response packet, or NULL - * meaning clean up and free our data */ - crReturnV; - - if (pktin) { - if (pktin->type == SSH2_MSG_CHANNEL_SUCCESS) { - logeventf(ssh, "Allocated pty (ospeed %dbps, ispeed %dbps)", - ssh->ospeed, ssh->ispeed); - ssh->got_pty = TRUE; - } else { - c_write_str(ssh, "Server refused to allocate pty\r\n"); - ssh->editing = ssh->echoing = 1; - } - } - - crFinishFreeV; -} - -static void ssh2_setup_env(struct ssh_channel *c, PktIn *pktin, - void *ctx) -{ - struct ssh2_setup_env_state { - int crLine; - int num_env, env_left, env_ok; - }; - Ssh ssh = c->ssh; - PktOut *pktout; - crStateP(ssh2_setup_env_state, ctx); - - crBeginState; - - /* - * Send environment variables. - * - * Simplest thing here is to send all the requests at once, and - * then wait for a whole bunch of successes or failures. - */ - s->num_env = 0; - { - char *key, *val; - - for (val = conf_get_str_strs(ssh->conf, CONF_environmt, NULL, &key); - val != NULL; - val = conf_get_str_strs(ssh->conf, CONF_environmt, key, &key)) { - pktout = ssh2_chanreq_init(ssh->mainchan, "env", ssh2_setup_env, s); - put_stringz(pktout, key); - put_stringz(pktout, val); - ssh2_pkt_send(ssh, pktout); - - s->num_env++; - } - if (s->num_env) - logeventf(ssh, "Sent %d environment variables", s->num_env); - } - - if (s->num_env) { - s->env_ok = 0; - s->env_left = s->num_env; - - while (s->env_left > 0) { - /* Wait to be called back with either a response packet, - * or NULL meaning clean up and free our data */ - crReturnV; - if (!pktin) goto out; - if (pktin->type == SSH2_MSG_CHANNEL_SUCCESS) - s->env_ok++; - s->env_left--; - } - - if (s->env_ok == s->num_env) { - logevent("All environment variables successfully set"); - } else if (s->env_ok == 0) { - logevent("All environment variables refused"); - c_write_str(ssh, "Server refused to set environment variables\r\n"); - } else { - logeventf(ssh, "%d environment variables refused", - s->num_env - s->env_ok); - c_write_str(ssh, "Server refused to set all environment variables\r\n"); - } - } - out:; - crFinishFreeV; -} - -/* - * Handle the SSH-2 userauth layer. - */ -static void ssh2_msg_userauth(Ssh ssh, PktIn *pktin) -{ - pq_push(&ssh->pq_ssh2_userauth, pktin); - if (pktin->type == SSH2_MSG_USERAUTH_SUCCESS) { - /* - * The very instant we see this message, the connection - * protocol has officially started, which means we must - * install the dispatch-table entries for all the - * connection-layer messages. In particular, we must do this - * _before_ we return to the loop in ssh_process_incoming_pkts - * that's processing the currently queued packets through the - * dispatch table, because if (say) an SSH_MSG_GLOBAL_REQUEST - * is already pending in in_pq, we can't afford to delay - * installing its dispatch table entry until after that queue - * run is done. - */ - ssh2_connection_setup(ssh); - } - queue_idempotent_callback(&ssh->ssh2_userauth_icb); -} - -static void do_ssh2_userauth(void *vctx) -{ - Ssh ssh = (Ssh)vctx; - PktIn *pktin; - - struct do_ssh2_userauth_state { - int crLine; - enum { - AUTH_TYPE_NONE, - AUTH_TYPE_PUBLICKEY, - AUTH_TYPE_PUBLICKEY_OFFER_LOUD, - AUTH_TYPE_PUBLICKEY_OFFER_QUIET, - AUTH_TYPE_PASSWORD, - AUTH_TYPE_GSSAPI, /* always QUIET */ - AUTH_TYPE_KEYBOARD_INTERACTIVE, - AUTH_TYPE_KEYBOARD_INTERACTIVE_QUIET - } type; - int done_service_req; - int need_pw, can_pubkey, can_passwd, can_keyb_inter; - int userpass_ret; - int tried_pubkey_config, done_agent; -#ifndef NO_GSSAPI - int can_gssapi; - int can_gssapi_keyex_auth; - int tried_gssapi; - int tried_gssapi_keyex_auth; - time_t gss_cred_expiry; -#endif - int kbd_inter_refused; - int we_are_in, userauth_success; - prompts_t *cur_prompt; - int num_prompts; - char *username; - char *password; - int got_username; - strbuf *publickey_blob; - int privatekey_available, privatekey_encrypted; - char *publickey_algorithm; - char *publickey_comment; - unsigned char *agent_response; - BinarySource asrc[1]; /* for reading SSH agent response */ - size_t pkblob_pos_in_agent; - int keyi, nkeys; - ptrlen pk, alg, comment; - int len; - PktOut *pktout; - Filename *keyfile; -#ifndef NO_GSSAPI - Ssh_gss_ctx gss_ctx; - Ssh_gss_buf gss_buf; - Ssh_gss_buf gss_rcvtok, gss_sndtok; - Ssh_gss_stat gss_stat; -#endif - }; - crState(do_ssh2_userauth_state); - - crBeginState; - - /* Register as a handler for all the messages this coroutine handles. */ - ssh->packet_dispatch[SSH2_MSG_SERVICE_ACCEPT] = ssh2_msg_userauth; - ssh->packet_dispatch[SSH2_MSG_USERAUTH_REQUEST] = ssh2_msg_userauth; - ssh->packet_dispatch[SSH2_MSG_USERAUTH_FAILURE] = ssh2_msg_userauth; - ssh->packet_dispatch[SSH2_MSG_USERAUTH_SUCCESS] = ssh2_msg_userauth; - ssh->packet_dispatch[SSH2_MSG_USERAUTH_BANNER] = ssh2_msg_userauth; - ssh->packet_dispatch[SSH2_MSG_USERAUTH_PK_OK] = ssh2_msg_userauth; - /* ssh->packet_dispatch[SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ] = ssh2_msg_userauth; duplicate case value */ - /* ssh->packet_dispatch[SSH2_MSG_USERAUTH_INFO_REQUEST] = ssh2_msg_userauth; duplicate case value */ - ssh->packet_dispatch[SSH2_MSG_USERAUTH_INFO_RESPONSE] = ssh2_msg_userauth; - - s->done_service_req = FALSE; - s->we_are_in = s->userauth_success = FALSE; - s->agent_response = NULL; -#ifndef NO_GSSAPI - s->tried_gssapi = FALSE; - s->tried_gssapi_keyex_auth = FALSE; -#endif - - if (!conf_get_int(ssh->conf, CONF_ssh_no_userauth)) { - /* - * Request userauth protocol, and await a response to it. - */ - s->pktout = ssh_bpp_new_pktout(ssh->bpp, SSH2_MSG_SERVICE_REQUEST); - put_stringz(s->pktout, "ssh-userauth"); - ssh2_pkt_send(ssh, s->pktout); - crMaybeWaitUntilV((pktin = pq_pop(&ssh->pq_ssh2_userauth)) != NULL); - if (pktin->type == SSH2_MSG_SERVICE_ACCEPT) - s->done_service_req = TRUE; - } - if (!s->done_service_req) { - /* - * Request connection protocol directly, without authentication. - */ - s->pktout = ssh_bpp_new_pktout(ssh->bpp, SSH2_MSG_SERVICE_REQUEST); - put_stringz(s->pktout, "ssh-connection"); - ssh2_pkt_send(ssh, s->pktout); - crMaybeWaitUntilV((pktin = pq_pop(&ssh->pq_ssh2_userauth)) != NULL); - if (pktin->type == SSH2_MSG_SERVICE_ACCEPT) { - s->we_are_in = TRUE; /* no auth required */ - } else { - bombout(("Server refused service request")); - crStopV; - } - } - - /* Arrange to be able to deal with any BANNERs that come in. - * (We do this now as packets may come in during the next bit.) */ - bufchain_init(&ssh->banner); - ssh->packet_dispatch[SSH2_MSG_USERAUTH_BANNER] = - ssh2_msg_userauth_banner; - - /* - * Misc one-time setup for authentication. - */ - s->publickey_blob = NULL; - if (!s->we_are_in) { - - /* - * Load the public half of any configured public key file - * for later use. - */ - s->keyfile = conf_get_filename(ssh->conf, CONF_keyfile); - if (!filename_is_null(s->keyfile)) { - int keytype; - logeventf(ssh, "Reading key file \"%.150s\"", - filename_to_str(s->keyfile)); - keytype = key_type(s->keyfile); - if (keytype == SSH_KEYTYPE_SSH2 || - keytype == SSH_KEYTYPE_SSH2_PUBLIC_RFC4716 || - keytype == SSH_KEYTYPE_SSH2_PUBLIC_OPENSSH) { - const char *error; - s->publickey_blob = strbuf_new(); - if (ssh2_userkey_loadpub(s->keyfile, - &s->publickey_algorithm, - BinarySink_UPCAST(s->publickey_blob), - &s->publickey_comment, &error)) { - s->privatekey_available = (keytype == SSH_KEYTYPE_SSH2); - if (!s->privatekey_available) - logeventf(ssh, "Key file contains public key only"); - s->privatekey_encrypted = - ssh2_userkey_encrypted(s->keyfile, NULL); - } else { - char *msgbuf; - logeventf(ssh, "Unable to load key (%s)", - error); - msgbuf = dupprintf("Unable to load key file " - "\"%.150s\" (%s)\r\n", - filename_to_str(s->keyfile), - error); - c_write_str(ssh, msgbuf); - sfree(msgbuf); - strbuf_free(s->publickey_blob); - s->publickey_blob = NULL; - } - } else { - char *msgbuf; - logeventf(ssh, "Unable to use this key file (%s)", - key_type_to_str(keytype)); - msgbuf = dupprintf("Unable to use key file \"%.150s\"" - " (%s)\r\n", - filename_to_str(s->keyfile), - key_type_to_str(keytype)); - c_write_str(ssh, msgbuf); - sfree(msgbuf); - s->publickey_blob = NULL; - } - } - - /* - * Find out about any keys Pageant has (but if there's a - * public key configured, filter out all others). - */ - s->nkeys = 0; - s->agent_response = NULL; - s->pkblob_pos_in_agent = 0; - if (conf_get_int(ssh->conf, CONF_tryagent) && agent_exists()) { - void *r; - int rlen; - strbuf *agent_request; - - logevent("Pageant is running. Requesting keys."); - - /* Request the keys held by the agent. */ - agent_request = strbuf_new_for_agent_query(); - put_byte(agent_request, SSH2_AGENTC_REQUEST_IDENTITIES); - ssh->auth_agent_query = agent_query( - agent_request, &r, &rlen, ssh_agent_callback, ssh); - strbuf_free(agent_request); - - if (ssh->auth_agent_query) { - ssh->agent_response = NULL; - crWaitUntilV(ssh->agent_response); - r = ssh->agent_response; - rlen = ssh->agent_response_len; - } - s->agent_response = r; - BinarySource_BARE_INIT(s->asrc, r, rlen); - get_uint32(s->asrc); /* skip length field */ - if (get_byte(s->asrc) == SSH2_AGENT_IDENTITIES_ANSWER) { - int keyi; - - s->nkeys = toint(get_uint32(s->asrc)); - - /* - * Vet the Pageant response to ensure that the key - * count and blob lengths make sense. - */ - if (s->nkeys < 0) { - logeventf(ssh, "Pageant response contained a negative" - " key count %d", s->nkeys); - s->nkeys = 0; - goto done_agent_query; - } else { - logeventf(ssh, "Pageant has %d SSH-2 keys", s->nkeys); - - /* See if configured key is in agent. */ - for (keyi = 0; keyi < s->nkeys; keyi++) { - size_t pos = s->asrc->pos; - ptrlen blob = get_string(s->asrc); - get_string(s->asrc); /* skip comment */ - if (get_err(s->asrc)) { - logeventf(ssh, "Pageant response was truncated"); - s->nkeys = 0; - goto done_agent_query; - } - - if (s->publickey_blob && - blob.len == s->publickey_blob->len && - !memcmp(blob.ptr, s->publickey_blob->s, - s->publickey_blob->len)) { - logeventf(ssh, "Pageant key #%d matches " - "configured key file", keyi); - s->keyi = keyi; - s->pkblob_pos_in_agent = pos; - break; - } - } - if (s->publickey_blob && !s->pkblob_pos_in_agent) { - logevent("Configured key file not in Pageant"); - s->nkeys = 0; - } - } - } else { - logevent("Failed to get reply from Pageant"); - } - done_agent_query:; - } - - } - - /* - * We repeat this whole loop, including the username prompt, - * until we manage a successful authentication. If the user - * types the wrong _password_, they can be sent back to the - * beginning to try another username, if this is configured on. - * (If they specify a username in the config, they are never - * asked, even if they do give a wrong password.) - * - * I think this best serves the needs of - * - * - the people who have no configuration, no keys, and just - * want to try repeated (username,password) pairs until they - * type both correctly - * - * - people who have keys and configuration but occasionally - * need to fall back to passwords - * - * - people with a key held in Pageant, who might not have - * logged in to a particular machine before; so they want to - * type a username, and then _either_ their key will be - * accepted, _or_ they will type a password. If they mistype - * the username they will want to be able to get back and - * retype it! - */ - s->got_username = FALSE; - while (!s->we_are_in) { - /* - * Get a username. - */ - if (s->got_username && !conf_get_int(ssh->conf, CONF_change_username)) { - /* - * We got a username last time round this loop, and - * with change_username turned off we don't try to get - * it again. - */ - } else if ((ssh->username = get_remote_username(ssh->conf)) == NULL) { - s->cur_prompt = new_prompts(ssh->frontend); - s->cur_prompt->to_server = TRUE; - s->cur_prompt->name = dupstr("SSH login name"); - add_prompt(s->cur_prompt, dupstr("login as: "), TRUE); - s->userpass_ret = get_userpass_input(s->cur_prompt, NULL); - while (1) { - while (s->userpass_ret < 0 && - bufchain_size(&ssh->user_input) > 0) - s->userpass_ret = get_userpass_input( - s->cur_prompt, &ssh->user_input); - - if (s->userpass_ret >= 0) - break; - - ssh->send_ok = 1; - crReturnV; - ssh->send_ok = 0; - } - if (!s->userpass_ret) { - /* - * get_userpass_input() failed to get a username. - * Terminate. - */ - free_prompts(s->cur_prompt); - ssh_disconnect(ssh, "No username provided", NULL, 0, TRUE); - crStopV; - } - ssh->username = dupstr(s->cur_prompt->prompts[0]->result); - free_prompts(s->cur_prompt); - } else { - char *stuff; - if ((flags & FLAG_VERBOSE) || (flags & FLAG_INTERACTIVE)) { - stuff = dupprintf("Using username \"%s\".\r\n", ssh->username); - c_write_str(ssh, stuff); - sfree(stuff); - } - } - s->got_username = TRUE; - - /* - * Send an authentication request using method "none": (a) - * just in case it succeeds, and (b) so that we know what - * authentication methods we can usefully try next. - */ - ssh->pls.actx = SSH2_PKTCTX_NOAUTH; - - s->pktout = ssh_bpp_new_pktout(ssh->bpp, SSH2_MSG_USERAUTH_REQUEST); - put_stringz(s->pktout, ssh->username); - put_stringz(s->pktout, "ssh-connection");/* service requested */ - put_stringz(s->pktout, "none"); /* method */ - ssh2_pkt_send(ssh, s->pktout); - s->type = AUTH_TYPE_NONE; - s->we_are_in = FALSE; - - s->tried_pubkey_config = FALSE; - s->kbd_inter_refused = FALSE; - - /* Reset agent request state. */ - s->done_agent = FALSE; - if (s->agent_response) { - if (s->pkblob_pos_in_agent) { - s->asrc->pos = s->pkblob_pos_in_agent; - } else { - s->asrc->pos = 9; /* skip length + type + key count */ - s->keyi = 0; - } - } - - while (1) { - ptrlen methods; - - methods.ptr = ""; - methods.len = 0; - - /* - * Wait for the result of the last authentication request. - */ - crMaybeWaitUntilV((pktin = pq_pop(&ssh->pq_ssh2_userauth)) != NULL); - - /* - * Now is a convenient point to spew any banner material - * that we've accumulated. (This should ensure that when - * we exit the auth loop, we haven't any left to deal - * with.) - */ - { - int size = bufchain_size(&ssh->banner); - /* - * Don't show the banner if we're operating in - * non-verbose non-interactive mode. (It's probably - * a script, which means nobody will read the - * banner _anyway_, and moreover the printing of - * the banner will screw up processing on the - * output of (say) plink.) - * - * The banner data has been sanitised already by this - * point, so we can safely send it straight to the - * output channel. - */ - if (size && (flags & (FLAG_VERBOSE | FLAG_INTERACTIVE))) { - char *banner = snewn(size, char); - bufchain_fetch(&ssh->banner, banner, size); - c_write(ssh, banner, size); - sfree(banner); - } - bufchain_clear(&ssh->banner); - } - if (pktin->type == SSH2_MSG_USERAUTH_SUCCESS) { - logevent("Access granted"); - s->we_are_in = s->userauth_success = TRUE; - break; - } - - if (pktin->type != SSH2_MSG_USERAUTH_FAILURE && s->type != AUTH_TYPE_GSSAPI) { - bombout(("Strange packet received during authentication: " - "type %d", pktin->type)); - crStopV; - } - - /* - * OK, we're now sitting on a USERAUTH_FAILURE message, so - * we can look at the string in it and know what we can - * helpfully try next. - */ - if (pktin->type == SSH2_MSG_USERAUTH_FAILURE) { - methods = get_string(pktin); - if (!get_bool(pktin)) { - /* - * We have received an unequivocal Access - * Denied. This can translate to a variety of - * messages, or no message at all. - * - * For forms of authentication which are attempted - * implicitly, by which I mean without printing - * anything in the window indicating that we're - * trying them, we should never print 'Access - * denied'. - * - * If we do print a message saying that we're - * attempting some kind of authentication, it's OK - * to print a followup message saying it failed - - * but the message may sometimes be more specific - * than simply 'Access denied'. - * - * Additionally, if we'd just tried password - * authentication, we should break out of this - * whole loop so as to go back to the username - * prompt (iff we're configured to allow - * username change attempts). - */ - if (s->type == AUTH_TYPE_NONE) { - /* do nothing */ - } else if (s->type == AUTH_TYPE_PUBLICKEY_OFFER_LOUD || - s->type == AUTH_TYPE_PUBLICKEY_OFFER_QUIET) { - if (s->type == AUTH_TYPE_PUBLICKEY_OFFER_LOUD) - c_write_str(ssh, "Server refused our key\r\n"); - logevent("Server refused our key"); - } else if (s->type == AUTH_TYPE_PUBLICKEY) { - /* This _shouldn't_ happen except by a - * protocol bug causing client and server to - * disagree on what is a correct signature. */ - c_write_str(ssh, "Server refused public-key signature" - " despite accepting key!\r\n"); - logevent("Server refused public-key signature" - " despite accepting key!"); - } else if (s->type==AUTH_TYPE_KEYBOARD_INTERACTIVE_QUIET) { - /* quiet, so no c_write */ - logevent("Server refused keyboard-interactive authentication"); - } else if (s->type==AUTH_TYPE_GSSAPI) { - /* always quiet, so no c_write */ - /* also, the code down in the GSSAPI block has - * already logged this in the Event Log */ - } else if (s->type == AUTH_TYPE_KEYBOARD_INTERACTIVE) { - logevent("Keyboard-interactive authentication failed"); - c_write_str(ssh, "Access denied\r\n"); - } else { - assert(s->type == AUTH_TYPE_PASSWORD); - logevent("Password authentication failed"); - c_write_str(ssh, "Access denied\r\n"); - - if (conf_get_int(ssh->conf, CONF_change_username)) { - /* XXX perhaps we should allow - * keyboard-interactive to do this too? */ - s->we_are_in = FALSE; - break; - } - } - } else { - c_write_str(ssh, "Further authentication required\r\n"); - logevent("Further authentication required"); - } - - s->can_pubkey = - in_commasep_string("publickey", methods.ptr, methods.len); - s->can_passwd = - in_commasep_string("password", methods.ptr, methods.len); - s->can_keyb_inter = - conf_get_int(ssh->conf, CONF_try_ki_auth) && - in_commasep_string("keyboard-interactive", - methods.ptr, methods.len); -#ifndef NO_GSSAPI - s->can_gssapi = - conf_get_int(ssh->conf, CONF_try_gssapi_auth) && - in_commasep_string("gssapi-with-mic", - methods.ptr, methods.len) && - ssh->gsslibs->nlibraries > 0; - s->can_gssapi_keyex_auth = - conf_get_int(ssh->conf, CONF_try_gssapi_kex) && - in_commasep_string("gssapi-keyex", - methods.ptr, methods.len) && - ssh->gsslibs->nlibraries > 0 && - ssh->gss_ctx; -#endif - } + connection_layer = ssh1_connection_new(ssh, ssh->conf, &ssh->cl); + ssh_connect_ppl(ssh, connection_layer); - ssh->pls.actx = SSH2_PKTCTX_NOAUTH; + ssh->base_layer = ssh1_login_new( + ssh->conf, ssh->savedhost, ssh->savedport, connection_layer); + ssh_connect_ppl(ssh, ssh->base_layer); -#ifndef NO_GSSAPI - if (s->can_gssapi_keyex_auth && !s->tried_gssapi_keyex_auth) { + } - /* gssapi-keyex authentication */ + } else { + ssh->bpp = ssh2_bare_bpp_new(); + ssh_connect_bpp(ssh); - s->type = AUTH_TYPE_GSSAPI; - s->tried_gssapi_keyex_auth = TRUE; - ssh->pls.actx = SSH2_PKTCTX_GSSAPI; + connection_layer = ssh2_connection_new( + ssh, NULL, FALSE, ssh->conf, ssh_verstring_get_remote(old_bpp), + &ssh->cl); + ssh_connect_ppl(ssh, connection_layer); + ssh->base_layer = connection_layer; + } - if (ssh->gsslib->gsslogmsg) - logevent(ssh->gsslib->gsslogmsg); + /* Connect the base layer - whichever it is - to the BPP, and set + * up its selfptr. */ + ssh->base_layer->selfptr = &ssh->base_layer; + ssh_ppl_setup_queues(ssh->base_layer, &ssh->bpp->in_pq, &ssh->bpp->out_pq); - logeventf(ssh, "Trying gssapi-keyex..."); - s->pktout = - ssh2_gss_authpacket(ssh, ssh->gss_ctx, "gssapi-keyex"); - ssh2_pkt_send(ssh, s->pktout); - ssh->gsslib->release_cred(ssh->gsslib, &ssh->gss_ctx); - ssh->gss_ctx = NULL; + update_specials_menu(ssh->frontend); + ssh->pinger = pinger_new(ssh->conf, &ssh->backend); - continue; - } else -#endif /* NO_GSSAPI */ + queue_idempotent_callback(&ssh->bpp->ic_in_raw); + ssh_ppl_process_queue(ssh->base_layer); - if (s->can_pubkey && !s->done_agent && s->nkeys) { + /* Pass in the initial terminal size, if we knew it already. */ + ssh_terminal_size(ssh->cl, ssh->term_width, ssh->term_height); - /* - * Attempt public-key authentication using a key from Pageant. - */ + ssh_bpp_free(old_bpp); +} - ssh->pls.actx = SSH2_PKTCTX_PUBLICKEY; +static void ssh_bpp_output_raw_data_callback(void *vctx) +{ + Ssh ssh = (Ssh)vctx; - logeventf(ssh, "Trying Pageant key #%d", s->keyi); + if (!ssh->s) + return; - /* Unpack key from agent response */ - s->pk = get_string(s->asrc); - s->comment = get_string(s->asrc); - { - BinarySource src[1]; - BinarySource_BARE_INIT(src, s->pk.ptr, s->pk.len); - s->alg = get_string(src); - } + while (bufchain_size(&ssh->out_raw) > 0) { + void *data; + int len, backlog; - /* See if server will accept it */ - s->pktout = ssh_bpp_new_pktout( - ssh->bpp, SSH2_MSG_USERAUTH_REQUEST); - put_stringz(s->pktout, ssh->username); - put_stringz(s->pktout, "ssh-connection"); - /* service requested */ - put_stringz(s->pktout, "publickey"); - /* method */ - put_bool(s->pktout, FALSE); /* no signature included */ - put_stringpl(s->pktout, s->alg); - put_stringpl(s->pktout, s->pk); - ssh2_pkt_send(ssh, s->pktout); - s->type = AUTH_TYPE_PUBLICKEY_OFFER_QUIET; - - crMaybeWaitUntilV((pktin = pq_pop(&ssh->pq_ssh2_userauth)) != NULL); - if (pktin->type != SSH2_MSG_USERAUTH_PK_OK) { - - /* Offer of key refused, presumably via - * USERAUTH_FAILURE. Requeue for the next iteration. */ - pq_push_front(&ssh->pq_ssh2_userauth, pktin); - - } else { - strbuf *agentreq, *sigdata; - void *r; - int rlen; - - if (flags & FLAG_VERBOSE) { - c_write_str(ssh, "Authenticating with " - "public key \""); - c_write(ssh, s->comment.ptr, s->comment.len); - c_write_str(ssh, "\" from agent\r\n"); - } - - /* - * Server is willing to accept the key. - * Construct a SIGN_REQUEST. - */ - s->pktout = ssh_bpp_new_pktout( - ssh->bpp, SSH2_MSG_USERAUTH_REQUEST); - put_stringz(s->pktout, ssh->username); - put_stringz(s->pktout, "ssh-connection"); - /* service requested */ - put_stringz(s->pktout, "publickey"); - /* method */ - put_bool(s->pktout, TRUE); /* signature included */ - put_stringpl(s->pktout, s->alg); - put_stringpl(s->pktout, s->pk); - - /* Ask agent for signature. */ - agentreq = strbuf_new_for_agent_query(); - put_byte(agentreq, SSH2_AGENTC_SIGN_REQUEST); - put_stringpl(agentreq, s->pk); - /* Now the data to be signed... */ - sigdata = strbuf_new(); - if (ssh->remote_bugs & BUG_SSH2_PK_SESSIONID) { - put_data(sigdata, ssh->v2_session_id, - ssh->v2_session_id_len); - } else { - put_string(sigdata, ssh->v2_session_id, - ssh->v2_session_id_len); - } - put_data(sigdata, s->pktout->data + 5, - s->pktout->length - 5); - put_stringsb(agentreq, sigdata); - /* And finally the (zero) flags word. */ - put_uint32(agentreq, 0); - ssh->auth_agent_query = agent_query( - agentreq, &r, &rlen, ssh_agent_callback, ssh); - strbuf_free(agentreq); - - if (ssh->auth_agent_query) { - ssh->agent_response = NULL; - crWaitUntilV(ssh->agent_response); - r = ssh->agent_response; - rlen = ssh->agent_response_len; - } - if (r) { - ptrlen sigblob; - BinarySource src[1]; - BinarySource_BARE_INIT(src, r, rlen); - get_uint32(src); /* skip length field */ - if (get_byte(src) == SSH2_AGENT_SIGN_RESPONSE && - (sigblob = get_string(src), !get_err(src))) { - logevent("Sending Pageant's response"); - ssh2_add_sigblob(ssh, s->pktout, - s->pk.ptr, s->pk.len, - sigblob.ptr, sigblob.len); - ssh2_pkt_send(ssh, s->pktout); - s->type = AUTH_TYPE_PUBLICKEY; - } else { - /* FIXME: less drastic response */ - bombout(("Pageant failed to answer challenge")); - crStopV; - } - } - } - - /* Do we have any keys left to try? */ - if (s->pkblob_pos_in_agent) { - s->done_agent = TRUE; - s->tried_pubkey_config = TRUE; - } else { - s->keyi++; - if (s->keyi >= s->nkeys) - s->done_agent = TRUE; - } - - } else if (s->can_pubkey && s->publickey_blob && - s->privatekey_available && !s->tried_pubkey_config) { - - struct ssh2_userkey *key; /* not live over crReturn */ - char *passphrase; /* not live over crReturn */ - - ssh->pls.actx = SSH2_PKTCTX_PUBLICKEY; - - s->tried_pubkey_config = TRUE; - - /* - * Try the public key supplied in the configuration. - * - * First, offer the public blob to see if the server is - * willing to accept it. - */ - s->pktout = ssh_bpp_new_pktout( - ssh->bpp, SSH2_MSG_USERAUTH_REQUEST); - put_stringz(s->pktout, ssh->username); - put_stringz(s->pktout, "ssh-connection"); - /* service requested */ - put_stringz(s->pktout, "publickey"); /* method */ - put_bool(s->pktout, FALSE); - /* no signature included */ - put_stringz(s->pktout, s->publickey_algorithm); - put_string(s->pktout, s->publickey_blob->s, - s->publickey_blob->len); - ssh2_pkt_send(ssh, s->pktout); - logevent("Offered public key"); - - crMaybeWaitUntilV((pktin = pq_pop(&ssh->pq_ssh2_userauth)) != NULL); - if (pktin->type != SSH2_MSG_USERAUTH_PK_OK) { - /* Key refused. Give up. */ - pq_push_front(&ssh->pq_ssh2_userauth, pktin); - s->type = AUTH_TYPE_PUBLICKEY_OFFER_LOUD; - continue; /* process this new message */ - } - logevent("Offer of public key accepted"); - - /* - * Actually attempt a serious authentication using - * the key. - */ - if (flags & FLAG_VERBOSE) { - c_write_str(ssh, "Authenticating with public key \""); - c_write_str(ssh, s->publickey_comment); - c_write_str(ssh, "\"\r\n"); - } - key = NULL; - while (!key) { - const char *error; /* not live over crReturn */ - if (s->privatekey_encrypted) { - /* - * Get a passphrase from the user. - */ - s->cur_prompt = new_prompts(ssh->frontend); - s->cur_prompt->to_server = FALSE; - s->cur_prompt->name = dupstr("SSH key passphrase"); - add_prompt(s->cur_prompt, - dupprintf("Passphrase for key \"%.100s\": ", - s->publickey_comment), - FALSE); - s->userpass_ret = get_userpass_input( - s->cur_prompt, NULL); - while (1) { - while (s->userpass_ret < 0 && - bufchain_size(&ssh->user_input) > 0) - s->userpass_ret = get_userpass_input( - s->cur_prompt, &ssh->user_input); - - if (s->userpass_ret >= 0) - break; - - ssh->send_ok = 1; - crReturnV; - ssh->send_ok = 0; - } - if (!s->userpass_ret) { - /* Failed to get a passphrase. Terminate. */ - free_prompts(s->cur_prompt); - ssh_disconnect(ssh, NULL, - "Unable to authenticate", - SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER, - TRUE); - crStopV; - } - passphrase = - dupstr(s->cur_prompt->prompts[0]->result); - free_prompts(s->cur_prompt); - } else { - passphrase = NULL; /* no passphrase needed */ - } - - /* - * Try decrypting the key. - */ - s->keyfile = conf_get_filename(ssh->conf, CONF_keyfile); - key = ssh2_load_userkey(s->keyfile, passphrase, &error); - if (passphrase) { - /* burn the evidence */ - smemclr(passphrase, strlen(passphrase)); - sfree(passphrase); - } - if (key == SSH2_WRONG_PASSPHRASE || key == NULL) { - if (passphrase && - (key == SSH2_WRONG_PASSPHRASE)) { - c_write_str(ssh, "Wrong passphrase\r\n"); - key = NULL; - /* and loop again */ - } else { - c_write_str(ssh, "Unable to load private key ("); - c_write_str(ssh, error); - c_write_str(ssh, ")\r\n"); - key = NULL; - break; /* try something else */ - } - } - } - - if (key) { - strbuf *pkblob, *sigdata, *sigblob; - - /* - * We have loaded the private key and the server - * has announced that it's willing to accept it. - * Hallelujah. Generate a signature and send it. - */ - s->pktout = ssh_bpp_new_pktout( - ssh->bpp, SSH2_MSG_USERAUTH_REQUEST); - put_stringz(s->pktout, ssh->username); - put_stringz(s->pktout, "ssh-connection"); - /* service requested */ - put_stringz(s->pktout, "publickey"); /* method */ - put_bool(s->pktout, TRUE); /* signature follows */ - put_stringz(s->pktout, ssh_key_ssh_id(key->key)); - pkblob = strbuf_new(); - ssh_key_public_blob(key->key, BinarySink_UPCAST(pkblob)); - put_string(s->pktout, pkblob->s, pkblob->len); - - /* - * The data to be signed is: - * - * string session-id - * - * followed by everything so far placed in the - * outgoing packet. - */ - sigdata = strbuf_new(); - if (ssh->remote_bugs & BUG_SSH2_PK_SESSIONID) { - put_data(sigdata, ssh->v2_session_id, - ssh->v2_session_id_len); - } else { - put_string(sigdata, ssh->v2_session_id, - ssh->v2_session_id_len); - } - put_data(sigdata, s->pktout->data + 5, - s->pktout->length - 5); - sigblob = strbuf_new(); - ssh_key_sign(key->key, sigdata->s, sigdata->len, - BinarySink_UPCAST(sigblob)); - strbuf_free(sigdata); - ssh2_add_sigblob(ssh, s->pktout, pkblob->s, pkblob->len, - sigblob->s, sigblob->len); - strbuf_free(pkblob); - strbuf_free(sigblob); - - ssh2_pkt_send(ssh, s->pktout); - logevent("Sent public key signature"); - s->type = AUTH_TYPE_PUBLICKEY; - ssh_key_free(key->key); - sfree(key->comment); - sfree(key); - } + bufchain_prefix(&ssh->out_raw, &data, &len); -#ifndef NO_GSSAPI - } else if (s->can_gssapi && !s->tried_gssapi) { - - /* gssapi-with-mic authentication */ - - ptrlen data; - - s->type = AUTH_TYPE_GSSAPI; - s->tried_gssapi = TRUE; - ssh->pls.actx = SSH2_PKTCTX_GSSAPI; - - if (ssh->gsslib->gsslogmsg) - logevent(ssh->gsslib->gsslogmsg); - - /* Sending USERAUTH_REQUEST with "gssapi-with-mic" method */ - logeventf(ssh, "Trying gssapi-with-mic..."); - s->pktout = ssh_bpp_new_pktout( - ssh->bpp, SSH2_MSG_USERAUTH_REQUEST); - put_stringz(s->pktout, ssh->username); - put_stringz(s->pktout, "ssh-connection"); - put_stringz(s->pktout, "gssapi-with-mic"); - logevent("Attempting GSSAPI authentication"); - - /* add mechanism info */ - ssh->gsslib->indicate_mech(ssh->gsslib, &s->gss_buf); - - /* number of GSSAPI mechanisms */ - put_uint32(s->pktout, 1); - - /* length of OID + 2 */ - put_uint32(s->pktout, s->gss_buf.length + 2); - put_byte(s->pktout, SSH2_GSS_OIDTYPE); - - /* length of OID */ - put_byte(s->pktout, s->gss_buf.length); - - put_data(s->pktout, s->gss_buf.value, s->gss_buf.length); - ssh2_pkt_send(ssh, s->pktout); - crMaybeWaitUntilV((pktin = pq_pop(&ssh->pq_ssh2_userauth)) != NULL); - if (pktin->type != SSH2_MSG_USERAUTH_GSSAPI_RESPONSE) { - logevent("GSSAPI authentication request refused"); - pq_push_front(&ssh->pq_ssh2_userauth, pktin); - continue; - } - - /* check returned packet ... */ - - data = get_string(pktin); - s->gss_rcvtok.value = (char *)data.ptr; - s->gss_rcvtok.length = data.len; - if (s->gss_rcvtok.length != s->gss_buf.length + 2 || - ((char *)s->gss_rcvtok.value)[0] != SSH2_GSS_OIDTYPE || - ((char *)s->gss_rcvtok.value)[1] != s->gss_buf.length || - memcmp((char *)s->gss_rcvtok.value + 2, - s->gss_buf.value,s->gss_buf.length) ) { - logevent("GSSAPI authentication - wrong response from server"); - continue; - } - - /* Import server name if not cached from KEX */ - if (ssh->gss_srv_name == GSS_C_NO_NAME) { - s->gss_stat = ssh->gsslib->import_name(ssh->gsslib, - ssh->fullhostname, - &ssh->gss_srv_name); - if (s->gss_stat != SSH_GSS_OK) { - if (s->gss_stat == SSH_GSS_BAD_HOST_NAME) - logevent("GSSAPI import name failed -" - " Bad service name"); - else - logevent("GSSAPI import name failed"); - continue; - } - } - - /* Allocate our gss_ctx */ - s->gss_stat = ssh->gsslib->acquire_cred(ssh->gsslib, - &s->gss_ctx, NULL); - if (s->gss_stat != SSH_GSS_OK) { - logevent("GSSAPI authentication failed to get credentials"); - continue; - } - - /* initial tokens are empty */ - SSH_GSS_CLEAR_BUF(&s->gss_rcvtok); - SSH_GSS_CLEAR_BUF(&s->gss_sndtok); - - /* now enter the loop */ - do { - /* - * When acquire_cred yields no useful expiration, go with - * the service ticket expiration. - */ - s->gss_stat = ssh->gsslib->init_sec_context - (ssh->gsslib, - &s->gss_ctx, - ssh->gss_srv_name, - conf_get_int(ssh->conf, CONF_gssapifwd), - &s->gss_rcvtok, - &s->gss_sndtok, - NULL, - NULL); - - if (s->gss_stat!=SSH_GSS_S_COMPLETE && - s->gss_stat!=SSH_GSS_S_CONTINUE_NEEDED) { - logevent("GSSAPI authentication initialisation failed"); - - if (ssh->gsslib->display_status(ssh->gsslib, - s->gss_ctx, &s->gss_buf) == SSH_GSS_OK) { - logevent(s->gss_buf.value); - sfree(s->gss_buf.value); - } - - pq_push_front(&ssh->pq_ssh2_userauth, pktin); - break; - } - logevent("GSSAPI authentication initialised"); - - /* - * Client and server now exchange tokens until GSSAPI - * no longer says CONTINUE_NEEDED - */ - if (s->gss_sndtok.length != 0) { - s->pktout = - ssh_bpp_new_pktout( - ssh->bpp, SSH2_MSG_USERAUTH_GSSAPI_TOKEN); - put_string(s->pktout, - s->gss_sndtok.value, s->gss_sndtok.length); - ssh2_pkt_send(ssh, s->pktout); - ssh->gsslib->free_tok(ssh->gsslib, &s->gss_sndtok); - } - - if (s->gss_stat == SSH_GSS_S_CONTINUE_NEEDED) { - crMaybeWaitUntilV((pktin = pq_pop(&ssh->pq_ssh2_userauth)) != NULL); - if (pktin->type != SSH2_MSG_USERAUTH_GSSAPI_TOKEN) { - logevent("GSSAPI authentication -" - " bad server response"); - s->gss_stat = SSH_GSS_FAILURE; - pq_push_front(&ssh->pq_ssh2_userauth, pktin); - break; - } - data = get_string(pktin); - s->gss_rcvtok.value = (char *)data.ptr; - s->gss_rcvtok.length = data.len; - } - } while (s-> gss_stat == SSH_GSS_S_CONTINUE_NEEDED); - - if (s->gss_stat != SSH_GSS_OK) { - ssh->gsslib->release_cred(ssh->gsslib, &s->gss_ctx); - continue; - } - logevent("GSSAPI authentication loop finished OK"); - - /* Now send the MIC */ - - s->pktout = - ssh2_gss_authpacket(ssh, s->gss_ctx, "gssapi-with-mic"); - ssh2_pkt_send(ssh, s->pktout); - - ssh->gsslib->release_cred(ssh->gsslib, &s->gss_ctx); - continue; -#endif - } else if (s->can_keyb_inter && !s->kbd_inter_refused) { - - /* - * Keyboard-interactive authentication. - */ - - s->type = AUTH_TYPE_KEYBOARD_INTERACTIVE; - - ssh->pls.actx = SSH2_PKTCTX_KBDINTER; - - s->pktout = ssh_bpp_new_pktout( - ssh->bpp, SSH2_MSG_USERAUTH_REQUEST); - put_stringz(s->pktout, ssh->username); - put_stringz(s->pktout, "ssh-connection"); - /* service requested */ - put_stringz(s->pktout, "keyboard-interactive"); - /* method */ - put_stringz(s->pktout, ""); /* lang */ - put_stringz(s->pktout, ""); /* submethods */ - ssh2_pkt_send(ssh, s->pktout); - - logevent("Attempting keyboard-interactive authentication"); - - crMaybeWaitUntilV((pktin = pq_pop(&ssh->pq_ssh2_userauth)) != NULL); - if (pktin->type != SSH2_MSG_USERAUTH_INFO_REQUEST) { - /* Server is not willing to do keyboard-interactive - * at all (or, bizarrely but legally, accepts the - * user without actually issuing any prompts). - * Give up on it entirely. */ - pq_push_front(&ssh->pq_ssh2_userauth, pktin); - s->type = AUTH_TYPE_KEYBOARD_INTERACTIVE_QUIET; - s->kbd_inter_refused = TRUE; /* don't try it again */ - continue; - } - - /* - * Loop while the server continues to send INFO_REQUESTs. - */ - while (pktin->type == SSH2_MSG_USERAUTH_INFO_REQUEST) { - - ptrlen name, inst; - int i; - - /* - * We've got a fresh USERAUTH_INFO_REQUEST. - * Get the preamble and start building a prompt. - */ - name = get_string(pktin); - inst = get_string(pktin); - get_string(pktin); /* skip language tag */ - s->cur_prompt = new_prompts(ssh->frontend); - s->cur_prompt->to_server = TRUE; - - /* - * Get any prompt(s) from the packet. - */ - s->num_prompts = get_uint32(pktin); - for (i = 0; i < s->num_prompts; i++) { - ptrlen prompt; - int echo; - static char noprompt[] = - ": "; - - prompt = get_string(pktin); - echo = get_bool(pktin); - if (!prompt.len) { - prompt.ptr = noprompt; - prompt.len = lenof(noprompt)-1; - } - add_prompt(s->cur_prompt, mkstr(prompt), echo); - } - - if (name.len) { - /* FIXME: better prefix to distinguish from - * local prompts? */ - s->cur_prompt->name = - dupprintf("SSH server: %.*s", PTRLEN_PRINTF(name)); - s->cur_prompt->name_reqd = TRUE; - } else { - s->cur_prompt->name = - dupstr("SSH server authentication"); - s->cur_prompt->name_reqd = FALSE; - } - /* We add a prefix to try to make it clear that a prompt - * has come from the server. - * FIXME: ugly to print "Using..." in prompt _every_ - * time round. Can this be done more subtly? */ - /* Special case: for reasons best known to themselves, - * some servers send k-i requests with no prompts and - * nothing to display. Keep quiet in this case. */ - if (s->num_prompts || name.len || inst.len) { - s->cur_prompt->instruction = - dupprintf("Using keyboard-interactive " - "authentication.%s%.*s", - inst.len ? "\n" : "", - PTRLEN_PRINTF(inst)); - s->cur_prompt->instr_reqd = TRUE; - } else { - s->cur_prompt->instr_reqd = FALSE; - } - - /* - * Display any instructions, and get the user's - * response(s). - */ - s->userpass_ret = get_userpass_input(s->cur_prompt, NULL); - while (1) { - while (s->userpass_ret < 0 && - bufchain_size(&ssh->user_input) > 0) - s->userpass_ret = get_userpass_input( - s->cur_prompt, &ssh->user_input); - - if (s->userpass_ret >= 0) - break; - - ssh->send_ok = 1; - crReturnV; - ssh->send_ok = 0; - } - if (!s->userpass_ret) { - /* - * Failed to get responses. Terminate. - */ - free_prompts(s->cur_prompt); - ssh_disconnect(ssh, NULL, "Unable to authenticate", - SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER, - TRUE); - crStopV; - } - - /* - * Send the response(s) to the server, padding - * them to disguise their true length. - */ - s->pktout = ssh_bpp_new_pktout( - ssh->bpp, SSH2_MSG_USERAUTH_INFO_RESPONSE); - put_uint32(s->pktout, s->num_prompts); - for (i=0; i < s->num_prompts; i++) { - put_stringz(s->pktout, - s->cur_prompt->prompts[i]->result); - } - s->pktout->minlen = 256; - ssh2_pkt_send(ssh, s->pktout); - - /* - * Free the prompts structure from this iteration. - * If there's another, a new one will be allocated - * when we return to the top of this while loop. - */ - free_prompts(s->cur_prompt); - - /* - * Get the next packet in case it's another - * INFO_REQUEST. - */ - crMaybeWaitUntilV((pktin = pq_pop(&ssh->pq_ssh2_userauth)) != NULL); - - } - - /* - * We should have SUCCESS or FAILURE now. - */ - pq_push_front(&ssh->pq_ssh2_userauth, pktin); - - } else if (s->can_passwd) { - - /* - * Plain old password authentication. - */ - int changereq_first_time; /* not live over crReturn */ - - ssh->pls.actx = SSH2_PKTCTX_PASSWORD; - - s->cur_prompt = new_prompts(ssh->frontend); - s->cur_prompt->to_server = TRUE; - s->cur_prompt->name = dupstr("SSH password"); - add_prompt(s->cur_prompt, dupprintf("%s@%s's password: ", - ssh->username, - ssh->savedhost), - FALSE); - - s->userpass_ret = get_userpass_input(s->cur_prompt, NULL); - while (1) { - while (s->userpass_ret < 0 && - bufchain_size(&ssh->user_input) > 0) - s->userpass_ret = get_userpass_input( - s->cur_prompt, &ssh->user_input); - - if (s->userpass_ret >= 0) - break; - - ssh->send_ok = 1; - crReturnV; - ssh->send_ok = 0; - } - if (!s->userpass_ret) { - /* - * Failed to get responses. Terminate. - */ - free_prompts(s->cur_prompt); - ssh_disconnect(ssh, NULL, "Unable to authenticate", - SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER, - TRUE); - crStopV; - } - /* - * Squirrel away the password. (We may need it later if - * asked to change it.) - */ - s->password = dupstr(s->cur_prompt->prompts[0]->result); - free_prompts(s->cur_prompt); - - /* - * Send the password packet. - * - * We pad out the password packet to 256 bytes to make - * it harder for an attacker to find the length of the - * user's password. - * - * Anyone using a password longer than 256 bytes - * probably doesn't have much to worry about from - * people who find out how long their password is! - */ - s->pktout = ssh_bpp_new_pktout( - ssh->bpp, SSH2_MSG_USERAUTH_REQUEST); - put_stringz(s->pktout, ssh->username); - put_stringz(s->pktout, "ssh-connection"); - /* service requested */ - put_stringz(s->pktout, "password"); - put_bool(s->pktout, FALSE); - put_stringz(s->pktout, s->password); - s->pktout->minlen = 256; - ssh2_pkt_send(ssh, s->pktout); - logevent("Sent password"); - s->type = AUTH_TYPE_PASSWORD; - - /* - * Wait for next packet, in case it's a password change - * request. - */ - crMaybeWaitUntilV((pktin = pq_pop(&ssh->pq_ssh2_userauth)) != NULL); - changereq_first_time = TRUE; - - while (pktin->type == SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ) { - - /* - * We're being asked for a new password - * (perhaps not for the first time). - * Loop until the server accepts it. - */ - - int got_new = FALSE; /* not live over crReturn */ - ptrlen prompt; /* not live over crReturn */ - - { - const char *msg; - if (changereq_first_time) - msg = "Server requested password change"; - else - msg = "Server rejected new password"; - logevent(msg); - c_write_str(ssh, msg); - c_write_str(ssh, "\r\n"); - } - - prompt = get_string(pktin); - - s->cur_prompt = new_prompts(ssh->frontend); - s->cur_prompt->to_server = TRUE; - s->cur_prompt->name = dupstr("New SSH password"); - s->cur_prompt->instruction = mkstr(prompt); - s->cur_prompt->instr_reqd = TRUE; - /* - * There's no explicit requirement in the protocol - * for the "old" passwords in the original and - * password-change messages to be the same, and - * apparently some Cisco kit supports password change - * by the user entering a blank password originally - * and the real password subsequently, so, - * reluctantly, we prompt for the old password again. - * - * (On the other hand, some servers don't even bother - * to check this field.) - */ - add_prompt(s->cur_prompt, - dupstr("Current password (blank for previously entered password): "), - FALSE); - add_prompt(s->cur_prompt, dupstr("Enter new password: "), - FALSE); - add_prompt(s->cur_prompt, dupstr("Confirm new password: "), - FALSE); - - /* - * Loop until the user manages to enter the same - * password twice. - */ - while (!got_new) { - s->userpass_ret = get_userpass_input( - s->cur_prompt, NULL); - while (1) { - while (s->userpass_ret < 0 && - bufchain_size(&ssh->user_input) > 0) - s->userpass_ret = get_userpass_input( - s->cur_prompt, &ssh->user_input); - - if (s->userpass_ret >= 0) - break; - - ssh->send_ok = 1; - crReturnV; - ssh->send_ok = 0; - } - if (!s->userpass_ret) { - /* - * Failed to get responses. Terminate. - */ - /* burn the evidence */ - free_prompts(s->cur_prompt); - smemclr(s->password, strlen(s->password)); - sfree(s->password); - ssh_disconnect(ssh, NULL, "Unable to authenticate", - SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER, - TRUE); - crStopV; - } - - /* - * If the user specified a new original password - * (IYSWIM), overwrite any previously specified - * one. - * (A side effect is that the user doesn't have to - * re-enter it if they louse up the new password.) - */ - if (s->cur_prompt->prompts[0]->result[0]) { - smemclr(s->password, strlen(s->password)); - /* burn the evidence */ - sfree(s->password); - s->password = - dupstr(s->cur_prompt->prompts[0]->result); - } - - /* - * Check the two new passwords match. - */ - got_new = (strcmp(s->cur_prompt->prompts[1]->result, - s->cur_prompt->prompts[2]->result) - == 0); - if (!got_new) - /* They don't. Silly user. */ - c_write_str(ssh, "Passwords do not match\r\n"); - - } - - /* - * Send the new password (along with the old one). - * (see above for padding rationale) - */ - s->pktout = ssh_bpp_new_pktout( - ssh->bpp, SSH2_MSG_USERAUTH_REQUEST); - put_stringz(s->pktout, ssh->username); - put_stringz(s->pktout, "ssh-connection"); - /* service requested */ - put_stringz(s->pktout, "password"); - put_bool(s->pktout, TRUE); - put_stringz(s->pktout, s->password); - put_stringz(s->pktout, - s->cur_prompt->prompts[1]->result); - free_prompts(s->cur_prompt); - s->pktout->minlen = 256; - ssh2_pkt_send(ssh, s->pktout); - logevent("Sent new password"); - - /* - * Now see what the server has to say about it. - * (If it's CHANGEREQ again, it's not happy with the - * new password.) - */ - crMaybeWaitUntilV((pktin = pq_pop(&ssh->pq_ssh2_userauth)) != NULL); - changereq_first_time = FALSE; - - } - - /* - * We need to reexamine the current pktin at the top - * of the loop. Either: - * - we weren't asked to change password at all, in - * which case it's a SUCCESS or FAILURE with the - * usual meaning - * - we sent a new password, and the server was - * either OK with it (SUCCESS or FAILURE w/partial - * success) or unhappy with the _old_ password - * (FAILURE w/o partial success) - * In any of these cases, we go back to the top of - * the loop and start again. - */ - pq_push_front(&ssh->pq_ssh2_userauth, pktin); - - /* - * We don't need the old password any more, in any - * case. Burn the evidence. - */ - smemclr(s->password, strlen(s->password)); - sfree(s->password); - - } else { - char *str = dupprintf( - "No supported authentication methods available" - " (server sent: %.*s)", PTRLEN_PRINTF(methods)); - - ssh_disconnect(ssh, str, - "No supported authentication methods available", - SSH2_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE, - FALSE); - sfree(str); - - crStopV; - - } + if (ssh->logctx) + log_packet(ssh->logctx, PKT_OUTGOING, -1, NULL, data, len, + 0, NULL, NULL, 0, NULL); + backlog = sk_write(ssh->s, data, len); - } + bufchain_consume(&ssh->out_raw, len); + + if (backlog > SSH_MAX_BACKLOG) { + ssh_throttle_all(ssh, 1, backlog); + return; + } } - ssh->packet_dispatch[SSH2_MSG_USERAUTH_BANNER] = NULL; - /* Clear up various bits and pieces from authentication. */ - if (s->publickey_blob) { - sfree(s->publickey_algorithm); - strbuf_free(s->publickey_blob); - sfree(s->publickey_comment); + if (ssh->send_outgoing_eof) + sk_write_eof(ssh->s); +} + +static void ssh_shutdown_internal(Ssh ssh) +{ + expire_timer_context(ssh); + + if (ssh->connshare) { + sharestate_free(ssh->connshare); + ssh->connshare = NULL; } - if (s->agent_response) - sfree(s->agent_response); - if (s->userauth_success) { - /* - * We've just received USERAUTH_SUCCESS, and we haven't sent - * any packets since. Signal the transport layer to consider - * doing an immediate rekey, if it has any reason to want to. - * - * (Relying on we_are_in is not sufficient. One of the reasons - * to do a post-userauth rekey is OpenSSH delayed compression; - * draft-miller-secsh-compression-delayed is quite clear that - * that triggers on USERAUTH_SUCCESS specifically, and - * we_are_in can become set for other reasons.) - */ - ssh->rekey_reason = NULL; /* will be filled in later */ - ssh->rekey_class = RK_POST_USERAUTH; - queue_idempotent_callback(&ssh->ssh2_transport_icb); + if (ssh->pinger) { + pinger_free(ssh->pinger); + ssh->pinger = NULL; } /* - * Finally, hand over to the connection layer. + * We only need to free the base PPL, which will free the others + * (if any) transitively. */ - do_ssh2_connection(ssh); - ssh->current_user_input_fn = ssh2_connection_input; - queue_idempotent_callback(&ssh->user_input_consumer); + if (ssh->base_layer) { + ssh_ppl_free(ssh->base_layer); + ssh->base_layer = NULL; + } - crFinishV; + ssh->cl = NULL; } -static void ssh2_userauth_input(Ssh ssh) +static void ssh_shutdown(Ssh ssh) { - do_ssh2_userauth(ssh); -} + ssh_shutdown_internal(ssh); -/* - * Handle the SSH-2 connection layer. - */ -static void ssh2_msg_connection(Ssh ssh, PktIn *pktin) -{ - pq_push(&ssh->pq_ssh2_connection, pktin); - queue_idempotent_callback(&ssh->ssh2_connection_icb); -} + if (ssh->bpp) { + ssh_bpp_free(ssh->bpp); + ssh->bpp = NULL; + } -static void ssh2_response_connection(struct ssh_channel *c, - PktIn *pktin, void *ctx) -{ - if (pktin) - ssh2_msg_connection(c->ssh, pktin); + if (ssh->s) { + sk_close(ssh->s); + ssh->s = NULL; + } + + bufchain_clear(&ssh->in_raw); + bufchain_clear(&ssh->out_raw); + bufchain_clear(&ssh->user_input); } -static void ssh2_connection_setup(Ssh ssh) +static void ssh_initiate_connection_close(Ssh ssh) { - /* - * Initially, most connection-protocol messages go to the function - * that queues them for handling by the main do_ssh2_connection - * coroutine. - */ - ssh->packet_dispatch[SSH2_MSG_REQUEST_SUCCESS] = ssh2_msg_connection; - ssh->packet_dispatch[SSH2_MSG_REQUEST_FAILURE] = ssh2_msg_connection; - ssh->packet_dispatch[SSH2_MSG_CHANNEL_OPEN] = ssh2_msg_connection; - ssh->packet_dispatch[SSH2_MSG_CHANNEL_OPEN_CONFIRMATION] = - ssh2_msg_connection; - ssh->packet_dispatch[SSH2_MSG_CHANNEL_OPEN_FAILURE] = ssh2_msg_connection; - ssh->packet_dispatch[SSH2_MSG_CHANNEL_DATA] = ssh2_msg_connection; - ssh->packet_dispatch[SSH2_MSG_CHANNEL_EXTENDED_DATA] = ssh2_msg_connection; - ssh->packet_dispatch[SSH2_MSG_CHANNEL_EOF] = ssh2_msg_connection; - ssh->packet_dispatch[SSH2_MSG_CHANNEL_CLOSE] = ssh2_msg_connection; + /* Wind up everything above the BPP. */ + ssh_shutdown_internal(ssh); - /* - * But a couple of them are easier to pass to special handler - * functions right from the start. - */ - ssh->packet_dispatch[SSH2_MSG_CHANNEL_WINDOW_ADJUST] = - ssh2_msg_channel_window_adjust; - ssh->packet_dispatch[SSH2_MSG_GLOBAL_REQUEST] = - ssh2_msg_global_request; + /* Force any remaining queued SSH packets through the BPP, and + * schedule sending of EOF on the network socket after them. */ + ssh_bpp_handle_output(ssh->bpp); + ssh->send_outgoing_eof = TRUE; - /* - * Ensure our channels tree exists. - */ - if (!ssh->channels) - ssh->channels = newtree234(ssh_channelcmp); + /* Now we expect the other end to close the connection too in + * response, so arrange that we'll receive notification of that + * via ssh_remote_eof. */ + ssh->bpp->expect_close = TRUE; } -typedef struct mainchan { - Ssh ssh; - SshChannel *sc; - - Channel chan; -} mainchan; - -static void mainchan_free(Channel *chan); -static void mainchan_open_confirmation(Channel *chan); -static void mainchan_open_failure(Channel *chan, const char *errtext); -static int mainchan_send(Channel *chan, int is_stderr, const void *, int); -static void mainchan_send_eof(Channel *chan); -static void mainchan_set_input_wanted(Channel *chan, int wanted); -static char *mainchan_log_close_msg(Channel *chan); - -static const struct ChannelVtable mainchan_channelvt = { - mainchan_free, - mainchan_open_confirmation, - mainchan_open_failure, - mainchan_send, - mainchan_send_eof, - mainchan_set_input_wanted, - mainchan_log_close_msg, - chan_no_eager_close, -}; +#define GET_FORMATTED_MSG \ + char *msg; \ + va_list ap; \ + va_start(ap, fmt); \ + msg = dupvprintf(fmt, ap); \ + va_end(ap); -static mainchan *mainchan_new(Ssh ssh) +void ssh_remote_error(Ssh ssh, const char *fmt, ...) { - mainchan *mc = snew(mainchan); - mc->ssh = ssh; - mc->sc = NULL; - mc->chan.vt = &mainchan_channelvt; - mc->chan.initial_fixed_window_size = 0; - return mc; -} + if (ssh->base_layer) { + GET_FORMATTED_MSG; -static void mainchan_free(Channel *chan) -{ - assert(chan->vt == &mainchan_channelvt); - mainchan *mc = FROMFIELD(chan, mainchan, chan); - mc->ssh->mainchan = NULL; - sfree(mc); -} + /* Error messages sent by the remote don't count as clean exits */ + ssh->exitcode = 128; -static void mainchan_open_confirmation(Channel *chan) -{ - assert(FALSE && "OPEN_CONFIRMATION for main channel should be " - "handled by connection layer setup"); -} + /* Close the socket immediately, since the server has already + * closed its end (or is about to). */ + ssh_shutdown(ssh); -static void mainchan_open_failure(Channel *chan, const char *errtext) -{ - assert(FALSE && "OPEN_FAILURE for main channel should be " - "handled by connection layer setup"); + logevent(ssh->frontend, msg); + connection_fatal(ssh->frontend, "%s", msg); + sfree(msg); + } } -static int mainchan_send(Channel *chan, int is_stderr, - const void *data, int length) +void ssh_remote_eof(Ssh ssh, const char *fmt, ...) { - assert(chan->vt == &mainchan_channelvt); - mainchan *mc = FROMFIELD(chan, mainchan, chan); - return from_backend(mc->ssh->frontend, is_stderr, data, length); -} + if (ssh->base_layer) { + GET_FORMATTED_MSG; -static void mainchan_send_eof(Channel *chan) -{ - assert(chan->vt == &mainchan_channelvt); - mainchan *mc = FROMFIELD(chan, mainchan, chan); + /* EOF from the remote, if we were expecting it, does count as + * a clean exit */ + ssh->exitcode = 0; - if (!mc->ssh->sent_console_eof && - (from_backend_eof(mc->ssh->frontend) || mc->ssh->got_pty)) { - /* - * Either from_backend_eof told us that the front end wants us - * to close the outgoing side of the connection as soon as we - * see EOF from the far end, or else we've unilaterally - * decided to do that because we've allocated a remote pty and - * hence EOF isn't a particularly meaningful concept. - */ - sshfwd_write_eof(mc->sc); + /* Close the socket immediately, since the server has already + * closed its end. */ + ssh_shutdown(ssh); + + logevent(ssh->frontend, msg); + sfree(msg); + notify_remote_exit(ssh->frontend); + } else { + /* This is responding to EOF after we've already seen some + * other reason for terminating the session. */ + ssh_shutdown(ssh); } - mc->ssh->sent_console_eof = TRUE; } -static void mainchan_set_input_wanted(Channel *chan, int wanted) +void ssh_proto_error(Ssh ssh, const char *fmt, ...) { - assert(chan->vt == &mainchan_channelvt); - mainchan *mc = FROMFIELD(chan, mainchan, chan); + if (ssh->base_layer) { + GET_FORMATTED_MSG; - /* - * This is the main channel of the SSH session, i.e. the one tied - * to the standard input (or GUI) of the primary SSH client user - * interface. So ssh->send_ok is how we control whether we're - * reading from that input. - */ - mc->ssh->send_ok = wanted; -} + ssh->exitcode = 128; -static char *mainchan_log_close_msg(Channel *chan) -{ - return dupstr("Main session channel closed"); + ssh_bpp_queue_disconnect(ssh->bpp, msg, + SSH2_DISCONNECT_PROTOCOL_ERROR); + ssh_initiate_connection_close(ssh); + + logevent(ssh->frontend, msg); + connection_fatal(ssh->frontend, "%s", msg); + sfree(msg); + } } -static void do_ssh2_connection(void *vctx) +void ssh_sw_abort(Ssh ssh, const char *fmt, ...) { - Ssh ssh = (Ssh)vctx; - PktIn *pktin; - - struct do_ssh2_connection_state { - int crLine; - PktOut *pktout; - }; - - crState(do_ssh2_connection_state); + if (ssh->base_layer) { + GET_FORMATTED_MSG; - crBeginState; + ssh->exitcode = 128; - /* - * Initialise our dispatch table entries. Normally this will have - * been done as a side effect of USERAUTH_SUCCESS, but in some - * cases, it might not (e.g. if we bypassed userauth, or if we're - * running the bare-connection protocol). - */ - ssh2_connection_setup(ssh); + ssh_initiate_connection_close(ssh); - /* - * Create the main session channel. - */ - if (conf_get_int(ssh->conf, CONF_ssh_no_shell)) { - ssh->mainchan = NULL; - } else { - mainchan *mc = mainchan_new(ssh); - - if (*conf_get_str(ssh->conf, CONF_ssh_nc_host)) { - /* - * Just start a direct-tcpip channel and use it as the main - * channel. - */ - mc->sc = ssh_lportfwd_open - (&ssh->cl, conf_get_str(ssh->conf, CONF_ssh_nc_host), - conf_get_int(ssh->conf, CONF_ssh_nc_port), - "main channel", &mc->chan); - ssh->mainchan = FROMFIELD(mc->sc, struct ssh_channel, sc); - ssh->ncmode = TRUE; - } else { - ssh->mainchan = snew(struct ssh_channel); - mc->sc = &ssh->mainchan->sc; - ssh->mainchan->ssh = ssh; - ssh_channel_init(ssh->mainchan); - ssh->mainchan->chan = &mc->chan; - s->pktout = ssh2_chanopen_init(ssh->mainchan, "session"); - logevent("Opening session as main channel"); - ssh2_pkt_send(ssh, s->pktout); - ssh->ncmode = FALSE; - } - crMaybeWaitUntilV((pktin = pq_pop(&ssh->pq_ssh2_connection)) != NULL); - if (pktin->type != SSH2_MSG_CHANNEL_OPEN_CONFIRMATION && - pktin->type != SSH2_MSG_CHANNEL_OPEN_FAILURE) { - bombout(("Server sent strange packet %d in response to main " - "channel open request", pktin->type)); - crStopV; - } - if (get_uint32(pktin) != ssh->mainchan->localid) { - bombout(("Server's response to main channel open cited wrong" - " channel number")); - crStopV; - } - if (pktin->type == SSH2_MSG_CHANNEL_OPEN_FAILURE) { - char *errtext = ssh2_channel_open_failure_error_text(pktin); - bombout(("Server refused to open main channel: %s", errtext)); - sfree(errtext); - crStopV; - } + logevent(ssh->frontend, msg); + connection_fatal(ssh->frontend, "%s", msg); + sfree(msg); - ssh->mainchan->remoteid = get_uint32(pktin); - ssh->mainchan->halfopen = FALSE; - ssh->mainchan->v.v2.remwindow = get_uint32(pktin); - ssh->mainchan->v.v2.remmaxpkt = get_uint32(pktin); - update_specials_menu(ssh->frontend); - logevent("Opened main channel"); + notify_remote_exit(ssh->frontend); } +} - /* - * Now we have a channel, make dispatch table entries for - * general channel-based messages. - */ - ssh->packet_dispatch[SSH2_MSG_CHANNEL_DATA] = - ssh->packet_dispatch[SSH2_MSG_CHANNEL_EXTENDED_DATA] = - ssh2_msg_channel_data; - ssh->packet_dispatch[SSH2_MSG_CHANNEL_EOF] = ssh2_msg_channel_eof; - ssh->packet_dispatch[SSH2_MSG_CHANNEL_CLOSE] = ssh2_msg_channel_close; - ssh->packet_dispatch[SSH2_MSG_CHANNEL_OPEN_CONFIRMATION] = - ssh2_msg_channel_open_confirmation; - ssh->packet_dispatch[SSH2_MSG_CHANNEL_OPEN_FAILURE] = - ssh2_msg_channel_open_failure; - ssh->packet_dispatch[SSH2_MSG_CHANNEL_REQUEST] = - ssh2_msg_channel_request; - ssh->packet_dispatch[SSH2_MSG_CHANNEL_OPEN] = - ssh2_msg_channel_open; - ssh->packet_dispatch[SSH2_MSG_CHANNEL_SUCCESS] = ssh2_msg_channel_response; - ssh->packet_dispatch[SSH2_MSG_CHANNEL_FAILURE] = ssh2_msg_channel_response; +void ssh_user_close(Ssh ssh, const char *fmt, ...) +{ + if (ssh->base_layer) { + GET_FORMATTED_MSG; - /* - * Put our current pending packet queue back to the front of - * the main pq, and then schedule a callback to re-process those - * packets (if any). That way, anything already in our queue that - * matches any of the table entries we've just modified will go to - * the right handler function, and won't come here to confuse us. - */ - if (pq_peek(&ssh->pq_ssh2_connection)) { - pq_concatenate(&ssh->bpp->in_pq, - &ssh->pq_ssh2_connection, &ssh->bpp->in_pq); - queue_idempotent_callback(ssh->bpp->in_pq.pqb.ic); - } + /* Closing the connection due to user action, even if the + * action is the user aborting during authentication prompts, + * does count as a clean exit - except that this is also how + * we signal ordinary session termination, in which case we + * should use the exit status already sent from the main + * session (if any). */ + if (ssh->exitcode < 0) + ssh->exitcode = 0; - /* - * Now the connection protocol is properly up and running, with - * all those dispatch table entries, so it's safe to let - * downstreams start trying to open extra channels through us. - */ - if (ssh->connshare) - share_activate(ssh->connshare, ssh->v_s); + ssh_initiate_connection_close(ssh); - if (ssh->mainchan && ssh_is_simple(ssh)) { - /* - * This message indicates to the server that we promise - * not to try to run any other channel in parallel with - * this one, so it's safe for it to advertise a very large - * window and leave the flow control to TCP. - */ - s->pktout = ssh2_chanreq_init(ssh->mainchan, - "simple@putty.projects.tartarus.org", - NULL, NULL); - ssh2_pkt_send(ssh, s->pktout); + logevent(ssh->frontend, msg); + sfree(msg); + + notify_remote_exit(ssh->frontend); } +} + +static void ssh_socket_log(Plug plug, int type, SockAddr addr, int port, + const char *error_msg, int error_code) +{ + Ssh ssh = FROMFIELD(plug, struct ssh_tag, plugvt); /* - * Enable port forwardings. + * While we're attempting connection sharing, don't loudly log + * everything that happens. Real TCP connections need to be logged + * when we _start_ trying to connect, because it might be ages + * before they respond if something goes wrong; but connection + * sharing is local and quick to respond, and it's sufficient to + * simply wait and see whether it worked afterwards. */ - portfwdmgr_config(ssh->portfwdmgr, ssh->conf); - - if (ssh->mainchan && !ssh->ncmode) { - /* - * Send the CHANNEL_REQUESTS for the main session channel. - * Each one is handled by its own little asynchronous - * co-routine. - */ - - /* Potentially enable X11 forwarding. */ - if (conf_get_int(ssh->conf, CONF_x11_forward)) { - ssh->x11disp = - x11_setup_display(conf_get_str(ssh->conf, CONF_x11_display), - ssh->conf); - if (!ssh->x11disp) { - /* FIXME: return an error message from x11_setup_display */ - logevent("X11 forwarding not enabled: unable to" - " initialise X display"); - } else { - ssh->x11auth = x11_invent_fake_auth - (ssh->x11authtree, conf_get_int(ssh->conf, CONF_x11_auth)); - ssh->x11auth->disp = ssh->x11disp; - ssh2_setup_x11(ssh->mainchan, NULL, NULL); - } - } - - /* Potentially enable agent forwarding. */ - if (ssh_agent_forwarding_permitted(&ssh->cl)) - ssh2_setup_agent(ssh->mainchan, NULL, NULL); + if (!ssh->attempting_connshare) + backend_socket_log(ssh->frontend, type, addr, port, + error_msg, error_code, ssh->conf, + ssh->session_started); +} - /* Now allocate a pty for the session. */ - if (!conf_get_int(ssh->conf, CONF_nopty)) - ssh2_setup_pty(ssh->mainchan, NULL, NULL); +static void ssh_closing(Plug plug, const char *error_msg, int error_code, + int calling_back) +{ + Ssh ssh = FROMFIELD(plug, struct ssh_tag, plugvt); + if (ssh->bpp) { + ssh->bpp->input_eof = TRUE; + queue_idempotent_callback(&ssh->bpp->ic_in_raw); + } +} - /* Send environment variables. */ - ssh2_setup_env(ssh->mainchan, NULL, NULL); +static void ssh_receive(Plug plug, int urgent, char *data, int len) +{ + Ssh ssh = FROMFIELD(plug, struct ssh_tag, plugvt); - /* - * Start a shell or a remote command. We may have to attempt - * this twice if the config data has provided a second choice - * of command. - */ - while (1) { - int subsys; - char *cmd; - - if (ssh->fallback_cmd) { - subsys = conf_get_int(ssh->conf, CONF_ssh_subsys2); - cmd = conf_get_str(ssh->conf, CONF_remote_cmd2); - } else { - subsys = conf_get_int(ssh->conf, CONF_ssh_subsys); - cmd = conf_get_str(ssh->conf, CONF_remote_cmd); - } - - if (subsys) { - s->pktout = ssh2_chanreq_init(ssh->mainchan, "subsystem", - ssh2_response_connection, NULL); - put_stringz(s->pktout, cmd); - } else if (*cmd) { - s->pktout = ssh2_chanreq_init(ssh->mainchan, "exec", - ssh2_response_connection, NULL); - put_stringz(s->pktout, cmd); - } else { - s->pktout = ssh2_chanreq_init(ssh->mainchan, "shell", - ssh2_response_connection, NULL); - } - ssh2_pkt_send(ssh, s->pktout); - - crMaybeWaitUntilV((pktin = pq_pop(&ssh->pq_ssh2_connection)) != NULL); - - if (pktin->type != SSH2_MSG_CHANNEL_SUCCESS) { - if (pktin->type != SSH2_MSG_CHANNEL_FAILURE) { - bombout(("Unexpected response to shell/command request:" - " packet type %d", pktin->type)); - crStopV; - } - /* - * We failed to start the command. If this is the - * fallback command, we really are finished; if it's - * not, and if the fallback command exists, try falling - * back to it before complaining. - */ - if (!ssh->fallback_cmd && - *conf_get_str(ssh->conf, CONF_remote_cmd2)) { - logevent("Primary command failed; attempting fallback"); - ssh->fallback_cmd = TRUE; - continue; - } - bombout(("Server refused to start a shell/command")); - crStopV; - } else { - logevent("Started a shell/command"); - } - break; - } - } else { - ssh->editing = ssh->echoing = TRUE; - } + /* Log raw data, if we're in that mode. */ + if (ssh->logctx) + log_packet(ssh->logctx, PKT_INCOMING, -1, NULL, data, len, + 0, NULL, NULL, 0, NULL); - ssh->state = SSH_STATE_SESSION; - if (ssh->size_needed) - backend_size(&ssh->backend, ssh->term_width, ssh->term_height); - if (ssh->eof_needed) - backend_special(&ssh->backend, SS_EOF, 0); + bufchain_add(&ssh->in_raw, data, len); + if (!ssh->frozen && ssh->bpp) + queue_idempotent_callback(&ssh->bpp->ic_in_raw); +} +static void ssh_sent(Plug plug, int bufsize) +{ + Ssh ssh = FROMFIELD(plug, struct ssh_tag, plugvt); /* - * Transfer data! + * If the send backlog on the SSH socket itself clears, we should + * unthrottle the whole world if it was throttled. Also trigger an + * extra call to the consumer of the BPP's output, to try to send + * some more data off its bufchain. */ - if (ssh->ldisc) - ldisc_echoedit_update(ssh->ldisc); /* cause ldisc to notice changes */ - if (ssh->mainchan) - ssh->send_ok = 1; - while (1) { - if ((pktin = pq_pop(&ssh->pq_ssh2_connection)) != NULL) { - - /* - * _All_ the connection-layer packets we expect to - * receive are now handled by the dispatch table. - * Anything that reaches here must be bogus. - */ - - bombout(("Strange packet received: type %d", pktin->type)); - crStopV; - } - while (ssh->mainchan && bufchain_size(&ssh->user_input) > 0) { - /* - * Add user input to the main channel's buffer. - */ - void *data; - int len; - bufchain_prefix(&ssh->user_input, &data, &len); - ssh_send_channel_data(ssh->mainchan, data, len); - bufchain_consume(&ssh->user_input, len); - } - crReturnV; + if (bufsize < SSH_MAX_BACKLOG) { + ssh_throttle_all(ssh, 0, bufsize); + queue_idempotent_callback(&ssh->ic_out_raw); } - - crFinishV; } -static void ssh2_connection_input(Ssh ssh) +static void ssh_hostport_setup(const char *host, int port, Conf *conf, + char **savedhost, int *savedport, + char **loghost_ret) { - do_ssh2_connection(ssh); -} + char *loghost = conf_get_str(conf, CONF_loghost); + if (loghost_ret) + *loghost_ret = loghost; -/* - * Handlers for SSH-2 messages that might arrive at any moment. - */ -static void ssh2_msg_disconnect(Ssh ssh, PktIn *pktin) -{ - /* log reason code in disconnect message */ - char *buf; - ptrlen msg; - int reason; + if (*loghost) { + char *tmphost; + char *colon; + + tmphost = dupstr(loghost); + *savedport = 22; /* default ssh port */ - reason = get_uint32(pktin); - msg = get_string(pktin); + /* + * A colon suffix on the hostname string also lets us affect + * savedport. (Unless there are multiple colons, in which case + * we assume this is an unbracketed IPv6 literal.) + */ + colon = host_strrchr(tmphost, ':'); + if (colon && colon == host_strchr(tmphost, ':')) { + *colon++ = '\0'; + if (*colon) + *savedport = atoi(colon); + } - if (reason > 0 && reason < lenof(ssh2_disconnect_reasons)) { - buf = dupprintf("Received disconnect message (%s)", - ssh2_disconnect_reasons[reason]); + *savedhost = host_strduptrim(tmphost); + sfree(tmphost); } else { - buf = dupprintf("Received disconnect message (unknown" - " type %d)", reason); + *savedhost = host_strduptrim(host); + if (port < 0) + port = 22; /* default ssh port */ + *savedport = port; } - logevent(buf); - sfree(buf); - buf = dupprintf("Disconnection message text: %.*s", PTRLEN_PRINTF(msg)); - logevent(buf); - bombout(("Server sent disconnect message\ntype %d (%s):\n\"%.*s\"", - reason, - (reason > 0 && reason < lenof(ssh2_disconnect_reasons)) ? - ssh2_disconnect_reasons[reason] : "unknown", PTRLEN_PRINTF(msg))); - sfree(buf); } -static void ssh2_msg_debug(Ssh ssh, PktIn *pktin) +static int ssh_test_for_upstream(const char *host, int port, Conf *conf) { - /* log the debug message */ - ptrlen msg; + char *savedhost; + int savedport; + int ret; - /* XXX maybe we should actually take notice of the return value */ - get_bool(pktin); - msg = get_string(pktin); + random_ref(); /* platform may need this to determine share socket name */ + ssh_hostport_setup(host, port, conf, &savedhost, &savedport, NULL); + ret = ssh_share_test_for_upstream(savedhost, savedport, conf); + sfree(savedhost); + random_unref(); - logeventf(ssh, "Remote debug message: %.*s", PTRLEN_PRINTF(msg)); + return ret; } -static void ssh2_msg_transport(Ssh ssh, PktIn *pktin) -{ - pq_push(&ssh->pq_ssh2_transport, pktin); - queue_idempotent_callback(&ssh->ssh2_transport_icb); -} +static const Plug_vtable Ssh_plugvt = { + ssh_socket_log, + ssh_closing, + ssh_receive, + ssh_sent, + NULL +}; /* - * Called if we receive a packet that isn't allowed by the protocol. - * This only applies to packets whose meaning PuTTY understands. - * Entirely unknown packets are handled below. + * Connect to specified host and port. + * Returns an error message, or NULL on success. + * Also places the canonical host name into `realhost'. It must be + * freed by the caller. */ -static void ssh2_msg_unexpected(Ssh ssh, PktIn *pktin) +static const char *connect_to_host(Ssh ssh, const char *host, int port, + char **realhost, int nodelay, int keepalive) { - char *buf = dupprintf("Server protocol violation: unexpected %s packet", - ssh2_pkt_type(ssh->pls.kctx, ssh->pls.actx, - pktin->type)); - ssh_disconnect(ssh, NULL, buf, SSH2_DISCONNECT_PROTOCOL_ERROR, FALSE); - sfree(buf); -} + SockAddr addr; + const char *err; + char *loghost; + int addressfamily, sshprot; -/* - * Handle the top-level SSH-2 protocol. - */ -static void ssh2_protocol_setup(Ssh ssh) -{ - int i; + ssh_hostport_setup(host, port, ssh->conf, + &ssh->savedhost, &ssh->savedport, &loghost); - ssh->bpp = ssh2_bpp_new(&ssh->stats); + ssh->plugvt = &Ssh_plugvt; -#ifndef NO_GSSAPI - /* Load and pick the highest GSS library on the preference list. */ - if (!ssh->gsslibs) - ssh->gsslibs = ssh_gss_setup(ssh->conf); - ssh->gsslib = NULL; - if (ssh->gsslibs->nlibraries > 0) { - int i, j; - for (i = 0; i < ngsslibs; i++) { - int want_id = conf_get_int_int(ssh->conf, - CONF_ssh_gsslist, i); - for (j = 0; j < ssh->gsslibs->nlibraries; j++) - if (ssh->gsslibs->libraries[j].id == want_id) { - ssh->gsslib = &ssh->gsslibs->libraries[j]; - goto got_gsslib; /* double break */ - } + /* + * Try connection-sharing, in case that means we don't open a + * socket after all. ssh_connection_sharing_init will connect to a + * previously established upstream if it can, and failing that, + * establish a listening socket for _us_ to be the upstream. In + * the latter case it will return NULL just as if it had done + * nothing, because here we only need to care if we're a + * downstream and need to do our connection setup differently. + */ + ssh->connshare = NULL; + ssh->attempting_connshare = TRUE; /* affects socket logging behaviour */ + ssh->s = ssh_connection_sharing_init( + ssh->savedhost, ssh->savedport, ssh->conf, ssh->frontend, + &ssh->plugvt, &ssh->connshare); + ssh->attempting_connshare = FALSE; + if (ssh->s != NULL) { + /* + * We are a downstream. + */ + ssh->bare_connection = TRUE; + ssh->fullhostname = NULL; + *realhost = dupstr(host); /* best we can do */ + + if ((flags & FLAG_VERBOSE) || (flags & FLAG_INTERACTIVE)) { + /* In an interactive session, or in verbose mode, announce + * in the console window that we're a sharing downstream, + * to avoid confusing users as to why this session doesn't + * behave in quite the usual way. */ + const char *msg = + "Reusing a shared connection to this server.\r\n"; + from_backend(ssh->frontend, TRUE, msg, strlen(msg)); } - got_gsslib: + } else { /* - * We always expect to have found something in - * the above loop: we only came here if there - * was at least one viable GSS library, and the - * preference list should always mention - * everything and only change the order. + * We're not a downstream, so open a normal socket. */ - assert(ssh->gsslib); - } -#endif - /* - * All message types we don't set explicitly will dispatch to - * ssh2_msg_unexpected. - */ - for (i = 0; i < SSH_MAX_MSG; i++) - ssh->packet_dispatch[i] = ssh2_msg_unexpected; + /* + * Try to find host. + */ + addressfamily = conf_get_int(ssh->conf, CONF_addressfamily); + addr = name_lookup(host, port, realhost, ssh->conf, addressfamily, + ssh->frontend, "SSH connection"); + if ((err = sk_addr_error(addr)) != NULL) { + sk_addr_free(addr); + return err; + } + ssh->fullhostname = dupstr(*realhost); /* save in case of GSSAPI */ - /* - * Initially, we only accept transport messages (and a few generic - * ones). do_ssh2_userauth and do_ssh2_connection will each add - * more when they start. - */ - ssh->packet_dispatch[SSH2_MSG_KEXINIT] = ssh2_msg_transport; - ssh->packet_dispatch[SSH2_MSG_NEWKEYS] = ssh2_msg_transport; - ssh->packet_dispatch[SSH2_MSG_KEXDH_INIT] = ssh2_msg_transport; - ssh->packet_dispatch[SSH2_MSG_KEXDH_REPLY] = ssh2_msg_transport; - /* ssh->packet_dispatch[SSH2_MSG_KEX_DH_GEX_REQUEST] = ssh2_msg_transport; duplicate case value */ - /* ssh->packet_dispatch[SSH2_MSG_KEX_DH_GEX_GROUP] = ssh2_msg_transport; duplicate case value */ - ssh->packet_dispatch[SSH2_MSG_KEX_DH_GEX_INIT] = ssh2_msg_transport; - ssh->packet_dispatch[SSH2_MSG_KEX_DH_GEX_REPLY] = ssh2_msg_transport; - ssh->packet_dispatch[SSH2_MSG_KEXGSS_GROUP] = ssh2_msg_transport; + ssh->s = new_connection(addr, *realhost, port, + 0, 1, nodelay, keepalive, + &ssh->plugvt, ssh->conf); + if ((err = sk_socket_error(ssh->s)) != NULL) { + ssh->s = NULL; + notify_remote_exit(ssh->frontend); + return err; + } + } /* - * These messages have a special handler from the start. + * The SSH version number is always fixed (since we no longer support + * fallback between versions), so set it now. */ - ssh->packet_dispatch[SSH2_MSG_DISCONNECT] = ssh2_msg_disconnect; - ssh->packet_dispatch[SSH2_MSG_IGNORE] = ssh_msg_ignore; /* shared with SSH-1 */ - ssh->packet_dispatch[SSH2_MSG_DEBUG] = ssh2_msg_debug; -} - -static void ssh2_bare_connection_protocol_setup(Ssh ssh) -{ - int i; - - ssh->bpp = ssh2_bare_bpp_new(); + sshprot = conf_get_int(ssh->conf, CONF_sshprot); + assert(sshprot == 0 || sshprot == 3); + if (sshprot == 0) + /* SSH-1 only */ + ssh->version = 1; + if (sshprot == 3 || ssh->bare_connection) { + /* SSH-2 only */ + ssh->version = 2; + } /* - * Everything defaults to ssh2_msg_unexpected for the moment; - * do_ssh2_connection will fill things in properly. But we do - * handle a couple of messages from the transport protocol which - * aren't related to key exchange (UNIMPLEMENTED, IGNORE, DEBUG, - * DISCONNECT). + * Set up the initial BPP that will do the version string + * exchange, and get it started so that it can send the outgoing + * version string early if it wants to. */ - for (i = 0; i < SSH_MAX_MSG; i++) - ssh->packet_dispatch[i] = ssh2_msg_unexpected; - - ssh->packet_dispatch[SSH2_MSG_DISCONNECT] = ssh2_msg_disconnect; - ssh->packet_dispatch[SSH2_MSG_IGNORE] = ssh_msg_ignore; - ssh->packet_dispatch[SSH2_MSG_DEBUG] = ssh2_msg_debug; -} - -#ifndef NO_GSSAPI -static PktOut *ssh2_gss_authpacket(Ssh ssh, Ssh_gss_ctx gss_ctx, - const char *authtype) -{ - strbuf *sb; - PktOut *p; - Ssh_gss_buf buf; - Ssh_gss_buf mic; + ssh->version_receiver.got_ssh_version = ssh_got_ssh_version; + ssh->bpp = ssh_verstring_new( + ssh->conf, ssh->frontend, ssh->bare_connection, + ssh->version == 1 ? "1.5" : "2.0", &ssh->version_receiver); + ssh_connect_bpp(ssh); + queue_idempotent_callback(&ssh->bpp->ic_in_raw); /* - * The mic is computed over the session id + intended - * USERAUTH_REQUEST packet. + * loghost, if configured, overrides realhost. */ - sb = strbuf_new(); - put_string(sb, ssh->v2_session_id, ssh->v2_session_id_len); - put_byte(sb, SSH2_MSG_USERAUTH_REQUEST); - put_stringz(sb, ssh->username); - put_stringz(sb, "ssh-connection"); - put_stringz(sb, authtype); - - /* Compute the mic */ - buf.value = sb->s; - buf.length = sb->len; - ssh->gsslib->get_mic(ssh->gsslib, gss_ctx, &buf, &mic); - strbuf_free(sb); - - /* Now we can build the real packet */ - if (strcmp(authtype, "gssapi-with-mic") == 0) { - p = ssh_bpp_new_pktout(ssh->bpp, SSH2_MSG_USERAUTH_GSSAPI_MIC); - } else { - p = ssh_bpp_new_pktout(ssh->bpp, SSH2_MSG_USERAUTH_REQUEST); - put_stringz(p, ssh->username); - put_stringz(p, "ssh-connection"); - put_stringz(p, authtype); + if (*loghost) { + sfree(*realhost); + *realhost = dupstr(loghost); } - put_string(p, mic.value, mic.length); - return p; + return NULL; } /* - * This is called at the beginning of each SSH rekey to determine whether we are - * GSS capable, and if we did GSS key exchange, and are delegating credentials, - * it is also called periodically to determine whether we should rekey in order - * to delegate (more) fresh credentials. This is called "credential cascading". - * - * On Windows, with SSPI, we may not get the credential expiration, as Windows - * automatically renews from cached passwords, so the credential effectively - * never expires. Since we still want to cascade when the local TGT is updated, - * we use the expiration of a newly obtained context as a proxy for the - * expiration of the TGT. + * Throttle or unthrottle the SSH connection. */ -static void ssh2_gss_update(Ssh ssh, int definitely_rekeying) +void ssh_throttle_conn(Ssh ssh, int adjust) { - int gss_stat; - time_t gss_cred_expiry; - unsigned long mins; - Ssh_gss_buf gss_sndtok; - Ssh_gss_buf gss_rcvtok; - Ssh_gss_ctx gss_ctx; - - ssh->gss_status = 0; + int old_count = ssh->conn_throttle_count; + int frozen; - /* - * Nothing to do if no GSSAPI libraries are configured or GSSAPI auth is not - * enabled. - */ - if (ssh->gsslibs->nlibraries == 0) - return; - if (!conf_get_int(ssh->conf, CONF_try_gssapi_auth) && - !conf_get_int(ssh->conf, CONF_try_gssapi_kex)) - return; + ssh->conn_throttle_count += adjust; + assert(ssh->conn_throttle_count >= 0); - /* Import server name and cache it */ - if (ssh->gss_srv_name == GSS_C_NO_NAME) { - gss_stat = ssh->gsslib->import_name(ssh->gsslib, - ssh->fullhostname, - &ssh->gss_srv_name); - if (gss_stat != SSH_GSS_OK) { - if (gss_stat == SSH_GSS_BAD_HOST_NAME) - logevent("GSSAPI import name failed -" - " Bad service name; won't use GSS key exchange"); - else - logevent("GSSAPI import name failed;" - " won't use GSS key exchange"); - return; - } + if (ssh->conn_throttle_count && !old_count) { + frozen = TRUE; + } else if (!ssh->conn_throttle_count && old_count) { + frozen = FALSE; + } else { + return; /* don't change current frozen state */ } - /* - * Do we (still) have credentials? Capture the credential expiration when - * available - */ - gss_stat = ssh->gsslib->acquire_cred(ssh->gsslib, - &gss_ctx, - &gss_cred_expiry); - if (gss_stat != SSH_GSS_OK) - return; + ssh->frozen = frozen; - SSH_GSS_CLEAR_BUF(&gss_sndtok); - SSH_GSS_CLEAR_BUF(&gss_rcvtok); + if (ssh->s) { + sk_set_frozen(ssh->s, frozen); - /* - * When acquire_cred yields no useful expiration, get a proxy for the cred - * expiration from the context expiration. - */ - gss_stat = ssh->gsslib->init_sec_context( - ssh->gsslib, &gss_ctx, ssh->gss_srv_name, - 0 /* don't delegate */, &gss_rcvtok, &gss_sndtok, - (gss_cred_expiry == GSS_NO_EXPIRATION ? &gss_cred_expiry : NULL), - &ssh->gss_ctxt_lifetime); - - /* This context was for testing only. */ - if (gss_ctx) - ssh->gsslib->release_cred(ssh->gsslib, &gss_ctx); - - if (gss_stat != SSH_GSS_OK && - gss_stat != SSH_GSS_S_CONTINUE_NEEDED) { /* - * No point in verbosely interrupting the user to tell them we - * couldn't get GSS credentials, if this was only a check - * between key exchanges to see if fresh ones were available. - * When we do do a rekey, this message (if displayed) will - * appear among the standard rekey blurb, but when we're not, - * it shouldn't pop up all the time regardless. + * Now process any SSH connection data that was stashed in our + * queue while we were frozen. */ - if (definitely_rekeying) - logeventf(ssh, "No GSSAPI security context available"); - - return; + queue_idempotent_callback(&ssh->bpp->ic_in_raw); } - - if (gss_sndtok.length) - ssh->gsslib->free_tok(ssh->gsslib, &gss_sndtok); - - ssh->gss_status |= GSS_KEX_CAPABLE; - - /* - * When rekeying to cascade, avoding doing this too close to the context - * expiration time, since the key exchange might fail. - */ - if (ssh->gss_ctxt_lifetime < MIN_CTXT_LIFETIME) - ssh->gss_status |= GSS_CTXT_MAYFAIL; - - /* - * If we're not delegating credentials, rekeying is not used to refresh - * them. We must avoid setting GSS_CRED_UPDATED or GSS_CTXT_EXPIRES when - * credential delegation is disabled. - */ - if (conf_get_int(ssh->conf, CONF_gssapifwd) == 0) - return; - - if (ssh->gss_cred_expiry != GSS_NO_EXPIRATION && - difftime(gss_cred_expiry, ssh->gss_cred_expiry) > 0) - ssh->gss_status |= GSS_CRED_UPDATED; - - mins = conf_get_int(ssh->conf, CONF_gssapirekey); - mins = rekey_mins(mins, GSS_DEF_REKEY_MINS); - if (mins > 0 && ssh->gss_ctxt_lifetime <= mins * 60) - ssh->gss_status |= GSS_CTXT_EXPIRES; } -#endif /* - * The rekey_time is zero except when re-configuring. - * - * We either schedule the next timer and return 0, or return 1 to run the - * callback now, which will call us again to re-schedule on completion. + * Throttle or unthrottle _all_ local data streams (for when sends + * on the SSH connection itself back up). */ -static int ssh2_timer_update(Ssh ssh, unsigned long rekey_time) -{ - unsigned long mins; - unsigned long ticks; - - mins = conf_get_int(ssh->conf, CONF_ssh_rekey_time); - mins = rekey_mins(mins, 60); - ticks = mins * 60 * TICKSPERSEC; - - /* Handle change from previous setting */ - if (rekey_time != 0 && rekey_time != mins) { - unsigned long next; - unsigned long now = GETTICKCOUNT(); - - mins = rekey_time; - ticks = mins * 60 * TICKSPERSEC; - next = ssh->last_rekey + ticks; - - /* If overdue, caller will rekey synchronously now */ - if (now - ssh->last_rekey > ticks) - return 1; - ticks = next - now; - } - -#ifndef NO_GSSAPI - if (ssh->gss_kex_used) { - /* - * If we've used GSSAPI key exchange, then we should - * periodically check whether we need to do another one to - * pass new credentials to the server. - */ - unsigned long gssmins; - - /* Check cascade conditions more frequently if configured */ - gssmins = conf_get_int(ssh->conf, CONF_gssapirekey); - gssmins = rekey_mins(gssmins, GSS_DEF_REKEY_MINS); - if (gssmins > 0) { - if (gssmins < mins) - ticks = (mins = gssmins) * 60 * TICKSPERSEC; - - if ((ssh->gss_status & GSS_KEX_CAPABLE) != 0) { - /* - * Run next timer even sooner if it would otherwise be too close - * to the context expiration time - */ - if ((ssh->gss_status & GSS_CTXT_EXPIRES) == 0 && - ssh->gss_ctxt_lifetime - mins * 60 < 2 * MIN_CTXT_LIFETIME) - ticks -= 2 * MIN_CTXT_LIFETIME * TICKSPERSEC; - } - } - } -#endif - - /* Schedule the next timer */ - ssh->next_rekey = schedule_timer(ticks, ssh2_timer, ssh); - return 0; -} - -static void ssh2_timer(void *ctx, unsigned long now) +static void ssh_throttle_all(Ssh ssh, int enable, int bufsize) { - Ssh ssh = (Ssh)ctx; - unsigned long mins; - unsigned long ticks; - - if (ssh->state == SSH_STATE_CLOSED || - ssh->kex_in_progress || - ssh->bare_connection || - now != ssh->next_rekey) - return; - - mins = conf_get_int(ssh->conf, CONF_ssh_rekey_time); - mins = rekey_mins(mins, 60); - if (mins == 0) + if (enable == ssh->throttled_all) return; + ssh->throttled_all = enable; + ssh->overall_bufsize = bufsize; - /* Rekey if enough time has elapsed */ - ticks = mins * 60 * TICKSPERSEC; - if (now - ssh->last_rekey > ticks - 30*TICKSPERSEC) { - ssh->rekey_reason = "timeout"; - ssh->rekey_class = RK_NORMAL; - queue_idempotent_callback(&ssh->ssh2_transport_icb); - return; - } - -#ifndef NO_GSSAPI - /* - * Rekey now if we have a new cred or context expires this cycle, but not if - * this is unsafe. - */ - if (conf_get_int(ssh->conf, CONF_gssapirekey)) { - ssh2_gss_update(ssh, FALSE); - if ((ssh->gss_status & GSS_KEX_CAPABLE) != 0 && - (ssh->gss_status & GSS_CTXT_MAYFAIL) == 0 && - (ssh->gss_status & (GSS_CRED_UPDATED|GSS_CTXT_EXPIRES)) != 0) { - ssh->rekey_reason = "GSS credentials updated"; - ssh->rekey_class = RK_GSS_UPDATE; - queue_idempotent_callback(&ssh->ssh2_transport_icb); - return; - } - } -#endif - - /* Try again later. */ - (void) ssh2_timer_update(ssh, 0); -} - -static void ssh2_general_packet_processing(Ssh ssh, PktIn *pktin) -{ - if (!ssh->kex_in_progress && ssh->max_data_size != 0 && - ssh->state != SSH_STATE_PREPACKET && !ssh->stats.in.running) { - ssh->rekey_reason = "too much data received"; - ssh->rekey_class = RK_NORMAL; - queue_idempotent_callback(&ssh->ssh2_transport_icb); - } + ssh_throttle_all_channels(ssh->cl, enable); } static void ssh_cache_conf_values(Ssh ssh) @@ -8959,143 +783,23 @@ static const char *ssh_init(Frontend *frontend, Backend **backend_handle, Ssh ssh; ssh = snew(struct ssh_tag); + memset(ssh, 0, sizeof(struct ssh_tag)); + ssh->conf = conf_copy(conf); ssh_cache_conf_values(ssh); - ssh->version = 0; /* when not ready yet */ - ssh->s = NULL; - ssh->kex = NULL; - ssh->dh_ctx = NULL; - ssh->hostkey_alg = NULL; - ssh->hostkey_str = NULL; ssh->exitcode = -1; - ssh->close_expected = FALSE; - ssh->clean_exit = FALSE; - ssh->disconnect_message_seen = FALSE; - ssh->state = SSH_STATE_PREPACKET; - ssh->size_needed = FALSE; - ssh->eof_needed = FALSE; - ssh->ldisc = NULL; - ssh->logctx = NULL; - ssh->fallback_cmd = 0; ssh->pls.kctx = SSH2_PKTCTX_NOKEX; ssh->pls.actx = SSH2_PKTCTX_NOAUTH; - ssh->x11disp = NULL; - ssh->x11auth = NULL; - ssh->x11authtree = newtree234(x11_authcmp); - ssh->v2_cbc_ignore_workaround = FALSE; - ssh->bpp = NULL; - ssh->do_ssh1_connection_crstate = 0; - ssh->do_ssh_init_state = NULL; - ssh->do_ssh_connection_init_state = NULL; - ssh->do_ssh1_login_state = NULL; - ssh->do_ssh2_transport_state = NULL; - ssh->do_ssh2_userauth_state = NULL; - ssh->do_ssh2_connection_state = NULL; - bufchain_init(&ssh->incoming_data); - ssh->incoming_data_seen_eof = FALSE; - ssh->incoming_data_eof_message = NULL; - ssh->incoming_data_consumer.fn = ssh_process_incoming_data; - ssh->incoming_data_consumer.ctx = ssh; - ssh->incoming_data_consumer.queued = FALSE; - ssh->incoming_pkt_consumer.fn = ssh_process_incoming_pkts; - ssh->incoming_pkt_consumer.ctx = ssh; - ssh->incoming_pkt_consumer.queued = FALSE; - pq_in_init(&ssh->pq_ssh1_login); - ssh->ssh1_login_icb.fn = do_ssh1_login; - ssh->ssh1_login_icb.ctx = ssh; - ssh->ssh1_login_icb.queued = FALSE; - pq_in_init(&ssh->pq_ssh1_connection); - ssh->ssh1_connection_icb.fn = do_ssh1_connection; - ssh->ssh1_connection_icb.ctx = ssh; - ssh->ssh1_connection_icb.queued = FALSE; - pq_in_init(&ssh->pq_ssh2_transport); - ssh->ssh2_transport_icb.fn = do_ssh2_transport; - ssh->ssh2_transport_icb.ctx = ssh; - ssh->ssh2_transport_icb.queued = FALSE; - pq_in_init(&ssh->pq_ssh2_userauth); - ssh->ssh2_userauth_icb.fn = do_ssh2_userauth; - ssh->ssh2_userauth_icb.ctx = ssh; - ssh->ssh2_userauth_icb.queued = FALSE; - pq_in_init(&ssh->pq_ssh2_connection); - ssh->ssh2_connection_icb.fn = do_ssh2_connection; - ssh->ssh2_connection_icb.ctx = ssh; - ssh->ssh2_connection_icb.queued = FALSE; + bufchain_init(&ssh->in_raw); + bufchain_init(&ssh->out_raw); bufchain_init(&ssh->user_input); - ssh->user_input_consumer.fn = ssh_process_user_input; - ssh->user_input_consumer.ctx = ssh; - ssh->user_input_consumer.queued = FALSE; - bufchain_init(&ssh->outgoing_data); - ssh->outgoing_data_sender.fn = ssh_send_outgoing_data; - ssh->outgoing_data_sender.ctx = ssh; - ssh->outgoing_data_sender.queued = FALSE; - ssh->current_user_input_fn = NULL; - ssh->rekey_reason = NULL; - ssh->rekey_class = RK_INITIAL; - ssh->v_c = NULL; - ssh->v_s = NULL; - ssh->mainchan = NULL; - ssh->throttled_all = 0; - ssh->v1_stdout_throttling = 0; - pq_out_init(&ssh->outq); - ssh->queueing = FALSE; - ssh->qhead = ssh->qtail = NULL; - ssh->deferred_rekey_reason = NULL; - ssh->frozen = FALSE; - ssh->username = NULL; - ssh->sent_console_eof = FALSE; - ssh->got_pty = FALSE; - ssh->bare_connection = FALSE; - ssh->X11_fwd_enabled = FALSE; - ssh->connshare = NULL; - ssh->attempting_connshare = FALSE; - ssh->session_started = FALSE; - ssh->specials = NULL; - ssh->n_uncert_hostkeys = 0; - ssh->cross_certifying = FALSE; - -#ifndef NO_GSSAPI - ssh->gss_cred_expiry = GSS_NO_EXPIRATION; - ssh->gss_srv_name = GSS_C_NO_NAME; - ssh->gss_ctx = NULL; - ssh_init_transient_hostkey_store(ssh); -#endif - ssh->gss_kex_used = FALSE; + ssh->ic_out_raw.fn = ssh_bpp_output_raw_data_callback; + ssh->ic_out_raw.ctx = ssh; ssh->backend.vt = &ssh_backend; *backend_handle = &ssh->backend; ssh->frontend = frontend; - ssh->term_width = conf_get_int(ssh->conf, CONF_width); - ssh->term_height = conf_get_int(ssh->conf, CONF_height); - - ssh->cl.vt = &ssh_connlayer_vtable; - ssh->cl.frontend = ssh->frontend; - - ssh->channels = NULL; - ssh->rportfwds = NULL; - ssh->portfwdmgr = portfwdmgr_new(&ssh->cl); - - ssh->send_ok = 0; - ssh->editing = 0; - ssh->echoing = 0; - ssh->conn_throttle_count = 0; - ssh->overall_bufsize = 0; - ssh->fallback_cmd = 0; - - ssh->general_packet_processing = NULL; - - ssh->pinger = NULL; - - memset(&ssh->stats, 0, sizeof(ssh->stats)); - ssh->max_data_size = parse_blocksize(conf_get_str(ssh->conf, - CONF_ssh_rekey_data)); - ssh->kex_in_progress = FALSE; - - ssh->auth_agent_query = NULL; - -#ifndef NO_GSSAPI - ssh->gsslibs = NULL; -#endif random_ref(); /* do this now - may be needed by sharing setup code */ ssh->need_random_unref = TRUE; @@ -9117,102 +821,28 @@ static const char *ssh_init(Frontend *frontend, Backend **backend_handle, static void ssh_free(Backend *be) { Ssh ssh = FROMFIELD(be, struct ssh_tag, backend); - struct ssh_channel *c; - struct ssh_rportfwd *pf; - struct X11FakeAuth *auth; int need_random_unref; - if (ssh->dh_ctx) - dh_cleanup(ssh->dh_ctx); - sfree(ssh->savedhost); - - pq_out_clear(&ssh->outq); + ssh_shutdown(ssh); - while (ssh->qhead) { - struct queued_handler *qh = ssh->qhead; - ssh->qhead = qh->next; - sfree(qh); - } - ssh->qhead = ssh->qtail = NULL; - - if (ssh->channels) { - while ((c = delpos234(ssh->channels, 0)) != NULL) { - ssh_channel_close_local(c, NULL); - if (ssh->version == 2) { - struct outstanding_channel_request *ocr, *nocr; - ocr = c->v.v2.chanreq_head; - while (ocr) { - ocr->handler(c, NULL, ocr->ctx); - nocr = ocr->next; - sfree(ocr); - ocr = nocr; - } - bufchain_clear(&c->v.v2.outbuffer); - } - sfree(c); - } - freetree234(ssh->channels); - ssh->channels = NULL; - } - - if (ssh->connshare) { + conf_free(ssh->conf); + if (ssh->connshare) sharestate_free(ssh->connshare); - ssh->connshare = NULL; - } - - if (ssh->rportfwds) { - while ((pf = delpos234(ssh->rportfwds, 0)) != NULL) - free_rportfwd(pf); - freetree234(ssh->rportfwds); - ssh->rportfwds = NULL; - } - portfwdmgr_free(ssh->portfwdmgr); - if (ssh->x11disp) - x11_free_display(ssh->x11disp); - while ((auth = delpos234(ssh->x11authtree, 0)) != NULL) - x11_free_fake_auth(auth); - if (ssh->bpp) - ssh_bpp_free(ssh->bpp); - freetree234(ssh->x11authtree); - sfree(ssh->do_ssh_init_state); - sfree(ssh->do_ssh1_login_state); - sfree(ssh->do_ssh2_transport_state); - sfree(ssh->do_ssh2_userauth_state); - sfree(ssh->do_ssh2_connection_state); - bufchain_clear(&ssh->incoming_data); - bufchain_clear(&ssh->outgoing_data); - sfree(ssh->incoming_data_eof_message); - pq_in_clear(&ssh->pq_ssh1_login); - pq_in_clear(&ssh->pq_ssh1_connection); - pq_in_clear(&ssh->pq_ssh2_transport); - pq_in_clear(&ssh->pq_ssh2_userauth); - pq_in_clear(&ssh->pq_ssh2_connection); - bufchain_clear(&ssh->user_input); - sfree(ssh->v_c); - sfree(ssh->v_s); + sfree(ssh->savedhost); sfree(ssh->fullhostname); - sfree(ssh->hostkey_str); sfree(ssh->specials); - if (ssh->s) - ssh_do_close(ssh, TRUE); - expire_timer_context(ssh); - if (ssh->pinger) - pinger_free(ssh->pinger); - sfree(ssh->username); - conf_free(ssh->conf); - - if (ssh->auth_agent_query) - agent_cancel_query(ssh->auth_agent_query); #ifndef NO_GSSAPI - if (ssh->gss_srv_name) - ssh->gsslib->release_name(ssh->gsslib, &ssh->gss_srv_name); - if (ssh->gss_ctx != NULL) - ssh->gsslib->release_cred(ssh->gsslib, &ssh->gss_ctx); - if (ssh->gsslibs) - ssh_gss_cleanup(ssh->gsslibs); - ssh_cleanup_transient_hostkey_store(ssh); + if (ssh->gss_state.srv_name) + ssh->gss_state.lib->release_name( + ssh->gss_state.lib, &ssh->gss_state.srv_name); + if (ssh->gss_state.ctx != NULL) + ssh->gss_state.lib->release_cred( + ssh->gss_state.lib, &ssh->gss_state.ctx); + if (ssh->gss_state.libs) + ssh_gss_cleanup(ssh->gss_state.libs); #endif + need_random_unref = ssh->need_random_unref; sfree(ssh); @@ -9226,72 +856,15 @@ static void ssh_free(Backend *be) static void ssh_reconfig(Backend *be, Conf *conf) { Ssh ssh = FROMFIELD(be, struct ssh_tag, backend); - const char *rekeying = NULL; - int rekey_mandatory = FALSE; - unsigned long old_max_data_size; - int i, rekey_time; - - pinger_reconfig(ssh->pinger, ssh->conf, conf); - portfwdmgr_config(ssh->portfwdmgr, conf); - - rekey_time = conf_get_int(conf, CONF_ssh_rekey_time); - if (ssh2_timer_update(ssh, rekey_mins(rekey_time, 60))) - rekeying = "timeout shortened"; - - old_max_data_size = ssh->max_data_size; - ssh->max_data_size = parse_blocksize(conf_get_str(ssh->conf, - CONF_ssh_rekey_data)); - if (old_max_data_size != ssh->max_data_size && - ssh->max_data_size != 0) { - if (ssh->max_data_size < old_max_data_size) { - unsigned long diff = old_max_data_size - ssh->max_data_size; - - /* Intentionally use bitwise OR instead of logical, so - * that we decrement both counters even if the first one - * runs out */ - if ((DTS_CONSUME(&ssh->stats, out, diff) != 0) | - (DTS_CONSUME(&ssh->stats, in, diff) != 0)) - rekeying = "data limit lowered"; - } else { - unsigned long diff = ssh->max_data_size - old_max_data_size; - if (ssh->stats.out.running) - ssh->stats.out.remaining += diff; - if (ssh->stats.in.running) - ssh->stats.in.remaining += diff; - } - } - if (conf_get_int(ssh->conf, CONF_compression) != - conf_get_int(conf, CONF_compression)) { - rekeying = "compression setting changed"; - rekey_mandatory = TRUE; - } + if (ssh->pinger) + pinger_reconfig(ssh->pinger, ssh->conf, conf); - for (i = 0; i < CIPHER_MAX; i++) - if (conf_get_int_int(ssh->conf, CONF_ssh_cipherlist, i) != - conf_get_int_int(conf, CONF_ssh_cipherlist, i)) { - rekeying = "cipher settings changed"; - rekey_mandatory = TRUE; - } - if (conf_get_int(ssh->conf, CONF_ssh2_des_cbc) != - conf_get_int(conf, CONF_ssh2_des_cbc)) { - rekeying = "cipher settings changed"; - rekey_mandatory = TRUE; - } + ssh_ppl_reconfigure(ssh->base_layer, conf); conf_free(ssh->conf); ssh->conf = conf_copy(conf); ssh_cache_conf_values(ssh); - - if (!ssh->bare_connection && rekeying) { - if (!ssh->kex_in_progress) { - ssh->rekey_reason = rekeying; - ssh->rekey_class = RK_NORMAL; - queue_idempotent_callback(&ssh->ssh2_transport_icb); - } else if (rekey_mandatory) { - ssh->deferred_rekey_reason = rekeying; - } - } } /* @@ -9305,7 +878,8 @@ static int ssh_send(Backend *be, const char *buf, int len) return 0; bufchain_add(&ssh->user_input, buf, len); - queue_idempotent_callback(&ssh->user_input_consumer); + if (ssh->base_layer) + ssh_ppl_got_user_input(ssh->base_layer); return backend_sendbuffer(&ssh->backend); } @@ -9316,30 +890,23 @@ static int ssh_send(Backend *be, const char *buf, int len) static int ssh_sendbuffer(Backend *be) { Ssh ssh = FROMFIELD(be, struct ssh_tag, backend); - int override_value; + int backlog; - if (ssh == NULL || ssh->s == NULL) + if (!ssh || !ssh->s || !ssh->cl) return 0; + backlog = ssh_stdin_backlog(ssh->cl); + + /* FIXME: also include sizes of pqs */ + /* * If the SSH socket itself has backed up, add the total backup * size on that to any individual buffer on the stdin channel. */ - override_value = 0; if (ssh->throttled_all) - override_value = ssh->overall_bufsize; - - if (ssh->version == 1) { - return override_value; - } else if (ssh->version == 2) { - if (!ssh->mainchan) - return override_value; - else - return (override_value + - bufchain_size(&ssh->mainchan->v.v2.outbuffer)); - } + backlog += ssh->overall_bufsize; - return 0; + return backlog; } /* @@ -9348,40 +915,34 @@ static int ssh_sendbuffer(Backend *be) static void ssh_size(Backend *be, int width, int height) { Ssh ssh = FROMFIELD(be, struct ssh_tag, backend); - PktOut *pktout; ssh->term_width = width; ssh->term_height = height; + if (ssh->cl) + ssh_terminal_size(ssh->cl, ssh->term_width, ssh->term_height); +} - switch (ssh->state) { - case SSH_STATE_BEFORE_SIZE: - case SSH_STATE_PREPACKET: - case SSH_STATE_CLOSED: - break; /* do nothing */ - case SSH_STATE_INTERMED: - ssh->size_needed = TRUE; /* buffer for later */ - break; - case SSH_STATE_SESSION: - if (!conf_get_int(ssh->conf, CONF_nopty)) { - if (ssh->version == 1) { - pktout = ssh_bpp_new_pktout(ssh->bpp, SSH1_CMSG_WINDOW_SIZE); - put_uint32(pktout, ssh->term_height); - put_uint32(pktout, ssh->term_width); - put_uint32(pktout, 0); - put_uint32(pktout, 0); - ssh_pkt_write(ssh, pktout); - } else if (ssh->mainchan) { - pktout = ssh2_chanreq_init(ssh->mainchan, "window-change", - NULL, NULL); - put_uint32(pktout, ssh->term_width); - put_uint32(pktout, ssh->term_height); - put_uint32(pktout, 0); - put_uint32(pktout, 0); - ssh2_pkt_send(ssh, pktout); - } - } - break; +struct ssh_add_special_ctx { + SessionSpecial *specials; + int nspecials, specials_size; +}; + +static void ssh_add_special(void *vctx, const char *text, + SessionSpecialCode code, int arg) +{ + struct ssh_add_special_ctx *ctx = (struct ssh_add_special_ctx *)vctx; + SessionSpecial *spec; + + if (ctx->nspecials >= ctx->specials_size) { + ctx->specials_size = ctx->nspecials * 5 / 4 + 32; + ctx->specials = sresize(ctx->specials, ctx->specials_size, + SessionSpecial); } + + spec = &ctx->specials[ctx->nspecials++]; + spec->name = text; + spec->code = code; + spec->arg = arg; } /* @@ -9390,244 +951,43 @@ static void ssh_size(Backend *be, int width, int height) */ static const SessionSpecial *ssh_get_specials(Backend *be) { - static const SessionSpecial ssh1_ignore_special[] = { - {"IGNORE message", SS_NOP} - }; - static const SessionSpecial ssh2_ignore_special[] = { - {"IGNORE message", SS_NOP}, - }; - static const SessionSpecial ssh2_rekey_special[] = { - {"Repeat key exchange", SS_REKEY}, - }; - static const SessionSpecial ssh2_session_specials[] = { - {NULL, SS_SEP}, - {"Break", SS_BRK}, - /* These are the signal names defined by RFC 4254. - * They include all the ISO C signals, but are a subset of the POSIX - * required signals. */ - {"SIGINT (Interrupt)", SS_SIGINT}, - {"SIGTERM (Terminate)", SS_SIGTERM}, - {"SIGKILL (Kill)", SS_SIGKILL}, - {"SIGQUIT (Quit)", SS_SIGQUIT}, - {"SIGHUP (Hangup)", SS_SIGHUP}, - {"More signals", SS_SUBMENU}, - {"SIGABRT", SS_SIGABRT}, {"SIGALRM", SS_SIGALRM}, - {"SIGFPE", SS_SIGFPE}, {"SIGILL", SS_SIGILL}, - {"SIGPIPE", SS_SIGPIPE}, {"SIGSEGV", SS_SIGSEGV}, - {"SIGUSR1", SS_SIGUSR1}, {"SIGUSR2", SS_SIGUSR2}, - {NULL, SS_EXITMENU} - }; - static const SessionSpecial specials_end[] = { - {NULL, SS_EXITMENU} - }; - - SessionSpecial *specials = NULL; - int nspecials = 0, specialsize = 0; - Ssh ssh = FROMFIELD(be, struct ssh_tag, backend); - sfree(ssh->specials); + /* + * Ask all our active protocol layers what specials they've got, + * and amalgamate the list into one combined one. + */ -#define ADD_SPECIALS(name) do \ - { \ - int len = lenof(name); \ - if (nspecials + len > specialsize) { \ - specialsize = (nspecials + len) * 5 / 4 + 32; \ - specials = sresize(specials, specialsize, SessionSpecial); \ - } \ - memcpy(specials+nspecials, name, len*sizeof(SessionSpecial)); \ - nspecials += len; \ - } while (0) - - if (ssh->version == 1) { - /* Don't bother offering IGNORE if we've decided the remote - * won't cope with it, since we wouldn't bother sending it if - * asked anyway. */ - if (!(ssh->remote_bugs & BUG_CHOKES_ON_SSH1_IGNORE)) - ADD_SPECIALS(ssh1_ignore_special); - } else if (ssh->version == 2) { - if (!(ssh->remote_bugs & BUG_CHOKES_ON_SSH2_IGNORE)) - ADD_SPECIALS(ssh2_ignore_special); - if (!(ssh->remote_bugs & BUG_SSH2_REKEY) && !ssh->bare_connection) - ADD_SPECIALS(ssh2_rekey_special); - if (ssh->mainchan) - ADD_SPECIALS(ssh2_session_specials); - - if (ssh->n_uncert_hostkeys) { - static const SessionSpecial uncert_start[] = { - {NULL, SS_SEP}, - {"Cache new host key type", SS_SUBMENU}, - }; - static const SessionSpecial uncert_end[] = { - {NULL, SS_EXITMENU}, - }; - int i; - - ADD_SPECIALS(uncert_start); - for (i = 0; i < ssh->n_uncert_hostkeys; i++) { - SessionSpecial uncert[1]; - const ssh_keyalg *alg = - hostkey_algs[ssh->uncert_hostkeys[i]].alg; - uncert[0].name = alg->ssh_id; - uncert[0].code = SS_XCERT; - uncert[0].arg = ssh->uncert_hostkeys[i]; - ADD_SPECIALS(uncert); - } - ADD_SPECIALS(uncert_end); - } - } /* else we're not ready yet */ + struct ssh_add_special_ctx ctx; - if (nspecials) - ADD_SPECIALS(specials_end); + ctx.specials = NULL; + ctx.nspecials = ctx.specials_size = 0; - ssh->specials = specials; + if (ssh->base_layer) + ssh_ppl_get_specials(ssh->base_layer, ssh_add_special, &ctx); - if (nspecials) { - return specials; - } else { - return NULL; + if (!ssh->specials) + return NULL; + + if (ctx.specials) { + /* If the list is non-empty, terminate it with a SS_EXITMENU. */ + ssh_add_special(&ctx, NULL, SS_EXITMENU, 0); } -#undef ADD_SPECIALS + + sfree(ssh->specials); + ssh->specials = ctx.specials; + return ssh->specials; } /* - * Send special codes. SS_EOF is useful for `plink', so you - * can send an EOF and collect resulting output (e.g. `plink - * hostname sort'). + * Send special codes. */ static void ssh_special(Backend *be, SessionSpecialCode code, int arg) { Ssh ssh = FROMFIELD(be, struct ssh_tag, backend); - PktOut *pktout; - - if (code == SS_EOF) { - if (ssh->state != SSH_STATE_SESSION) { - /* - * Buffer the EOF in case we are pre-SESSION, so we can - * send it as soon as we reach SESSION. - */ - if (code == SS_EOF) - ssh->eof_needed = TRUE; - return; - } - if (ssh->version == 1) { - pktout = ssh_bpp_new_pktout(ssh->bpp, SSH1_CMSG_EOF); - ssh_pkt_write(ssh, pktout); - } else if (ssh->mainchan) { - sshfwd_write_eof(&ssh->mainchan->sc); - ssh->send_ok = 0; /* now stop trying to read from stdin */ - } - logevent("Sent EOF message"); - } else if (code == SS_PING || code == SS_NOP) { - if (ssh->state == SSH_STATE_CLOSED - || ssh->state == SSH_STATE_PREPACKET) return; - if (ssh->version == 1) { - if (!(ssh->remote_bugs & BUG_CHOKES_ON_SSH1_IGNORE)) { - pktout = ssh_bpp_new_pktout(ssh->bpp, SSH1_MSG_IGNORE); - put_stringz(pktout, ""); - ssh_pkt_write(ssh, pktout); - } - } else { - if (!(ssh->remote_bugs & BUG_CHOKES_ON_SSH2_IGNORE)) { - pktout = ssh_bpp_new_pktout(ssh->bpp, SSH2_MSG_IGNORE); - put_stringz(pktout, ""); - ssh_pkt_write(ssh, pktout); - } - } - } else if (code == SS_REKEY) { - if (!ssh->kex_in_progress && !ssh->bare_connection && - ssh->version == 2) { - ssh->rekey_reason = "at user request"; - ssh->rekey_class = RK_NORMAL; - queue_idempotent_callback(&ssh->ssh2_transport_icb); - } - } else if (code == SS_XCERT) { - ssh->hostkey_alg = hostkey_algs[arg].alg; - ssh->cross_certifying = TRUE; - if (!ssh->kex_in_progress && !ssh->bare_connection && - ssh->version == 2) { - ssh->rekey_reason = "cross-certifying new host key"; - ssh->rekey_class = RK_NORMAL; - queue_idempotent_callback(&ssh->ssh2_transport_icb); - } - } else if (code == SS_BRK) { - if (ssh->state == SSH_STATE_CLOSED - || ssh->state == SSH_STATE_PREPACKET) return; - if (ssh->version == 1) { - logevent("Unable to send BREAK signal in SSH-1"); - } else if (ssh->mainchan) { - pktout = ssh2_chanreq_init(ssh->mainchan, "break", NULL, NULL); - put_uint32(pktout, 0); /* default break length */ - ssh2_pkt_send(ssh, pktout); - } - } else { - /* Is is a POSIX signal? */ - const char *signame = NULL; - if (code == SS_SIGABRT) signame = "ABRT"; - if (code == SS_SIGALRM) signame = "ALRM"; - if (code == SS_SIGFPE) signame = "FPE"; - if (code == SS_SIGHUP) signame = "HUP"; - if (code == SS_SIGILL) signame = "ILL"; - if (code == SS_SIGINT) signame = "INT"; - if (code == SS_SIGKILL) signame = "KILL"; - if (code == SS_SIGPIPE) signame = "PIPE"; - if (code == SS_SIGQUIT) signame = "QUIT"; - if (code == SS_SIGSEGV) signame = "SEGV"; - if (code == SS_SIGTERM) signame = "TERM"; - if (code == SS_SIGUSR1) signame = "USR1"; - if (code == SS_SIGUSR2) signame = "USR2"; - /* The SSH-2 protocol does in principle support arbitrary named - * signals, including signame@domain, but we don't support those. */ - if (signame) { - /* It's a signal. */ - if (ssh->version == 2 && ssh->mainchan) { - pktout = ssh2_chanreq_init(ssh->mainchan, "signal", NULL, NULL); - put_stringz(pktout, signame); - ssh2_pkt_send(ssh, pktout); - logeventf(ssh, "Sent signal SIG%s", signame); - } - } else { - /* Never heard of it. Do nothing */ - } - } -} - -static unsigned (ssh_alloc_sharing_channel)( - ConnectionLayer *cl, ssh_sharing_connstate *connstate) -{ - Ssh ssh = FROMFIELD(cl, struct ssh_tag, cl); - struct ssh_channel *c; - c = snew(struct ssh_channel); - - c->ssh = ssh; - ssh_channel_init(c); - c->chan = NULL; - c->sharectx = connstate; - return c->localid; -} - -static void (ssh_delete_sharing_channel)(ConnectionLayer *cl, unsigned localid) -{ - Ssh ssh = FROMFIELD(cl, struct ssh_tag, cl); - struct ssh_channel *c; - c = find234(ssh->channels, &localid, ssh_channelfind); - if (c) - ssh_channel_destroy(c); -} - -static void (ssh_send_packet_from_downstream)( - ConnectionLayer *cl, unsigned id, int type, - const void *data, int datalen, const char *additional_log_text) -{ - Ssh ssh = FROMFIELD(cl, struct ssh_tag, cl); - PktOut *pkt; - - pkt = ssh_bpp_new_pktout(ssh->bpp, type); - pkt->downstream_id = id; - pkt->additional_log_text = additional_log_text; - put_data(pkt, data, datalen); - ssh2_pkt_send(ssh, pkt); + if (ssh->base_layer) + ssh_ppl_special_cmd(ssh->base_layer, code, arg); } /* @@ -9638,69 +998,7 @@ static void ssh_unthrottle(Backend *be, int bufsize) { Ssh ssh = FROMFIELD(be, struct ssh_tag, backend); - if (ssh->version == 1) { - if (ssh->v1_stdout_throttling && bufsize < SSH1_BUFFER_LIMIT) { - ssh->v1_stdout_throttling = 0; - ssh_throttle_conn(ssh, -1); - } - } else { - if (ssh->mainchan) - ssh_channel_unthrottle(ssh->mainchan, bufsize); - } - - /* - * Now process any SSH connection data that was stashed in our - * queue while we were frozen. - */ - queue_idempotent_callback(&ssh->incoming_data_consumer); -} - -static SshChannel *(ssh_lportfwd_open)( - ConnectionLayer *cl, const char *hostname, int port, - const char *org, Channel *chan) -{ - Ssh ssh = FROMFIELD(cl, struct ssh_tag, cl); - struct ssh_channel *c = snew(struct ssh_channel); - PktOut *pktout; - - c->ssh = ssh; - ssh_channel_init(c); - c->halfopen = TRUE; - c->chan = chan; - - logeventf(ssh, "Opening connection to %s:%d for %s", hostname, port, org); - - if (ssh->version == 1) { - pktout = ssh_bpp_new_pktout(ssh->bpp, SSH1_MSG_PORT_OPEN); - put_uint32(pktout, c->localid); - put_stringz(pktout, hostname); - put_uint32(pktout, port); - /* originator string would go here, but we didn't specify - * SSH_PROTOFLAG_HOST_IN_FWD_OPEN */ - ssh_pkt_write(ssh, pktout); - } else { - pktout = ssh2_chanopen_init(c, "direct-tcpip"); - { - char *trimmed_host = host_strduptrim(hostname); - put_stringz(pktout, trimmed_host); - sfree(trimmed_host); - } - put_uint32(pktout, port); - /* - * We make up values for the originator data; partly it's - * too much hassle to keep track, and partly I'm not - * convinced the server should be told details like that - * about my local network configuration. - * The "originator IP address" is syntactically a numeric - * IP address, and some servers (e.g., Tectia) get upset - * if it doesn't match this syntax. - */ - put_stringz(pktout, "0.0.0.0"); - put_uint32(pktout, 0); - ssh2_pkt_send(ssh, pktout); - } - - return &c->sc; + ssh_stdout_unthrottle(ssh->cl, bufsize); } static int ssh_connected(Backend *be) @@ -9712,17 +1010,21 @@ static int ssh_connected(Backend *be) static int ssh_sendok(Backend *be) { Ssh ssh = FROMFIELD(be, struct ssh_tag, backend); - return ssh->send_ok; + return ssh->base_layer && ssh_ppl_want_user_input(ssh->base_layer); +} + +void ssh_ldisc_update(Ssh ssh) +{ + /* Called when the connection layer wants to propagate an update + * to the line discipline options */ + if (ssh->ldisc) + ldisc_echoedit_update(ssh->ldisc); } static int ssh_ldisc(Backend *be, int option) { Ssh ssh = FROMFIELD(be, struct ssh_tag, backend); - if (option == LD_ECHO) - return ssh->echoing; - if (option == LD_EDIT) - return ssh->editing; - return FALSE; + return ssh->cl ? ssh_ldisc_option(ssh->cl, option) : FALSE; } static void ssh_provide_ldisc(Backend *be, Ldisc *ldisc) @@ -9737,10 +1039,15 @@ static void ssh_provide_logctx(Backend *be, LogContext *logctx) ssh->logctx = logctx; } +void ssh_got_exitcode(Ssh ssh, int exitcode) +{ + ssh->exitcode = exitcode; +} + static int ssh_return_exitcode(Backend *be) { Ssh ssh = FROMFIELD(be, struct ssh_tag, backend); - if (ssh->s != NULL) + if (ssh->s && (!ssh->session_started || ssh->base_layer)) return -1; else return (ssh->exitcode >= 0 ? ssh->exitcode : INT_MAX); @@ -9773,6 +1080,11 @@ extern int ssh_fallback_cmd(Backend *be) return ssh->fallback_cmd; } +void ssh_got_fallback_cmd(Ssh ssh) +{ + ssh->fallback_cmd = TRUE; +} + const struct Backend_vtable ssh_backend = { ssh_init, ssh_free, diff --git a/ssh.h b/ssh.h index e9db3219..797b40c9 100644 --- a/ssh.h +++ b/ssh.h @@ -183,7 +183,18 @@ void share_setup_x11_channel(ssh_sharing_connstate *cs, share_channel *chan, int protomajor, int protominor, const void *initial_data, int initial_len); -struct ssh_rportfwd; +/* Structure definition centralised here because the SSH-1 and SSH-2 + * connection layers both use it. But the client module (portfwd.c) + * should not try to look inside here. */ +struct ssh_rportfwd { + unsigned sport, dport; + char *shost, *dhost; + int addressfamily; + char *log_description; /* name of remote listening port, for logging */ + ssh_sharing_connstate *share_ctx; + PortFwdRecord *pfr; +}; +void free_rportfwd(struct ssh_rportfwd *rpf); struct ConnectionLayerVtable { /* Allocate and free remote-to-local port forwardings, called by @@ -227,6 +238,25 @@ struct ConnectionLayerVtable { /* Query whether the connection layer is doing agent forwarding */ int (*agent_forwarding_permitted)(ConnectionLayer *cl); + + /* Set the size of the main terminal window (if any) */ + void (*terminal_size)(ConnectionLayer *cl, int width, int height); + + /* Indicate that the backlog on standard output has cleared */ + void (*stdout_unthrottle)(ConnectionLayer *cl, int bufsize); + + /* Query the size of the backlog on standard _input_ */ + int (*stdin_backlog)(ConnectionLayer *cl); + + /* Tell the connection layer that the SSH connection itself has + * backed up, so it should tell all currently open channels to + * cease reading from their local input sources if they can. (Or + * tell it that that state of affairs has gone away again.) */ + void (*throttle_all_channels)(ConnectionLayer *cl, int throttled); + + /* Ask the connection layer about its current preference for + * line-discipline options. */ + int (*ldisc_option)(ConnectionLayer *cl, int option); }; struct ConnectionLayer { @@ -253,6 +283,13 @@ struct ConnectionLayer { ((cl)->vt->sharing_queue_global_request(cl, cs)) #define ssh_agent_forwarding_permitted(cl) \ ((cl)->vt->agent_forwarding_permitted(cl)) +#define ssh_terminal_size(cl, w, h) ((cl)->vt->terminal_size(cl, w, h)) +#define ssh_stdout_unthrottle(cl, bufsize) \ + ((cl)->vt->stdout_unthrottle(cl, bufsize)) +#define ssh_stdin_backlog(cl) ((cl)->vt->stdin_backlog(cl)) +#define ssh_throttle_all_channels(cl, throttled) \ + ((cl)->vt->throttle_all_channels(cl, throttled)) +#define ssh_ldisc_option(cl, option) ((cl)->vt->ldisc_option(cl, option)) /* Exports from portfwd.c */ PortFwdManager *portfwdmgr_new(ConnectionLayer *cl); @@ -266,6 +303,19 @@ char *portfwdmgr_connect(PortFwdManager *mgr, Channel **chan_ret, Frontend *ssh_get_frontend(Ssh ssh); +/* Communications back to ssh.c from connection layers */ +void ssh_throttle_conn(Ssh ssh, int adjust); +void ssh_got_exitcode(Ssh ssh, int status); +void ssh_ldisc_update(Ssh ssh); +void ssh_got_fallback_cmd(Ssh ssh); + +/* Functions to abort the connection, for various reasons. */ +void ssh_remote_error(Ssh ssh, const char *fmt, ...); +void ssh_remote_eof(Ssh ssh, const char *fmt, ...); +void ssh_proto_error(Ssh ssh, const char *fmt, ...); +void ssh_sw_abort(Ssh ssh, const char *fmt, ...); +void ssh_user_close(Ssh ssh, const char *fmt, ...); + #define SSH_CIPHER_IDEA 1 #define SSH_CIPHER_DES 2 #define SSH_CIPHER_3DES 3 @@ -1241,10 +1291,6 @@ enum { #undef DEF_ENUM_UNIVERSAL #undef DEF_ENUM_CONTEXTUAL -/* Given that virtual packet types exist, this is how big the dispatch - * table has to be */ -#define SSH_MAX_MSG 0x101 - /* * SSH-1 agent messages. */ diff --git a/ssh1bpp.c b/ssh1bpp.c index 4b775929..e57676cc 100644 --- a/ssh1bpp.c +++ b/ssh1bpp.c @@ -88,8 +88,11 @@ void ssh1_bpp_new_cipher(BinaryPacketProtocol *bpp, #define BPP_READ(ptr, len) do \ { \ - crMaybeWaitUntilV(bufchain_try_fetch_consume( \ + crMaybeWaitUntilV(s->bpp.input_eof || \ + bufchain_try_fetch_consume( \ s->bpp.in_raw, ptr, len)); \ + if (s->bpp.input_eof) \ + goto eof; \ } while (0) static void ssh1_bpp_handle_input(BinaryPacketProtocol *bpp) @@ -109,9 +112,9 @@ static void ssh1_bpp_handle_input(BinaryPacketProtocol *bpp) } if (s->len < 0 || s->len > 262144) { /* SSH1.5-mandated max size */ - s->bpp.error = dupprintf( - "Extremely large packet length from server suggests" - " data stream corruption"); + ssh_sw_abort(s->bpp.ssh, + "Extremely large packet length from server suggests" + " data stream corruption"); crStopV; } @@ -134,8 +137,8 @@ static void ssh1_bpp_handle_input(BinaryPacketProtocol *bpp) if (s->cipher && detect_attack(s->crcda_ctx, s->data, s->biglen, NULL)) { - s->bpp.error = dupprintf( - "Network attack (CRC compensation) detected!"); + ssh_sw_abort(s->bpp.ssh, + "Network attack (CRC compensation) detected!"); crStopV; } @@ -145,8 +148,7 @@ static void ssh1_bpp_handle_input(BinaryPacketProtocol *bpp) s->realcrc = crc32_compute(s->data, s->biglen - 4); s->gotcrc = GET_32BIT(s->data + s->biglen - 4); if (s->gotcrc != s->realcrc) { - s->bpp.error = dupprintf( - "Incorrect CRC received on packet"); + ssh_sw_abort(s->bpp.ssh, "Incorrect CRC received on packet"); crStopV; } @@ -156,8 +158,8 @@ static void ssh1_bpp_handle_input(BinaryPacketProtocol *bpp) if (!ssh_decompressor_decompress( s->decompctx, s->data + s->pad, s->length + 1, &decompblk, &decomplen)) { - s->bpp.error = dupprintf( - "Zlib decompression encountered invalid data"); + ssh_sw_abort(s->bpp.ssh, + "Zlib decompression encountered invalid data"); crStopV; } @@ -204,10 +206,6 @@ static void ssh1_bpp_handle_input(BinaryPacketProtocol *bpp) s->pktin = NULL; switch (type) { - case SSH1_MSG_DISCONNECT: - s->bpp.seen_disconnect = TRUE; - break; - case SSH1_SMSG_SUCCESS: case SSH1_SMSG_FAILURE: if (s->pending_compression_request) { @@ -239,6 +237,15 @@ static void ssh1_bpp_handle_input(BinaryPacketProtocol *bpp) } } } + + eof: + if (!s->bpp.expect_close) { + ssh_remote_error(s->bpp.ssh, + "Server unexpectedly closed network connection"); + } else { + ssh_remote_eof(s->bpp.ssh, "Server closed network connection"); + } + crFinishV; } diff --git a/ssh1connection.c b/ssh1connection.c new file mode 100644 index 00000000..cf1616d6 --- /dev/null +++ b/ssh1connection.c @@ -0,0 +1,1211 @@ +/* + * Packet protocol layer for the SSH-1 'connection protocol', i.e. + * everything after authentication finishes. + */ + +#include + +#include "putty.h" +#include "ssh.h" +#include "sshbpp.h" +#include "sshppl.h" +#include "sshchan.h" +#include "sshcr.h" + +struct ssh1_channel; + +struct outstanding_succfail; + +struct ssh1_connection_state { + int crState; + + Ssh ssh; + + Conf *conf; + int local_protoflags; + + tree234 *channels; /* indexed by local id */ + + int got_pty; + int echoedit; + int ospeed, ispeed; + int stdout_throttling; + int session_ready; + int session_eof_pending, session_eof_sent, session_terminated; + int term_width, term_height, term_width_orig, term_height_orig; + + int X11_fwd_enabled; + struct X11Display *x11disp; + struct X11FakeAuth *x11auth; + tree234 *x11authtree; + + int agent_fwd_enabled; + + tree234 *rportfwds; + PortFwdManager *portfwdmgr; + int portfwdmgr_configured; + + int finished_setup; + + /* + * These store the list of requests that we're waiting for + * SSH_SMSG_{SUCCESS,FAILURE} replies to. (Those messages don't + * come with any indication of what they're in response to, so we + * have to keep track of the queue ourselves.) + */ + struct outstanding_succfail *succfail_head, *succfail_tail; + + ConnectionLayer cl; + PacketProtocolLayer ppl; +}; + +static int ssh1_rportfwd_cmp(void *av, void *bv) +{ + struct ssh_rportfwd *a = (struct ssh_rportfwd *) av; + struct ssh_rportfwd *b = (struct ssh_rportfwd *) bv; + int i; + if ( (i = strcmp(a->dhost, b->dhost)) != 0) + return i < 0 ? -1 : +1; + if (a->dport > b->dport) + return +1; + if (a->dport < b->dport) + return -1; + return 0; +} + +static void ssh1_connection_free(PacketProtocolLayer *); +static void ssh1_connection_process_queue(PacketProtocolLayer *); +static void ssh1_connection_special_cmd(PacketProtocolLayer *ppl, + SessionSpecialCode code, int arg); +static int ssh1_connection_want_user_input(PacketProtocolLayer *ppl); +static void ssh1_connection_got_user_input(PacketProtocolLayer *ppl); +static void ssh1_connection_reconfigure(PacketProtocolLayer *ppl, Conf *conf); + +static const struct PacketProtocolLayerVtable ssh1_connection_vtable = { + ssh1_connection_free, + ssh1_connection_process_queue, + ssh1_common_get_specials, + ssh1_connection_special_cmd, + ssh1_connection_want_user_input, + ssh1_connection_got_user_input, + ssh1_connection_reconfigure, + NULL /* no layer names in SSH-1 */, +}; + +static struct ssh_rportfwd *ssh1_rportfwd_alloc( + ConnectionLayer *cl, + const char *shost, int sport, const char *dhost, int dport, + int addressfamily, const char *log_description, PortFwdRecord *pfr, + ssh_sharing_connstate *share_ctx); +static void ssh1_rportfwd_remove( + ConnectionLayer *cl, struct ssh_rportfwd *rpf); +static SshChannel *ssh1_lportfwd_open( + ConnectionLayer *cl, const char *hostname, int port, + const char *org, Channel *chan); +static int ssh1_agent_forwarding_permitted(ConnectionLayer *cl); +static void ssh1_terminal_size(ConnectionLayer *cl, int width, int height); +static void ssh1_stdout_unthrottle(ConnectionLayer *cl, int bufsize); +static int ssh1_stdin_backlog(ConnectionLayer *cl); +static void ssh1_throttle_all_channels(ConnectionLayer *cl, int throttled); +static int ssh1_ldisc_option(ConnectionLayer *cl, int option); + +static const struct ConnectionLayerVtable ssh1_connlayer_vtable = { + ssh1_rportfwd_alloc, + ssh1_rportfwd_remove, + ssh1_lportfwd_open, + NULL /* add_sharing_x11_display */, + NULL /* remove_sharing_x11_display */, + NULL /* send_packet_from_downstream */, + NULL /* alloc_sharing_channel */, + NULL /* delete_sharing_channel */, + NULL /* sharing_queue_global_request */, + ssh1_agent_forwarding_permitted, + ssh1_terminal_size, + ssh1_stdout_unthrottle, + ssh1_stdin_backlog, + ssh1_throttle_all_channels, + ssh1_ldisc_option, +}; + +struct ssh1_channel { + struct ssh1_connection_state *connlayer; + + unsigned remoteid, localid; + int type; + /* True if we opened this channel but server hasn't confirmed. */ + int halfopen; + + /* Bitmap of whether we've sent/received CHANNEL_CLOSE and + * CHANNEL_CLOSE_CONFIRMATION. */ +#define CLOSES_SENT_CLOSE 1 +#define CLOSES_SENT_CLOSECONF 2 +#define CLOSES_RCVD_CLOSE 4 +#define CLOSES_RCVD_CLOSECONF 8 + int closes; + + /* + * This flag indicates that an EOF is pending on the outgoing side + * of the channel: that is, wherever we're getting the data for + * this channel has sent us some data followed by EOF. We can't + * actually send the EOF until we've finished sending the data, so + * we set this flag instead to remind us to do so once our buffer + * is clear. + */ + int pending_eof; + + /* + * True if this channel is causing the underlying connection to be + * throttled. + */ + int throttling_conn; + + /* + * True if we currently have backed-up data on the direction of + * this channel pointing out of the SSH connection, and therefore + * would prefer the 'Channel' implementation not to read further + * local input if possible. + */ + int throttled_by_backlog; + + Channel *chan; /* handle the client side of this channel, if not */ + SshChannel sc; /* entry point for chan to talk back to */ +}; + +static int ssh1channel_write(SshChannel *c, const void *buf, int len); +static void ssh1channel_write_eof(SshChannel *c); +static void ssh1channel_unclean_close(SshChannel *c, const char *err); +static void ssh1channel_unthrottle(SshChannel *c, int bufsize); +static Conf *ssh1channel_get_conf(SshChannel *c); + +static const struct SshChannelVtable ssh1channel_vtable = { + ssh1channel_write, + ssh1channel_write_eof, + ssh1channel_unclean_close, + ssh1channel_unthrottle, + ssh1channel_get_conf, + NULL /* window_override_removed is only used by SSH-2 sharing */, + NULL /* x11_sharing_handover, likewise */, +}; + +static void ssh1_channel_init(struct ssh1_channel *c); +static void ssh1_channel_try_eof(struct ssh1_channel *c); +static void ssh1_channel_close_local(struct ssh1_channel *c, + const char *reason); +static void ssh1_channel_destroy(struct ssh1_channel *c); +static void ssh1_channel_check_close(struct ssh1_channel *c); + +static int ssh1_check_termination(struct ssh1_connection_state *s); + +typedef void (*sf_handler_fn_t)(struct ssh1_connection_state *s, + PktIn *pktin, void *ctx); +struct outstanding_succfail { + sf_handler_fn_t handler; + void *ctx; + struct outstanding_succfail *next; +}; +static void ssh1_queue_succfail_handler( + struct ssh1_connection_state *s, sf_handler_fn_t handler, void *ctx) +{ + struct outstanding_succfail *osf = + snew(struct outstanding_succfail); + osf->handler = handler; + osf->ctx = ctx; + if (s->succfail_tail) + s->succfail_tail->next = osf; + else + s->succfail_head = osf; + s->succfail_tail = osf; +} + +static int ssh1_channelcmp(void *av, void *bv) +{ + const struct ssh1_channel *a = (const struct ssh1_channel *) av; + const struct ssh1_channel *b = (const struct ssh1_channel *) bv; + if (a->localid < b->localid) + return -1; + if (a->localid > b->localid) + return +1; + return 0; +} + +static int ssh1_channelfind(void *av, void *bv) +{ + const unsigned *a = (const unsigned *) av; + const struct ssh1_channel *b = (const struct ssh1_channel *) bv; + if (*a < b->localid) + return -1; + if (*a > b->localid) + return +1; + return 0; +} + +static void ssh1_channel_free(struct ssh1_channel *c) +{ + if (c->chan) + chan_free(c->chan); + sfree(c); +} + +PacketProtocolLayer *ssh1_connection_new( + Ssh ssh, Conf *conf, ConnectionLayer **cl_out) +{ + struct ssh1_connection_state *s = snew(struct ssh1_connection_state); + memset(s, 0, sizeof(*s)); + s->ppl.vt = &ssh1_connection_vtable; + + s->conf = conf_copy(conf); + + s->channels = newtree234(ssh1_channelcmp); + + s->x11authtree = newtree234(x11_authcmp); + + /* Need to get the frontend for s->cl now, because we won't be + * helpfully notified when a copy is written into s->ppl by our + * owner. */ + s->cl.vt = &ssh1_connlayer_vtable; + s->cl.frontend = ssh_get_frontend(ssh); + + s->portfwdmgr = portfwdmgr_new(&s->cl); + s->rportfwds = newtree234(ssh1_rportfwd_cmp); + + *cl_out = &s->cl; + return &s->ppl; +} + +static void ssh1_connection_free(PacketProtocolLayer *ppl) +{ + struct ssh1_connection_state *s = + FROMFIELD(ppl, struct ssh1_connection_state, ppl); + struct X11FakeAuth *auth; + struct ssh1_channel *c; + struct ssh_rportfwd *rpf; + + conf_free(s->conf); + + while ((c = delpos234(s->channels, 0)) != NULL) + ssh1_channel_free(c); + freetree234(s->channels); + + if (s->x11disp) + x11_free_display(s->x11disp); + while ((auth = delpos234(s->x11authtree, 0)) != NULL) + x11_free_fake_auth(auth); + freetree234(s->x11authtree); + + while ((rpf = delpos234(s->rportfwds, 0)) != NULL) + free_rportfwd(rpf); + freetree234(s->rportfwds); + portfwdmgr_free(s->portfwdmgr); + + sfree(s); +} + +void ssh1_connection_set_local_protoflags(PacketProtocolLayer *ppl, int flags) +{ + assert(ppl->vt == &ssh1_connection_vtable); + struct ssh1_connection_state *s = + FROMFIELD(ppl, struct ssh1_connection_state, ppl); + s->local_protoflags = flags; +} + +static int ssh1_connection_filter_queue(struct ssh1_connection_state *s) +{ + PktIn *pktin; + PktOut *pktout; + ptrlen data, host; + struct ssh1_channel *c; + unsigned localid, remid; + int port, expect_halfopen; + struct ssh_rportfwd pf, *pfp; + PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */ + + /* Cross-reference to ssh1login.c to handle the common packets + * between login and connection: DISCONNECT, DEBUG and IGNORE. */ + extern int ssh1_common_filter_queue(PacketProtocolLayer *ppl); + + while (1) { + if (ssh1_common_filter_queue(&s->ppl)) + return TRUE; + if ((pktin = pq_peek(s->ppl.in_pq)) == NULL) + return FALSE; + + switch (pktin->type) { + case SSH1_SMSG_SUCCESS: + case SSH1_SMSG_FAILURE: + if (!s->finished_setup) { + /* During initial setup, these messages are not + * filtered out, but go back to the main coroutine. */ + return FALSE; + } + + if (!s->succfail_head) { + ssh_remote_error(s->ppl.ssh, + "Received %s with no outstanding request", + ssh1_pkt_type(pktin->type)); + return TRUE; + } + + s->succfail_head->handler(s, pktin, s->succfail_head->ctx); + { + struct outstanding_succfail *tmp = s->succfail_head; + s->succfail_head = s->succfail_head->next; + sfree(tmp); + } + + pq_pop(s->ppl.in_pq); + break; + + case SSH1_SMSG_X11_OPEN: + remid = get_uint32(pktin); + + /* Refuse if X11 forwarding is disabled. */ + if (!s->X11_fwd_enabled) { + pktout = ssh_bpp_new_pktout( + s->ppl.bpp, SSH1_MSG_CHANNEL_OPEN_FAILURE); + put_uint32(pktout, remid); + pq_push(s->ppl.out_pq, pktout); + ppl_logevent(("Rejected X11 connect request")); + } else { + c = snew(struct ssh1_channel); + c->connlayer = s; + ssh1_channel_init(c); + c->remoteid = remid; + c->chan = x11_new_channel(s->x11authtree, &c->sc, + NULL, -1, FALSE); + c->remoteid = remid; + c->halfopen = FALSE; + + pktout = ssh_bpp_new_pktout( + s->ppl.bpp, SSH1_MSG_CHANNEL_OPEN_CONFIRMATION); + put_uint32(pktout, c->remoteid); + put_uint32(pktout, c->localid); + pq_push(s->ppl.out_pq, pktout); + ppl_logevent(("Opened X11 forward channel")); + } + + pq_pop(s->ppl.in_pq); + break; + + case SSH1_SMSG_AGENT_OPEN: + remid = get_uint32(pktin); + + /* Refuse if agent forwarding is disabled. */ + if (!s->agent_fwd_enabled) { + pktout = ssh_bpp_new_pktout( + s->ppl.bpp, SSH1_MSG_CHANNEL_OPEN_FAILURE); + put_uint32(pktout, remid); + pq_push(s->ppl.out_pq, pktout); + } else { + c = snew(struct ssh1_channel); + c->connlayer = s; + ssh1_channel_init(c); + c->remoteid = remid; + c->chan = agentf_new(&c->sc); + c->halfopen = FALSE; + + pktout = ssh_bpp_new_pktout( + s->ppl.bpp, SSH1_MSG_CHANNEL_OPEN_CONFIRMATION); + put_uint32(pktout, c->remoteid); + put_uint32(pktout, c->localid); + pq_push(s->ppl.out_pq, pktout); + } + + pq_pop(s->ppl.in_pq); + break; + + case SSH1_MSG_PORT_OPEN: + remid = get_uint32(pktin); + host = get_string(pktin); + port = toint(get_uint32(pktin)); + + pf.dhost = mkstr(host); + pf.dport = port; + pfp = find234(s->rportfwds, &pf, NULL); + + if (!pfp) { + ppl_logevent(("Rejected remote port open request for %s:%d", + pf.dhost, port)); + pktout = ssh_bpp_new_pktout( + s->ppl.bpp, SSH1_MSG_CHANNEL_OPEN_FAILURE); + put_uint32(pktout, remid); + pq_push(s->ppl.out_pq, pktout); + } else { + char *err; + + c = snew(struct ssh1_channel); + c->connlayer = s; + ppl_logevent(("Received remote port open request for %s:%d", + pf.dhost, port)); + err = portfwdmgr_connect( + s->portfwdmgr, &c->chan, pf.dhost, port, + &c->sc, pfp->addressfamily); + + if (err) { + ppl_logevent(("Port open failed: %s", err)); + sfree(err); + ssh1_channel_free(c); + pktout = ssh_bpp_new_pktout( + s->ppl.bpp, SSH1_MSG_CHANNEL_OPEN_FAILURE); + put_uint32(pktout, remid); + pq_push(s->ppl.out_pq, pktout); + } else { + ssh1_channel_init(c); + c->remoteid = remid; + c->halfopen = FALSE; + pktout = ssh_bpp_new_pktout( + s->ppl.bpp, SSH1_MSG_CHANNEL_OPEN_CONFIRMATION); + put_uint32(pktout, c->remoteid); + put_uint32(pktout, c->localid); + pq_push(s->ppl.out_pq, pktout); + ppl_logevent(("Forwarded port opened successfully")); + } + } + + sfree(pf.dhost); + + pq_pop(s->ppl.in_pq); + break; + + case SSH1_MSG_CHANNEL_DATA: + case SSH1_MSG_CHANNEL_OPEN_CONFIRMATION: + case SSH1_MSG_CHANNEL_OPEN_FAILURE: + case SSH1_MSG_CHANNEL_CLOSE: + case SSH1_MSG_CHANNEL_CLOSE_CONFIRMATION: + /* + * Common preliminary code for all the messages from the + * server that cite one of our channel ids: look up that + * channel id, check it exists, and if it's for a sharing + * downstream, pass it on. + */ + localid = get_uint32(pktin); + c = find234(s->channels, &localid, ssh1_channelfind); + + expect_halfopen = ( + pktin->type == SSH1_MSG_CHANNEL_OPEN_CONFIRMATION || + pktin->type == SSH1_MSG_CHANNEL_OPEN_FAILURE); + + if (!c || c->halfopen != expect_halfopen) { + ssh_remote_error( + s->ppl.ssh, "Received %s for %s channel %u", + ssh1_pkt_type(pktin->type), + !c ? "nonexistent" : c->halfopen ? "half-open" : "open", + localid); + return TRUE; + } + + switch (pktin->type) { + case SSH1_MSG_CHANNEL_OPEN_CONFIRMATION: + assert(c->halfopen); + c->remoteid = get_uint32(pktin); + c->halfopen = FALSE; + c->throttling_conn = FALSE; + + chan_open_confirmation(c->chan); + + /* + * Now that the channel is fully open, it's possible + * in principle to immediately close it. Check whether + * it wants us to! + * + * This can occur if a local socket error occurred + * between us sending out CHANNEL_OPEN and receiving + * OPEN_CONFIRMATION. If that happens, all we can do + * is immediately initiate close proceedings now that + * we know the server's id to put in the close + * message. We'll have handled that in this code by + * having already turned c->chan into a zombie, so its + * want_close method (which ssh1_channel_check_close + * will consult) will already be returning TRUE. + */ + ssh1_channel_check_close(c); + + if (c->pending_eof) + ssh1_channel_try_eof(c); /* in case we had a pending EOF */ + break; + + case SSH1_MSG_CHANNEL_OPEN_FAILURE: + assert(c->halfopen); + + chan_open_failed(c->chan, NULL); + chan_free(c->chan); + + del234(s->channels, c); + ssh1_channel_free(c); + break; + + case SSH1_MSG_CHANNEL_DATA: + data = get_string(pktin); + if (!get_err(pktin)) { + int bufsize = chan_send( + c->chan, FALSE, data.ptr, data.len); + + if (!c->throttling_conn && bufsize > SSH1_BUFFER_LIMIT) { + c->throttling_conn = TRUE; + ssh_throttle_conn(s->ppl.ssh, +1); + } + } + break; + + case SSH1_MSG_CHANNEL_CLOSE: + if (!(c->closes & CLOSES_RCVD_CLOSE)) { + c->closes |= CLOSES_RCVD_CLOSE; + chan_send_eof(c->chan); + ssh1_channel_check_close(c); + } + break; + + case SSH1_MSG_CHANNEL_CLOSE_CONFIRMATION: + if (!(c->closes & CLOSES_RCVD_CLOSECONF)) { + if (!(c->closes & CLOSES_SENT_CLOSE)) { + ssh_remote_error( + s->ppl.ssh, + "Received CHANNEL_CLOSE_CONFIRMATION for channel" + " %u for which we never sent CHANNEL_CLOSE\n", + c->localid); + return TRUE; + } + + c->closes |= CLOSES_RCVD_CLOSECONF; + ssh1_channel_check_close(c); + } + break; + } + + pq_pop(s->ppl.in_pq); + break; + + case SSH1_SMSG_STDOUT_DATA: + case SSH1_SMSG_STDERR_DATA: + data = get_string(pktin); + if (!get_err(pktin)) { + int bufsize = from_backend( + s->ppl.frontend, pktin->type == SSH1_SMSG_STDERR_DATA, + data.ptr, data.len); + if (!s->stdout_throttling && bufsize > SSH1_BUFFER_LIMIT) { + s->stdout_throttling = 1; + ssh_throttle_conn(s->ppl.ssh, +1); + } + } + + pq_pop(s->ppl.in_pq); + break; + + case SSH1_SMSG_EXIT_STATUS: + { + int exitcode = get_uint32(pktin); + ppl_logevent(("Server sent command exit status %d", exitcode)); + ssh_got_exitcode(s->ppl.ssh, exitcode); + + s->session_terminated = TRUE; + if (ssh1_check_termination(s)) + return TRUE; + } + pq_pop(s->ppl.in_pq); + break; + + default: + return FALSE; + } + } +} + +static PktIn *ssh1_connection_pop(struct ssh1_connection_state *s) +{ + ssh1_connection_filter_queue(s); + return pq_pop(s->ppl.in_pq); +} + +static void ssh1_connection_process_queue(PacketProtocolLayer *ppl) +{ + struct ssh1_connection_state *s = + FROMFIELD(ppl, struct ssh1_connection_state, ppl); + PktIn *pktin; + PktOut *pktout; + + if (ssh1_connection_filter_queue(s)) /* no matter why we were called */ + return; + + crBegin(s->crState); + + if (ssh_agent_forwarding_permitted(&s->cl)) { + ppl_logevent(("Requesting agent forwarding")); + pktout = ssh_bpp_new_pktout(s->ppl.bpp, + SSH1_CMSG_AGENT_REQUEST_FORWARDING); + pq_push(s->ppl.out_pq, pktout); + crMaybeWaitUntilV((pktin = ssh1_connection_pop(s)) != NULL); + if (pktin->type == SSH1_SMSG_SUCCESS) { + ppl_logevent(("Agent forwarding enabled")); + s->agent_fwd_enabled = TRUE; + } else if (pktin->type == SSH1_SMSG_FAILURE) { + ppl_logevent(("Agent forwarding refused")); + } else { + ssh_proto_error(s->ppl.ssh, "Unexpected packet received" + " in response to agent forwarding request, " + "type %d (%s)", pktin->type, + ssh1_pkt_type(pktin->type)); + return; + } + } + + if (conf_get_int(s->conf, CONF_x11_forward)) { + s->x11disp = + x11_setup_display(conf_get_str(s->conf, CONF_x11_display), + s->conf); + if (!s->x11disp) { + /* FIXME: return an error message from x11_setup_display */ + ppl_logevent(("X11 forwarding not enabled: unable to" + " initialise X display")); + } else { + s->x11auth = x11_invent_fake_auth + (s->x11authtree, conf_get_int(s->conf, CONF_x11_auth)); + s->x11auth->disp = s->x11disp; + + ppl_logevent(("Requesting X11 forwarding")); + pktout = ssh_bpp_new_pktout( + s->ppl.bpp, SSH1_CMSG_X11_REQUEST_FORWARDING); + put_stringz(pktout, s->x11auth->protoname); + put_stringz(pktout, s->x11auth->datastring); + if (s->local_protoflags & SSH1_PROTOFLAG_SCREEN_NUMBER) + put_uint32(pktout, s->x11disp->screennum); + pq_push(s->ppl.out_pq, pktout); + crMaybeWaitUntilV((pktin = ssh1_connection_pop(s)) != NULL); + if (pktin->type == SSH1_SMSG_SUCCESS) { + ppl_logevent(("X11 forwarding enabled")); + s->X11_fwd_enabled = TRUE; + } else if (pktin->type == SSH1_SMSG_FAILURE) { + ppl_logevent(("X11 forwarding refused")); + } else { + ssh_proto_error(s->ppl.ssh, "Unexpected packet received" + " in response to X11 forwarding request, " + "type %d (%s)", pktin->type, + ssh1_pkt_type(pktin->type)); + return; + } + } + } + + portfwdmgr_config(s->portfwdmgr, s->conf); + s->portfwdmgr_configured = TRUE; + + if (!conf_get_int(s->conf, CONF_nopty)) { + /* Unpick the terminal-speed string. */ + /* XXX perhaps we should allow no speeds to be sent. */ + s->ospeed = 38400; s->ispeed = 38400; /* last-resort defaults */ + sscanf(conf_get_str(s->conf, CONF_termspeed), "%d,%d", + &s->ospeed, &s->ispeed); + /* Send the pty request. */ + pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_REQUEST_PTY); + put_stringz(pktout, conf_get_str(s->conf, CONF_termtype)); + put_uint32(pktout, s->term_height); + put_uint32(pktout, s->term_width); + s->term_width_orig = s->term_width; + s->term_height_orig = s->term_height; + put_uint32(pktout, 0); /* width in pixels */ + put_uint32(pktout, 0); /* height in pixels */ + write_ttymodes_to_packet_from_conf( + BinarySink_UPCAST(pktout), s->ppl.frontend, s->conf, + 1, s->ospeed, s->ispeed); + pq_push(s->ppl.out_pq, pktout); + crMaybeWaitUntilV((pktin = ssh1_connection_pop(s)) != NULL); + if (pktin->type == SSH1_SMSG_SUCCESS) { + ppl_logevent(("Allocated pty (ospeed %dbps, ispeed %dbps)", + s->ospeed, s->ispeed)); + s->got_pty = TRUE; + } else if (pktin->type == SSH1_SMSG_FAILURE) { + ppl_printf(("Server refused to allocate pty\r\n")); + s->echoedit = TRUE; + } else { + ssh_proto_error(s->ppl.ssh, "Unexpected packet received" + " in response to pty request, " + "type %d (%s)", pktin->type, + ssh1_pkt_type(pktin->type)); + crStopV; + } + } else { + s->echoedit = TRUE; + } + + /* + * Start the shell or command. + * + * Special case: if the first-choice command is an SSH-2 + * subsystem (hence not usable here) and the second choice + * exists, we fall straight back to that. + */ + { + char *cmd = conf_get_str(s->conf, CONF_remote_cmd); + + if (conf_get_int(s->conf, CONF_ssh_subsys) && + conf_get_str(s->conf, CONF_remote_cmd2)) { + cmd = conf_get_str(s->conf, CONF_remote_cmd2); + ssh_got_fallback_cmd(s->ppl.ssh); + } + if (*cmd) { + pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_EXEC_CMD); + put_stringz(pktout, cmd); + } else { + pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_EXEC_SHELL); + } + pq_push(s->ppl.out_pq, pktout); + ppl_logevent(("Started session")); + } + + s->session_ready = TRUE; + + /* If an EOF or a window-size change arrived before we were ready + * to handle either one, handle them now. */ + if (s->session_eof_pending) { + ssh_ppl_special_cmd(&s->ppl, SS_EOF, 0); + s->session_eof_pending = FALSE; + } + if (s->term_width_orig != s->term_width || + s->term_height_orig != s->term_height) + ssh_terminal_size(&s->cl, s->term_width, s->term_height); + + ssh_ldisc_update(s->ppl.ssh); + s->finished_setup = TRUE; + + while (1) { + + /* + * By this point, most incoming packets are already being + * handled by filter_queue, and we need only pay attention to + * the unusual ones. + */ + + if ((pktin = ssh1_connection_pop(s)) != NULL) { + ssh_proto_error(s->ppl.ssh, "Unexpected packet received, " + "type %d (%s)", pktin->type, + ssh1_pkt_type(pktin->type)); + return; + } + while (bufchain_size(s->ppl.user_input) > 0) { + void *data; + int len; + bufchain_prefix(s->ppl.user_input, &data, &len); + if (len > 512) + len = 512; + pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_STDIN_DATA); + put_string(pktout, data, len); + pq_push(s->ppl.out_pq, pktout); + bufchain_consume(s->ppl.user_input, len); + } + crReturnV; + } + + crFinishV; +} + +static void ssh1_channel_check_close(struct ssh1_channel *c) +{ + struct ssh1_connection_state *s = c->connlayer; + PktOut *pktout; + + if (c->halfopen) { + /* + * If we've sent out our own CHANNEL_OPEN but not yet seen + * either OPEN_CONFIRMATION or OPEN_FAILURE in response, then + * it's too early to be sending close messages of any kind. + */ + return; + } + + if ((!((CLOSES_SENT_CLOSE | CLOSES_RCVD_CLOSE) & ~c->closes) || + chan_want_close(c->chan, (c->closes & CLOSES_SENT_CLOSE), + (c->closes & CLOSES_RCVD_CLOSE))) && + !(c->closes & CLOSES_SENT_CLOSECONF)) { + /* + * We have both sent and received CLOSE (or the channel type + * doesn't need us to), which means the channel is in final + * wind-up. Send CLOSE and/or CLOSE_CONFIRMATION, whichever we + * haven't sent yet. + */ + if (!(c->closes & CLOSES_SENT_CLOSE)) { + pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_MSG_CHANNEL_CLOSE); + put_uint32(pktout, c->remoteid); + pq_push(s->ppl.out_pq, pktout); + c->closes |= CLOSES_SENT_CLOSE; + } + if (c->closes & CLOSES_RCVD_CLOSE) { + pktout = ssh_bpp_new_pktout( + s->ppl.bpp, SSH1_MSG_CHANNEL_CLOSE_CONFIRMATION); + put_uint32(pktout, c->remoteid); + pq_push(s->ppl.out_pq, pktout); + c->closes |= CLOSES_SENT_CLOSECONF; + } + } + + if (!((CLOSES_SENT_CLOSECONF | CLOSES_RCVD_CLOSECONF) & ~c->closes)) { + /* + * We have both sent and received CLOSE_CONFIRMATION, which + * means we're completely done with the channel. + */ + ssh1_channel_destroy(c); + } +} + +static void ssh1_channel_try_eof(struct ssh1_channel *c) +{ + struct ssh1_connection_state *s = c->connlayer; + PktOut *pktout; + assert(c->pending_eof); /* precondition for calling us */ + if (c->halfopen) + return; /* can't close: not even opened yet */ + + c->pending_eof = FALSE; /* we're about to send it */ + + pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_MSG_CHANNEL_CLOSE); + put_uint32(pktout, c->remoteid); + pq_push(s->ppl.out_pq, pktout); + c->closes |= CLOSES_SENT_CLOSE; + + ssh1_channel_check_close(c); +} + +/* + * Close any local socket and free any local resources associated with + * a channel. This converts the channel into a zombie. + */ +static void ssh1_channel_close_local(struct ssh1_channel *c, + const char *reason) +{ + struct ssh1_connection_state *s = c->connlayer; + PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */ + const char *msg = chan_log_close_msg(c->chan); + + if (msg != NULL) + ppl_logevent(("%s%s%s", msg, reason ? " " : "", reason ? reason : "")); + + chan_free(c->chan); + c->chan = zombiechan_new(); +} + +static void ssh1_check_termination_callback(void *vctx) +{ + struct ssh1_connection_state *s = (struct ssh1_connection_state *)vctx; + ssh1_check_termination(s); +} + +static void ssh1_channel_destroy(struct ssh1_channel *c) +{ + struct ssh1_connection_state *s = c->connlayer; + + ssh1_channel_close_local(c, NULL); + del234(s->channels, c); + ssh1_channel_free(c); + + /* + * If that was the last channel left open, we might need to + * terminate. But we'll be a bit cautious, by doing that in a + * toplevel callback, just in case anything on the current call + * stack objects to this entire PPL being freed. + */ + queue_toplevel_callback(ssh1_check_termination_callback, s); +} + +static int ssh1_check_termination(struct ssh1_connection_state *s) +{ + /* + * Decide whether we should terminate the SSH connection now. + * Called after a channel goes away, or when the main session + * returns SSH1_SMSG_EXIT_STATUS; we terminate when none of either + * is left. + */ + if (s->session_terminated && count234(s->channels) == 0) { + PktOut *pktout = ssh_bpp_new_pktout( + s->ppl.bpp, SSH1_CMSG_EXIT_CONFIRMATION); + pq_push(s->ppl.out_pq, pktout); + + ssh_user_close(s->ppl.ssh, "Session finished"); + return TRUE; + } + + return FALSE; +} + +/* + * Set up most of a new ssh1_channel. Leaves chan untouched (since it + * will sometimes have been filled in before calling this). + */ +static void ssh1_channel_init(struct ssh1_channel *c) +{ + struct ssh1_connection_state *s = c->connlayer; + c->closes = 0; + c->pending_eof = FALSE; + c->throttling_conn = FALSE; + c->sc.vt = &ssh1channel_vtable; + c->localid = alloc_channel_id(s->channels, struct ssh1_channel); + add234(s->channels, c); +} + +static Conf *ssh1channel_get_conf(SshChannel *sc) +{ + struct ssh1_channel *c = FROMFIELD(sc, struct ssh1_channel, sc); + struct ssh1_connection_state *s = c->connlayer; + return s->conf; +} + +static void ssh1channel_write_eof(SshChannel *sc) +{ + struct ssh1_channel *c = FROMFIELD(sc, struct ssh1_channel, sc); + + if (c->closes & CLOSES_SENT_CLOSE) + return; + + c->pending_eof = TRUE; + ssh1_channel_try_eof(c); +} + +static void ssh1channel_unclean_close(SshChannel *sc, const char *err) +{ + struct ssh1_channel *c = FROMFIELD(sc, struct ssh1_channel, sc); + char *reason; + + reason = dupprintf("due to local error: %s", err); + ssh1_channel_close_local(c, reason); + sfree(reason); + c->pending_eof = FALSE; /* this will confuse a zombie channel */ + + ssh1_channel_check_close(c); +} + +static void ssh1channel_unthrottle(SshChannel *sc, int bufsize) +{ + struct ssh1_channel *c = FROMFIELD(sc, struct ssh1_channel, sc); + struct ssh1_connection_state *s = c->connlayer; + + if (c->throttling_conn && bufsize <= SSH1_BUFFER_LIMIT) { + c->throttling_conn = 0; + ssh_throttle_conn(s->ppl.ssh, -1); + } +} + +static int ssh1channel_write(SshChannel *sc, const void *buf, int len) +{ + struct ssh1_channel *c = FROMFIELD(sc, struct ssh1_channel, sc); + struct ssh1_connection_state *s = c->connlayer; + + assert(!(c->closes & CLOSES_SENT_CLOSE)); + + PktOut *pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_MSG_CHANNEL_DATA); + put_uint32(pktout, c->remoteid); + put_string(pktout, buf, len); + pq_push(s->ppl.out_pq, pktout); + + /* + * In SSH-1 we can return 0 here - implying that channels are + * never individually throttled - because the only circumstance + * that can cause throttling will be the whole SSH connection + * backing up, in which case _everything_ will be throttled as a + * whole. + */ + return 0; +} + +static SshChannel *ssh1_lportfwd_open( + ConnectionLayer *cl, const char *hostname, int port, + const char *org, Channel *chan) +{ + struct ssh1_connection_state *s = + FROMFIELD(cl, struct ssh1_connection_state, cl); + PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */ + struct ssh1_channel *c = snew(struct ssh1_channel); + PktOut *pktout; + + c->connlayer = s; + ssh1_channel_init(c); + c->halfopen = TRUE; + c->chan = chan; + + ppl_logevent(("Opening connection to %s:%d for %s", hostname, port, org)); + + pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_MSG_PORT_OPEN); + put_uint32(pktout, c->localid); + put_stringz(pktout, hostname); + put_uint32(pktout, port); + /* originator string would go here, but we didn't specify + * SSH_PROTOFLAG_HOST_IN_FWD_OPEN */ + pq_push(s->ppl.out_pq, pktout); + + return &c->sc; +} + +static void ssh1_rportfwd_response(struct ssh1_connection_state *s, + PktIn *pktin, void *ctx) +{ + PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */ + struct ssh_rportfwd *rpf = (struct ssh_rportfwd *)ctx; + + if (pktin->type == SSH1_SMSG_SUCCESS) { + ppl_logevent(("Remote port forwarding from %s enabled", + rpf->log_description)); + } else { + ppl_logevent(("Remote port forwarding from %s refused", + rpf->log_description)); + + struct ssh_rportfwd *realpf = del234(s->rportfwds, rpf); + assert(realpf == rpf); + portfwdmgr_close(s->portfwdmgr, rpf->pfr); + free_rportfwd(rpf); + } +} + +static struct ssh_rportfwd *ssh1_rportfwd_alloc( + ConnectionLayer *cl, + const char *shost, int sport, const char *dhost, int dport, + int addressfamily, const char *log_description, PortFwdRecord *pfr, + ssh_sharing_connstate *share_ctx) +{ + struct ssh1_connection_state *s = + FROMFIELD(cl, struct ssh1_connection_state, cl); + struct ssh_rportfwd *rpf = snew(struct ssh_rportfwd); + + rpf->shost = dupstr(shost); + rpf->sport = sport; + rpf->dhost = dupstr(dhost); + rpf->dport = dport; + rpf->addressfamily = addressfamily; + rpf->log_description = dupstr(log_description); + rpf->pfr = pfr; + + if (add234(s->rportfwds, rpf) != rpf) { + free_rportfwd(rpf); + return NULL; + } + + PktOut *pktout = ssh_bpp_new_pktout( + s->ppl.bpp, SSH1_CMSG_PORT_FORWARD_REQUEST); + put_uint32(pktout, rpf->sport); + put_stringz(pktout, rpf->dhost); + put_uint32(pktout, rpf->dport); + pq_push(s->ppl.out_pq, pktout); + + ssh1_queue_succfail_handler(s, ssh1_rportfwd_response, rpf); + + return rpf; +} + +static void ssh1_rportfwd_remove(ConnectionLayer *cl, struct ssh_rportfwd *rpf) +{ + /* + * We cannot cancel listening ports on the server side in SSH-1! + * There's no message to support it. + */ +} + +static int ssh1_agent_forwarding_permitted(ConnectionLayer *cl) +{ + struct ssh1_connection_state *s = + FROMFIELD(cl, struct ssh1_connection_state, cl); + return conf_get_int(s->conf, CONF_agentfwd) && agent_exists(); +} + +static void ssh1_connection_special_cmd(PacketProtocolLayer *ppl, + SessionSpecialCode code, int arg) +{ + struct ssh1_connection_state *s = + FROMFIELD(ppl, struct ssh1_connection_state, ppl); + PktOut *pktout; + + if (code == SS_PING || code == SS_NOP) { + if (!(s->ppl.remote_bugs & BUG_CHOKES_ON_SSH1_IGNORE)) { + pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_MSG_IGNORE); + put_stringz(pktout, ""); + pq_push(s->ppl.out_pq, pktout); + } + } else if (code == SS_EOF) { + if (!s->session_ready) { + /* + * Buffer the EOF to send as soon as the main session is + * fully set up. + */ + s->session_eof_pending = TRUE; + } else if (!s->session_eof_sent) { + pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_EOF); + pq_push(s->ppl.out_pq, pktout); + ppl_logevent(("Sent EOF message")); + s->session_eof_sent = TRUE; + } + } +} + +static void ssh1_terminal_size(ConnectionLayer *cl, int width, int height) +{ + struct ssh1_connection_state *s = + FROMFIELD(cl, struct ssh1_connection_state, cl); + + s->term_width = width; + s->term_height = height; + + if (s->session_ready) { + PktOut *pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_WINDOW_SIZE); + put_uint32(pktout, s->term_height); + put_uint32(pktout, s->term_width); + put_uint32(pktout, 0); + put_uint32(pktout, 0); + pq_push(s->ppl.out_pq, pktout); + } +} + +static void ssh1_stdout_unthrottle(ConnectionLayer *cl, int bufsize) +{ + struct ssh1_connection_state *s = + FROMFIELD(cl, struct ssh1_connection_state, cl); + + if (s->stdout_throttling && bufsize < SSH1_BUFFER_LIMIT) { + s->stdout_throttling = 0; + ssh_throttle_conn(s->ppl.ssh, -1); + } +} + +static int ssh1_stdin_backlog(ConnectionLayer *cl) +{ + return 0; +} + +static void ssh1_throttle_all_channels(ConnectionLayer *cl, int throttled) +{ + struct ssh1_connection_state *s = + FROMFIELD(cl, struct ssh1_connection_state, cl); + struct ssh1_channel *c; + int i; + + for (i = 0; NULL != (c = index234(s->channels, i)); i++) + chan_set_input_wanted(c->chan, !throttled); +} + +static int ssh1_ldisc_option(ConnectionLayer *cl, int option) +{ + struct ssh1_connection_state *s = + FROMFIELD(cl, struct ssh1_connection_state, cl); + + /* We always return the same value for LD_ECHO and LD_EDIT */ + return s->echoedit; +} + +static int ssh1_connection_want_user_input(PacketProtocolLayer *ppl) +{ + struct ssh1_connection_state *s = + FROMFIELD(ppl, struct ssh1_connection_state, ppl); + return s->session_ready && !s->session_eof_sent; +} + +static void ssh1_connection_got_user_input(PacketProtocolLayer *ppl) +{ + struct ssh1_connection_state *s = + FROMFIELD(ppl, struct ssh1_connection_state, ppl); + if (s->session_ready && !s->session_eof_sent) + queue_idempotent_callback(&s->ppl.ic_process_queue); +} + +static void ssh1_connection_reconfigure(PacketProtocolLayer *ppl, Conf *conf) +{ + struct ssh1_connection_state *s = + FROMFIELD(ppl, struct ssh1_connection_state, ppl); + + conf_free(s->conf); + s->conf = conf_copy(conf); + + if (s->portfwdmgr_configured) + portfwdmgr_config(s->portfwdmgr, s->conf); +} diff --git a/ssh1login.c b/ssh1login.c new file mode 100644 index 00000000..f676a6eb --- /dev/null +++ b/ssh1login.c @@ -0,0 +1,1206 @@ +/* + * Packet protocol layer for the SSH-1 login phase (combining what + * SSH-2 would think of as key exchange and user authentication). + */ + +#include + +#include "putty.h" +#include "ssh.h" +#include "sshbpp.h" +#include "sshppl.h" +#include "sshcr.h" + +struct ssh1_login_state { + int crState; + + PacketProtocolLayer *successor_layer; + + Conf *conf; + + char *savedhost; + int savedport; + int try_agent_auth; + + int remote_protoflags; + int local_protoflags; + unsigned char session_key[32]; + char *username; + agent_pending_query *auth_agent_query; + + int len; + unsigned char *rsabuf; + unsigned long supported_ciphers_mask, supported_auths_mask; + int tried_publickey, tried_agent; + int tis_auth_refused, ccard_auth_refused; + unsigned char cookie[8]; + unsigned char session_id[16]; + int cipher_type; + strbuf *publickey_blob; + char *publickey_comment; + int privatekey_available, privatekey_encrypted; + prompts_t *cur_prompt; + int userpass_ret; + char c; + int pwpkt_type; + void *agent_response_to_free; + ptrlen agent_response; + BinarySource asrc[1]; /* response from SSH agent */ + int keyi, nkeys; + int authed; + struct RSAKey key; + Bignum challenge; + ptrlen comment; + int dlgret; + Filename *keyfile; + struct RSAKey servkey, hostkey; + int want_user_input; + + PacketProtocolLayer ppl; +}; + +static void ssh1_login_free(PacketProtocolLayer *); +static void ssh1_login_process_queue(PacketProtocolLayer *); +static void ssh1_login_dialog_callback(void *, int); +static void ssh1_login_special_cmd(PacketProtocolLayer *ppl, + SessionSpecialCode code, int arg); +static int ssh1_login_want_user_input(PacketProtocolLayer *ppl); +static void ssh1_login_got_user_input(PacketProtocolLayer *ppl); +static void ssh1_login_reconfigure(PacketProtocolLayer *ppl, Conf *conf); + +static const struct PacketProtocolLayerVtable ssh1_login_vtable = { + ssh1_login_free, + ssh1_login_process_queue, + ssh1_common_get_specials, + ssh1_login_special_cmd, + ssh1_login_want_user_input, + ssh1_login_got_user_input, + ssh1_login_reconfigure, + NULL /* no layer names in SSH-1 */, +}; + +static void ssh1_login_agent_query(struct ssh1_login_state *s, strbuf *req); +static void ssh1_login_agent_callback(void *loginv, void *reply, int replylen); + +PacketProtocolLayer *ssh1_login_new( + Conf *conf, const char *host, int port, + PacketProtocolLayer *successor_layer) +{ + struct ssh1_login_state *s = snew(struct ssh1_login_state); + memset(s, 0, sizeof(*s)); + s->ppl.vt = &ssh1_login_vtable; + + s->conf = conf_copy(conf); + s->savedhost = dupstr(host); + s->savedport = port; + s->successor_layer = successor_layer; + return &s->ppl; +} + +static void ssh1_login_free(PacketProtocolLayer *ppl) +{ + struct ssh1_login_state *s = FROMFIELD(ppl, struct ssh1_login_state, ppl); + + if (s->successor_layer) + ssh_ppl_free(s->successor_layer); + + conf_free(s->conf); + sfree(s->savedhost); + sfree(s->rsabuf); + sfree(s->username); + if (s->publickey_blob) + strbuf_free(s->publickey_blob); + sfree(s->publickey_comment); + if (s->cur_prompt) + free_prompts(s->cur_prompt); + sfree(s->agent_response_to_free); + if (s->auth_agent_query) + agent_cancel_query(s->auth_agent_query); + sfree(s); +} + +int ssh1_common_filter_queue(PacketProtocolLayer *ppl) +{ + PktIn *pktin; + ptrlen msg; + + while ((pktin = pq_peek(ppl->in_pq)) != NULL) { + switch (pktin->type) { + case SSH1_MSG_DISCONNECT: + msg = get_string(pktin); + ssh_remote_error(ppl->ssh, + "Server sent disconnect message:\n\"%.*s\"", + PTRLEN_PRINTF(msg)); + return TRUE; /* indicate that we've been freed */ + + case SSH1_MSG_DEBUG: + msg = get_string(pktin); + ppl_logevent(("Remote debug message: %.*s", PTRLEN_PRINTF(msg))); + pq_pop(ppl->in_pq); + break; + + case SSH1_MSG_IGNORE: + /* Do nothing, because we're ignoring it! Duhh. */ + pq_pop(ppl->in_pq); + break; + + default: + return FALSE; + } + } + + return FALSE; +} + +static int ssh1_login_filter_queue(struct ssh1_login_state *s) +{ + return ssh1_common_filter_queue(&s->ppl); +} + +static PktIn *ssh1_login_pop(struct ssh1_login_state *s) +{ + if (ssh1_login_filter_queue(s)) + return NULL; + return pq_pop(s->ppl.in_pq); +} + +static void ssh1_login_process_queue(PacketProtocolLayer *ppl) +{ + struct ssh1_login_state *s = FROMFIELD(ppl, struct ssh1_login_state, ppl); + PktIn *pktin; + PktOut *pkt; + int i; + + /* Filter centrally handled messages off the front of the queue on + * every entry to this coroutine, no matter where we're resuming + * from, even if we're _not_ looping on pq_pop. That way we can + * still proactively handle those messages even if we're waiting + * for a user response. */ + if (ssh1_login_filter_queue(s)) + return; + + crBegin(s->crState); + + crMaybeWaitUntilV((pktin = ssh1_login_pop(s)) != NULL); + + if (pktin->type != SSH1_SMSG_PUBLIC_KEY) { + ssh_proto_error(s->ppl.ssh, "Public key packet not received"); + return; + } + + ppl_logevent(("Received public keys")); + + { + ptrlen pl = get_data(pktin, 8); + memcpy(s->cookie, pl.ptr, pl.len); + } + + get_rsa_ssh1_pub(pktin, &s->servkey, RSA_SSH1_EXPONENT_FIRST); + get_rsa_ssh1_pub(pktin, &s->hostkey, RSA_SSH1_EXPONENT_FIRST); + + s->hostkey.comment = NULL; /* avoid confusing rsa_ssh1_fingerprint */ + + /* + * Log the host key fingerprint. + */ + if (!get_err(pktin)) { + char *fingerprint = rsa_ssh1_fingerprint(&s->hostkey); + ppl_logevent(("Host key fingerprint is:")); + ppl_logevent((" %s", fingerprint)); + sfree(fingerprint); + } + + s->remote_protoflags = get_uint32(pktin); + s->supported_ciphers_mask = get_uint32(pktin); + s->supported_auths_mask = get_uint32(pktin); + + if (get_err(pktin)) { + ssh_proto_error(s->ppl.ssh, "Bad SSH-1 public key packet"); + return; + } + + if ((s->ppl.remote_bugs & BUG_CHOKES_ON_RSA)) + s->supported_auths_mask &= ~(1 << SSH1_AUTH_RSA); + + s->local_protoflags = + s->remote_protoflags & SSH1_PROTOFLAGS_SUPPORTED; + s->local_protoflags |= SSH1_PROTOFLAG_SCREEN_NUMBER; + + { + struct MD5Context md5c; + + MD5Init(&md5c); + for (i = (bignum_bitcount(s->hostkey.modulus) + 7) / 8; i-- ;) + put_byte(&md5c, bignum_byte(s->hostkey.modulus, i)); + for (i = (bignum_bitcount(s->servkey.modulus) + 7) / 8; i-- ;) + put_byte(&md5c, bignum_byte(s->servkey.modulus, i)); + put_data(&md5c, s->cookie, 8); + MD5Final(s->session_id, &md5c); + } + + for (i = 0; i < 32; i++) + s->session_key[i] = random_byte(); + + /* + * Verify that the `bits' and `bytes' parameters match. + */ + if (s->hostkey.bits > s->hostkey.bytes * 8 || + s->servkey.bits > s->servkey.bytes * 8) { + ssh_proto_error(s->ppl.ssh, "SSH-1 public keys were badly formatted"); + return; + } + + s->len = (s->hostkey.bytes > s->servkey.bytes ? + s->hostkey.bytes : s->servkey.bytes); + + s->rsabuf = snewn(s->len, unsigned char); + + /* + * Verify the host key. + */ + { + /* + * First format the key into a string. + */ + int len = rsastr_len(&s->hostkey); + char *fingerprint; + char *keystr = snewn(len, char); + rsastr_fmt(keystr, &s->hostkey); + fingerprint = rsa_ssh1_fingerprint(&s->hostkey); + + /* First check against manually configured host keys. */ + s->dlgret = verify_ssh_manual_host_key(s->conf, fingerprint, NULL); + sfree(fingerprint); + if (s->dlgret == 0) { /* did not match */ + sfree(keystr); + ssh_proto_error(s->ppl.ssh, "Host key did not appear in manually " + "configured list"); + return; + } else if (s->dlgret < 0) { /* none configured; use standard handling */ + s->dlgret = verify_ssh_host_key( + s->ppl.frontend, s->savedhost, s->savedport, + "rsa", keystr, fingerprint, ssh1_login_dialog_callback, s); + sfree(keystr); +#ifdef FUZZING + s->dlgret = 1; +#endif + crMaybeWaitUntilV(s->dlgret >= 0); + + if (s->dlgret == 0) { + ssh_user_close(s->ppl.ssh, + "User aborted at host key verification"); + return; + } + } else { + sfree(keystr); + } + } + + for (i = 0; i < 32; i++) { + s->rsabuf[i] = s->session_key[i]; + if (i < 16) + s->rsabuf[i] ^= s->session_id[i]; + } + + { + struct RSAKey *smaller = (s->hostkey.bytes > s->servkey.bytes ? + &s->servkey : &s->hostkey); + struct RSAKey *larger = (s->hostkey.bytes > s->servkey.bytes ? + &s->hostkey : &s->servkey); + + if (!rsa_ssh1_encrypt(s->rsabuf, 32, smaller) || + !rsa_ssh1_encrypt(s->rsabuf, smaller->bytes, larger)) { + ssh_proto_error(s->ppl.ssh, "SSH-1 public key encryptions failed " + "due to bad formatting"); + return; + } + } + + ppl_logevent(("Encrypted session key")); + + { + int cipher_chosen = 0, warn = 0; + const char *cipher_string = NULL; + int i; + for (i = 0; !cipher_chosen && i < CIPHER_MAX; i++) { + int next_cipher = conf_get_int_int( + s->conf, CONF_ssh_cipherlist, i); + if (next_cipher == CIPHER_WARN) { + /* If/when we choose a cipher, warn about it */ + warn = 1; + } else if (next_cipher == CIPHER_AES) { + /* XXX Probably don't need to mention this. */ + ppl_logevent(("AES not supported in SSH-1, skipping")); + } else { + switch (next_cipher) { + case CIPHER_3DES: s->cipher_type = SSH_CIPHER_3DES; + cipher_string = "3DES"; break; + case CIPHER_BLOWFISH: s->cipher_type = SSH_CIPHER_BLOWFISH; + cipher_string = "Blowfish"; break; + case CIPHER_DES: s->cipher_type = SSH_CIPHER_DES; + cipher_string = "single-DES"; break; + } + if (s->supported_ciphers_mask & (1 << s->cipher_type)) + cipher_chosen = 1; + } + } + if (!cipher_chosen) { + if ((s->supported_ciphers_mask & (1 << SSH_CIPHER_3DES)) == 0) { + ssh_proto_error(s->ppl.ssh, "Server violates SSH-1 protocol " + "by not supporting 3DES encryption"); + } else { + /* shouldn't happen */ + ssh_sw_abort(s->ppl.ssh, "No supported ciphers found"); + } + return; + } + + /* Warn about chosen cipher if necessary. */ + if (warn) { + s->dlgret = askalg(s->ppl.frontend, "cipher", cipher_string, + ssh1_login_dialog_callback, s); + crMaybeWaitUntilV(s->dlgret >= 0); + if (s->dlgret == 0) { + ssh_user_close(s->ppl.ssh, "User aborted at cipher warning"); + return; + } + } + } + + switch (s->cipher_type) { + case SSH_CIPHER_3DES: + ppl_logevent(("Using 3DES encryption")); + break; + case SSH_CIPHER_DES: + ppl_logevent(("Using single-DES encryption")); + break; + case SSH_CIPHER_BLOWFISH: + ppl_logevent(("Using Blowfish encryption")); + break; + } + + pkt = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_SESSION_KEY); + put_byte(pkt, s->cipher_type); + put_data(pkt, s->cookie, 8); + put_uint16(pkt, s->len * 8); + put_data(pkt, s->rsabuf, s->len); + put_uint32(pkt, s->local_protoflags); + pq_push(s->ppl.out_pq, pkt); + + ppl_logevent(("Trying to enable encryption...")); + + sfree(s->rsabuf); + s->rsabuf = NULL; + + /* + * Force the BPP to synchronously marshal all packets up to and + * including the SESSION_KEY into wire format, before we turn on + * crypto. + */ + ssh_bpp_handle_output(s->ppl.bpp); + + { + const struct ssh1_cipheralg *cipher = + (s->cipher_type == SSH_CIPHER_BLOWFISH ? &ssh1_blowfish : + s->cipher_type == SSH_CIPHER_DES ? &ssh1_des : &ssh1_3des); + ssh1_bpp_new_cipher(s->ppl.bpp, cipher, s->session_key); + ppl_logevent(("Initialised %s encryption", cipher->text_name)); + } + + if (s->servkey.modulus) { + sfree(s->servkey.modulus); + s->servkey.modulus = NULL; + } + if (s->servkey.exponent) { + sfree(s->servkey.exponent); + s->servkey.exponent = NULL; + } + if (s->hostkey.modulus) { + sfree(s->hostkey.modulus); + s->hostkey.modulus = NULL; + } + if (s->hostkey.exponent) { + sfree(s->hostkey.exponent); + s->hostkey.exponent = NULL; + } + crMaybeWaitUntilV((pktin = ssh1_login_pop(s)) != NULL); + + if (pktin->type != SSH1_SMSG_SUCCESS) { + ssh_proto_error(s->ppl.ssh, "Encryption not successfully enabled"); + return; + } + + ppl_logevent(("Successfully started encryption")); + + if ((s->username = get_remote_username(s->conf)) == NULL) { + s->cur_prompt = new_prompts(s->ppl.frontend); + s->cur_prompt->to_server = TRUE; + s->cur_prompt->name = dupstr("SSH login name"); + add_prompt(s->cur_prompt, dupstr("login as: "), TRUE); + s->userpass_ret = get_userpass_input(s->cur_prompt, NULL); + while (1) { + while (s->userpass_ret < 0 && + bufchain_size(s->ppl.user_input) > 0) + s->userpass_ret = get_userpass_input( + s->cur_prompt, s->ppl.user_input); + + if (s->userpass_ret >= 0) + break; + + s->want_user_input = TRUE; + crReturnV; + s->want_user_input = FALSE; + } + if (!s->userpass_ret) { + /* + * Failed to get a username. Terminate. + */ + ssh_user_close(s->ppl.ssh, "No username provided"); + return; + } + s->username = dupstr(s->cur_prompt->prompts[0]->result); + free_prompts(s->cur_prompt); + s->cur_prompt = NULL; + } + + pkt = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_USER); + put_stringz(pkt, s->username); + pq_push(s->ppl.out_pq, pkt); + + ppl_logevent(("Sent username \"%s\"", s->username)); + if ((flags & FLAG_VERBOSE) || (flags & FLAG_INTERACTIVE)) + ppl_printf(("Sent username \"%s\"\r\n", s->username)); + + crMaybeWaitUntilV((pktin = ssh1_login_pop(s)) != NULL); + + if (!(s->supported_auths_mask & (1 << SSH1_AUTH_RSA))) { + /* We must not attempt PK auth. Pretend we've already tried it. */ + s->tried_publickey = s->tried_agent = TRUE; + } else { + s->tried_publickey = s->tried_agent = FALSE; + } + s->tis_auth_refused = s->ccard_auth_refused = FALSE; + + /* + * Load the public half of any configured keyfile for later use. + */ + s->keyfile = conf_get_filename(s->conf, CONF_keyfile); + if (!filename_is_null(s->keyfile)) { + int keytype; + ppl_logevent(("Reading key file \"%.150s\"", + filename_to_str(s->keyfile))); + keytype = key_type(s->keyfile); + if (keytype == SSH_KEYTYPE_SSH1 || + keytype == SSH_KEYTYPE_SSH1_PUBLIC) { + const char *error; + s->publickey_blob = strbuf_new(); + if (rsa_ssh1_loadpub(s->keyfile, + BinarySink_UPCAST(s->publickey_blob), + &s->publickey_comment, &error)) { + s->privatekey_available = (keytype == SSH_KEYTYPE_SSH1); + if (!s->privatekey_available) + ppl_logevent(("Key file contains public key only")); + s->privatekey_encrypted = rsa_ssh1_encrypted(s->keyfile, NULL); + } else { + ppl_logevent(("Unable to load key (%s)", error)); + ppl_printf(("Unable to load key file \"%s\" (%s)\r\n", + filename_to_str(s->keyfile), error)); + + strbuf_free(s->publickey_blob); + s->publickey_blob = NULL; + } + } else { + ppl_logevent(("Unable to use this key file (%s)", + key_type_to_str(keytype))); + ppl_printf(("Unable to use key file \"%s\" (%s)\r\n", + filename_to_str(s->keyfile), + key_type_to_str(keytype))); + } + } + + /* Check whether we're configured to try Pageant, and also whether + * it's available. */ + s->try_agent_auth = (conf_get_int(s->conf, CONF_tryagent) && + agent_exists()); + + while (pktin->type == SSH1_SMSG_FAILURE) { + s->pwpkt_type = SSH1_CMSG_AUTH_PASSWORD; + + if (s->try_agent_auth && !s->tried_agent) { + /* + * Attempt RSA authentication using Pageant. + */ + s->authed = FALSE; + s->tried_agent = 1; + ppl_logevent(("Pageant is running. Requesting keys.")); + + /* Request the keys held by the agent. */ + { + strbuf *request = strbuf_new_for_agent_query(); + put_byte(request, SSH1_AGENTC_REQUEST_RSA_IDENTITIES); + ssh1_login_agent_query(s, request); + strbuf_free(request); + crMaybeWaitUntilV(!s->auth_agent_query); + } + BinarySource_BARE_INIT( + s->asrc, s->agent_response.ptr, s->agent_response.len); + + get_uint32(s->asrc); /* skip length field */ + if (get_byte(s->asrc) == SSH1_AGENT_RSA_IDENTITIES_ANSWER) { + s->nkeys = toint(get_uint32(s->asrc)); + if (s->nkeys < 0) { + ppl_logevent(("Pageant reported negative key count %d", + s->nkeys)); + s->nkeys = 0; + } + ppl_logevent(("Pageant has %d SSH-1 keys", s->nkeys)); + for (s->keyi = 0; s->keyi < s->nkeys; s->keyi++) { + size_t start, end; + start = s->asrc->pos; + get_rsa_ssh1_pub(s->asrc, &s->key, + RSA_SSH1_EXPONENT_FIRST); + end = s->asrc->pos; + s->comment = get_string(s->asrc); + if (get_err(s->asrc)) { + ppl_logevent(("Pageant key list packet was truncated")); + break; + } + if (s->publickey_blob) { + ptrlen keystr = make_ptrlen( + (const char *)s->asrc->data + start, end - start); + + if (keystr.len == s->publickey_blob->len && + !memcmp(keystr.ptr, s->publickey_blob->s, + s->publickey_blob->len)) { + ppl_logevent(("Pageant key #%d matches " + "configured key file", s->keyi)); + s->tried_publickey = 1; + } else + /* Skip non-configured key */ + continue; + } + ppl_logevent(("Trying Pageant key #%d", s->keyi)); + pkt = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_AUTH_RSA); + put_mp_ssh1(pkt, s->key.modulus); + pq_push(s->ppl.out_pq, pkt); + crMaybeWaitUntilV((pktin = ssh1_login_pop(s)) + != NULL); + if (pktin->type != SSH1_SMSG_AUTH_RSA_CHALLENGE) { + ppl_logevent(("Key refused")); + continue; + } + ppl_logevent(("Received RSA challenge")); + s->challenge = get_mp_ssh1(pktin); + if (get_err(pktin)) { + freebn(s->challenge); + ssh_proto_error(s->ppl.ssh, "Server's RSA challenge " + "was badly formatted"); + return; + } + + { + strbuf *agentreq; + const char *ret; + + agentreq = strbuf_new_for_agent_query(); + put_byte(agentreq, SSH1_AGENTC_RSA_CHALLENGE); + put_uint32(agentreq, bignum_bitcount(s->key.modulus)); + put_mp_ssh1(agentreq, s->key.exponent); + put_mp_ssh1(agentreq, s->key.modulus); + put_mp_ssh1(agentreq, s->challenge); + put_data(agentreq, s->session_id, 16); + put_uint32(agentreq, 1); /* response format */ + ssh1_login_agent_query(s, agentreq); + strbuf_free(agentreq); + crMaybeWaitUntilV(!s->auth_agent_query); + + ret = s->agent_response.ptr; + if (ret) { + if (s->agent_response.len >= 5+16 && + ret[4] == SSH1_AGENT_RSA_RESPONSE) { + ppl_logevent(("Sending Pageant's response")); + pkt = ssh_bpp_new_pktout( + s->ppl.bpp, SSH1_CMSG_AUTH_RSA_RESPONSE); + put_data(pkt, ret + 5, 16); + pq_push(s->ppl.out_pq, pkt); + sfree((char *)ret); + crMaybeWaitUntilV( + (pktin = ssh1_login_pop(s)) + != NULL); + if (pktin->type == SSH1_SMSG_SUCCESS) { + ppl_logevent(("Pageant's response " + "accepted")); + if (flags & FLAG_VERBOSE) { + ppl_printf(("Authenticated using RSA " + "key \"%.*s\" from " + "agent\r\n", PTRLEN_PRINTF( + s->comment))); + } + s->authed = TRUE; + } else + ppl_logevent(("Pageant's response not " + "accepted")); + } else { + ppl_logevent(("Pageant failed to answer " + "challenge")); + sfree((char *)ret); + } + } else { + ppl_logevent(("No reply received from Pageant")); + } + } + freebn(s->key.exponent); + freebn(s->key.modulus); + freebn(s->challenge); + if (s->authed) + break; + } + sfree(s->agent_response_to_free); + s->agent_response_to_free = NULL; + if (s->publickey_blob && !s->tried_publickey) + ppl_logevent(("Configured key file not in Pageant")); + } else { + ppl_logevent(("Failed to get reply from Pageant")); + } + if (s->authed) + break; + } + if (s->publickey_blob && s->privatekey_available && + !s->tried_publickey) { + /* + * Try public key authentication with the specified + * key file. + */ + int got_passphrase; /* need not be kept over crReturn */ + if (flags & FLAG_VERBOSE) + ppl_printf(("Trying public key authentication.\r\n")); + ppl_logevent(("Trying public key \"%s\"", + filename_to_str(s->keyfile))); + s->tried_publickey = 1; + got_passphrase = FALSE; + while (!got_passphrase) { + /* + * Get a passphrase, if necessary. + */ + int retd; + char *passphrase = NULL; /* only written after crReturn */ + const char *error; + if (!s->privatekey_encrypted) { + if (flags & FLAG_VERBOSE) + ppl_printf(("No passphrase required.\r\n")); + passphrase = NULL; + } else { + s->cur_prompt = new_prompts(s->ppl.frontend); + s->cur_prompt->to_server = FALSE; + s->cur_prompt->name = dupstr("SSH key passphrase"); + add_prompt(s->cur_prompt, + dupprintf("Passphrase for key \"%.100s\": ", + s->publickey_comment), FALSE); + s->userpass_ret = get_userpass_input(s->cur_prompt, NULL); + while (1) { + while (s->userpass_ret < 0 && + bufchain_size(s->ppl.user_input) > 0) + s->userpass_ret = get_userpass_input( + s->cur_prompt, s->ppl.user_input); + + if (s->userpass_ret >= 0) + break; + + s->want_user_input = TRUE; + crReturnV; + s->want_user_input = FALSE; + } + if (!s->userpass_ret) { + /* Failed to get a passphrase. Terminate. */ + ssh_sw_abort(s->ppl.ssh, "Unable to authenticate"); + return; + } + passphrase = dupstr(s->cur_prompt->prompts[0]->result); + free_prompts(s->cur_prompt); + s->cur_prompt = NULL; + } + /* + * Try decrypting key with passphrase. + */ + retd = rsa_ssh1_loadkey( + s->keyfile, &s->key, passphrase, &error); + if (passphrase) { + smemclr(passphrase, strlen(passphrase)); + sfree(passphrase); + } + if (retd == 1) { + /* Correct passphrase. */ + got_passphrase = TRUE; + } else if (retd == 0) { + ppl_printf(("Couldn't load private key from %s (%s).\r\n", + filename_to_str(s->keyfile), error)); + got_passphrase = FALSE; + break; /* go and try something else */ + } else if (retd == -1) { + ppl_printf(("Wrong passphrase.\r\n")); + got_passphrase = FALSE; + /* and try again */ + } else { + assert(0 && "unexpected return from rsa_ssh1_loadkey()"); + got_passphrase = FALSE; /* placate optimisers */ + } + } + + if (got_passphrase) { + + /* + * Send a public key attempt. + */ + pkt = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_AUTH_RSA); + put_mp_ssh1(pkt, s->key.modulus); + pq_push(s->ppl.out_pq, pkt); + + crMaybeWaitUntilV((pktin = ssh1_login_pop(s)) + != NULL); + if (pktin->type == SSH1_SMSG_FAILURE) { + ppl_printf(("Server refused our public key.\r\n")); + continue; /* go and try something else */ + } + if (pktin->type != SSH1_SMSG_AUTH_RSA_CHALLENGE) { + ssh_proto_error(s->ppl.ssh, "Received unexpected packet" + " in response to offer of public key, " + "type %d (%s)", pktin->type, + ssh1_pkt_type(pktin->type)); + return; + } + + { + int i; + unsigned char buffer[32]; + Bignum challenge, response; + + challenge = get_mp_ssh1(pktin); + if (get_err(pktin)) { + freebn(challenge); + ssh_proto_error(s->ppl.ssh, "Server's RSA challenge " + "was badly formatted"); + return; + } + response = rsa_ssh1_decrypt(challenge, &s->key); + freebn(s->key.private_exponent);/* burn the evidence */ + + for (i = 0; i < 32; i++) { + buffer[i] = bignum_byte(response, 31 - i); + } + + { + struct MD5Context md5c; + MD5Init(&md5c); + put_data(&md5c, buffer, 32); + put_data(&md5c, s->session_id, 16); + MD5Final(buffer, &md5c); + } + + pkt = ssh_bpp_new_pktout( + s->ppl.bpp, SSH1_CMSG_AUTH_RSA_RESPONSE); + put_data(pkt, buffer, 16); + pq_push(s->ppl.out_pq, pkt); + + freebn(challenge); + freebn(response); + } + + crMaybeWaitUntilV((pktin = ssh1_login_pop(s)) + != NULL); + if (pktin->type == SSH1_SMSG_FAILURE) { + if (flags & FLAG_VERBOSE) + ppl_printf(("Failed to authenticate with" + " our public key.\r\n")); + continue; /* go and try something else */ + } else if (pktin->type != SSH1_SMSG_SUCCESS) { + ssh_proto_error(s->ppl.ssh, "Received unexpected packet" + " in response to RSA authentication, " + "type %d (%s)", pktin->type, + ssh1_pkt_type(pktin->type)); + return; + } + + break; /* we're through! */ + } + + } + + /* + * Otherwise, try various forms of password-like authentication. + */ + s->cur_prompt = new_prompts(s->ppl.frontend); + + if (conf_get_int(s->conf, CONF_try_tis_auth) && + (s->supported_auths_mask & (1 << SSH1_AUTH_TIS)) && + !s->tis_auth_refused) { + s->pwpkt_type = SSH1_CMSG_AUTH_TIS_RESPONSE; + ppl_logevent(("Requested TIS authentication")); + pkt = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_AUTH_TIS); + pq_push(s->ppl.out_pq, pkt); + crMaybeWaitUntilV((pktin = ssh1_login_pop(s)) != NULL); + if (pktin->type == SSH1_SMSG_FAILURE) { + ppl_logevent(("TIS authentication declined")); + if (flags & FLAG_INTERACTIVE) + ppl_printf(("TIS authentication refused.\r\n")); + s->tis_auth_refused = 1; + continue; + } else if (pktin->type == SSH1_SMSG_AUTH_TIS_CHALLENGE) { + ptrlen challenge; + char *instr_suf, *prompt; + + challenge = get_string(pktin); + if (get_err(pktin)) { + ssh_proto_error(s->ppl.ssh, "TIS challenge packet was " + "badly formed"); + return; + } + ppl_logevent(("Received TIS challenge")); + s->cur_prompt->to_server = TRUE; + s->cur_prompt->name = dupstr("SSH TIS authentication"); + /* Prompt heuristic comes from OpenSSH */ + if (memchr(challenge.ptr, '\n', challenge.len)) { + instr_suf = dupstr(""); + prompt = mkstr(challenge); + } else { + instr_suf = mkstr(challenge); + prompt = dupstr("Response: "); + } + s->cur_prompt->instruction = + dupprintf("Using TIS authentication.%s%s", + (*instr_suf) ? "\n" : "", + instr_suf); + s->cur_prompt->instr_reqd = TRUE; + add_prompt(s->cur_prompt, prompt, FALSE); + sfree(instr_suf); + } else { + ssh_proto_error(s->ppl.ssh, "Received unexpected packet" + " in response to TIS authentication, " + "type %d (%s)", pktin->type, + ssh1_pkt_type(pktin->type)); + return; + } + } + if (conf_get_int(s->conf, CONF_try_tis_auth) && + (s->supported_auths_mask & (1 << SSH1_AUTH_CCARD)) && + !s->ccard_auth_refused) { + s->pwpkt_type = SSH1_CMSG_AUTH_CCARD_RESPONSE; + ppl_logevent(("Requested CryptoCard authentication")); + pkt = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_AUTH_CCARD); + pq_push(s->ppl.out_pq, pkt); + crMaybeWaitUntilV((pktin = ssh1_login_pop(s)) != NULL); + if (pktin->type == SSH1_SMSG_FAILURE) { + ppl_logevent(("CryptoCard authentication declined")); + ppl_printf(("CryptoCard authentication refused.\r\n")); + s->ccard_auth_refused = 1; + continue; + } else if (pktin->type == SSH1_SMSG_AUTH_CCARD_CHALLENGE) { + ptrlen challenge; + char *instr_suf, *prompt; + + challenge = get_string(pktin); + if (get_err(pktin)) { + ssh_proto_error(s->ppl.ssh, "CryptoCard challenge packet " + "was badly formed"); + return; + } + ppl_logevent(("Received CryptoCard challenge")); + s->cur_prompt->to_server = TRUE; + s->cur_prompt->name = dupstr("SSH CryptoCard authentication"); + s->cur_prompt->name_reqd = FALSE; + /* Prompt heuristic comes from OpenSSH */ + if (memchr(challenge.ptr, '\n', challenge.len)) { + instr_suf = dupstr(""); + prompt = mkstr(challenge); + } else { + instr_suf = mkstr(challenge); + prompt = dupstr("Response: "); + } + s->cur_prompt->instruction = + dupprintf("Using CryptoCard authentication.%s%s", + (*instr_suf) ? "\n" : "", + instr_suf); + s->cur_prompt->instr_reqd = TRUE; + add_prompt(s->cur_prompt, prompt, FALSE); + sfree(instr_suf); + } else { + ssh_proto_error(s->ppl.ssh, "Received unexpected packet" + " in response to TIS authentication, " + "type %d (%s)", pktin->type, + ssh1_pkt_type(pktin->type)); + return; + } + } + if (s->pwpkt_type == SSH1_CMSG_AUTH_PASSWORD) { + if ((s->supported_auths_mask & (1 << SSH1_AUTH_PASSWORD)) == 0) { + ssh_sw_abort(s->ppl.ssh, "No supported authentication methods " + "available"); + return; + } + s->cur_prompt->to_server = TRUE; + s->cur_prompt->name = dupstr("SSH password"); + add_prompt(s->cur_prompt, dupprintf("%s@%s's password: ", + s->username, s->savedhost), + FALSE); + } + + /* + * Show password prompt, having first obtained it via a TIS + * or CryptoCard exchange if we're doing TIS or CryptoCard + * authentication. + */ + s->userpass_ret = get_userpass_input(s->cur_prompt, NULL); + while (1) { + while (s->userpass_ret < 0 && + bufchain_size(s->ppl.user_input) > 0) + s->userpass_ret = get_userpass_input( + s->cur_prompt, s->ppl.user_input); + + if (s->userpass_ret >= 0) + break; + + s->want_user_input = TRUE; + crReturnV; + s->want_user_input = FALSE; + } + if (!s->userpass_ret) { + /* + * Failed to get a password (for example + * because one was supplied on the command line + * which has already failed to work). Terminate. + */ + ssh_sw_abort(s->ppl.ssh, "Unable to authenticate"); + return; + } + + if (s->pwpkt_type == SSH1_CMSG_AUTH_PASSWORD) { + /* + * Defence against traffic analysis: we send a + * whole bunch of packets containing strings of + * different lengths. One of these strings is the + * password, in a SSH1_CMSG_AUTH_PASSWORD packet. + * The others are all random data in + * SSH1_MSG_IGNORE packets. This way a passive + * listener can't tell which is the password, and + * hence can't deduce the password length. + * + * Anybody with a password length greater than 16 + * bytes is going to have enough entropy in their + * password that a listener won't find it _that_ + * much help to know how long it is. So what we'll + * do is: + * + * - if password length < 16, we send 15 packets + * containing string lengths 1 through 15 + * + * - otherwise, we let N be the nearest multiple + * of 8 below the password length, and send 8 + * packets containing string lengths N through + * N+7. This won't obscure the order of + * magnitude of the password length, but it will + * introduce a bit of extra uncertainty. + * + * A few servers can't deal with SSH1_MSG_IGNORE, at + * least in this context. For these servers, we need + * an alternative defence. We make use of the fact + * that the password is interpreted as a C string: + * so we can append a NUL, then some random data. + * + * A few servers can deal with neither SSH1_MSG_IGNORE + * here _nor_ a padded password string. + * For these servers we are left with no defences + * against password length sniffing. + */ + if (!(s->ppl.remote_bugs & BUG_CHOKES_ON_SSH1_IGNORE) && + !(s->ppl.remote_bugs & BUG_NEEDS_SSH1_PLAIN_PASSWORD)) { + /* + * The server can deal with SSH1_MSG_IGNORE, so + * we can use the primary defence. + */ + int bottom, top, pwlen, i; + + pwlen = strlen(s->cur_prompt->prompts[0]->result); + if (pwlen < 16) { + bottom = 0; /* zero length passwords are OK! :-) */ + top = 15; + } else { + bottom = pwlen & ~7; + top = bottom + 7; + } + + assert(pwlen >= bottom && pwlen <= top); + + for (i = bottom; i <= top; i++) { + if (i == pwlen) { + pkt = ssh_bpp_new_pktout(s->ppl.bpp, s->pwpkt_type); + put_stringz(pkt, s->cur_prompt->prompts[0]->result); + pq_push(s->ppl.out_pq, pkt); + } else { + int j; + strbuf *random_data = strbuf_new(); + for (j = 0; j < i; j++) + put_byte(random_data, random_byte()); + + pkt = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_MSG_IGNORE); + put_stringsb(pkt, random_data); + pq_push(s->ppl.out_pq, pkt); + } + } + ppl_logevent(("Sending password with camouflage packets")); + } + else if (!(s->ppl.remote_bugs & BUG_NEEDS_SSH1_PLAIN_PASSWORD)) { + /* + * The server can't deal with SSH1_MSG_IGNORE + * but can deal with padded passwords, so we + * can use the secondary defence. + */ + strbuf *padded_pw = strbuf_new(); + + ppl_logevent(("Sending length-padded password")); + pkt = ssh_bpp_new_pktout(s->ppl.bpp, s->pwpkt_type); + put_asciz(padded_pw, s->cur_prompt->prompts[0]->result); + do { + put_byte(padded_pw, random_byte()); + } while (padded_pw->len % 64 != 0); + put_stringsb(pkt, padded_pw); + pq_push(s->ppl.out_pq, pkt); + } else { + /* + * The server is believed unable to cope with + * any of our password camouflage methods. + */ + ppl_logevent(("Sending unpadded password")); + pkt = ssh_bpp_new_pktout(s->ppl.bpp, s->pwpkt_type); + put_stringz(pkt, s->cur_prompt->prompts[0]->result); + pq_push(s->ppl.out_pq, pkt); + } + } else { + pkt = ssh_bpp_new_pktout(s->ppl.bpp, s->pwpkt_type); + put_stringz(pkt, s->cur_prompt->prompts[0]->result); + pq_push(s->ppl.out_pq, pkt); + } + ppl_logevent(("Sent password")); + free_prompts(s->cur_prompt); + s->cur_prompt = NULL; + crMaybeWaitUntilV((pktin = ssh1_login_pop(s)) != NULL); + if (pktin->type == SSH1_SMSG_FAILURE) { + if (flags & FLAG_VERBOSE) + ppl_printf(("Access denied\r\n")); + ppl_logevent(("Authentication refused")); + } else if (pktin->type != SSH1_SMSG_SUCCESS) { + ssh_proto_error(s->ppl.ssh, "Received unexpected packet" + " in response to password authentication, type %d " + "(%s)", pktin->type, ssh1_pkt_type(pktin->type)); + return; + } + } + + ppl_logevent(("Authentication successful")); + + if (conf_get_int(s->conf, CONF_compression)) { + ppl_logevent(("Requesting compression")); + pkt = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_REQUEST_COMPRESSION); + put_uint32(pkt, 6); /* gzip compression level */ + pq_push(s->ppl.out_pq, pkt); + crMaybeWaitUntilV((pktin = ssh1_login_pop(s)) != NULL); + if (pktin->type == SSH1_SMSG_SUCCESS) { + /* + * We don't have to actually do anything here: the SSH-1 + * BPP will take care of automatically starting the + * compression, by recognising our outgoing request packet + * and the success response. (Horrible, but it's the + * easiest way to avoid race conditions if other packets + * cross in transit.) + */ + ppl_logevent(("Started zlib (RFC1950) compression")); + } else if (pktin->type == SSH1_SMSG_FAILURE) { + ppl_logevent(("Server refused to enable compression")); + ppl_printf(("Server refused to compress\r\n")); + } else { + ssh_proto_error(s->ppl.ssh, "Received unexpected packet" + " in response to compression request, type %d " + "(%s)", pktin->type, ssh1_pkt_type(pktin->type)); + return; + } + } + + ssh1_connection_set_local_protoflags( + s->successor_layer, s->local_protoflags); + { + PacketProtocolLayer *successor = s->successor_layer; + s->successor_layer = NULL; /* avoid freeing it ourself */ + ssh_ppl_replace(&s->ppl, successor); + return; /* we've just freed s, so avoid even touching s->crState */ + } + + crFinishV; +} + +static void ssh1_login_dialog_callback(void *loginv, int ret) +{ + struct ssh1_login_state *s = (struct ssh1_login_state *)loginv; + s->dlgret = ret; + ssh_ppl_process_queue(&s->ppl); +} + +static void ssh1_login_agent_query(struct ssh1_login_state *s, strbuf *req) +{ + void *response; + int response_len; + + sfree(s->agent_response_to_free); + s->agent_response_to_free = NULL; + + s->auth_agent_query = agent_query(req, &response, &response_len, + ssh1_login_agent_callback, s); + if (!s->auth_agent_query) + ssh1_login_agent_callback(s, response, response_len); +} + +static void ssh1_login_agent_callback(void *loginv, void *reply, int replylen) +{ + struct ssh1_login_state *s = (struct ssh1_login_state *)loginv; + + s->auth_agent_query = NULL; + s->agent_response_to_free = reply; + s->agent_response = make_ptrlen(reply, replylen); + + queue_idempotent_callback(&s->ppl.ic_process_queue); +} + +static void ssh1_login_special_cmd(PacketProtocolLayer *ppl, + SessionSpecialCode code, int arg) +{ + struct ssh1_login_state *s = + FROMFIELD(ppl, struct ssh1_login_state, ppl); + PktOut *pktout; + + if (code == SS_PING || code == SS_NOP) { + if (!(s->ppl.remote_bugs & BUG_CHOKES_ON_SSH1_IGNORE)) { + pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_MSG_IGNORE); + put_stringz(pktout, ""); + pq_push(s->ppl.out_pq, pktout); + } + } +} + +static int ssh1_login_want_user_input(PacketProtocolLayer *ppl) +{ + struct ssh1_login_state *s = + FROMFIELD(ppl, struct ssh1_login_state, ppl); + return s->want_user_input; +} + +static void ssh1_login_got_user_input(PacketProtocolLayer *ppl) +{ + struct ssh1_login_state *s = + FROMFIELD(ppl, struct ssh1_login_state, ppl); + if (s->want_user_input) + queue_idempotent_callback(&s->ppl.ic_process_queue); +} + +static void ssh1_login_reconfigure(PacketProtocolLayer *ppl, Conf *conf) +{ + struct ssh1_login_state *s = + FROMFIELD(ppl, struct ssh1_login_state, ppl); + ssh_ppl_reconfigure(s->successor_layer, conf); +} diff --git a/ssh2bpp-bare.c b/ssh2bpp-bare.c index 5b58a3c7..49689c3b 100644 --- a/ssh2bpp-bare.c +++ b/ssh2bpp-bare.c @@ -52,8 +52,11 @@ static void ssh2_bare_bpp_free(BinaryPacketProtocol *bpp) #define BPP_READ(ptr, len) do \ { \ - crMaybeWaitUntilV(bufchain_try_fetch_consume( \ + crMaybeWaitUntilV(s->bpp.input_eof || \ + bufchain_try_fetch_consume( \ s->bpp.in_raw, ptr, len)); \ + if (s->bpp.input_eof) \ + goto eof; \ } while (0) static void ssh2_bare_bpp_handle_input(BinaryPacketProtocol *bpp) @@ -72,7 +75,7 @@ static void ssh2_bare_bpp_handle_input(BinaryPacketProtocol *bpp) } if (s->packetlen <= 0 || s->packetlen >= (long)OUR_V2_PACKETLIMIT) { - s->bpp.error = dupstr("Invalid packet length received"); + ssh_sw_abort(s->bpp.ssh, "Invalid packet length received"); crStopV; } @@ -123,15 +126,17 @@ static void ssh2_bare_bpp_handle_input(BinaryPacketProtocol *bpp) } pq_push(&s->bpp.in_pq, s->pktin); + s->pktin = NULL; + } - { - int type = s->pktin->type; - s->pktin = NULL; - - if (type == SSH2_MSG_DISCONNECT) - s->bpp.seen_disconnect = TRUE; - } + eof: + if (!s->bpp.expect_close) { + ssh_remote_error(s->bpp.ssh, + "Server unexpectedly closed network connection"); + } else { + ssh_remote_eof(s->bpp.ssh, "Server closed network connection"); } + crFinishV; } diff --git a/ssh2bpp.c b/ssh2bpp.c index b476f33b..8ddb49f7 100644 --- a/ssh2bpp.c +++ b/ssh2bpp.c @@ -168,8 +168,11 @@ void ssh2_bpp_new_incoming_crypto( #define BPP_READ(ptr, len) do \ { \ - crMaybeWaitUntilV(bufchain_try_fetch_consume( \ + crMaybeWaitUntilV(s->bpp.input_eof || \ + bufchain_try_fetch_consume( \ s->bpp.in_raw, ptr, len)); \ + if (s->bpp.input_eof) \ + goto eof; \ } while (0) static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp) @@ -246,8 +249,8 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp) s->packetlen-4)) break; if (s->packetlen >= (long)OUR_V2_PACKETLIMIT) { - s->bpp.error = dupprintf( - "No valid incoming packet found"); + ssh_sw_abort(s->bpp.ssh, + "No valid incoming packet found"); crStopV; } } @@ -293,8 +296,8 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp) */ if (s->len < 0 || s->len > (long)OUR_V2_PACKETLIMIT || s->len % s->cipherblk != 0) { - s->bpp.error = dupprintf( - "Incoming packet length field was garbled"); + ssh_sw_abort(s->bpp.ssh, + "Incoming packet length field was garbled"); crStopV; } @@ -323,7 +326,7 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp) */ if (s->in.mac && !ssh2_mac_verify( s->in.mac, s->data, s->len + 4, s->in.sequence)) { - s->bpp.error = dupprintf("Incorrect MAC received on packet"); + ssh_sw_abort(s->bpp.ssh, "Incorrect MAC received on packet"); crStopV; } @@ -358,8 +361,8 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp) */ if (s->len < 0 || s->len > (long)OUR_V2_PACKETLIMIT || (s->len + 4) % s->cipherblk != 0) { - s->bpp.error = dupprintf( - "Incoming packet was garbled on decryption"); + ssh_sw_abort(s->bpp.ssh, + "Incoming packet was garbled on decryption"); crStopV; } @@ -396,15 +399,15 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp) */ if (s->in.mac && !ssh2_mac_verify( s->in.mac, s->data, s->len + 4, s->in.sequence)) { - s->bpp.error = dupprintf("Incorrect MAC received on packet"); + ssh_sw_abort(s->bpp.ssh, "Incorrect MAC received on packet"); crStopV; } } /* Get and sanity-check the amount of random padding. */ s->pad = s->data[4]; if (s->pad < 4 || s->len - s->pad < 1) { - s->bpp.error = dupprintf( - "Invalid padding length on received packet"); + ssh_sw_abort(s->bpp.ssh, + "Invalid padding length on received packet"); crStopV; } /* @@ -492,8 +495,6 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp) int type = s->pktin->type; s->pktin = NULL; - if (type == SSH2_MSG_DISCONNECT) - s->bpp.seen_disconnect = TRUE; if (type == SSH2_MSG_NEWKEYS) { /* * Mild layer violation: in this situation we must @@ -506,6 +507,15 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp) } } } + + eof: + if (!s->bpp.expect_close) { + ssh_remote_error(s->bpp.ssh, + "Server unexpectedly closed network connection"); + } else { + ssh_remote_eof(s->bpp.ssh, "Server closed network connection"); + } + crFinishV; } diff --git a/ssh2connection.c b/ssh2connection.c new file mode 100644 index 00000000..38566dc0 --- /dev/null +++ b/ssh2connection.c @@ -0,0 +1,2501 @@ +/* + * Packet protocol layer for the SSH-2 connection protocol (RFC 4254). + */ + +#include + +#include "putty.h" +#include "ssh.h" +#include "sshbpp.h" +#include "sshppl.h" +#include "sshchan.h" +#include "sshcr.h" + +struct ssh2_channel; + +typedef enum MainChanType { + MAINCHAN_DIRECT_TCPIP, MAINCHAN_SESSION, MAINCHAN_NONE +} MainChanType; + +struct outstanding_global_request; + +struct ssh2_connection_state { + int crState; + + Ssh ssh; + + ssh_sharing_state *connshare; + char *peer_verstring; + + struct ssh2_channel *mainchan; /* primary session channel */ + MainChanType mctype; + char *mainchan_open_error; + int mainchan_ready; + int echoedit; + int mainchan_eof_pending, mainchan_eof_sent; + int session_attempt, session_status; + int term_width, term_height, term_width_orig, term_height_orig; + int want_user_input; + + int ssh_is_simple; + + Conf *conf; + + tree234 *channels; /* indexed by local id */ + int all_channels_throttled; + + int X11_fwd_enabled; + struct X11Display *x11disp; + struct X11FakeAuth *x11auth; + tree234 *x11authtree; + + int got_pty; + int agent_fwd_enabled; + + tree234 *rportfwds; + PortFwdManager *portfwdmgr; + int portfwdmgr_configured; + + /* + * These store the list of global requests that we're waiting for + * replies to. (REQUEST_FAILURE doesn't come with any indication + * of what message caused it, so we have to keep track of the + * queue ourselves.) + */ + struct outstanding_global_request *globreq_head, *globreq_tail; + + ConnectionLayer cl; + PacketProtocolLayer ppl; +}; + +static int ssh2_rportfwd_cmp(void *av, void *bv) +{ + struct ssh_rportfwd *a = (struct ssh_rportfwd *) av; + struct ssh_rportfwd *b = (struct ssh_rportfwd *) bv; + int i; + if ( (i = strcmp(a->shost, b->shost)) != 0) + return i < 0 ? -1 : +1; + if (a->sport > b->sport) + return +1; + if (a->sport < b->sport) + return -1; + return 0; +} + +static void ssh2_connection_free(PacketProtocolLayer *); +static void ssh2_connection_process_queue(PacketProtocolLayer *); +static int ssh2_connection_get_specials( + PacketProtocolLayer *ppl, add_special_fn_t add_special, void *ctx); +static void ssh2_connection_special_cmd(PacketProtocolLayer *ppl, + SessionSpecialCode code, int arg); +static int ssh2_connection_want_user_input(PacketProtocolLayer *ppl); +static void ssh2_connection_got_user_input(PacketProtocolLayer *ppl); +static void ssh2_connection_reconfigure(PacketProtocolLayer *ppl, Conf *conf); + +static const struct PacketProtocolLayerVtable ssh2_connection_vtable = { + ssh2_connection_free, + ssh2_connection_process_queue, + ssh2_connection_get_specials, + ssh2_connection_special_cmd, + ssh2_connection_want_user_input, + ssh2_connection_got_user_input, + ssh2_connection_reconfigure, + "ssh-connection", +}; + +static struct ssh_rportfwd *ssh2_rportfwd_alloc( + ConnectionLayer *cl, + const char *shost, int sport, const char *dhost, int dport, + int addressfamily, const char *log_description, PortFwdRecord *pfr, + ssh_sharing_connstate *share_ctx); +static void ssh2_rportfwd_remove( + ConnectionLayer *cl, struct ssh_rportfwd *rpf); +static SshChannel *ssh2_lportfwd_open( + ConnectionLayer *cl, const char *hostname, int port, + const char *org, Channel *chan); +static struct X11FakeAuth *ssh2_add_sharing_x11_display( + ConnectionLayer *cl, int authtype, ssh_sharing_connstate *share_cs, + share_channel *share_chan); +static void ssh2_remove_sharing_x11_display(ConnectionLayer *cl, + struct X11FakeAuth *auth); +static void ssh2_send_packet_from_downstream( + ConnectionLayer *cl, unsigned id, int type, + const void *pkt, int pktlen, const char *additional_log_text); +static unsigned ssh2_alloc_sharing_channel( + ConnectionLayer *cl, ssh_sharing_connstate *connstate); +static void ssh2_delete_sharing_channel( + ConnectionLayer *cl, unsigned localid); +static void ssh2_sharing_queue_global_request( + ConnectionLayer *cl, ssh_sharing_connstate *share_ctx); +static int ssh2_agent_forwarding_permitted(ConnectionLayer *cl); +static void ssh2_terminal_size(ConnectionLayer *cl, int width, int height); +static void ssh2_stdout_unthrottle(ConnectionLayer *cl, int bufsize); +static int ssh2_stdin_backlog(ConnectionLayer *cl); +static void ssh2_throttle_all_channels(ConnectionLayer *cl, int throttled); +static int ssh2_ldisc_option(ConnectionLayer *cl, int option); + +static const struct ConnectionLayerVtable ssh2_connlayer_vtable = { + ssh2_rportfwd_alloc, + ssh2_rportfwd_remove, + ssh2_lportfwd_open, + ssh2_add_sharing_x11_display, + ssh2_remove_sharing_x11_display, + ssh2_send_packet_from_downstream, + ssh2_alloc_sharing_channel, + ssh2_delete_sharing_channel, + ssh2_sharing_queue_global_request, + ssh2_agent_forwarding_permitted, + ssh2_terminal_size, + ssh2_stdout_unthrottle, + ssh2_stdin_backlog, + ssh2_throttle_all_channels, + ssh2_ldisc_option, +}; + +static char *ssh2_channel_open_failure_error_text(PktIn *pktin) +{ + static const char *const reasons[] = { + NULL, + "Administratively prohibited", + "Connect failed", + "Unknown channel type", + "Resource shortage", + }; + unsigned reason_code; + const char *reason_code_string; + char reason_code_buf[256]; + ptrlen reason; + + reason_code = get_uint32(pktin); + if (reason_code < lenof(reasons) && reasons[reason_code]) { + reason_code_string = reasons[reason_code]; + } else { + reason_code_string = reason_code_buf; + sprintf(reason_code_buf, "unknown reason code %#x", reason_code); + } + + reason = get_string(pktin); + + return dupprintf("%s [%.*s]", reason_code_string, PTRLEN_PRINTF(reason)); +} + +struct outstanding_channel_request; +struct outstanding_global_request; + +struct ssh2_channel { + struct ssh2_connection_state *connlayer; + + unsigned remoteid, localid; + int type; + /* True if we opened this channel but server hasn't confirmed. */ + int halfopen; + + /* Bitmap of whether we've sent/received CHANNEL_EOF and + * CHANNEL_CLOSE. */ +#define CLOSES_SENT_EOF 1 +#define CLOSES_SENT_CLOSE 2 +#define CLOSES_RCVD_EOF 4 +#define CLOSES_RCVD_CLOSE 8 + int closes; + + /* + * This flag indicates that an EOF is pending on the outgoing side + * of the channel: that is, wherever we're getting the data for + * this channel has sent us some data followed by EOF. We can't + * actually send the EOF until we've finished sending the data, so + * we set this flag instead to remind us to do so once our buffer + * is clear. + */ + int pending_eof; + + /* + * True if this channel is causing the underlying connection to be + * throttled. + */ + int throttling_conn; + + /* + * True if we currently have backed-up data on the direction of + * this channel pointing out of the SSH connection, and therefore + * would prefer the 'Channel' implementation not to read further + * local input if possible. + */ + int throttled_by_backlog; + + bufchain outbuffer; + unsigned remwindow, remmaxpkt; + /* locwindow is signed so we can cope with excess data. */ + int locwindow, locmaxwin; + /* + * remlocwin is the amount of local window that we think + * the remote end had available to it after it sent the + * last data packet or window adjust ack. + */ + int remlocwin; + + /* + * These store the list of channel requests that we're waiting for + * replies to. (CHANNEL_FAILURE doesn't come with any indication + * of what message caused it, so we have to keep track of the + * queue ourselves.) + */ + struct outstanding_channel_request *chanreq_head, *chanreq_tail; + + enum { THROTTLED, UNTHROTTLING, UNTHROTTLED } throttle_state; + + ssh_sharing_connstate *sharectx; /* sharing context, if this is a + * downstream channel */ + Channel *chan; /* handle the client side of this channel, if not */ + SshChannel sc; /* entry point for chan to talk back to */ +}; + +static int ssh2channel_write(SshChannel *c, const void *buf, int len); +static void ssh2channel_write_eof(SshChannel *c); +static void ssh2channel_unclean_close(SshChannel *c, const char *err); +static void ssh2channel_unthrottle(SshChannel *c, int bufsize); +static Conf *ssh2channel_get_conf(SshChannel *c); +static void ssh2channel_window_override_removed(SshChannel *c); +static void ssh2channel_x11_sharing_handover( + SshChannel *c, ssh_sharing_connstate *share_cs, share_channel *share_chan, + const char *peer_addr, int peer_port, int endian, + int protomajor, int protominor, const void *initial_data, int initial_len); + +static const struct SshChannelVtable ssh2channel_vtable = { + ssh2channel_write, + ssh2channel_write_eof, + ssh2channel_unclean_close, + ssh2channel_unthrottle, + ssh2channel_get_conf, + ssh2channel_window_override_removed, + ssh2channel_x11_sharing_handover, +}; + +typedef void (*cr_handler_fn_t)(struct ssh2_channel *, PktIn *, void *); + +static void ssh2_channel_init(struct ssh2_channel *c); +static PktOut *ssh2_chanopen_init(struct ssh2_channel *c, const char *type); +static PktOut *ssh2_chanreq_init(struct ssh2_channel *c, const char *type, + cr_handler_fn_t handler, void *ctx); +static void ssh2_channel_check_close(struct ssh2_channel *c); +static void ssh2_channel_try_eof(struct ssh2_channel *c); +static void ssh2_set_window(struct ssh2_channel *c, int newwin); +static int ssh2_try_send(struct ssh2_channel *c); +static void ssh2_try_send_and_unthrottle(struct ssh2_channel *c); +static void ssh2_channel_check_throttle(struct ssh2_channel *c); +static void ssh2_channel_close_local(struct ssh2_channel *c, + const char *reason); +static void ssh2_channel_destroy(struct ssh2_channel *c); + +static void ssh2_check_termination(struct ssh2_connection_state *s); + +typedef void (*gr_handler_fn_t)(struct ssh2_connection_state *s, + PktIn *pktin, void *ctx); +struct outstanding_global_request { + gr_handler_fn_t handler; + void *ctx; + struct outstanding_global_request *next; +}; +static void ssh2_queue_global_request_handler( + struct ssh2_connection_state *s, gr_handler_fn_t handler, void *ctx) +{ + struct outstanding_global_request *ogr = + snew(struct outstanding_global_request); + ogr->handler = handler; + ogr->ctx = ctx; + if (s->globreq_tail) + s->globreq_tail->next = ogr; + else + s->globreq_head = ogr; + s->globreq_tail = ogr; +} + +typedef struct mainchan { + struct ssh2_connection_state *connlayer; + SshChannel *sc; + + Channel chan; +} mainchan; +static mainchan *mainchan_new(struct ssh2_connection_state *s); +static void ssh2_setup_x11(struct ssh2_channel *c, PktIn *pktin, void *ctx); +static void ssh2_setup_agent(struct ssh2_channel *c, PktIn *pktin, void *ctx); +static void ssh2_setup_pty(struct ssh2_channel *c, PktIn *pktin, void *ctx); +static void ssh2_setup_env(struct ssh2_channel *c, PktIn *pktin, void *ctx); +static void ssh2_response_session(struct ssh2_channel *c, PktIn *, void *); + +static int ssh2_channelcmp(void *av, void *bv) +{ + const struct ssh2_channel *a = (const struct ssh2_channel *) av; + const struct ssh2_channel *b = (const struct ssh2_channel *) bv; + if (a->localid < b->localid) + return -1; + if (a->localid > b->localid) + return +1; + return 0; +} + +static int ssh2_channelfind(void *av, void *bv) +{ + const unsigned *a = (const unsigned *) av; + const struct ssh2_channel *b = (const struct ssh2_channel *) bv; + if (*a < b->localid) + return -1; + if (*a > b->localid) + return +1; + return 0; +} + +/* + * Each channel has a queue of outstanding CHANNEL_REQUESTS and their + * handlers. + */ +struct outstanding_channel_request { + cr_handler_fn_t handler; + void *ctx; + struct outstanding_channel_request *next; +}; + +static void ssh2_channel_free(struct ssh2_channel *c) +{ + bufchain_clear(&c->outbuffer); + while (c->chanreq_head) { + struct outstanding_channel_request *chanreq = c->chanreq_head; + c->chanreq_head = c->chanreq_head->next; + sfree(chanreq); + } + if (c->chan) + chan_free(c->chan); + sfree(c); +} + +PacketProtocolLayer *ssh2_connection_new( + Ssh ssh, ssh_sharing_state *connshare, int is_simple, + Conf *conf, const char *peer_verstring, ConnectionLayer **cl_out) +{ + struct ssh2_connection_state *s = snew(struct ssh2_connection_state); + memset(s, 0, sizeof(*s)); + s->ppl.vt = &ssh2_connection_vtable; + + s->conf = conf_copy(conf); + + s->ssh_is_simple = is_simple; + + s->connshare = connshare; + s->peer_verstring = dupstr(peer_verstring); + + s->channels = newtree234(ssh2_channelcmp); + + s->x11authtree = newtree234(x11_authcmp); + + /* Need to get the frontend for s->cl now, because we won't be + * helpfully notified when a copy is written into s->ppl by our + * owner. */ + s->cl.vt = &ssh2_connlayer_vtable; + s->cl.frontend = ssh_get_frontend(ssh); + + s->portfwdmgr = portfwdmgr_new(&s->cl); + s->rportfwds = newtree234(ssh2_rportfwd_cmp); + + *cl_out = &s->cl; + if (s->connshare) + ssh_connshare_provide_connlayer(s->connshare, &s->cl); + + return &s->ppl; +} + +static void ssh2_connection_free(PacketProtocolLayer *ppl) +{ + struct ssh2_connection_state *s = + FROMFIELD(ppl, struct ssh2_connection_state, ppl); + struct X11FakeAuth *auth; + struct ssh2_channel *c; + struct ssh_rportfwd *rpf; + + sfree(s->peer_verstring); + + conf_free(s->conf); + + sfree(s->mainchan_open_error); + + while ((c = delpos234(s->channels, 0)) != NULL) + ssh2_channel_free(c); + freetree234(s->channels); + + if (s->x11disp) + x11_free_display(s->x11disp); + while ((auth = delpos234(s->x11authtree, 0)) != NULL) + x11_free_fake_auth(auth); + freetree234(s->x11authtree); + + while ((rpf = delpos234(s->rportfwds, 0)) != NULL) + free_rportfwd(rpf); + freetree234(s->rportfwds); + portfwdmgr_free(s->portfwdmgr); + + sfree(s); +} + +static int ssh2_connection_filter_queue(struct ssh2_connection_state *s) +{ + PktIn *pktin; + PktOut *pktout; + ptrlen type, data; + struct ssh2_channel *c; + struct outstanding_channel_request *ocr; + unsigned localid, remid, winsize, pktsize, ext_type; + int want_reply, reply_type, expect_halfopen; + const char *error; + PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */ + + /* Cross-reference to ssh2transport.c to handle the common packets + * between login and connection: DISCONNECT, DEBUG and IGNORE. If + * we have an instance of ssh2transport below us, then those + * messages won't come here anyway, but they could if we're + * running in bare ssh2-connection mode. */ + extern int ssh2_common_filter_queue(PacketProtocolLayer *ppl); + + while (1) { + if (ssh2_common_filter_queue(&s->ppl)) + return TRUE; + if ((pktin = pq_peek(s->ppl.in_pq)) == NULL) + return FALSE; + + switch (pktin->type) { + case SSH2_MSG_GLOBAL_REQUEST: + /* type = */ get_string(pktin); + want_reply = get_bool(pktin); + + /* + * 'reply_type' is the message type we'll send in + * response, if want_reply is set. Initialise it to the + * default value of REQUEST_FAILURE, for any request we + * don't recognise and handle below. + */ + reply_type = SSH2_MSG_REQUEST_FAILURE; + + /* + * We currently don't support any incoming global requests + * at all. Here's where to insert some code to handle + * them, if and when we do. + */ + + if (want_reply) { + pktout = ssh_bpp_new_pktout(s->ppl.bpp, reply_type); + pq_push(s->ppl.out_pq, pktout); + } + pq_pop(s->ppl.in_pq); + break; + + case SSH2_MSG_REQUEST_SUCCESS: + case SSH2_MSG_REQUEST_FAILURE: + if (!s->globreq_head) { + ssh_proto_error( + s->ppl.ssh, + "Received %s with no outstanding global request", + ssh2_pkt_type(s->ppl.bpp->pls->kctx, s->ppl.bpp->pls->actx, + pktin->type)); + return TRUE; + } + + s->globreq_head->handler(s, pktin, s->globreq_head->ctx); + { + struct outstanding_global_request *tmp = s->globreq_head; + s->globreq_head = s->globreq_head->next; + sfree(tmp); + } + + pq_pop(s->ppl.in_pq); + break; + + case SSH2_MSG_CHANNEL_OPEN: + error = NULL; + + type = get_string(pktin); + c = snew(struct ssh2_channel); + c->connlayer = s; + + remid = get_uint32(pktin); + winsize = get_uint32(pktin); + pktsize = get_uint32(pktin); + + if (ptrlen_eq_string(type, "x11")) { + char *addrstr = mkstr(get_string(pktin)); + int peerport = get_uint32(pktin); + + ppl_logevent(("Received X11 connect request from %s:%d", + addrstr, peerport)); + + if (!s->X11_fwd_enabled && !s->connshare) { + error = "X11 forwarding is not enabled"; + } else { + c->chan = x11_new_channel( + s->x11authtree, &c->sc, addrstr, peerport, + s->connshare != NULL); + ppl_logevent(("Opened X11 forward channel")); + } + + sfree(addrstr); + } else if (ptrlen_eq_string(type, "forwarded-tcpip")) { + struct ssh_rportfwd pf, *realpf; + ptrlen peeraddr; + int peerport; + + pf.shost = mkstr(get_string(pktin)); + pf.sport = get_uint32(pktin); + peeraddr = get_string(pktin); + peerport = get_uint32(pktin); + realpf = find234(s->rportfwds, &pf, NULL); + ppl_logevent(("Received remote port %s:%d open request " + "from %.*s:%d", pf.shost, pf.sport, + PTRLEN_PRINTF(peeraddr), peerport)); + sfree(pf.shost); + + if (realpf == NULL) { + error = "Remote port is not recognised"; + } else { + char *err; + + if (realpf->share_ctx) { + /* + * This port forwarding is on behalf of a + * connection-sharing downstream, so abandon our own + * channel-open procedure and just pass the message on + * to sshshare.c. + */ + share_got_pkt_from_server( + realpf->share_ctx, pktin->type, + BinarySource_UPCAST(pktin)->data, + BinarySource_UPCAST(pktin)->len); + sfree(c); + break; + } + + err = portfwdmgr_connect( + s->portfwdmgr, &c->chan, realpf->dhost, realpf->dport, + &c->sc, realpf->addressfamily); + ppl_logevent(("Attempting to forward remote port to " + "%s:%d", realpf->dhost, realpf->dport)); + if (err != NULL) { + ppl_logevent(("Port open failed: %s", err)); + sfree(err); + error = "Port open failed"; + } else { + ppl_logevent(("Forwarded port opened successfully")); + } + } + } else if (ptrlen_eq_string(type, "auth-agent@openssh.com")) { + if (!s->agent_fwd_enabled) + error = "Agent forwarding is not enabled"; + else + c->chan = agentf_new(&c->sc); + } else { + error = "Unsupported channel type requested"; + } + + c->remoteid = remid; + c->halfopen = FALSE; + if (error) { + pktout = ssh_bpp_new_pktout( + s->ppl.bpp, SSH2_MSG_CHANNEL_OPEN_FAILURE); + put_uint32(pktout, c->remoteid); + put_uint32(pktout, SSH2_OPEN_CONNECT_FAILED); + put_stringz(pktout, error); + put_stringz(pktout, "en"); /* language tag */ + pq_push(s->ppl.out_pq, pktout); + ppl_logevent(("Rejected channel open: %s", error)); + sfree(c); + } else { + ssh2_channel_init(c); + c->remwindow = winsize; + c->remmaxpkt = pktsize; + if (c->chan->initial_fixed_window_size) { + c->locwindow = c->locmaxwin = c->remlocwin = + c->chan->initial_fixed_window_size; + } + pktout = ssh_bpp_new_pktout( + s->ppl.bpp, SSH2_MSG_CHANNEL_OPEN_CONFIRMATION); + put_uint32(pktout, c->remoteid); + put_uint32(pktout, c->localid); + put_uint32(pktout, c->locwindow); + put_uint32(pktout, OUR_V2_MAXPKT); /* our max pkt size */ + pq_push(s->ppl.out_pq, pktout); + } + + pq_pop(s->ppl.in_pq); + break; + + case SSH2_MSG_CHANNEL_DATA: + case SSH2_MSG_CHANNEL_WINDOW_ADJUST: + case SSH2_MSG_CHANNEL_REQUEST: + case SSH2_MSG_CHANNEL_EOF: + case SSH2_MSG_CHANNEL_CLOSE: + case SSH2_MSG_CHANNEL_OPEN_CONFIRMATION: + case SSH2_MSG_CHANNEL_OPEN_FAILURE: + case SSH2_MSG_CHANNEL_SUCCESS: + case SSH2_MSG_CHANNEL_FAILURE: + /* + * Common preliminary code for all the messages from the + * server that cite one of our channel ids: look up that + * channel id, check it exists, and if it's for a sharing + * downstream, pass it on. + */ + localid = get_uint32(pktin); + c = find234(s->channels, &localid, ssh2_channelfind); + + if (c && c->sharectx) { + share_got_pkt_from_server(c->sharectx, pktin->type, + BinarySource_UPCAST(pktin)->data, + BinarySource_UPCAST(pktin)->len); + pq_pop(s->ppl.in_pq); + break; + } + + expect_halfopen = ( + pktin->type == SSH2_MSG_CHANNEL_OPEN_CONFIRMATION || + pktin->type == SSH2_MSG_CHANNEL_OPEN_FAILURE); + + if (!c || c->halfopen != expect_halfopen) { + ssh_proto_error(s->ppl.ssh, + "Received %s for %s channel %u", + ssh2_pkt_type(s->ppl.bpp->pls->kctx, + s->ppl.bpp->pls->actx, + pktin->type), + (!c ? "nonexistent" : + c->halfopen ? "half-open" : "open"), + localid); + return TRUE; + } + + switch (pktin->type) { + case SSH2_MSG_CHANNEL_OPEN_CONFIRMATION: + assert(c->halfopen); + c->remoteid = get_uint32(pktin); + c->halfopen = FALSE; + c->remwindow = get_uint32(pktin); + c->remmaxpkt = get_uint32(pktin); + + chan_open_confirmation(c->chan); + + /* + * Now that the channel is fully open, it's possible + * in principle to immediately close it. Check whether + * it wants us to! + * + * This can occur if a local socket error occurred + * between us sending out CHANNEL_OPEN and receiving + * OPEN_CONFIRMATION. If that happens, all we can do + * is immediately initiate close proceedings now that + * we know the server's id to put in the close + * message. We'll have handled that in this code by + * having already turned c->chan into a zombie, so its + * want_close method (which ssh2_channel_check_close + * will consult) will already be returning TRUE. + */ + ssh2_channel_check_close(c); + + if (c->pending_eof) + ssh2_channel_try_eof(c); /* in case we had a pending EOF */ + break; + + case SSH2_MSG_CHANNEL_OPEN_FAILURE: + assert(c->halfopen); + + { + char *err = ssh2_channel_open_failure_error_text(pktin); + chan_open_failed(c->chan, err); + sfree(err); + } + chan_free(c->chan); + + del234(s->channels, c); + ssh2_channel_free(c); + + break; + + case SSH2_MSG_CHANNEL_DATA: + case SSH2_MSG_CHANNEL_EXTENDED_DATA: + ext_type = (pktin->type == SSH2_MSG_CHANNEL_DATA ? 0 : + get_uint32(pktin)); + data = get_string(pktin); + if (!get_err(pktin)) { + int bufsize; + c->locwindow -= data.len; + c->remlocwin -= data.len; + if (ext_type != 0 && ext_type != SSH2_EXTENDED_DATA_STDERR) + data.len = 0; /* ignore unknown extended data */ + bufsize = chan_send( + c->chan, ext_type == SSH2_EXTENDED_DATA_STDERR, + data.ptr, data.len); + + /* + * If it looks like the remote end hit the end of + * its window, and we didn't want it to do that, + * think about using a larger window. + */ + if (c->remlocwin <= 0 && + c->throttle_state == UNTHROTTLED && + c->locmaxwin < 0x40000000) + c->locmaxwin += OUR_V2_WINSIZE; + + /* + * If we are not buffering too much data, enlarge + * the window again at the remote side. If we are + * buffering too much, we may still need to adjust + * the window if the server's sent excess data. + */ + if (bufsize < c->locmaxwin) + ssh2_set_window(c, c->locmaxwin - bufsize); + + /* + * If we're either buffering way too much data, or + * if we're buffering anything at all and we're in + * "simple" mode, throttle the whole channel. + */ + if ((bufsize > c->locmaxwin || + (s->ssh_is_simple && bufsize>0)) && + !c->throttling_conn) { + c->throttling_conn = TRUE; + ssh_throttle_conn(s->ppl.ssh, +1); + } + } + break; + + case SSH2_MSG_CHANNEL_WINDOW_ADJUST: + if (!(c->closes & CLOSES_SENT_EOF)) { + c->remwindow += get_uint32(pktin); + ssh2_try_send_and_unthrottle(c); + } + break; + + case SSH2_MSG_CHANNEL_REQUEST: + type = get_string(pktin); + want_reply = get_bool(pktin); + + /* + * 'reply_type' is the message type we'll send in + * response, if want_reply is set. Initialise it to + * the default value of CHANNEL_FAILURE, for any + * request we don't recognise and handle below. + */ + reply_type = SSH2_MSG_CHANNEL_FAILURE; + + if (c->closes & CLOSES_SENT_CLOSE) { + /* + * We don't reply to channel requests after we've + * sent CHANNEL_CLOSE for the channel, because our + * reply might cross in the network with the other + * side's CHANNEL_CLOSE and arrive after they have + * wound the channel up completely. + */ + want_reply = FALSE; + } + + /* + * Having got the channel number, we now look at the + * request type string to see if it's something we + * recognise. + */ + if (c == s->mainchan) { + int exitcode; + + /* + * We recognise "exit-status" and "exit-signal" on + * the primary channel. + */ + if (ptrlen_eq_string(type, "exit-status")) { + exitcode = toint(get_uint32(pktin)); + ssh_got_exitcode(s->ppl.ssh, exitcode); + ppl_logevent(("Server sent command exit status %d", + exitcode)); + reply_type = SSH2_MSG_CHANNEL_SUCCESS; + } else if (ptrlen_eq_string(type, "exit-signal")) { + char *fmt_sig = NULL, *fmt_msg = NULL; + ptrlen errmsg; + int core = FALSE; + int format; + + /* + * ICK: older versions of OpenSSH (e.g. 3.4p1) + * provide an `int' for the signal, despite + * its having been a `string' in the drafts of + * RFC 4254 since at least 2001. (Fixed in + * session.c 1.147.) Try to infer which we can + * safely parse it as. + */ + + size_t startpos = BinarySource_UPCAST(pktin)->pos; + + for (format = 0; format < 2; format++) { + BinarySource_UPCAST(pktin)->pos = startpos; + BinarySource_UPCAST(pktin)->err = BSE_NO_ERROR; + + if (format == 0) { + /* standard string-based format */ + ptrlen signame = get_string(pktin); + fmt_sig = dupprintf(" \"%.*s\"", + PTRLEN_PRINTF(signame)); + + /* + * Really hideous method of translating the + * signal description back into a locally + * meaningful number. + */ + + if (0) + ; +#define TRANSLATE_SIGNAL(s) \ + else if (ptrlen_eq_string(signame, #s)) \ + exitcode = 128 + SIG ## s +#ifdef SIGABRT + TRANSLATE_SIGNAL(ABRT); +#endif +#ifdef SIGALRM + TRANSLATE_SIGNAL(ALRM); +#endif +#ifdef SIGFPE + TRANSLATE_SIGNAL(FPE); +#endif +#ifdef SIGHUP + TRANSLATE_SIGNAL(HUP); +#endif +#ifdef SIGILL + TRANSLATE_SIGNAL(ILL); +#endif +#ifdef SIGINT + TRANSLATE_SIGNAL(INT); +#endif +#ifdef SIGKILL + TRANSLATE_SIGNAL(KILL); +#endif +#ifdef SIGPIPE + TRANSLATE_SIGNAL(PIPE); +#endif +#ifdef SIGQUIT + TRANSLATE_SIGNAL(QUIT); +#endif +#ifdef SIGSEGV + TRANSLATE_SIGNAL(SEGV); +#endif +#ifdef SIGTERM + TRANSLATE_SIGNAL(TERM); +#endif +#ifdef SIGUSR1 + TRANSLATE_SIGNAL(USR1); +#endif +#ifdef SIGUSR2 + TRANSLATE_SIGNAL(USR2); +#endif +#undef TRANSLATE_SIGNAL + else + exitcode = 128; + } else { + /* nonstandard integer format */ + unsigned signum = get_uint32(pktin); + fmt_sig = dupprintf(" %u", signum); + exitcode = 128 + signum; + } + + core = get_bool(pktin); + errmsg = get_string(pktin); /* error message */ + get_string(pktin); /* language tag */ + if (!get_err(pktin) && get_avail(pktin) == 0) + break; /* successful parse */ + + sfree(fmt_sig); + } + + if (format == 2) { + fmt_sig = NULL; + exitcode = 128; + } + + if (errmsg.len) { + fmt_msg = dupprintf(" (\"%.*s\")", + PTRLEN_PRINTF(errmsg)); + } + + ssh_got_exitcode(s->ppl.ssh, exitcode); + ppl_logevent(("Server exited on signal%s%s%s", + fmt_sig ? fmt_sig : "", + core ? " (core dumped)" : "", + fmt_msg ? fmt_msg : "")); + sfree(fmt_sig); + sfree(fmt_msg); + reply_type = SSH2_MSG_CHANNEL_SUCCESS; + } + } + if (want_reply) { + pktout = ssh_bpp_new_pktout(s->ppl.bpp, reply_type); + put_uint32(pktout, c->remoteid); + pq_push(s->ppl.out_pq, pktout); + } + break; + + case SSH2_MSG_CHANNEL_SUCCESS: + case SSH2_MSG_CHANNEL_FAILURE: + ocr = c->chanreq_head; + if (!ocr) { + ssh_proto_error( + s->ppl.ssh, + "Received %s for channel %d with no outstanding " + "channel request", + ssh2_pkt_type(s->ppl.bpp->pls->kctx, + s->ppl.bpp->pls->actx, pktin->type)); + return TRUE; + } + ocr->handler(c, pktin, ocr->ctx); + c->chanreq_head = ocr->next; + sfree(ocr); + /* + * We may now initiate channel-closing procedures, if + * that CHANNEL_REQUEST was the last thing outstanding + * before we send CHANNEL_CLOSE. + */ + ssh2_channel_check_close(c); + break; + + case SSH2_MSG_CHANNEL_EOF: + if (!(c->closes & CLOSES_RCVD_EOF)) { + c->closes |= CLOSES_RCVD_EOF; + chan_send_eof(c->chan); + ssh2_channel_check_close(c); + } + break; + + case SSH2_MSG_CHANNEL_CLOSE: + /* + * When we receive CLOSE on a channel, we assume it + * comes with an implied EOF if we haven't seen EOF + * yet. + */ + if (!(c->closes & CLOSES_RCVD_EOF)) { + c->closes |= CLOSES_RCVD_EOF; + chan_send_eof(c->chan); + } + + if (!(s->ppl.remote_bugs & BUG_SENDS_LATE_REQUEST_REPLY)) { + /* + * It also means we stop expecting to see replies + * to any outstanding channel requests, so clean + * those up too. (ssh_chanreq_init will enforce by + * assertion that we don't subsequently put + * anything back on this list.) + */ + while (c->chanreq_head) { + struct outstanding_channel_request *ocr = + c->chanreq_head; + ocr->handler(c, NULL, ocr->ctx); + c->chanreq_head = ocr->next; + sfree(ocr); + } + } + + /* + * And we also send an outgoing EOF, if we haven't + * already, on the assumption that CLOSE is a pretty + * forceful announcement that the remote side is doing + * away with the entire channel. (If it had wanted to + * send us EOF and continue receiving data from us, it + * would have just sent CHANNEL_EOF.) + */ + if (!(c->closes & CLOSES_SENT_EOF)) { + /* + * Abandon any buffered data we still wanted to + * send to this channel. Receiving a CHANNEL_CLOSE + * is an indication that the server really wants + * to get on and _destroy_ this channel, and it + * isn't going to send us any further + * WINDOW_ADJUSTs to permit us to send pending + * stuff. + */ + bufchain_clear(&c->outbuffer); + + /* + * Send outgoing EOF. + */ + sshfwd_write_eof(&c->sc); + + /* + * Make sure we don't read any more from whatever + * our local data source is for this channel. + * (This will pick up on the changes made by + * sshfwd_write_eof.) + */ + ssh2_channel_check_throttle(c); + } + + /* + * Now process the actual close. + */ + if (!(c->closes & CLOSES_RCVD_CLOSE)) { + c->closes |= CLOSES_RCVD_CLOSE; + ssh2_channel_check_close(c); + } + + break; + } + + pq_pop(s->ppl.in_pq); + break; + + default: + return FALSE; + } + } +} + +static void ssh2_handle_winadj_response(struct ssh2_channel *c, + PktIn *pktin, void *ctx) +{ + unsigned *sizep = ctx; + + /* + * Winadj responses should always be failures. However, at least + * one server ("boks_sshd") is known to return SUCCESS for channel + * requests it's never heard of, such as "winadj@putty". Raised + * with foxt.com as bug 090916-090424, but for the sake of a quiet + * life, we don't worry about what kind of response we got. + */ + + c->remlocwin += *sizep; + sfree(sizep); + /* + * winadj messages are only sent when the window is fully open, so + * if we get an ack of one, we know any pending unthrottle is + * complete. + */ + if (c->throttle_state == UNTHROTTLING) + c->throttle_state = UNTHROTTLED; +} + +static void ssh2_set_window(struct ssh2_channel *c, int newwin) +{ + struct ssh2_connection_state *s = c->connlayer; + + /* + * Never send WINDOW_ADJUST for a channel that the remote side has + * already sent EOF on; there's no point, since it won't be + * sending any more data anyway. Ditto if _we've_ already sent + * CLOSE. + */ + if (c->closes & (CLOSES_RCVD_EOF | CLOSES_SENT_CLOSE)) + return; + + /* + * If the client-side Channel is in an initial setup phase with a + * fixed window size, e.g. for an X11 channel when we're still + * waiting to see its initial auth and may yet hand it off to a + * downstream, don't send any WINDOW_ADJUST either. + */ + if (c->chan->initial_fixed_window_size) + return; + + /* + * If the remote end has a habit of ignoring maxpkt, limit the + * window so that it has no choice (assuming it doesn't ignore the + * window as well). + */ + if ((s->ppl.remote_bugs & BUG_SSH2_MAXPKT) && newwin > OUR_V2_MAXPKT) + newwin = OUR_V2_MAXPKT; + + /* + * Only send a WINDOW_ADJUST if there's significantly more window + * available than the other end thinks there is. This saves us + * sending a WINDOW_ADJUST for every character in a shell session. + * + * "Significant" is arbitrarily defined as half the window size. + */ + if (newwin / 2 >= c->locwindow) { + PktOut *pktout; + unsigned *up; + + /* + * In order to keep track of how much window the client + * actually has available, we'd like it to acknowledge each + * WINDOW_ADJUST. We can't do that directly, so we accompany + * it with a CHANNEL_REQUEST that has to be acknowledged. + * + * This is only necessary if we're opening the window wide. + * If we're not, then throughput is being constrained by + * something other than the maximum window size anyway. + */ + if (newwin == c->locmaxwin && + !(s->ppl.remote_bugs & BUG_CHOKES_ON_WINADJ)) { + up = snew(unsigned); + *up = newwin - c->locwindow; + pktout = ssh2_chanreq_init(c, "winadj@putty.projects.tartarus.org", + ssh2_handle_winadj_response, up); + pq_push(s->ppl.out_pq, pktout); + + if (c->throttle_state != UNTHROTTLED) + c->throttle_state = UNTHROTTLING; + } else { + /* Pretend the WINDOW_ADJUST was acked immediately. */ + c->remlocwin = newwin; + c->throttle_state = THROTTLED; + } + pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH2_MSG_CHANNEL_WINDOW_ADJUST); + put_uint32(pktout, c->remoteid); + put_uint32(pktout, newwin - c->locwindow); + pq_push(s->ppl.out_pq, pktout); + c->locwindow = newwin; + } +} + +static PktIn *ssh2_connection_pop(struct ssh2_connection_state *s) +{ + ssh2_connection_filter_queue(s); + return pq_pop(s->ppl.in_pq); +} + +static void ssh2_connection_process_queue(PacketProtocolLayer *ppl) +{ + struct ssh2_connection_state *s = + FROMFIELD(ppl, struct ssh2_connection_state, ppl); + PktIn *pktin; + PktOut *pktout; + + if (ssh2_connection_filter_queue(s)) /* no matter why we were called */ + return; + + crBegin(s->crState); + + /* + * Create the main session channel, if any. + */ + if (conf_get_int(s->conf, CONF_ssh_no_shell)) { + s->mctype = MAINCHAN_NONE; + } else if (*conf_get_str(s->conf, CONF_ssh_nc_host)) { + s->mctype = MAINCHAN_DIRECT_TCPIP; + } else { + s->mctype = MAINCHAN_SESSION; + } + + if (s->mctype != MAINCHAN_NONE) { + mainchan *mc = mainchan_new(s); + + switch (s->mctype) { + case MAINCHAN_NONE: + assert(0 && "Unreachable"); + break; + + case MAINCHAN_SESSION: + s->mainchan = snew(struct ssh2_channel); + mc->sc = &s->mainchan->sc; + s->mainchan->connlayer = s; + ssh2_channel_init(s->mainchan); + s->mainchan->chan = &mc->chan; + s->mainchan->halfopen = TRUE; + pktout = ssh2_chanopen_init(s->mainchan, "session"); + ppl_logevent(("Opening session as main channel")); + pq_push(s->ppl.out_pq, pktout); + break; + + case MAINCHAN_DIRECT_TCPIP: + mc->sc = ssh_lportfwd_open( + &s->cl, conf_get_str(s->conf, CONF_ssh_nc_host), + conf_get_int(s->conf, CONF_ssh_nc_port), + "main channel", &mc->chan); + s->mainchan = FROMFIELD(mc->sc, struct ssh2_channel, sc); + break; + } + + /* + * Wait until that channel has been successfully opened (or + * not). + */ + crMaybeWaitUntilV(!s->mainchan || !s->mainchan->halfopen); + if (!s->mainchan) { + ssh_sw_abort(s->ppl.ssh, "Server refused to open main channel: %s", + s->mainchan_open_error); + return; + } + } + + /* + * Now the connection protocol is properly up and running, with + * all those dispatch table entries, so it's safe to let + * downstreams start trying to open extra channels through us. + */ + if (s->connshare) + share_activate(s->connshare, s->peer_verstring); + + if (s->mainchan && s->ssh_is_simple) { + /* + * This message indicates to the server that we promise + * not to try to run any other channel in parallel with + * this one, so it's safe for it to advertise a very large + * window and leave the flow control to TCP. + */ + pktout = ssh2_chanreq_init( + s->mainchan, "simple@putty.projects.tartarus.org", NULL, NULL); + pq_push(s->ppl.out_pq, pktout); + } + + /* + * Enable port forwardings. + */ + portfwdmgr_config(s->portfwdmgr, s->conf); + s->portfwdmgr_configured = TRUE; + + if (s->mainchan && s->mctype == MAINCHAN_SESSION) { + /* + * Send the CHANNEL_REQUESTS for the main session channel. + * Each one is handled by its own little asynchronous + * co-routine. + */ + + /* Potentially enable X11 forwarding. */ + if (conf_get_int(s->conf, CONF_x11_forward)) { + s->x11disp = x11_setup_display( + conf_get_str(s->conf, CONF_x11_display), s->conf); + if (!s->x11disp) { + /* FIXME: return an error message from x11_setup_display */ + ppl_logevent(("X11 forwarding not enabled: unable to" + " initialise X display")); + } else { + s->x11auth = x11_invent_fake_auth( + s->x11authtree, conf_get_int(s->conf, CONF_x11_auth)); + s->x11auth->disp = s->x11disp; + + ssh2_setup_x11(s->mainchan, NULL, NULL); + } + } + + /* Potentially enable agent forwarding. */ + if (ssh_agent_forwarding_permitted(&s->cl)) + ssh2_setup_agent(s->mainchan, NULL, NULL); + + /* Now allocate a pty for the session. */ + if (!conf_get_int(s->conf, CONF_nopty)) + ssh2_setup_pty(s->mainchan, NULL, NULL); + + /* Send environment variables. */ + ssh2_setup_env(s->mainchan, NULL, NULL); + + /* + * Start a shell or a remote command. We may have to attempt + * this twice if the config data has provided a second choice + * of command. + */ + for (s->session_attempt = 0; s->session_attempt < 2; + s->session_attempt++) { + int subsys; + char *cmd; + + if (s->session_attempt == 0) { + subsys = conf_get_int(s->conf, CONF_ssh_subsys); + cmd = conf_get_str(s->conf, CONF_remote_cmd); + } else { + subsys = conf_get_int(s->conf, CONF_ssh_subsys2); + cmd = conf_get_str(s->conf, CONF_remote_cmd2); + if (!*cmd) + break; + ppl_logevent(("Primary command failed; attempting fallback")); + } + + if (subsys) { + pktout = ssh2_chanreq_init(s->mainchan, "subsystem", + ssh2_response_session, s); + put_stringz(pktout, cmd); + } else if (*cmd) { + pktout = ssh2_chanreq_init(s->mainchan, "exec", + ssh2_response_session, s); + put_stringz(pktout, cmd); + } else { + pktout = ssh2_chanreq_init(s->mainchan, "shell", + ssh2_response_session, s); + } + pq_push(s->ppl.out_pq, pktout); + s->session_status = 0; + + /* Wait for success or failure message to be passed to + * ssh2_response_session, which will set session_status to + * +1 for success or -1 for failure */ + crMaybeWaitUntilV(s->session_status != 0); + + if (s->session_status > 0) { + if (s->session_attempt == 1) + ssh_got_fallback_cmd(s->ppl.ssh); + ppl_logevent(("Started a shell/command")); + break; + } + } + + if (s->session_status < 0) { + /* + * We failed to start either the primary or the fallback + * command. + */ + ssh_sw_abort(s->ppl.ssh, + "Server refused to start a shell/command"); + return; + } + } else { + s->echoedit = TRUE; + } + + s->mainchan_ready = TRUE; + if (s->mainchan) + s->want_user_input = TRUE; + + /* If an EOF or a window-size change arrived before we were ready + * to handle either one, handle them now. */ + if (s->mainchan_eof_pending) + ssh_ppl_special_cmd(&s->ppl, SS_EOF, 0); + if (s->term_width_orig != s->term_width || + s->term_height_orig != s->term_height) + ssh_terminal_size(&s->cl, s->term_width, s->term_height); + + ssh_ldisc_update(s->ppl.ssh); + + /* + * Transfer data! + */ + + while (1) { + if ((pktin = ssh2_connection_pop(s)) != NULL) { + + /* + * _All_ the connection-layer packets we expect to + * receive are now handled by the dispatch table. + * Anything that reaches here must be bogus. + */ + + ssh_proto_error(s->ppl.ssh, "Received unexpected connection-layer " + "packet, type %d (%s)", pktin->type, + ssh2_pkt_type(s->ppl.bpp->pls->kctx, + s->ppl.bpp->pls->actx, + pktin->type)); + return; + } + crReturnV; + } + + crFinishV; +} + +static void ssh2_channel_check_close(struct ssh2_channel *c) +{ + struct ssh2_connection_state *s = c->connlayer; + PktOut *pktout; + + if (c->halfopen) { + /* + * If we've sent out our own CHANNEL_OPEN but not yet seen + * either OPEN_CONFIRMATION or OPEN_FAILURE in response, then + * it's too early to be sending close messages of any kind. + */ + return; + } + + if ((!((CLOSES_SENT_EOF | CLOSES_RCVD_EOF) & ~c->closes) || + chan_want_close(c->chan, (c->closes & CLOSES_SENT_EOF), + (c->closes & CLOSES_RCVD_EOF))) && + !c->chanreq_head && + !(c->closes & CLOSES_SENT_CLOSE)) { + /* + * We have both sent and received EOF (or the channel is a + * zombie), and we have no outstanding channel requests, which + * means the channel is in final wind-up. But we haven't sent + * CLOSE, so let's do so now. + */ + pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH2_MSG_CHANNEL_CLOSE); + put_uint32(pktout, c->remoteid); + pq_push(s->ppl.out_pq, pktout); + c->closes |= CLOSES_SENT_EOF | CLOSES_SENT_CLOSE; + } + + if (!((CLOSES_SENT_CLOSE | CLOSES_RCVD_CLOSE) & ~c->closes)) { + assert(c->chanreq_head == NULL); + /* + * We have both sent and received CLOSE, which means we're + * completely done with the channel. + */ + ssh2_channel_destroy(c); + } +} + +static void ssh2_channel_try_eof(struct ssh2_channel *c) +{ + struct ssh2_connection_state *s = c->connlayer; + PktOut *pktout; + assert(c->pending_eof); /* precondition for calling us */ + if (c->halfopen) + return; /* can't close: not even opened yet */ + if (bufchain_size(&c->outbuffer) > 0) + return; /* can't send EOF: pending outgoing data */ + + c->pending_eof = FALSE; /* we're about to send it */ + + pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH2_MSG_CHANNEL_EOF); + put_uint32(pktout, c->remoteid); + pq_push(s->ppl.out_pq, pktout); + c->closes |= CLOSES_SENT_EOF; + ssh2_channel_check_close(c); +} + +/* + * Attempt to send data on an SSH-2 channel. + */ +static int ssh2_try_send(struct ssh2_channel *c) +{ + struct ssh2_connection_state *s = c->connlayer; + PktOut *pktout; + int bufsize; + + while (c->remwindow > 0 && bufchain_size(&c->outbuffer) > 0) { + int len; + void *data; + bufchain_prefix(&c->outbuffer, &data, &len); + if ((unsigned)len > c->remwindow) + len = c->remwindow; + if ((unsigned)len > c->remmaxpkt) + len = c->remmaxpkt; + pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH2_MSG_CHANNEL_DATA); + put_uint32(pktout, c->remoteid); + put_string(pktout, data, len); + pq_push(s->ppl.out_pq, pktout); + bufchain_consume(&c->outbuffer, len); + c->remwindow -= len; + } + + /* + * After having sent as much data as we can, return the amount + * still buffered. + */ + bufsize = bufchain_size(&c->outbuffer); + + /* + * And if there's no data pending but we need to send an EOF, send + * it. + */ + if (!bufsize && c->pending_eof) + ssh2_channel_try_eof(c); + + return bufsize; +} + +static void ssh2_try_send_and_unthrottle(struct ssh2_channel *c) +{ + int bufsize; + if (c->closes & CLOSES_SENT_EOF) + return; /* don't send on channels we've EOFed */ + bufsize = ssh2_try_send(c); + if (bufsize == 0) { + c->throttled_by_backlog = FALSE; + ssh2_channel_check_throttle(c); + } +} + +static void ssh2_channel_check_throttle(struct ssh2_channel *c) +{ + /* + * We don't want this channel to read further input if this + * particular channel has a backed-up SSH window, or if the + * outgoing side of the whole SSH connection is currently + * throttled, or if this channel already has an outgoing EOF + * either sent or pending. + */ + chan_set_input_wanted(c->chan, + !c->throttled_by_backlog && + !c->connlayer->all_channels_throttled && + !c->pending_eof && + !(c->closes & CLOSES_SENT_EOF)); +} + +/* + * Close any local socket and free any local resources associated with + * a channel. This converts the channel into a zombie. + */ +static void ssh2_channel_close_local(struct ssh2_channel *c, + const char *reason) +{ + struct ssh2_connection_state *s = c->connlayer; + PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */ + char *msg = NULL; + + if (c->sharectx) + return; + + msg = chan_log_close_msg(c->chan); + + if (msg) + ppl_logevent(("%s%s%s", msg, reason ? " " : "", reason ? reason : "")); + + sfree(msg); + + chan_free(c->chan); + c->chan = zombiechan_new(); +} + +static void ssh2_check_termination_callback(void *vctx) +{ + struct ssh2_connection_state *s = (struct ssh2_connection_state *)vctx; + ssh2_check_termination(s); +} + +static void ssh2_channel_destroy(struct ssh2_channel *c) +{ + struct ssh2_connection_state *s = c->connlayer; + + assert(c->chanreq_head == NULL); + + ssh2_channel_close_local(c, NULL); + del234(s->channels, c); + ssh2_channel_free(c); + + /* + * If that was the last channel left open, we might need to + * terminate. But we'll be a bit cautious, by doing that in a + * toplevel callback, just in case anything on the current call + * stack objects to this entire PPL being freed. + */ + queue_toplevel_callback(ssh2_check_termination_callback, s); +} + +static void ssh2_check_termination(struct ssh2_connection_state *s) +{ + /* + * Decide whether we should terminate the SSH connection now. + * Called after a channel or a downstream goes away. The general + * policy is that we terminate when none of either is left. + */ + + if (s->mctype == MAINCHAN_NONE) { + /* + * Exception: in ssh_no_shell mode we persist even in the + * absence of any channels (because our purpose is probably to + * be a background port forwarder). + */ + return; + } + + if (count234(s->channels) == 0 && + !(s->connshare && share_ndownstreams(s->connshare) > 0)) { + /* + * We used to send SSH_MSG_DISCONNECT here, because I'd + * believed that _every_ conforming SSH-2 connection had to + * end with a disconnect being sent by at least one side; + * apparently I was wrong and it's perfectly OK to + * unceremoniously slam the connection shut when you're done, + * and indeed OpenSSH feels this is more polite than sending a + * DISCONNECT. So now we don't. + */ + ssh_user_close(s->ppl.ssh, "All channels closed"); + return; + } +} + +static void ssh2_setup_x11(struct ssh2_channel *c, PktIn *pktin, void *ctx) +{ + struct ssh2_setup_x11_state { + int crLine; + }; + struct ssh2_connection_state *cs = c->connlayer; + PacketProtocolLayer *ppl = &cs->ppl; /* for ppl_logevent */ + PktOut *pktout; + crStateP(ssh2_setup_x11_state, ctx); + + crBeginState; + + ppl_logevent(("Requesting X11 forwarding")); + pktout = ssh2_chanreq_init(cs->mainchan, "x11-req", ssh2_setup_x11, s); + put_bool(pktout, 0); /* many connections */ + put_stringz(pktout, cs->x11auth->protoname); + put_stringz(pktout, cs->x11auth->datastring); + put_uint32(pktout, cs->x11disp->screennum); + pq_push(cs->ppl.out_pq, pktout); + + /* Wait to be called back with either a response packet, or NULL + * meaning clean up and free our data */ + crReturnV; + + if (pktin) { + if (pktin->type == SSH2_MSG_CHANNEL_SUCCESS) { + ppl_logevent(("X11 forwarding enabled")); + cs->X11_fwd_enabled = TRUE; + } else + ppl_logevent(("X11 forwarding refused")); + } + + crFinishFreeV; +} + +static void ssh2_setup_agent(struct ssh2_channel *c, PktIn *pktin, void *ctx) +{ + struct ssh2_setup_agent_state { + int crLine; + }; + struct ssh2_connection_state *cs = c->connlayer; + PacketProtocolLayer *ppl = &cs->ppl; /* for ppl_logevent */ + PktOut *pktout; + crStateP(ssh2_setup_agent_state, ctx); + + crBeginState; + + ppl_logevent(("Requesting OpenSSH-style agent forwarding")); + pktout = ssh2_chanreq_init(cs->mainchan, "auth-agent-req@openssh.com", + ssh2_setup_agent, s); + pq_push(cs->ppl.out_pq, pktout); + + /* Wait to be called back with either a response packet, or NULL + * meaning clean up and free our data */ + crReturnV; + + if (pktin) { + if (pktin->type == SSH2_MSG_CHANNEL_SUCCESS) { + ppl_logevent(("Agent forwarding enabled")); + cs->agent_fwd_enabled = TRUE; + } else + ppl_logevent(("Agent forwarding refused")); + } + + crFinishFreeV; +} + +static void ssh2_setup_pty(struct ssh2_channel *c, PktIn *pktin, void *ctx) +{ + struct ssh2_setup_pty_state { + int crLine; + int ospeed, ispeed; + }; + struct ssh2_connection_state *cs = c->connlayer; + PacketProtocolLayer *ppl = &cs->ppl; /* for ppl_logevent, ppl_printf */ + PktOut *pktout; + crStateP(ssh2_setup_pty_state, ctx); + + crBeginState; + + /* Unpick the terminal-speed string. */ + s->ospeed = 38400; s->ispeed = 38400; /* last-resort defaults */ + sscanf(conf_get_str(cs->conf, CONF_termspeed), "%d,%d", + &s->ospeed, &s->ispeed); + /* Build the pty request. */ + pktout = ssh2_chanreq_init(cs->mainchan, "pty-req", ssh2_setup_pty, s); + put_stringz(pktout, conf_get_str(cs->conf, CONF_termtype)); + put_uint32(pktout, cs->term_width); + put_uint32(pktout, cs->term_height); + cs->term_width_orig = cs->term_width; + cs->term_height_orig = cs->term_height; + put_uint32(pktout, 0); /* pixel width */ + put_uint32(pktout, 0); /* pixel height */ + { + strbuf *modebuf = strbuf_new(); + write_ttymodes_to_packet_from_conf( + BinarySink_UPCAST(modebuf), cs->ppl.frontend, cs->conf, + 2, s->ospeed, s->ispeed); + put_stringsb(pktout, modebuf); + } + pq_push(cs->ppl.out_pq, pktout); + + /* Wait to be called back with either a response packet, or NULL + * meaning clean up and free our data */ + crReturnV; + + if (pktin) { + if (pktin->type == SSH2_MSG_CHANNEL_SUCCESS) { + ppl_logevent(("Allocated pty (ospeed %dbps, ispeed %dbps)", + s->ospeed, s->ispeed)); + cs->got_pty = TRUE; + } else { + ppl_printf(("Server refused to allocate pty\r\n")); + cs->echoedit = TRUE; + } + } + + crFinishFreeV; +} + +static void ssh2_setup_env(struct ssh2_channel *c, PktIn *pktin, void *ctx) +{ + struct ssh2_setup_env_state { + int crLine; + int num_env, env_left, env_ok; + }; + struct ssh2_connection_state *cs = c->connlayer; + PacketProtocolLayer *ppl = &cs->ppl; /* for ppl_logevent, ppl_printf */ + PktOut *pktout; + crStateP(ssh2_setup_env_state, ctx); + + crBeginState; + + /* + * Send environment variables. + * + * Simplest thing here is to send all the requests at once, and + * then wait for a whole bunch of successes or failures. + */ + s->num_env = 0; + { + char *key, *val; + + for (val = conf_get_str_strs(cs->conf, CONF_environmt, NULL, &key); + val != NULL; + val = conf_get_str_strs(cs->conf, CONF_environmt, key, &key)) { + pktout = ssh2_chanreq_init(cs->mainchan, "env", ssh2_setup_env, s); + put_stringz(pktout, key); + put_stringz(pktout, val); + pq_push(cs->ppl.out_pq, pktout); + + s->num_env++; + } + if (s->num_env) + ppl_logevent(("Sent %d environment variables", s->num_env)); + } + + if (s->num_env) { + s->env_ok = 0; + s->env_left = s->num_env; + + while (s->env_left > 0) { + /* Wait to be called back with either a response packet, + * or NULL meaning clean up and free our data */ + crReturnV; + if (!pktin) goto out; + if (pktin->type == SSH2_MSG_CHANNEL_SUCCESS) + s->env_ok++; + s->env_left--; + } + + if (s->env_ok == s->num_env) { + ppl_logevent(("All environment variables successfully set")); + } else if (s->env_ok == 0) { + ppl_logevent(("All environment variables refused")); + ppl_printf(("Server refused to set environment variables\r\n")); + } else { + ppl_logevent(("%d environment variables refused", + s->num_env - s->env_ok)); + ppl_printf(("Server refused to set all environment " + "variables\r\n")); + } + } + out:; + crFinishFreeV; +} + +static void ssh2_response_session(struct ssh2_channel *c, PktIn *pktin, + void *ctx) +{ + struct ssh2_connection_state *s = c->connlayer; + s->session_status = (pktin->type == SSH2_MSG_CHANNEL_SUCCESS ? +1 : -1); +} + +/* + * Set up most of a new ssh2_channel. Nulls out sharectx, but leaves + * chan untouched (since it will sometimes have been filled in before + * calling this). + */ +static void ssh2_channel_init(struct ssh2_channel *c) +{ + struct ssh2_connection_state *s = c->connlayer; + c->closes = 0; + c->pending_eof = FALSE; + c->throttling_conn = FALSE; + c->sharectx = NULL; + c->locwindow = c->locmaxwin = c->remlocwin = + s->ssh_is_simple ? OUR_V2_BIGWIN : OUR_V2_WINSIZE; + c->chanreq_head = NULL; + c->throttle_state = UNTHROTTLED; + bufchain_init(&c->outbuffer); + c->sc.vt = &ssh2channel_vtable; + c->localid = alloc_channel_id(s->channels, struct ssh2_channel); + add234(s->channels, c); +} + +/* + * Construct the common parts of a CHANNEL_OPEN. + */ +static PktOut *ssh2_chanopen_init(struct ssh2_channel *c, const char *type) +{ + struct ssh2_connection_state *s = c->connlayer; + PktOut *pktout; + + pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH2_MSG_CHANNEL_OPEN); + put_stringz(pktout, type); + put_uint32(pktout, c->localid); + put_uint32(pktout, c->locwindow); /* our window size */ + put_uint32(pktout, OUR_V2_MAXPKT); /* our max pkt size */ + return pktout; +} + +/* + * Construct the common parts of a CHANNEL_REQUEST. If handler is not + * NULL then a reply will be requested and the handler will be called + * when it arrives. The returned packet is ready to have any + * request-specific data added and be sent. Note that if a handler is + * provided, it's essential that the request actually be sent. + * + * The handler will usually be passed the response packet in pktin. If + * pktin is NULL, this means that no reply will ever be forthcoming + * (e.g. because the entire connection is being destroyed, or because + * the server initiated channel closure before we saw the response) + * and the handler should free any storage it's holding. + */ +static PktOut *ssh2_chanreq_init(struct ssh2_channel *c, const char *type, + cr_handler_fn_t handler, void *ctx) +{ + struct ssh2_connection_state *s = c->connlayer; + PktOut *pktout; + + assert(!(c->closes & (CLOSES_SENT_CLOSE | CLOSES_RCVD_CLOSE))); + pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH2_MSG_CHANNEL_REQUEST); + put_uint32(pktout, c->remoteid); + put_stringz(pktout, type); + put_bool(pktout, handler != NULL); + if (handler != NULL) { + struct outstanding_channel_request *ocr = + snew(struct outstanding_channel_request); + + ocr->handler = handler; + ocr->ctx = ctx; + ocr->next = NULL; + if (!c->chanreq_head) + c->chanreq_head = ocr; + else + c->chanreq_tail->next = ocr; + c->chanreq_tail = ocr; + } + return pktout; +} + +static Conf *ssh2channel_get_conf(SshChannel *sc) +{ + struct ssh2_channel *c = FROMFIELD(sc, struct ssh2_channel, sc); + struct ssh2_connection_state *s = c->connlayer; + return s->conf; +} + +static void ssh2channel_write_eof(SshChannel *sc) +{ + struct ssh2_channel *c = FROMFIELD(sc, struct ssh2_channel, sc); + + if (c->closes & CLOSES_SENT_EOF) + return; + + c->pending_eof = TRUE; + ssh2_channel_try_eof(c); +} + +static void ssh2channel_unclean_close(SshChannel *sc, const char *err) +{ + struct ssh2_channel *c = FROMFIELD(sc, struct ssh2_channel, sc); + char *reason; + + reason = dupprintf("due to local error: %s", err); + ssh2_channel_close_local(c, reason); + sfree(reason); + c->pending_eof = FALSE; /* this will confuse a zombie channel */ + + ssh2_channel_check_close(c); +} + +static void ssh2channel_unthrottle(SshChannel *sc, int bufsize) +{ + struct ssh2_channel *c = FROMFIELD(sc, struct ssh2_channel, sc); + struct ssh2_connection_state *s = c->connlayer; + int buflimit; + + buflimit = s->ssh_is_simple ? 0 : c->locmaxwin; + if (bufsize < buflimit) + ssh2_set_window(c, buflimit - bufsize); + + if (c->throttling_conn && bufsize <= buflimit) { + c->throttling_conn = 0; + ssh_throttle_conn(s->ppl.ssh, -1); + } +} + +static int ssh2channel_write(SshChannel *sc, const void *buf, int len) +{ + struct ssh2_channel *c = FROMFIELD(sc, struct ssh2_channel, sc); + assert(!(c->closes & CLOSES_SENT_EOF)); + bufchain_add(&c->outbuffer, buf, len); + return ssh2_try_send(c); +} + +static void ssh2channel_x11_sharing_handover( + SshChannel *sc, ssh_sharing_connstate *share_cs, share_channel *share_chan, + const char *peer_addr, int peer_port, int endian, + int protomajor, int protominor, const void *initial_data, int initial_len) +{ + struct ssh2_channel *c = FROMFIELD(sc, struct ssh2_channel, sc); + /* + * This function is called when we've just discovered that an X + * forwarding channel on which we'd been handling the initial auth + * ourselves turns out to be destined for a connection-sharing + * downstream. So we turn the channel into a sharing one, meaning + * that we completely stop tracking windows and buffering data and + * just pass more or less unmodified SSH messages back and forth. + */ + c->sharectx = share_cs; + share_setup_x11_channel(share_cs, share_chan, + c->localid, c->remoteid, c->remwindow, + c->remmaxpkt, c->locwindow, + peer_addr, peer_port, endian, + protomajor, protominor, + initial_data, initial_len); + chan_free(c->chan); + c->chan = NULL; +} + +static void ssh2channel_window_override_removed(SshChannel *sc) +{ + struct ssh2_channel *c = FROMFIELD(sc, struct ssh2_channel, sc); + struct ssh2_connection_state *s = c->connlayer; + + /* + * This function is called when a client-side Channel has just + * stopped requiring an initial fixed-size window. + */ + assert(!c->chan->initial_fixed_window_size); + ssh2_set_window(c, s->ssh_is_simple ? OUR_V2_BIGWIN : OUR_V2_WINSIZE); +} + +static SshChannel *ssh2_lportfwd_open( + ConnectionLayer *cl, const char *hostname, int port, + const char *org, Channel *chan) +{ + struct ssh2_connection_state *s = + FROMFIELD(cl, struct ssh2_connection_state, cl); + PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */ + struct ssh2_channel *c = snew(struct ssh2_channel); + PktOut *pktout; + + c->connlayer = s; + ssh2_channel_init(c); + c->halfopen = TRUE; + c->chan = chan; + + ppl_logevent(("Opening connection to %s:%d for %s", hostname, port, org)); + + pktout = ssh2_chanopen_init(c, "direct-tcpip"); + { + char *trimmed_host = host_strduptrim(hostname); + put_stringz(pktout, trimmed_host); + sfree(trimmed_host); + } + put_uint32(pktout, port); + /* + * We make up values for the originator data; partly it's too much + * hassle to keep track, and partly I'm not convinced the server + * should be told details like that about my local network + * configuration. The "originator IP address" is syntactically a + * numeric IP address, and some servers (e.g., Tectia) get upset + * if it doesn't match this syntax. + */ + put_stringz(pktout, "0.0.0.0"); + put_uint32(pktout, 0); + pq_push(s->ppl.out_pq, pktout); + + return &c->sc; +} + +static void ssh2_rportfwd_globreq_response(struct ssh2_connection_state *s, + PktIn *pktin, void *ctx) +{ + PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */ + struct ssh_rportfwd *rpf = (struct ssh_rportfwd *)ctx; + + if (pktin->type == SSH2_MSG_REQUEST_SUCCESS) { + ppl_logevent(("Remote port forwarding from %s enabled", + rpf->log_description)); + } else { + ppl_logevent(("Remote port forwarding from %s refused", + rpf->log_description)); + + struct ssh_rportfwd *realpf = del234(s->rportfwds, rpf); + assert(realpf == rpf); + portfwdmgr_close(s->portfwdmgr, rpf->pfr); + free_rportfwd(rpf); + } +} + +static struct ssh_rportfwd *ssh2_rportfwd_alloc( + ConnectionLayer *cl, + const char *shost, int sport, const char *dhost, int dport, + int addressfamily, const char *log_description, PortFwdRecord *pfr, + ssh_sharing_connstate *share_ctx) +{ + struct ssh2_connection_state *s = + FROMFIELD(cl, struct ssh2_connection_state, cl); + struct ssh_rportfwd *rpf = snew(struct ssh_rportfwd); + + rpf->shost = dupstr(shost); + rpf->sport = sport; + rpf->dhost = dupstr(dhost); + rpf->dport = dport; + rpf->addressfamily = addressfamily; + rpf->log_description = dupstr(log_description); + rpf->pfr = pfr; + rpf->share_ctx = share_ctx; + + if (add234(s->rportfwds, rpf) != rpf) { + free_rportfwd(rpf); + return NULL; + } + + if (!rpf->share_ctx) { + PktOut *pktout = ssh_bpp_new_pktout( + s->ppl.bpp, SSH2_MSG_GLOBAL_REQUEST); + put_stringz(pktout, "tcpip-forward"); + put_bool(pktout, 1); /* want reply */ + put_stringz(pktout, rpf->shost); + put_uint32(pktout, rpf->sport); + pq_push(s->ppl.out_pq, pktout); + + ssh2_queue_global_request_handler( + s, ssh2_rportfwd_globreq_response, rpf); + } + + return rpf; +} + +static void ssh2_rportfwd_remove(ConnectionLayer *cl, struct ssh_rportfwd *rpf) +{ + struct ssh2_connection_state *s = + FROMFIELD(cl, struct ssh2_connection_state, cl); + + if (rpf->share_ctx) { + /* + * We don't manufacture a cancel-tcpip-forward message for + * remote port forwardings being removed on behalf of a + * downstream; we just pass through the one the downstream + * sent to us. + */ + } else { + PktOut *pktout = ssh_bpp_new_pktout( + s->ppl.bpp, SSH2_MSG_GLOBAL_REQUEST); + put_stringz(pktout, "cancel-tcpip-forward"); + put_bool(pktout, 0); /* _don't_ want reply */ + put_stringz(pktout, rpf->shost); + put_uint32(pktout, rpf->sport); + pq_push(s->ppl.out_pq, pktout); + } + + struct ssh_rportfwd *realpf = del234(s->rportfwds, rpf); + assert(realpf == rpf); + free_rportfwd(rpf); +} + +static void ssh2_sharing_globreq_response( + struct ssh2_connection_state *s, PktIn *pktin, void *ctx) +{ + ssh_sharing_connstate *cs = (ssh_sharing_connstate *)ctx; + share_got_pkt_from_server(cs, pktin->type, + BinarySource_UPCAST(pktin)->data, + BinarySource_UPCAST(pktin)->len); +} + +static void ssh2_sharing_queue_global_request( + ConnectionLayer *cl, ssh_sharing_connstate *cs) +{ + struct ssh2_connection_state *s = + FROMFIELD(cl, struct ssh2_connection_state, cl); + ssh2_queue_global_request_handler(s, ssh2_sharing_globreq_response, cs); +} + +static struct X11FakeAuth *ssh2_add_sharing_x11_display( + ConnectionLayer *cl, int authtype, ssh_sharing_connstate *share_cs, + share_channel *share_chan) +{ + struct ssh2_connection_state *s = + FROMFIELD(cl, struct ssh2_connection_state, cl); + struct X11FakeAuth *auth; + + /* + * Make up a new set of fake X11 auth data, and add it to the tree + * of currently valid ones with an indication of the sharing + * context that it's relevant to. + */ + auth = x11_invent_fake_auth(s->x11authtree, authtype); + auth->share_cs = share_cs; + auth->share_chan = share_chan; + + return auth; +} + +static void ssh2_remove_sharing_x11_display( + ConnectionLayer *cl, struct X11FakeAuth *auth) +{ + struct ssh2_connection_state *s = + FROMFIELD(cl, struct ssh2_connection_state, cl); + del234(s->x11authtree, auth); + x11_free_fake_auth(auth); +} + +static unsigned ssh2_alloc_sharing_channel( + ConnectionLayer *cl, ssh_sharing_connstate *connstate) +{ + struct ssh2_connection_state *s = + FROMFIELD(cl, struct ssh2_connection_state, cl); + struct ssh2_channel *c = snew(struct ssh2_channel); + + c->connlayer = s; + ssh2_channel_init(c); + c->chan = NULL; + c->sharectx = connstate; + return c->localid; +} + +static void ssh2_delete_sharing_channel(ConnectionLayer *cl, unsigned localid) +{ + struct ssh2_connection_state *s = + FROMFIELD(cl, struct ssh2_connection_state, cl); + struct ssh2_channel *c = find234(s->channels, &localid, ssh2_channelfind); + if (c) + ssh2_channel_destroy(c); +} + +static void ssh2_send_packet_from_downstream( + ConnectionLayer *cl, unsigned id, int type, + const void *data, int datalen, const char *additional_log_text) +{ + struct ssh2_connection_state *s = + FROMFIELD(cl, struct ssh2_connection_state, cl); + PktOut *pkt = ssh_bpp_new_pktout(s->ppl.bpp, type); + pkt->downstream_id = id; + pkt->additional_log_text = additional_log_text; + put_data(pkt, data, datalen); + pq_push(s->ppl.out_pq, pkt); +} + +static int ssh2_agent_forwarding_permitted(ConnectionLayer *cl) +{ + struct ssh2_connection_state *s = + FROMFIELD(cl, struct ssh2_connection_state, cl); + return conf_get_int(s->conf, CONF_agentfwd) && agent_exists(); +} + +static void mainchan_free(Channel *chan); +static void mainchan_open_confirmation(Channel *chan); +static void mainchan_open_failure(Channel *chan, const char *errtext); +static int mainchan_send(Channel *chan, int is_stderr, const void *, int); +static void mainchan_send_eof(Channel *chan); +static void mainchan_set_input_wanted(Channel *chan, int wanted); +static char *mainchan_log_close_msg(Channel *chan); + +static const struct ChannelVtable mainchan_channelvt = { + mainchan_free, + mainchan_open_confirmation, + mainchan_open_failure, + mainchan_send, + mainchan_send_eof, + mainchan_set_input_wanted, + mainchan_log_close_msg, + chan_no_eager_close, +}; + +static mainchan *mainchan_new(struct ssh2_connection_state *s) +{ + mainchan *mc = snew(mainchan); + mc->connlayer = s; + mc->sc = NULL; + mc->chan.vt = &mainchan_channelvt; + mc->chan.initial_fixed_window_size = 0; + return mc; +} + +static void mainchan_free(Channel *chan) +{ + assert(chan->vt == &mainchan_channelvt); + mainchan *mc = FROMFIELD(chan, mainchan, chan); + struct ssh2_connection_state *s = mc->connlayer; + s->mainchan = NULL; + sfree(mc); +} + +static void mainchan_open_confirmation(Channel *chan) +{ + mainchan *mc = FROMFIELD(chan, mainchan, chan); + struct ssh2_connection_state *s = mc->connlayer; + PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */ + + update_specials_menu(s->ppl.frontend); + ppl_logevent(("Opened main channel")); +} + +static void mainchan_open_failure(Channel *chan, const char *errtext) +{ + assert(chan->vt == &mainchan_channelvt); + mainchan *mc = FROMFIELD(chan, mainchan, chan); + struct ssh2_connection_state *s = mc->connlayer; + + /* + * Record the failure reason we're given, and let the main + * coroutine handle closing the SSH session. + */ + s->mainchan_open_error = dupstr(errtext); + queue_idempotent_callback(&s->ppl.ic_process_queue); +} + +static int mainchan_send(Channel *chan, int is_stderr, + const void *data, int length) +{ + assert(chan->vt == &mainchan_channelvt); + mainchan *mc = FROMFIELD(chan, mainchan, chan); + struct ssh2_connection_state *s = mc->connlayer; + return from_backend(s->ppl.frontend, is_stderr, data, length); +} + +static void mainchan_send_eof(Channel *chan) +{ + assert(chan->vt == &mainchan_channelvt); + mainchan *mc = FROMFIELD(chan, mainchan, chan); + struct ssh2_connection_state *s = mc->connlayer; + PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */ + + if (!s->mainchan_eof_sent && + (from_backend_eof(s->ppl.frontend) || s->got_pty)) { + /* + * Either from_backend_eof told us that the front end wants us + * to close the outgoing side of the connection as soon as we + * see EOF from the far end, or else we've unilaterally + * decided to do that because we've allocated a remote pty and + * hence EOF isn't a particularly meaningful concept. + */ + sshfwd_write_eof(mc->sc); + ppl_logevent(("Sent EOF message")); + } + s->mainchan_eof_sent = TRUE; + s->want_user_input = FALSE; /* now stop reading from stdin */ +} + +static void mainchan_set_input_wanted(Channel *chan, int wanted) +{ + assert(chan->vt == &mainchan_channelvt); + mainchan *mc = FROMFIELD(chan, mainchan, chan); + struct ssh2_connection_state *s = mc->connlayer; + + /* + * This is the main channel of the SSH session, i.e. the one tied + * to the standard input (or GUI) of the primary SSH client user + * interface. So ssh->send_ok is how we control whether we're + * reading from that input. + */ + s->want_user_input = wanted; +} + +static char *mainchan_log_close_msg(Channel *chan) +{ + return dupstr("Main session channel closed"); +} + +/* + * List of signal names defined by RFC 4254. These include all the ISO + * C signals, but are a subset of the POSIX required signals. + * + * The list macro takes parameters MAIN and SUB, which is an arbitrary + * UI decision to expose the signals we think users are most likely to + * want, with extra descriptive text, and relegate the less probable + * ones to a submenu for people who know what they're doing. + */ +#define SIGNAL_LIST(MAIN, SUB) \ + MAIN(INT, "Interrupt") \ + MAIN(TERM, "Terminate") \ + MAIN(KILL, "Kill") \ + MAIN(QUIT, "Quit") \ + MAIN(HUP, "Hangup") \ + SUB(ABRT) \ + SUB(ALRM) \ + SUB(FPE) \ + SUB(ILL) \ + SUB(PIPE) \ + SUB(SEGV) \ + SUB(USR1) \ + SUB(USR2) \ + /* end of list */ + +static int ssh2_connection_get_specials( + PacketProtocolLayer *ppl, add_special_fn_t add_special, void *ctx) +{ + struct ssh2_connection_state *s = + FROMFIELD(ppl, struct ssh2_connection_state, ppl); + int toret = FALSE; + + if (s->mainchan) { + add_special(ctx, "Break", SS_BRK, 0); + + #define ADD_MAIN(name, desc) \ + add_special(ctx, "SIG" #name " (" desc ")", SS_SIG ## name, 0); + #define ADD_SUB(name) \ + add_special(ctx, "SIG" #name, SS_SIG ## name, 0); + + #define NO_ADD_SUB(name) + #define NO_ADD_MAIN(name, desc) + + SIGNAL_LIST(ADD_MAIN, NO_ADD_SUB); + add_special(ctx, "More signals", SS_SUBMENU, 0); + SIGNAL_LIST(NO_ADD_MAIN, ADD_SUB); + add_special(ctx, NULL, SS_EXITMENU, 0); + + #undef ADD_MAIN + #undef ADD_SUB + #undef NO_ADD_MAIN + #undef NO_ADD_SUB + + toret = TRUE; + } + + /* + * Don't bother offering IGNORE if we've decided the remote + * won't cope with it, since we wouldn't bother sending it if + * asked anyway. + */ + if (!(s->ppl.remote_bugs & BUG_CHOKES_ON_SSH2_IGNORE)) { + if (toret) + add_special(ctx, NULL, SS_SEP, 0); + + add_special(ctx, "IGNORE message", SS_NOP, 0); + toret = TRUE; + } + + return toret; +} + +static const char *ssh_signal_lookup(SessionSpecialCode code) +{ + #define CHECK_SUB(name) \ + if (code == SS_SIG ## name) return #name; + #define CHECK_MAIN(name, desc) CHECK_SUB(name) + + SIGNAL_LIST(CHECK_MAIN, CHECK_SUB); + return NULL; + + #undef CHECK_MAIN + #undef CHECK_SUB +} + +static void ssh2_connection_special_cmd(PacketProtocolLayer *ppl, + SessionSpecialCode code, int arg) +{ + struct ssh2_connection_state *s = + FROMFIELD(ppl, struct ssh2_connection_state, ppl); + PktOut *pktout; + const char *signame; + + if (code == SS_PING || code == SS_NOP) { + if (!(s->ppl.remote_bugs & BUG_CHOKES_ON_SSH2_IGNORE)) { + pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH2_MSG_IGNORE); + put_stringz(pktout, ""); + pq_push(s->ppl.out_pq, pktout); + } + } else if (code == SS_EOF) { + if (!s->mainchan_ready) { + /* + * Buffer the EOF to send as soon as the main channel is + * fully set up. + */ + s->mainchan_eof_pending = TRUE; + } else if (s->mainchan && !s->mainchan_eof_sent) { + sshfwd_write_eof(&s->mainchan->sc); + } + } else if (code == SS_BRK) { + if (s->mainchan) { + pktout = ssh2_chanreq_init(s->mainchan, "break", NULL, NULL); + put_uint32(pktout, 0); /* default break length */ + pq_push(s->ppl.out_pq, pktout); + } + } else if ((signame = ssh_signal_lookup(code)) != NULL) { + /* It's a signal. */ + if (s->mainchan) { + pktout = ssh2_chanreq_init(s->mainchan, "signal", NULL, NULL); + put_stringz(pktout, signame); + pq_push(s->ppl.out_pq, pktout); + ppl_logevent(("Sent signal SIG%s", signame)); + } + } +} + +static void ssh2_terminal_size(ConnectionLayer *cl, int width, int height) +{ + struct ssh2_connection_state *s = + FROMFIELD(cl, struct ssh2_connection_state, cl); + + s->term_width = width; + s->term_height = height; + + if (s->mainchan_ready) { + PktOut *pktout = ssh2_chanreq_init( + s->mainchan, "window-change", NULL, NULL); + put_uint32(pktout, s->term_width); + put_uint32(pktout, s->term_height); + put_uint32(pktout, 0); + put_uint32(pktout, 0); + pq_push(s->ppl.out_pq, pktout); + } +} + +static void ssh2_stdout_unthrottle(ConnectionLayer *cl, int bufsize) +{ + struct ssh2_connection_state *s = + FROMFIELD(cl, struct ssh2_connection_state, cl); + + if (s->mainchan) + ssh2channel_unthrottle(&s->mainchan->sc, bufsize); +} + +static int ssh2_stdin_backlog(ConnectionLayer *cl) +{ + struct ssh2_connection_state *s = + FROMFIELD(cl, struct ssh2_connection_state, cl); + + return s->mainchan ? bufchain_size(&s->mainchan->outbuffer) : 0; +} + +static void ssh2_throttle_all_channels(ConnectionLayer *cl, int throttled) +{ + struct ssh2_connection_state *s = + FROMFIELD(cl, struct ssh2_connection_state, cl); + struct ssh2_channel *c; + int i; + + s->all_channels_throttled = throttled; + + for (i = 0; NULL != (c = index234(s->channels, i)); i++) + ssh2_channel_check_throttle(c); +} + +static int ssh2_ldisc_option(ConnectionLayer *cl, int option) +{ + struct ssh2_connection_state *s = + FROMFIELD(cl, struct ssh2_connection_state, cl); + + /* We always return the same value for LD_ECHO and LD_EDIT */ + return s->echoedit; +} + +static int ssh2_connection_want_user_input(PacketProtocolLayer *ppl) +{ + struct ssh2_connection_state *s = + FROMFIELD(ppl, struct ssh2_connection_state, ppl); + return s->want_user_input; +} + +static void ssh2_connection_got_user_input(PacketProtocolLayer *ppl) +{ + struct ssh2_connection_state *s = + FROMFIELD(ppl, struct ssh2_connection_state, ppl); + + while (s->mainchan && bufchain_size(s->ppl.user_input) > 0) { + /* + * Add user input to the main channel's buffer. + */ + void *data; + int len; + bufchain_prefix(s->ppl.user_input, &data, &len); + sshfwd_write(&s->mainchan->sc, data, len); + bufchain_consume(s->ppl.user_input, len); + } +} + +static void ssh2_connection_reconfigure(PacketProtocolLayer *ppl, Conf *conf) +{ + struct ssh2_connection_state *s = + FROMFIELD(ppl, struct ssh2_connection_state, ppl); + + conf_free(s->conf); + s->conf = conf_copy(conf); + + if (s->portfwdmgr_configured) + portfwdmgr_config(s->portfwdmgr, s->conf); +} diff --git a/ssh2transport.c b/ssh2transport.c new file mode 100644 index 00000000..1dcd4a8c --- /dev/null +++ b/ssh2transport.c @@ -0,0 +1,2967 @@ +/* + * Packet protocol layer for the SSH-2 transport protocol (RFC 4253). + */ + +#include + +#include "putty.h" +#include "ssh.h" +#include "sshbpp.h" +#include "sshppl.h" +#include "sshcr.h" +#include "storage.h" + +#ifndef NO_GSSAPI +#include "sshgssc.h" +#include "sshgss.h" +#define MIN_CTXT_LIFETIME 5 /* Avoid rekey with short lifetime (seconds) */ +#define GSS_KEX_CAPABLE (1<<0) /* Can do GSS KEX */ +#define GSS_CRED_UPDATED (1<<1) /* Cred updated since previous delegation */ +#define GSS_CTXT_EXPIRES (1<<2) /* Context expires before next timer */ +#define GSS_CTXT_MAYFAIL (1<<3) /* Context may expire during handshake */ +#endif + +#define DH_MIN_SIZE 1024 +#define DH_MAX_SIZE 8192 + +enum kexlist { + KEXLIST_KEX, KEXLIST_HOSTKEY, KEXLIST_CSCIPHER, KEXLIST_SCCIPHER, + KEXLIST_CSMAC, KEXLIST_SCMAC, KEXLIST_CSCOMP, KEXLIST_SCCOMP, + NKEXLIST +}; +#define MAXKEXLIST 16 +struct kexinit_algorithm { + const char *name; + union { + struct { + const struct ssh_kex *kex; + int warn; + } kex; + struct { + const ssh_keyalg *hostkey; + int warn; + } hk; + struct { + const struct ssh2_cipheralg *cipher; + int warn; + } cipher; + struct { + const struct ssh2_macalg *mac; + int etm; + } mac; + const struct ssh_compression_alg *comp; + } u; +}; + +struct ssh_signkey_with_user_pref_id { + const ssh_keyalg *alg; + int id; +}; +const static struct ssh_signkey_with_user_pref_id hostkey_algs[] = { + { &ssh_ecdsa_ed25519, HK_ED25519 }, + { &ssh_ecdsa_nistp256, HK_ECDSA }, + { &ssh_ecdsa_nistp384, HK_ECDSA }, + { &ssh_ecdsa_nistp521, HK_ECDSA }, + { &ssh_dss, HK_DSA }, + { &ssh_rsa, HK_RSA }, +}; + +const static struct ssh2_macalg *const macs[] = { + &ssh_hmac_sha256, &ssh_hmac_sha1, &ssh_hmac_sha1_96, &ssh_hmac_md5 +}; +const static struct ssh2_macalg *const buggymacs[] = { + &ssh_hmac_sha1_buggy, &ssh_hmac_sha1_96_buggy, &ssh_hmac_md5 +}; + +static ssh_compressor *ssh_comp_none_init(void) +{ + return NULL; +} +static void ssh_comp_none_cleanup(ssh_compressor *handle) +{ +} +static ssh_decompressor *ssh_decomp_none_init(void) +{ + return NULL; +} +static void ssh_decomp_none_cleanup(ssh_decompressor *handle) +{ +} +static void ssh_comp_none_block(ssh_compressor *handle, + unsigned char *block, int len, + unsigned char **outblock, int *outlen, + int minlen) +{ +} +static int ssh_decomp_none_block(ssh_decompressor *handle, + unsigned char *block, int len, + unsigned char **outblock, int *outlen) +{ + return 0; +} +const static struct ssh_compression_alg ssh_comp_none = { + "none", NULL, + ssh_comp_none_init, ssh_comp_none_cleanup, ssh_comp_none_block, + ssh_decomp_none_init, ssh_decomp_none_cleanup, ssh_decomp_none_block, + NULL +}; +const static struct ssh_compression_alg *const compressions[] = { + &ssh_zlib, &ssh_comp_none +}; + +/* + * Enumeration of high-level classes of reason why we might need to do + * a repeat key exchange. A full detailed reason in human-readable + * string form for the Event Log is also provided, but this enum type + * is used to discriminate between classes of reason that the code + * needs to treat differently. + * + * RK_NONE == 0 is the value indicating that no rekey is currently + * needed at all. RK_INITIAL indicates that we haven't even done the + * _first_ key exchange yet. RK_SERVER indicates that we're rekeying + * because the server asked for it, not because we decided it + * ourselves. RK_NORMAL is the usual case. RK_GSS_UPDATE indicates + * that we're rekeying because we've just got new GSSAPI credentials + * (hence there's no point in doing a preliminary check for new GSS + * creds, because we already know the answer); RK_POST_USERAUTH + * indicates that _if_ we're going to need a post-userauth immediate + * rekey for any reason, this is the moment to do it. + * + * So RK_POST_USERAUTH only tells the transport layer to _consider_ + * rekeying, not to definitely do it. Also, that one enum value is + * special in that the user-readable reason text is passed in to the + * transport layer as NULL, whereas fills in the reason text after it + * decides whether it needs a rekey at all. In the other cases, + * rekey_reason is passed in to the at the same time as rekey_class. + */ +typedef enum RekeyClass { + RK_NONE = 0, + RK_INITIAL, + RK_SERVER, + RK_NORMAL, + RK_POST_USERAUTH, + RK_GSS_UPDATE +} RekeyClass; + +struct ssh2_transport_state { + int crState; + + PacketProtocolLayer *higher_layer; + PktInQueue pq_in_higher; + PktOutQueue pq_out_higher; + IdempotentCallback ic_pq_out_higher; + + Conf *conf; + char *savedhost; + int savedport; + const char *rekey_reason; + enum RekeyClass rekey_class; + + unsigned long max_data_size; + + const struct ssh_kex *kex_alg; + const ssh_keyalg *hostkey_alg; + char *hostkey_str; /* string representation, for easy checking in rekeys */ + unsigned char session_id[SSH2_KEX_MAX_HASH_LEN]; + int session_id_len; + struct dh_ctx *dh_ctx; + ssh_hash *exhash; + + struct DataTransferStats *stats; + + char *client_greeting, *server_greeting; + + int kex_in_progress; + unsigned long next_rekey, last_rekey; + const char *deferred_rekey_reason; + int higher_layer_ok; + + /* + * Fully qualified host name, which we need if doing GSSAPI. + */ + char *fullhostname; + + /* shgss is outside the ifdef on purpose to keep APIs simple. If + * NO_GSSAPI is not defined, then it's just an opaque structure + * tag and the pointer will be NULL. */ + struct ssh_connection_shared_gss_state *shgss; +#ifndef NO_GSSAPI + int gss_status; + time_t gss_cred_expiry; /* Re-delegate if newer */ + unsigned long gss_ctxt_lifetime; /* Re-delegate when short */ + tree234 *transient_hostkey_cache; +#endif + + int gss_kex_used; + + int nbits, pbits, warn_kex, warn_hk, warn_cscipher, warn_sccipher; + Bignum p, g, e, f, K; + void *our_kexinit; + int our_kexinitlen; + int kex_init_value, kex_reply_value; + const struct ssh2_macalg *const *maclist; + int nmacs; + struct { + const struct ssh2_cipheralg *cipher; + const struct ssh2_macalg *mac; + int etm_mode; + const struct ssh_compression_alg *comp; + } in, out; + ptrlen hostkeydata, sigdata; + char *keystr, *fingerprint; + ssh_key *hkey; /* actual host key */ + struct RSAKey *rsa_kex_key; /* for RSA kex */ + struct ec_key *ecdh_key; /* for ECDH kex */ + unsigned char exchange_hash[SSH2_KEX_MAX_HASH_LEN]; + int n_preferred_kex; + int can_gssapi_keyex; + int need_gss_transient_hostkey; + int warned_about_no_gss_transient_hostkey; + const struct ssh_kexes *preferred_kex[KEX_MAX + 1]; /* +1 for GSSAPI */ + int n_preferred_hk; + int preferred_hk[HK_MAX]; + int n_preferred_ciphers; + const struct ssh2_ciphers *preferred_ciphers[CIPHER_MAX]; + const struct ssh_compression_alg *preferred_comp; + int userauth_succeeded; /* for delayed compression */ + int pending_compression; + int got_session_id; + int dlgret; + int guessok; + int ignorepkt; + struct kexinit_algorithm kexlists[NKEXLIST][MAXKEXLIST]; +#ifndef NO_GSSAPI + Ssh_gss_buf gss_buf; + Ssh_gss_buf gss_rcvtok, gss_sndtok; + Ssh_gss_stat gss_stat; + Ssh_gss_buf mic; + int init_token_sent; + int complete_rcvd; + int gss_delegate; +#endif + + /* + * List of host key algorithms for which we _don't_ have a stored + * host key. These are indices into the main hostkey_algs[] array + */ + int uncert_hostkeys[lenof(hostkey_algs)]; + int n_uncert_hostkeys; + + /* + * Flag indicating that the current rekey is intended to finish + * with a newly cross-certified host key. + */ + int cross_certifying; + + PacketProtocolLayer ppl; +}; + +static void ssh2_transport_free(PacketProtocolLayer *); +static void ssh2_transport_process_queue(PacketProtocolLayer *); +static int ssh2_transport_get_specials( + PacketProtocolLayer *ppl, add_special_fn_t add_special, void *ctx); +static void ssh2_transport_special_cmd(PacketProtocolLayer *ppl, + SessionSpecialCode code, int arg); +static int ssh2_transport_want_user_input(PacketProtocolLayer *ppl); +static void ssh2_transport_got_user_input(PacketProtocolLayer *ppl); +static void ssh2_transport_reconfigure(PacketProtocolLayer *ppl, Conf *conf); + +static void ssh2_transport_dialog_callback(void *, int); +static void ssh2_transport_set_max_data_size(struct ssh2_transport_state *s); +static unsigned long sanitise_rekey_time(int rekey_time, unsigned long def); +static void ssh2_transport_higher_layer_packet_callback(void *context); + +static const struct PacketProtocolLayerVtable ssh2_transport_vtable = { + ssh2_transport_free, + ssh2_transport_process_queue, + ssh2_transport_get_specials, + ssh2_transport_special_cmd, + ssh2_transport_want_user_input, + ssh2_transport_got_user_input, + ssh2_transport_reconfigure, + NULL, /* no protocol name for this layer */ +}; + +#ifndef NO_GSSAPI +static void ssh2_transport_gss_update(struct ssh2_transport_state *s, + int definitely_rekeying); +static void ssh_init_transient_hostkey_store(struct ssh2_transport_state *); +static void ssh_cleanup_transient_hostkey_store(struct ssh2_transport_state *); +static void ssh_store_transient_hostkey( + struct ssh2_transport_state *s, ssh_key *key); +static int ssh_verify_transient_hostkey( + struct ssh2_transport_state *s, ssh_key *key); +static int ssh_have_transient_hostkey( + struct ssh2_transport_state *s, const ssh_keyalg *alg); +static int ssh_have_any_transient_hostkey( + struct ssh2_transport_state *s); +#endif + +static int ssh2_transport_timer_update(struct ssh2_transport_state *s, + unsigned long rekey_time); + +static const char *const kexlist_descr[NKEXLIST] = { + "key exchange algorithm", + "host key algorithm", + "client-to-server cipher", + "server-to-client cipher", + "client-to-server MAC", + "server-to-client MAC", + "client-to-server compression method", + "server-to-client compression method" +}; + +PacketProtocolLayer *ssh2_transport_new( + Conf *conf, const char *host, int port, const char *fullhostname, + const char *client_greeting, const char *server_greeting, + struct ssh_connection_shared_gss_state *shgss, + struct DataTransferStats *stats, + PacketProtocolLayer *higher_layer) +{ + struct ssh2_transport_state *s = snew(struct ssh2_transport_state); + memset(s, 0, sizeof(*s)); + s->ppl.vt = &ssh2_transport_vtable; + + s->conf = conf_copy(conf); + s->savedhost = dupstr(host); + s->savedport = port; + s->fullhostname = dupstr(fullhostname); + s->shgss = shgss; + s->client_greeting = dupstr(client_greeting); + s->server_greeting = dupstr(server_greeting); + s->stats = stats; + + pq_in_init(&s->pq_in_higher); + pq_out_init(&s->pq_out_higher); + s->pq_out_higher.pqb.ic = &s->ic_pq_out_higher; + s->ic_pq_out_higher.fn = ssh2_transport_higher_layer_packet_callback; + s->ic_pq_out_higher.ctx = &s->ppl; + + s->higher_layer = higher_layer; + s->higher_layer->selfptr = &s->higher_layer; + ssh_ppl_setup_queues(s->higher_layer, &s->pq_in_higher, &s->pq_out_higher); + +#ifndef NO_GSSAPI + s->gss_cred_expiry = GSS_NO_EXPIRATION; + s->shgss->srv_name = GSS_C_NO_NAME; + s->shgss->ctx = NULL; + ssh_init_transient_hostkey_store(s); +#endif + s->gss_kex_used = FALSE; + + ssh2_transport_set_max_data_size(s); + + return &s->ppl; +} + +static void ssh2_transport_free(PacketProtocolLayer *ppl) +{ + struct ssh2_transport_state *s = + FROMFIELD(ppl, struct ssh2_transport_state, ppl); + + /* + * As our last act before being freed, move any outgoing packets + * off our higher layer's output queue on to our own output queue. + * We might be being freed while the SSH connection is still alive + * (because we're initiating shutdown from our end), in which case + * we don't want those last few packets to get lost. + * + * (If our owner were to have already destroyed our output pq + * before wanting to free us, then it would have to reset our + * publicly visible out_pq field to NULL to inhibit this attempt. + * But that's not how I expect the shutdown sequence to go in + * practice.) + */ + if (s->ppl.out_pq) + pq_concatenate(s->ppl.out_pq, s->ppl.out_pq, &s->pq_out_higher); + + conf_free(s->conf); + + ssh_ppl_free(s->higher_layer); + + pq_in_clear(&s->pq_in_higher); + pq_out_clear(&s->pq_out_higher); + + sfree(s->savedhost); + sfree(s->fullhostname); + sfree(s->client_greeting); + sfree(s->server_greeting); + sfree(s->keystr); + sfree(s->hostkey_str); + sfree(s->fingerprint); + if (s->hkey) { + ssh_key_free(s->hkey); + s->hkey = NULL; + } + if (s->e) freebn(s->e); + if (s->f) freebn(s->f); + if (s->p) freebn(s->p); + if (s->g) freebn(s->g); + if (s->K) freebn(s->K); + if (s->dh_ctx) + dh_cleanup(s->dh_ctx); + if (s->rsa_kex_key) + ssh_rsakex_freekey(s->rsa_kex_key); + if (s->ecdh_key) + ssh_ecdhkex_freekey(s->ecdh_key); + if (s->exhash) + ssh_hash_free(s->exhash); +#ifndef NO_GSSAPI + ssh_cleanup_transient_hostkey_store(s); +#endif + sfree(s); +} + +/* + * SSH-2 key derivation (RFC 4253 section 7.2). + */ +static void ssh2_mkkey( + struct ssh2_transport_state *s, strbuf *out, + Bignum K, unsigned char *H, char chr, int keylen) +{ + int hlen = s->kex_alg->hash->hlen; + int keylen_padded; + unsigned char *key; + ssh_hash *h; + + if (keylen == 0) + return; + + /* + * Round the requested amount of key material up to a multiple of + * the length of the hash we're using to make it. This makes life + * simpler because then we can just write each hash output block + * straight into the output buffer without fiddling about + * truncating the last one. Since it's going into a strbuf, and + * strbufs are always smemclr()ed on free, there's no need to + * worry about leaving extra potentially-sensitive data in memory + * that the caller didn't ask for. + */ + keylen_padded = ((keylen + hlen - 1) / hlen) * hlen; + + out->len = 0; + key = strbuf_append(out, keylen_padded); + + /* First hlen bytes. */ + h = ssh_hash_new(s->kex_alg->hash); + if (!(s->ppl.remote_bugs & BUG_SSH2_DERIVEKEY)) + put_mp_ssh2(h, K); + put_data(h, H, hlen); + put_byte(h, chr); + put_data(h, s->session_id, s->session_id_len); + ssh_hash_final(h, key); + + /* Subsequent blocks of hlen bytes. */ + if (keylen_padded > hlen) { + int offset; + + h = ssh_hash_new(s->kex_alg->hash); + if (!(s->ppl.remote_bugs & BUG_SSH2_DERIVEKEY)) + put_mp_ssh2(h, K); + put_data(h, H, hlen); + + for (offset = hlen; offset < keylen_padded; offset += hlen) { + put_data(h, key + offset - hlen, hlen); + ssh_hash *h2 = ssh_hash_copy(h); + ssh_hash_final(h2, key + offset); + } + + ssh_hash_free(h); + } +} + +/* + * Find a slot in a KEXINIT algorithm list to use for a new algorithm. + * If the algorithm is already in the list, return a pointer to its + * entry, otherwise return an entry from the end of the list. + * This assumes that every time a particular name is passed in, it + * comes from the same string constant. If this isn't true, this + * function may need to be rewritten to use strcmp() instead. + */ +static struct kexinit_algorithm *ssh2_kexinit_addalg(struct kexinit_algorithm + *list, const char *name) +{ + int i; + + for (i = 0; i < MAXKEXLIST; i++) + if (list[i].name == NULL || list[i].name == name) { + list[i].name = name; + return &list[i]; + } + assert(!"No space in KEXINIT list"); + return NULL; +} + +int ssh2_common_filter_queue(PacketProtocolLayer *ppl) +{ + static const char *const ssh2_disconnect_reasons[] = { + NULL, + "host not allowed to connect", + "protocol error", + "key exchange failed", + "host authentication failed", + "MAC error", + "compression error", + "service not available", + "protocol version not supported", + "host key not verifiable", + "connection lost", + "by application", + "too many connections", + "auth cancelled by user", + "no more auth methods available", + "illegal user name", + }; + + PktIn *pktin; + ptrlen msg; + int reason; + + while ((pktin = pq_peek(ppl->in_pq)) != NULL) { + switch (pktin->type) { + case SSH2_MSG_DISCONNECT: + reason = get_uint32(pktin); + msg = get_string(pktin); + + ssh_remote_error( + ppl->ssh, "Server sent disconnect message\n" + "type %d (%s):\n\"%.*s\"", reason, + ((reason > 0 && reason < lenof(ssh2_disconnect_reasons)) ? + ssh2_disconnect_reasons[reason] : "unknown"), + PTRLEN_PRINTF(msg)); + return TRUE; /* indicate that we've been freed */ + + case SSH2_MSG_DEBUG: + /* XXX maybe we should actually take notice of the return value */ + get_bool(pktin); + msg = get_string(pktin); + ppl_logevent(("Remote debug message: %.*s", PTRLEN_PRINTF(msg))); + pq_pop(ppl->in_pq); + break; + + case SSH2_MSG_IGNORE: + /* Do nothing, because we're ignoring it! Duhh. */ + pq_pop(ppl->in_pq); + break; + + default: + return FALSE; + } + } + + return FALSE; +} + +static int ssh2_transport_filter_queue(struct ssh2_transport_state *s) +{ + PktIn *pktin; + + while (1) { + if (ssh2_common_filter_queue(&s->ppl)) + return TRUE; + if ((pktin = pq_peek(s->ppl.in_pq)) == NULL) + return FALSE; + + /* Pass on packets to the next layer if they're outside + * the range reserved for the transport protocol. */ + if (pktin->type >= 50) { + /* ... except that we shouldn't tolerate higher-layer + * packets coming from the server before we've seen + * the first NEWKEYS. */ + if (!s->higher_layer_ok) { + ssh_proto_error(s->ppl.ssh, "Received premature higher-" + "layer packet, type %d (%s)", pktin->type, + ssh2_pkt_type(s->ppl.bpp->pls->kctx, + s->ppl.bpp->pls->actx, + pktin->type)); + return TRUE; + } + + pq_pop(s->ppl.in_pq); + pq_push(&s->pq_in_higher, pktin); + } else { + /* Anything else is a transport-layer packet that the main + * process_queue coroutine should handle. */ + return FALSE; + } + } +} + +static PktIn *ssh2_transport_pop(struct ssh2_transport_state *s) +{ + ssh2_transport_filter_queue(s); + return pq_pop(s->ppl.in_pq); +} + +static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) +{ + struct ssh2_transport_state *s = + FROMFIELD(ppl, struct ssh2_transport_state, ppl); + PktIn *pktin; + PktOut *pktout; + + /* Filter centrally handled messages off the front of the queue on + * every entry to this coroutine, no matter where we're resuming + * from, even if we're _not_ looping on pq_pop. That way we can + * still proactively handle those messages even if we're waiting + * for a user response. */ + ssh2_transport_filter_queue(s); + + crBegin(s->crState); + + s->in.cipher = s->out.cipher = NULL; + s->in.mac = s->out.mac = NULL; + s->in.comp = s->out.comp = NULL; + + s->got_session_id = FALSE; + s->userauth_succeeded = FALSE; + s->pending_compression = FALSE; + s->need_gss_transient_hostkey = FALSE; + s->warned_about_no_gss_transient_hostkey = FALSE; + + /* + * Be prepared to work around the buggy MAC problem. + */ + if (s->ppl.remote_bugs & BUG_SSH2_HMAC) + s->maclist = buggymacs, s->nmacs = lenof(buggymacs); + else + s->maclist = macs, s->nmacs = lenof(macs); + + begin_key_exchange: + +#ifndef NO_GSSAPI + if (s->need_gss_transient_hostkey) { + /* + * This flag indicates a special case in which we must not do + * GSS key exchange even if we could. (See comments below, + * where the flag was set on the previous key exchange.) + */ + s->can_gssapi_keyex = FALSE; + } else if (conf_get_int(s->conf, CONF_try_gssapi_kex)) { + /* + * We always check if we have GSS creds before we come up with + * the kex algorithm list, otherwise future rekeys will fail + * when creds expire. To make this so, this code section must + * follow the begin_key_exchange label above, otherwise this + * section would execute just once per-connection. + * + * Update GSS state unless the reason we're here is that a + * timer just checked the GSS state and decided that we should + * rekey to update delegated credentials. In that case, the + * state is "fresh". + */ + if (s->rekey_class != RK_GSS_UPDATE) + ssh2_transport_gss_update(s, TRUE); + + /* Do GSSAPI KEX when capable */ + s->can_gssapi_keyex = s->gss_status & GSS_KEX_CAPABLE; + + /* + * But not when failure is likely. [ GSS implementations may + * attempt (and fail) to use a ticket that is almost expired + * when retrieved from the ccache that actually expires by the + * time the server receives it. ] + * + * Note: The first time always try KEXGSS if we can, failures + * will be very rare, and disabling the initial GSS KEX is + * worse. Some day GSS libraries will ignore cached tickets + * whose lifetime is critically short, and will instead use + * fresh ones. + */ + if (!s->got_session_id && (s->gss_status & GSS_CTXT_MAYFAIL) != 0) + s->can_gssapi_keyex = 0; + s->gss_delegate = conf_get_int(s->conf, CONF_gssapifwd); + } else { + s->can_gssapi_keyex = FALSE; + } +#endif + + s->ppl.bpp->pls->kctx = SSH2_PKTCTX_NOKEX; + { + int i, j, k, warn; + struct kexinit_algorithm *alg; + + /* + * Set up the preferred key exchange. (NULL => warn below here) + */ + s->n_preferred_kex = 0; + if (s->can_gssapi_keyex) + s->preferred_kex[s->n_preferred_kex++] = &ssh_gssk5_sha1_kex; + for (i = 0; i < KEX_MAX; i++) { + switch (conf_get_int_int(s->conf, CONF_ssh_kexlist, i)) { + case KEX_DHGEX: + s->preferred_kex[s->n_preferred_kex++] = + &ssh_diffiehellman_gex; + break; + case KEX_DHGROUP14: + s->preferred_kex[s->n_preferred_kex++] = + &ssh_diffiehellman_group14; + break; + case KEX_DHGROUP1: + s->preferred_kex[s->n_preferred_kex++] = + &ssh_diffiehellman_group1; + break; + case KEX_RSA: + s->preferred_kex[s->n_preferred_kex++] = + &ssh_rsa_kex; + break; + case KEX_ECDH: + s->preferred_kex[s->n_preferred_kex++] = + &ssh_ecdh_kex; + break; + case KEX_WARN: + /* Flag for later. Don't bother if it's the last in + * the list. */ + if (i < KEX_MAX - 1) { + s->preferred_kex[s->n_preferred_kex++] = NULL; + } + break; + } + } + + /* + * Set up the preferred host key types. These are just the ids + * in the enum in putty.h, so 'warn below here' is indicated + * by HK_WARN. + */ + s->n_preferred_hk = 0; + for (i = 0; i < HK_MAX; i++) { + int id = conf_get_int_int(s->conf, CONF_ssh_hklist, i); + /* As above, don't bother with HK_WARN if it's last in the + * list */ + if (id != HK_WARN || i < HK_MAX - 1) + s->preferred_hk[s->n_preferred_hk++] = id; + } + + /* + * Set up the preferred ciphers. (NULL => warn below here) + */ + s->n_preferred_ciphers = 0; + for (i = 0; i < CIPHER_MAX; i++) { + switch (conf_get_int_int(s->conf, CONF_ssh_cipherlist, i)) { + case CIPHER_BLOWFISH: + s->preferred_ciphers[s->n_preferred_ciphers++] = &ssh2_blowfish; + break; + case CIPHER_DES: + if (conf_get_int(s->conf, CONF_ssh2_des_cbc)) + s->preferred_ciphers[s->n_preferred_ciphers++] = &ssh2_des; + break; + case CIPHER_3DES: + s->preferred_ciphers[s->n_preferred_ciphers++] = &ssh2_3des; + break; + case CIPHER_AES: + s->preferred_ciphers[s->n_preferred_ciphers++] = &ssh2_aes; + break; + case CIPHER_ARCFOUR: + s->preferred_ciphers[s->n_preferred_ciphers++] = &ssh2_arcfour; + break; + case CIPHER_CHACHA20: + s->preferred_ciphers[s->n_preferred_ciphers++] = &ssh2_ccp; + break; + case CIPHER_WARN: + /* Flag for later. Don't bother if it's the last in + * the list. */ + if (i < CIPHER_MAX - 1) { + s->preferred_ciphers[s->n_preferred_ciphers++] = NULL; + } + break; + } + } + + /* + * Set up preferred compression. + */ + if (conf_get_int(s->conf, CONF_compression)) + s->preferred_comp = &ssh_zlib; + else + s->preferred_comp = &ssh_comp_none; + + /* + * Flag that KEX is in progress. + */ + s->kex_in_progress = TRUE; + + for (i = 0; i < NKEXLIST; i++) + for (j = 0; j < MAXKEXLIST; j++) + s->kexlists[i][j].name = NULL; + /* List key exchange algorithms. */ + warn = FALSE; + for (i = 0; i < s->n_preferred_kex; i++) { + const struct ssh_kexes *k = s->preferred_kex[i]; + if (!k) warn = TRUE; + else for (j = 0; j < k->nkexes; j++) { + alg = ssh2_kexinit_addalg(s->kexlists[KEXLIST_KEX], + k->list[j]->name); + alg->u.kex.kex = k->list[j]; + alg->u.kex.warn = warn; + } + } + /* List server host key algorithms. */ + if (!s->got_session_id) { + /* + * In the first key exchange, we list all the algorithms + * we're prepared to cope with, but prefer those algorithms + * for which we have a host key for this host. + * + * If the host key algorithm is below the warning + * threshold, we warn even if we did already have a key + * for it, on the basis that if the user has just + * reconfigured that host key type to be warned about, + * they surely _do_ want to be alerted that a server + * they're actually connecting to is using it. + */ + warn = FALSE; + for (i = 0; i < s->n_preferred_hk; i++) { + if (s->preferred_hk[i] == HK_WARN) + warn = TRUE; + for (j = 0; j < lenof(hostkey_algs); j++) { + if (hostkey_algs[j].id != s->preferred_hk[i]) + continue; + if (have_ssh_host_key(s->savedhost, s->savedport, + hostkey_algs[j].alg->cache_id)) { + alg = ssh2_kexinit_addalg(s->kexlists[KEXLIST_HOSTKEY], + hostkey_algs[j].alg->ssh_id); + alg->u.hk.hostkey = hostkey_algs[j].alg; + alg->u.hk.warn = warn; + } + } + } + warn = FALSE; + for (i = 0; i < s->n_preferred_hk; i++) { + if (s->preferred_hk[i] == HK_WARN) + warn = TRUE; + for (j = 0; j < lenof(hostkey_algs); j++) { + if (hostkey_algs[j].id != s->preferred_hk[i]) + continue; + alg = ssh2_kexinit_addalg(s->kexlists[KEXLIST_HOSTKEY], + hostkey_algs[j].alg->ssh_id); + alg->u.hk.hostkey = hostkey_algs[j].alg; + alg->u.hk.warn = warn; + } + } +#ifndef NO_GSSAPI + } else if (s->gss_kex_used && !s->need_gss_transient_hostkey) { + /* + * If we've previously done a GSSAPI KEX, then we list + * precisely the algorithms for which a previous GSS key + * exchange has delivered us a host key, because we expect + * one of exactly those keys to be used in any subsequent + * non-GSS-based rekey. + * + * An exception is if this is the key exchange we + * triggered for the purposes of populating that cache - + * in which case the cache will currently be empty, which + * isn't helpful! + */ + warn = FALSE; + for (i = 0; i < s->n_preferred_hk; i++) { + if (s->preferred_hk[i] == HK_WARN) + warn = TRUE; + for (j = 0; j < lenof(hostkey_algs); j++) { + if (hostkey_algs[j].id != s->preferred_hk[i]) + continue; + if (ssh_have_transient_hostkey(s, hostkey_algs[j].alg)) { + alg = ssh2_kexinit_addalg(s->kexlists[KEXLIST_HOSTKEY], + hostkey_algs[j].alg->ssh_id); + alg->u.hk.hostkey = hostkey_algs[j].alg; + alg->u.hk.warn = warn; + } + } + } +#endif + } else { + /* + * In subsequent key exchanges, we list only the kex + * algorithm that was selected in the first key exchange, + * so that we keep getting the same host key and hence + * don't have to interrupt the user's session to ask for + * reverification. + */ + assert(s->kex_alg); + alg = ssh2_kexinit_addalg(s->kexlists[KEXLIST_HOSTKEY], + s->hostkey_alg->ssh_id); + alg->u.hk.hostkey = s->hostkey_alg; + alg->u.hk.warn = FALSE; + } + if (s->can_gssapi_keyex) { + alg = ssh2_kexinit_addalg(s->kexlists[KEXLIST_HOSTKEY], "null"); + alg->u.hk.hostkey = NULL; + } + /* List encryption algorithms (client->server then server->client). */ + for (k = KEXLIST_CSCIPHER; k <= KEXLIST_SCCIPHER; k++) { + warn = FALSE; +#ifdef FUZZING + alg = ssh2_kexinit_addalg(s->kexlists[k], "none"); + alg->u.cipher.cipher = NULL; + alg->u.cipher.warn = warn; +#endif /* FUZZING */ + for (i = 0; i < s->n_preferred_ciphers; i++) { + const struct ssh2_ciphers *c = s->preferred_ciphers[i]; + if (!c) warn = TRUE; + else for (j = 0; j < c->nciphers; j++) { + alg = ssh2_kexinit_addalg(s->kexlists[k], + c->list[j]->name); + alg->u.cipher.cipher = c->list[j]; + alg->u.cipher.warn = warn; + } + } + } + /* List MAC algorithms (client->server then server->client). */ + for (j = KEXLIST_CSMAC; j <= KEXLIST_SCMAC; j++) { +#ifdef FUZZING + alg = ssh2_kexinit_addalg(s->kexlists[j], "none"); + alg->u.mac.mac = NULL; + alg->u.mac.etm = FALSE; +#endif /* FUZZING */ + for (i = 0; i < s->nmacs; i++) { + alg = ssh2_kexinit_addalg(s->kexlists[j], s->maclist[i]->name); + alg->u.mac.mac = s->maclist[i]; + alg->u.mac.etm = FALSE; + } + for (i = 0; i < s->nmacs; i++) + /* For each MAC, there may also be an ETM version, + * which we list second. */ + if (s->maclist[i]->etm_name) { + alg = ssh2_kexinit_addalg(s->kexlists[j], + s->maclist[i]->etm_name); + alg->u.mac.mac = s->maclist[i]; + alg->u.mac.etm = TRUE; + } + } + /* List client->server compression algorithms, + * then server->client compression algorithms. (We use the + * same set twice.) */ + for (j = KEXLIST_CSCOMP; j <= KEXLIST_SCCOMP; j++) { + assert(lenof(compressions) > 1); + /* Prefer non-delayed versions */ + alg = ssh2_kexinit_addalg(s->kexlists[j], s->preferred_comp->name); + alg->u.comp = s->preferred_comp; + /* We don't even list delayed versions of algorithms until + * they're allowed to be used, to avoid a race. See the end of + * this function. */ + if (s->userauth_succeeded && s->preferred_comp->delayed_name) { + alg = ssh2_kexinit_addalg(s->kexlists[j], + s->preferred_comp->delayed_name); + alg->u.comp = s->preferred_comp; + } + for (i = 0; i < lenof(compressions); i++) { + const struct ssh_compression_alg *c = compressions[i]; + alg = ssh2_kexinit_addalg(s->kexlists[j], c->name); + alg->u.comp = c; + if (s->userauth_succeeded && c->delayed_name) { + alg = ssh2_kexinit_addalg(s->kexlists[j], c->delayed_name); + alg->u.comp = c; + } + } + } + /* + * Construct and send our key exchange packet. + */ + pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH2_MSG_KEXINIT); + for (i = 0; i < 16; i++) + put_byte(pktout, (unsigned char) random_byte()); + for (i = 0; i < NKEXLIST; i++) { + strbuf *list = strbuf_new(); + for (j = 0; j < MAXKEXLIST; j++) { + if (s->kexlists[i][j].name == NULL) break; + add_to_commasep(list, s->kexlists[i][j].name); + } + put_stringsb(pktout, list); + } + /* List client->server languages. Empty list. */ + put_stringz(pktout, ""); + /* List server->client languages. Empty list. */ + put_stringz(pktout, ""); + /* First KEX packet does _not_ follow, because we're not that brave. */ + put_bool(pktout, FALSE); + /* Reserved. */ + put_uint32(pktout, 0); + } + + s->our_kexinitlen = pktout->length - 5; + s->our_kexinit = snewn(s->our_kexinitlen, unsigned char); + memcpy(s->our_kexinit, pktout->data + 5, s->our_kexinitlen); + + pq_push(s->ppl.out_pq, pktout); + + crMaybeWaitUntilV((pktin = ssh2_transport_pop(s)) != NULL); + + /* + * Now examine the other side's KEXINIT to see what we're up + * to. + */ + { + ptrlen str; + int i, j; + + if (pktin->type != SSH2_MSG_KEXINIT) { + ssh_proto_error(s->ppl.ssh, "Received unexpected packet when " + "expecting KEXINIT, type %d (%s)", pktin->type, + ssh2_pkt_type(s->ppl.bpp->pls->kctx, + s->ppl.bpp->pls->actx, pktin->type)); + return; + } + s->kex_alg = NULL; + s->hostkey_alg = NULL; + s->in.cipher = s->out.cipher = NULL; + s->in.mac = s->out.mac = NULL; + s->in.comp = s->out.comp = NULL; + s->warn_kex = s->warn_hk = FALSE; + s->warn_cscipher = s->warn_sccipher = FALSE; + + get_data(pktin, 16); /* skip garbage cookie */ + + s->guessok = FALSE; + for (i = 0; i < NKEXLIST; i++) { + str = get_string(pktin); + if (get_err(pktin)) { + ssh_proto_error(s->ppl.ssh, "KEXINIT packet was incomplete"); + return; + } + + /* If we've already selected a cipher which requires a + * particular MAC, then just select that, and don't even + * bother looking through the server's KEXINIT string for + * MACs. */ + if (i == KEXLIST_CSMAC && s->out.cipher && + s->out.cipher->required_mac) { + s->out.mac = s->out.cipher->required_mac; + s->out.etm_mode = !!(s->out.mac->etm_name); + goto matched; + } + if (i == KEXLIST_SCMAC && s->in.cipher && + s->in.cipher->required_mac) { + s->in.mac = s->in.cipher->required_mac; + s->in.etm_mode = !!(s->in.mac->etm_name); + goto matched; + } + + for (j = 0; j < MAXKEXLIST; j++) { + struct kexinit_algorithm *alg = &s->kexlists[i][j]; + if (alg->name == NULL) break; + if (in_commasep_string(alg->name, str.ptr, str.len)) { + /* We've found a matching algorithm. */ + if (i == KEXLIST_KEX || i == KEXLIST_HOSTKEY) { + /* Check if we might need to ignore first kex pkt */ + if (j != 0 || + !first_in_commasep_string(alg->name, + str.ptr, str.len)) + s->guessok = FALSE; + } + if (i == KEXLIST_KEX) { + s->kex_alg = alg->u.kex.kex; + s->warn_kex = alg->u.kex.warn; + } else if (i == KEXLIST_HOSTKEY) { + /* + * Ignore an unexpected/inappropriate offer of "null", + * we offer "null" when we're willing to use GSS KEX, + * but it is only acceptable when GSSKEX is actually + * selected. + */ + if (alg->u.hk.hostkey == NULL && + s->kex_alg->main_type != KEXTYPE_GSS) + continue; + s->hostkey_alg = alg->u.hk.hostkey; + s->warn_hk = alg->u.hk.warn; + } else if (i == KEXLIST_CSCIPHER) { + s->out.cipher = alg->u.cipher.cipher; + s->warn_cscipher = alg->u.cipher.warn; + } else if (i == KEXLIST_SCCIPHER) { + s->in.cipher = alg->u.cipher.cipher; + s->warn_sccipher = alg->u.cipher.warn; + } else if (i == KEXLIST_CSMAC) { + s->out.mac = alg->u.mac.mac; + s->out.etm_mode = alg->u.mac.etm; + } else if (i == KEXLIST_SCMAC) { + s->in.mac = alg->u.mac.mac; + s->in.etm_mode = alg->u.mac.etm; + } else if (i == KEXLIST_CSCOMP) { + s->out.comp = alg->u.comp; + } else if (i == KEXLIST_SCCOMP) { + s->in.comp = alg->u.comp; + } + goto matched; + } + + /* Set a flag if there's a delayed compression option + * available for a compression method that we just + * failed to select the immediate version of. */ + s->pending_compression = ( + (i == KEXLIST_CSCOMP || i == KEXLIST_SCCOMP) && + in_commasep_string(alg->u.comp->delayed_name, + str.ptr, str.len) && + !s->userauth_succeeded); + } + ssh_sw_abort(s->ppl.ssh, "Couldn't agree a %s (available: %.*s)", + kexlist_descr[i], PTRLEN_PRINTF(str)); + return; + matched:; + + if (i == KEXLIST_HOSTKEY && + !s->gss_kex_used && + s->kex_alg->main_type != KEXTYPE_GSS) { + int j; + + /* + * In addition to deciding which host key we're + * actually going to use, we should make a list of the + * host keys offered by the server which we _don't_ + * have cached. These will be offered as cross- + * certification options by ssh_get_specials. + * + * We also count the key we're currently using for KEX + * as one we've already got, because by the time this + * menu becomes visible, it will be. + */ + s->n_uncert_hostkeys = 0; + + for (j = 0; j < lenof(hostkey_algs); j++) { + if (hostkey_algs[j].alg != s->hostkey_alg && + in_commasep_string(hostkey_algs[j].alg->ssh_id, + str.ptr, str.len) && + !have_ssh_host_key(s->savedhost, s->savedport, + hostkey_algs[j].alg->cache_id)) { + s->uncert_hostkeys[s->n_uncert_hostkeys++] = j; + } + } + } + } + + if (s->pending_compression) { + ppl_logevent(("Server supports delayed compression; " + "will try this later")); + } + get_string(pktin); /* client->server language */ + get_string(pktin); /* server->client language */ + s->ignorepkt = get_bool(pktin) && !s->guessok; + + s->exhash = ssh_hash_new(s->kex_alg->hash); + put_stringz(s->exhash, s->client_greeting); + put_stringz(s->exhash, s->server_greeting); + put_string(s->exhash, s->our_kexinit, s->our_kexinitlen); + sfree(s->our_kexinit); + /* Include the type byte in the hash of server's KEXINIT */ + put_string(s->exhash, + (const char *)BinarySource_UPCAST(pktin)->data - 1, + BinarySource_UPCAST(pktin)->len + 1); + + if (s->warn_kex) { + s->dlgret = askalg(s->ppl.frontend, "key-exchange algorithm", + s->kex_alg->name, + ssh2_transport_dialog_callback, s); + crMaybeWaitUntilV(s->dlgret >= 0); + if (s->dlgret == 0) { + ssh_user_close(s->ppl.ssh, "User aborted at kex warning"); + return; + } + } + + if (s->warn_hk) { + int j, k; + char *betteralgs; + + /* + * Change warning box wording depending on why we chose a + * warning-level host key algorithm. If it's because + * that's all we have *cached*, use the askhk mechanism, + * and list the host keys we could usefully cross-certify. + * Otherwise, use askalg for the standard wording. + */ + betteralgs = NULL; + for (j = 0; j < s->n_uncert_hostkeys; j++) { + const struct ssh_signkey_with_user_pref_id *hktype = + &hostkey_algs[s->uncert_hostkeys[j]]; + int better = FALSE; + for (k = 0; k < HK_MAX; k++) { + int id = conf_get_int_int(s->conf, CONF_ssh_hklist, k); + if (id == HK_WARN) { + break; + } else if (id == hktype->id) { + better = TRUE; + break; + } + } + if (better) { + if (betteralgs) { + char *old_ba = betteralgs; + betteralgs = dupcat(betteralgs, ",", + hktype->alg->ssh_id, + (const char *)NULL); + sfree(old_ba); + } else { + betteralgs = dupstr(hktype->alg->ssh_id); + } + } + } + if (betteralgs) { + s->dlgret = askhk( + s->ppl.frontend, s->hostkey_alg->ssh_id, betteralgs, + ssh2_transport_dialog_callback, s); + sfree(betteralgs); + } else { + s->dlgret = askalg(s->ppl.frontend, "host key type", + s->hostkey_alg->ssh_id, + ssh2_transport_dialog_callback, s); + } + crMaybeWaitUntilV(s->dlgret >= 0); + if (s->dlgret == 0) { + ssh_user_close(s->ppl.ssh, "User aborted at host key warning"); + return; + } + } + + if (s->warn_cscipher) { + s->dlgret = askalg(s->ppl.frontend, + "client-to-server cipher", + s->out.cipher->name, + ssh2_transport_dialog_callback, s); + crMaybeWaitUntilV(s->dlgret >= 0); + if (s->dlgret == 0) { + ssh_user_close(s->ppl.ssh, "User aborted at cipher warning"); + return; + } + } + + if (s->warn_sccipher) { + s->dlgret = askalg(s->ppl.frontend, + "server-to-client cipher", + s->in.cipher->name, + ssh2_transport_dialog_callback, s); + crMaybeWaitUntilV(s->dlgret >= 0); + if (s->dlgret == 0) { + ssh_user_close(s->ppl.ssh, "User aborted at cipher warning"); + return; + } + } + + if (s->ignorepkt) /* first_kex_packet_follows */ + crMaybeWaitUntilV((pktin = ssh2_transport_pop(s)) != NULL); + } + + if (s->kex_alg->main_type == KEXTYPE_DH) { + /* + * Work out the number of bits of key we will need from the + * key exchange. We start with the maximum key length of + * either cipher... + */ + { + int csbits, scbits; + + csbits = s->out.cipher ? s->out.cipher->real_keybits : 0; + scbits = s->in.cipher ? s->in.cipher->real_keybits : 0; + s->nbits = (csbits > scbits ? csbits : scbits); + } + /* The keys only have hlen-bit entropy, since they're based on + * a hash. So cap the key size at hlen bits. */ + if (s->nbits > s->kex_alg->hash->hlen * 8) + s->nbits = s->kex_alg->hash->hlen * 8; + + /* + * If we're doing Diffie-Hellman group exchange, start by + * requesting a group. + */ + if (dh_is_gex(s->kex_alg)) { + ppl_logevent(("Doing Diffie-Hellman group exchange")); + s->ppl.bpp->pls->kctx = SSH2_PKTCTX_DHGEX; + /* + * Work out how big a DH group we will need to allow that + * much data. + */ + s->pbits = 512 << ((s->nbits - 1) / 64); + if (s->pbits < DH_MIN_SIZE) + s->pbits = DH_MIN_SIZE; + if (s->pbits > DH_MAX_SIZE) + s->pbits = DH_MAX_SIZE; + if ((s->ppl.remote_bugs & BUG_SSH2_OLDGEX)) { + pktout = ssh_bpp_new_pktout( + s->ppl.bpp, SSH2_MSG_KEX_DH_GEX_REQUEST_OLD); + put_uint32(pktout, s->pbits); + } else { + pktout = ssh_bpp_new_pktout( + s->ppl.bpp, SSH2_MSG_KEX_DH_GEX_REQUEST); + put_uint32(pktout, DH_MIN_SIZE); + put_uint32(pktout, s->pbits); + put_uint32(pktout, DH_MAX_SIZE); + } + pq_push(s->ppl.out_pq, pktout); + + crMaybeWaitUntilV((pktin = ssh2_transport_pop(s)) != NULL); + if (pktin->type != SSH2_MSG_KEX_DH_GEX_GROUP) { + ssh_proto_error(s->ppl.ssh, "Received unexpected packet when " + "expecting Diffie-Hellman group, type %d (%s)", + pktin->type, + ssh2_pkt_type(s->ppl.bpp->pls->kctx, + s->ppl.bpp->pls->actx, + pktin->type)); + return; + } + s->p = get_mp_ssh2(pktin); + s->g = get_mp_ssh2(pktin); + if (get_err(pktin)) { + ssh_proto_error(s->ppl.ssh, + "Unable to parse Diffie-Hellman group packet"); + return; + } + s->dh_ctx = dh_setup_gex(s->p, s->g); + s->kex_init_value = SSH2_MSG_KEX_DH_GEX_INIT; + s->kex_reply_value = SSH2_MSG_KEX_DH_GEX_REPLY; + } else { + s->ppl.bpp->pls->kctx = SSH2_PKTCTX_DHGROUP; + s->dh_ctx = dh_setup_group(s->kex_alg); + s->kex_init_value = SSH2_MSG_KEXDH_INIT; + s->kex_reply_value = SSH2_MSG_KEXDH_REPLY; + ppl_logevent(("Using Diffie-Hellman with standard group \"%s\"", + s->kex_alg->groupname)); + } + + ppl_logevent(("Doing Diffie-Hellman key exchange with hash %s", + s->kex_alg->hash->text_name)); + /* + * Now generate and send e for Diffie-Hellman. + */ + set_busy_status(s->ppl.frontend, BUSY_CPU); /* this can take a while */ + s->e = dh_create_e(s->dh_ctx, s->nbits * 2); + pktout = ssh_bpp_new_pktout(s->ppl.bpp, s->kex_init_value); + put_mp_ssh2(pktout, s->e); + pq_push(s->ppl.out_pq, pktout); + + set_busy_status(s->ppl.frontend, BUSY_WAITING); /* wait for server */ + crMaybeWaitUntilV((pktin = ssh2_transport_pop(s)) != NULL); + if (pktin->type != s->kex_reply_value) { + ssh_proto_error(s->ppl.ssh, "Received unexpected packet when " + "expecting Diffie-Hellman reply, type %d (%s)", + pktin->type, + ssh2_pkt_type(s->ppl.bpp->pls->kctx, + s->ppl.bpp->pls->actx, + pktin->type)); + return; + } + set_busy_status(s->ppl.frontend, BUSY_CPU); /* cogitate */ + s->hostkeydata = get_string(pktin); + s->hkey = ssh_key_new_pub(s->hostkey_alg, s->hostkeydata); + s->f = get_mp_ssh2(pktin); + s->sigdata = get_string(pktin); + if (get_err(pktin)) { + ssh_proto_error(s->ppl.ssh, + "Unable to parse Diffie-Hellman reply packet"); + return; + } + + { + const char *err = dh_validate_f(s->dh_ctx, s->f); + if (err) { + ssh_proto_error(s->ppl.ssh, "Diffie-Hellman reply failed " + "validation: %s", err); + return; + } + } + s->K = dh_find_K(s->dh_ctx, s->f); + + /* We assume everything from now on will be quick, and it might + * involve user interaction. */ + set_busy_status(s->ppl.frontend, BUSY_NOT); + + put_stringpl(s->exhash, s->hostkeydata); + if (dh_is_gex(s->kex_alg)) { + if (!(s->ppl.remote_bugs & BUG_SSH2_OLDGEX)) + put_uint32(s->exhash, DH_MIN_SIZE); + put_uint32(s->exhash, s->pbits); + if (!(s->ppl.remote_bugs & BUG_SSH2_OLDGEX)) + put_uint32(s->exhash, DH_MAX_SIZE); + put_mp_ssh2(s->exhash, s->p); + put_mp_ssh2(s->exhash, s->g); + } + put_mp_ssh2(s->exhash, s->e); + put_mp_ssh2(s->exhash, s->f); + + dh_cleanup(s->dh_ctx); + s->dh_ctx = NULL; + freebn(s->f); s->f = NULL; + freebn(s->e); s->e = NULL; + if (dh_is_gex(s->kex_alg)) { + freebn(s->g); s->g = NULL; + freebn(s->p); s->p = NULL; + } + } else if (s->kex_alg->main_type == KEXTYPE_ECDH) { + + ppl_logevent(("Doing ECDH key exchange with curve %s and hash %s", + ssh_ecdhkex_curve_textname(s->kex_alg), + s->kex_alg->hash->text_name)); + s->ppl.bpp->pls->kctx = SSH2_PKTCTX_ECDHKEX; + + s->ecdh_key = ssh_ecdhkex_newkey(s->kex_alg); + if (!s->ecdh_key) { + ssh_sw_abort(s->ppl.ssh, "Unable to generate key for ECDH"); + return; + } + + pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH2_MSG_KEX_ECDH_INIT); + { + strbuf *pubpoint = strbuf_new(); + ssh_ecdhkex_getpublic(s->ecdh_key, BinarySink_UPCAST(pubpoint)); + put_stringsb(pktout, pubpoint); + } + + pq_push(s->ppl.out_pq, pktout); + + crMaybeWaitUntilV((pktin = ssh2_transport_pop(s)) != NULL); + if (pktin->type != SSH2_MSG_KEX_ECDH_REPLY) { + ssh_proto_error(s->ppl.ssh, "Received unexpected packet when " + "expecting ECDH reply, type %d (%s)", pktin->type, + ssh2_pkt_type(s->ppl.bpp->pls->kctx, + s->ppl.bpp->pls->actx, + pktin->type)); + return; + } + + s->hostkeydata = get_string(pktin); + put_stringpl(s->exhash, s->hostkeydata); + s->hkey = ssh_key_new_pub(s->hostkey_alg, s->hostkeydata); + + { + strbuf *pubpoint = strbuf_new(); + ssh_ecdhkex_getpublic(s->ecdh_key, BinarySink_UPCAST(pubpoint)); + put_string(s->exhash, pubpoint->u, pubpoint->len); + strbuf_free(pubpoint); + } + + { + ptrlen keydata = get_string(pktin); + put_stringpl(s->exhash, keydata); + s->K = ssh_ecdhkex_getkey(s->ecdh_key, keydata.ptr, keydata.len); + if (!get_err(pktin) && !s->K) { + ssh_proto_error(s->ppl.ssh, "Received invalid elliptic curve " + "point in ECDH reply"); + return; + } + } + + s->sigdata = get_string(pktin); + if (get_err(pktin)) { + ssh_proto_error(s->ppl.ssh, "Unable to parse ECDH reply packet"); + return; + } + + ssh_ecdhkex_freekey(s->ecdh_key); + s->ecdh_key = NULL; +#ifndef NO_GSSAPI + } else if (s->kex_alg->main_type == KEXTYPE_GSS) { + ptrlen data; + + s->ppl.bpp->pls->kctx = SSH2_PKTCTX_GSSKEX; + s->init_token_sent = 0; + s->complete_rcvd = 0; + s->hkey = NULL; + s->fingerprint = NULL; + s->keystr = NULL; + + /* + * Work out the number of bits of key we will need from the + * key exchange. We start with the maximum key length of + * either cipher... + * + * This is rote from the KEXTYPE_DH section above. + */ + { + int csbits, scbits; + + csbits = s->out.cipher->real_keybits; + scbits = s->in.cipher->real_keybits; + s->nbits = (csbits > scbits ? csbits : scbits); + } + /* The keys only have hlen-bit entropy, since they're based on + * a hash. So cap the key size at hlen bits. */ + if (s->nbits > s->kex_alg->hash->hlen * 8) + s->nbits = s->kex_alg->hash->hlen * 8; + + if (dh_is_gex(s->kex_alg)) { + /* + * Work out how big a DH group we will need to allow that + * much data. + */ + s->pbits = 512 << ((s->nbits - 1) / 64); + ppl_logevent(("Doing GSSAPI (with Kerberos V5) Diffie-Hellman " + "group exchange, with minimum %d bits", s->pbits)); + pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH2_MSG_KEXGSS_GROUPREQ); + put_uint32(pktout, s->pbits); /* min */ + put_uint32(pktout, s->pbits); /* preferred */ + put_uint32(pktout, s->pbits * 2); /* max */ + pq_push(s->ppl.out_pq, pktout); + + crMaybeWaitUntilV( + (pktin = ssh2_transport_pop(s)) != NULL); + if (pktin->type != SSH2_MSG_KEXGSS_GROUP) { + ssh_proto_error(s->ppl.ssh, "Received unexpected packet when " + "expecting Diffie-Hellman group, type %d (%s)", + pktin->type, + ssh2_pkt_type(s->ppl.bpp->pls->kctx, + s->ppl.bpp->pls->actx, + pktin->type)); + return; + } + s->p = get_mp_ssh2(pktin); + s->g = get_mp_ssh2(pktin); + if (get_err(pktin)) { + ssh_proto_error(s->ppl.ssh, + "Unable to parse Diffie-Hellman group packet"); + return; + } + s->dh_ctx = dh_setup_gex(s->p, s->g); + } else { + s->dh_ctx = dh_setup_group(s->kex_alg); + ppl_logevent(("Using GSSAPI (with Kerberos V5) Diffie-Hellman with" + " standard group \"%s\"", s->kex_alg->groupname)); + } + + ppl_logevent(("Doing GSSAPI (with Kerberos V5) Diffie-Hellman key " + "exchange with hash %s", s->kex_alg->hash->text_name)); + /* Now generate e for Diffie-Hellman. */ + set_busy_status(s->ppl.frontend, BUSY_CPU); /* this can take a while */ + s->e = dh_create_e(s->dh_ctx, s->nbits * 2); + + if (s->shgss->lib->gsslogmsg) + ppl_logevent(("%s", s->shgss->lib->gsslogmsg)); + + /* initial tokens are empty */ + SSH_GSS_CLEAR_BUF(&s->gss_rcvtok); + SSH_GSS_CLEAR_BUF(&s->gss_sndtok); + SSH_GSS_CLEAR_BUF(&s->mic); + s->gss_stat = s->shgss->lib->acquire_cred( + s->shgss->lib, &s->shgss->ctx, &s->gss_cred_expiry); + if (s->gss_stat != SSH_GSS_OK) { + ssh_sw_abort(s->ppl.ssh, + "GSSAPI key exchange failed to initialise"); + return; + } + + /* now enter the loop */ + assert(s->shgss->srv_name); + do { + /* + * When acquire_cred yields no useful expiration, go with the + * service ticket expiration. + */ + s->gss_stat = s->shgss->lib->init_sec_context( + s->shgss->lib, &s->shgss->ctx, s->shgss->srv_name, + s->gss_delegate, &s->gss_rcvtok, &s->gss_sndtok, + (s->gss_cred_expiry == GSS_NO_EXPIRATION ? + &s->gss_cred_expiry : NULL), NULL); + SSH_GSS_CLEAR_BUF(&s->gss_rcvtok); + + if (s->gss_stat == SSH_GSS_S_COMPLETE && s->complete_rcvd) + break; /* MIC is verified after the loop */ + + if (s->gss_stat != SSH_GSS_S_COMPLETE && + s->gss_stat != SSH_GSS_S_CONTINUE_NEEDED) { + if (s->shgss->lib->display_status( + s->shgss->lib, s->shgss->ctx, + &s->gss_buf) == SSH_GSS_OK) { + char *err = s->gss_buf.value; + ssh_sw_abort(s->ppl.ssh, + "GSSAPI key exchange failed to initialise " + "context: %s", err); + sfree(err); + return; + } + } + assert(s->gss_stat == SSH_GSS_S_COMPLETE || + s->gss_stat == SSH_GSS_S_CONTINUE_NEEDED); + + if (!s->init_token_sent) { + s->init_token_sent = 1; + pktout = ssh_bpp_new_pktout(s->ppl.bpp, + SSH2_MSG_KEXGSS_INIT); + if (s->gss_sndtok.length == 0) { + ssh_sw_abort(s->ppl.ssh, "GSSAPI key exchange failed: " + "no initial context token"); + return; + } + put_string(pktout, + s->gss_sndtok.value, s->gss_sndtok.length); + put_mp_ssh2(pktout, s->e); + pq_push(s->ppl.out_pq, pktout); + s->shgss->lib->free_tok(s->shgss->lib, &s->gss_sndtok); + ppl_logevent(("GSSAPI key exchange initialised")); + } else if (s->gss_sndtok.length != 0) { + pktout = ssh_bpp_new_pktout( + s->ppl.bpp, SSH2_MSG_KEXGSS_CONTINUE); + put_string(pktout, + s->gss_sndtok.value, s->gss_sndtok.length); + pq_push(s->ppl.out_pq, pktout); + s->shgss->lib->free_tok(s->shgss->lib, &s->gss_sndtok); + } + + if (s->gss_stat == SSH_GSS_S_COMPLETE && s->complete_rcvd) + break; + + wait_for_gss_token: + crMaybeWaitUntilV( + (pktin = ssh2_transport_pop(s)) != NULL); + switch (pktin->type) { + case SSH2_MSG_KEXGSS_CONTINUE: + data = get_string(pktin); + s->gss_rcvtok.value = (char *)data.ptr; + s->gss_rcvtok.length = data.len; + continue; + case SSH2_MSG_KEXGSS_COMPLETE: + s->complete_rcvd = 1; + s->f = get_mp_ssh2(pktin); + data = get_string(pktin); + s->mic.value = (char *)data.ptr; + s->mic.length = data.len; + /* Save expiration time of cred when delegating */ + if (s->gss_delegate && s->gss_cred_expiry != GSS_NO_EXPIRATION) + s->gss_cred_expiry = s->gss_cred_expiry; + /* If there's a final token we loop to consume it */ + if (get_bool(pktin)) { + data = get_string(pktin); + s->gss_rcvtok.value = (char *)data.ptr; + s->gss_rcvtok.length = data.len; + continue; + } + break; + case SSH2_MSG_KEXGSS_HOSTKEY: + s->hostkeydata = get_string(pktin); + if (s->hostkey_alg) { + s->hkey = ssh_key_new_pub(s->hostkey_alg, + s->hostkeydata); + put_string(s->exhash, + s->hostkeydata.ptr, s->hostkeydata.len); + } + /* + * Can't loop as we have no token to pass to + * init_sec_context. + */ + goto wait_for_gss_token; + case SSH2_MSG_KEXGSS_ERROR: + /* + * We have no use for the server's major and minor + * status. The minor status is really only + * meaningful to the server, and with luck the major + * status means something to us (but not really all + * that much). The string is more meaningful, and + * hopefully the server sends any error tokens, as + * that will produce the most useful information for + * us. + */ + get_uint32(pktin); /* server's major status */ + get_uint32(pktin); /* server's minor status */ + data = get_string(pktin); + ppl_logevent(("GSSAPI key exchange failed; " + "server's message: %.*s", PTRLEN_PRINTF(data))); + /* Language tag, but we have no use for it */ + get_string(pktin); + /* + * Wait for an error token, if there is one, or the + * server's disconnect. The error token, if there + * is one, must follow the SSH2_MSG_KEXGSS_ERROR + * message, per the RFC. + */ + goto wait_for_gss_token; + default: + ssh_proto_error(s->ppl.ssh, "Received unexpected packet " + "during GSSAPI key exchange, type %d (%s)", + pktin->type, + ssh2_pkt_type(s->ppl.bpp->pls->kctx, + s->ppl.bpp->pls->actx, + pktin->type)); + return; + } + } while (s->gss_rcvtok.length || + s->gss_stat == SSH_GSS_S_CONTINUE_NEEDED || + !s->complete_rcvd); + + s->K = dh_find_K(s->dh_ctx, s->f); + + /* We assume everything from now on will be quick, and it might + * involve user interaction. */ + set_busy_status(s->ppl.frontend, BUSY_NOT); + + if (!s->hkey) + put_stringz(s->exhash, ""); + if (dh_is_gex(s->kex_alg)) { + /* min, preferred, max */ + put_uint32(s->exhash, s->pbits); + put_uint32(s->exhash, s->pbits); + put_uint32(s->exhash, s->pbits * 2); + + put_mp_ssh2(s->exhash, s->p); + put_mp_ssh2(s->exhash, s->g); + } + put_mp_ssh2(s->exhash, s->e); + put_mp_ssh2(s->exhash, s->f); + + /* + * MIC verification is done below, after we compute the hash + * used as the MIC input. + */ + + dh_cleanup(s->dh_ctx); + s->dh_ctx = NULL; + freebn(s->f); s->f = NULL; + freebn(s->e); s->e = NULL; + if (dh_is_gex(s->kex_alg)) { + freebn(s->g); s->g = NULL; + freebn(s->p); s->p = NULL; + } +#endif + } else { + ptrlen rsakeydata; + + assert(s->kex_alg->main_type == KEXTYPE_RSA); + ppl_logevent(("Doing RSA key exchange with hash %s", + s->kex_alg->hash->text_name)); + s->ppl.bpp->pls->kctx = SSH2_PKTCTX_RSAKEX; + /* + * RSA key exchange. First expect a KEXRSA_PUBKEY packet + * from the server. + */ + crMaybeWaitUntilV((pktin = ssh2_transport_pop(s)) != NULL); + if (pktin->type != SSH2_MSG_KEXRSA_PUBKEY) { + ssh_proto_error(s->ppl.ssh, "Received unexpected packet when " + "expecting RSA public key, type %d (%s)", + pktin->type, + ssh2_pkt_type(s->ppl.bpp->pls->kctx, + s->ppl.bpp->pls->actx, + pktin->type)); + return; + } + + s->hostkeydata = get_string(pktin); + put_stringpl(s->exhash, s->hostkeydata); + s->hkey = ssh_key_new_pub(s->hostkey_alg, s->hostkeydata); + + rsakeydata = get_string(pktin); + + s->rsa_kex_key = ssh_rsakex_newkey(rsakeydata.ptr, rsakeydata.len); + if (!s->rsa_kex_key) { + ssh_proto_error(s->ppl.ssh, + "Unable to parse RSA public key packet"); + return; + } + + put_stringpl(s->exhash, rsakeydata); + + /* + * Next, set up a shared secret K, of precisely KLEN - + * 2*HLEN - 49 bits, where KLEN is the bit length of the + * RSA key modulus and HLEN is the bit length of the hash + * we're using. + */ + { + int klen = ssh_rsakex_klen(s->rsa_kex_key); + int nbits = klen - (2*s->kex_alg->hash->hlen*8 + 49); + int i, byte = 0; + strbuf *buf; + unsigned char *outstr; + int outstrlen; + + s->K = bn_power_2(nbits - 1); + + for (i = 0; i < nbits; i++) { + if ((i & 7) == 0) { + byte = random_byte(); + } + bignum_set_bit(s->K, i, (byte >> (i & 7)) & 1); + } + + /* + * Encode this as an mpint. + */ + buf = strbuf_new(); + put_mp_ssh2(buf, s->K); + + /* + * Encrypt it with the given RSA key. + */ + outstrlen = (klen + 7) / 8; + outstr = snewn(outstrlen, unsigned char); + ssh_rsakex_encrypt(s->kex_alg->hash, buf->u, buf->len, + outstr, outstrlen, s->rsa_kex_key); + + /* + * And send it off in a return packet. + */ + pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH2_MSG_KEXRSA_SECRET); + put_string(pktout, outstr, outstrlen); + pq_push(s->ppl.out_pq, pktout); + + put_string(s->exhash, outstr, outstrlen); + + strbuf_free(buf); + sfree(outstr); + } + + ssh_rsakex_freekey(s->rsa_kex_key); + s->rsa_kex_key = NULL; + + crMaybeWaitUntilV((pktin = ssh2_transport_pop(s)) != NULL); + if (pktin->type != SSH2_MSG_KEXRSA_DONE) { + ssh_proto_error(s->ppl.ssh, "Received unexpected packet when " + "expecting RSA kex signature, type %d (%s)", + pktin->type, + ssh2_pkt_type(s->ppl.bpp->pls->kctx, + s->ppl.bpp->pls->actx, + pktin->type)); + return; + } + + s->sigdata = get_string(pktin); + if (get_err(pktin)) { + ssh_proto_error(s->ppl.ssh, "Unable to parse RSA kex signature"); + return; + } + } + + put_mp_ssh2(s->exhash, s->K); + assert(ssh_hash_alg(s->exhash)->hlen <= sizeof(s->exchange_hash)); + ssh_hash_final(s->exhash, s->exchange_hash); + s->exhash = NULL; + +#ifndef NO_GSSAPI + if (s->kex_alg->main_type == KEXTYPE_GSS) { + Ssh_gss_buf gss_buf; + SSH_GSS_CLEAR_BUF(&s->gss_buf); + + gss_buf.value = s->exchange_hash; + gss_buf.length = s->kex_alg->hash->hlen; + s->gss_stat = s->shgss->lib->verify_mic( + s->shgss->lib, s->shgss->ctx, &gss_buf, &s->mic); + if (s->gss_stat != SSH_GSS_OK) { + if (s->shgss->lib->display_status( + s->shgss->lib, s->shgss->ctx, &s->gss_buf) == SSH_GSS_OK) { + char *err = s->gss_buf.value; + ssh_sw_abort(s->ppl.ssh, "GSSAPI key exchange MIC was " + "not valid: %s", err); + sfree(err); + } else { + ssh_sw_abort(s->ppl.ssh, "GSSAPI key exchange MIC was " + "not valid"); + } + return; + } + + s->gss_kex_used = TRUE; + + /*- + * If this the first KEX, save the GSS context for "gssapi-keyex" + * authentication. + * + * http://tools.ietf.org/html/rfc4462#section-4 + * + * This method may be used only if the initial key exchange was + * performed using a GSS-API-based key exchange method defined in + * accordance with Section 2. The GSS-API context used with this + * method is always that established during an initial GSS-API-based + * key exchange. Any context established during key exchange for the + * purpose of rekeying MUST NOT be used with this method. + */ + if (s->got_session_id) { + s->shgss->lib->release_cred(s->shgss->lib, &s->shgss->ctx); + } + ppl_logevent(("GSSAPI Key Exchange complete!")); + } +#endif + + s->dh_ctx = NULL; + +#if 0 + debug(("Exchange hash is:\n")); + dmemdump(s->exchange_hash, s->kex_alg->hash->hlen); +#endif + + /* In GSS keyex there's no hostkey signature to verify */ + if (s->kex_alg->main_type != KEXTYPE_GSS) { + if (!s->hkey) { + ssh_proto_error(s->ppl.ssh, "Server's host key is invalid"); + return; + } + + if (!ssh_key_verify( + s->hkey, s->sigdata, + make_ptrlen(s->exchange_hash, s->kex_alg->hash->hlen))) { +#ifndef FUZZING + ssh_proto_error(s->ppl.ssh, "Signature from server's host key " + "is invalid"); + return; +#endif + } + } + + s->keystr = (s->hkey ? ssh_key_cache_str(s->hkey) : NULL); +#ifndef NO_GSSAPI + if (s->gss_kex_used) { + /* + * In a GSS-based session, check the host key (if any) against + * the transient host key cache. See comment above, at the + * definition of ssh_transient_hostkey_cache_entry. + */ + if (s->kex_alg->main_type == KEXTYPE_GSS) { + + /* + * We've just done a GSS key exchange. If it gave us a + * host key, store it. + */ + if (s->hkey) { + s->fingerprint = ssh2_fingerprint(s->hkey); + ppl_logevent(("GSS kex provided fallback host key:")); + ppl_logevent(("%s", s->fingerprint)); + sfree(s->fingerprint); + s->fingerprint = NULL; + ssh_store_transient_hostkey(s, s->hkey); + } else if (!ssh_have_any_transient_hostkey(s)) { + /* + * But if it didn't, then we currently have no + * fallback host key to use in subsequent non-GSS + * rekeys. So we should immediately trigger a non-GSS + * rekey of our own, to set one up, before the session + * keys have been used for anything else. + * + * This is similar to the cross-certification done at + * user request in the permanent host key cache, but + * here we do it automatically, once, at session + * startup, and only add the key to the transient + * cache. + */ + if (s->hostkey_alg) { + s->need_gss_transient_hostkey = TRUE; + } else { + /* + * If we negotiated the "null" host key algorithm + * in the key exchange, that's an indication that + * no host key at all is available from the server + * (both because we listed "null" last, and + * because RFC 4462 section 5 says that a server + * MUST NOT offer "null" as a host key algorithm + * unless that is the only algorithm it provides + * at all). + * + * In that case we actually _can't_ perform a + * non-GSSAPI key exchange, so it's pointless to + * attempt one proactively. This is also likely to + * cause trouble later if a rekey is required at a + * moment whne GSS credentials are not available, + * but someone setting up a server in this + * configuration presumably accepts that as a + * consequence. + */ + if (!s->warned_about_no_gss_transient_hostkey) { + ppl_logevent(("No fallback host key available")); + s->warned_about_no_gss_transient_hostkey = TRUE; + } + } + } + } else { + /* + * We've just done a fallback key exchange, so make + * sure the host key it used is in the cache of keys + * we previously received in GSS kexes. + * + * An exception is if this was the non-GSS key exchange we + * triggered on purpose to populate the transient cache. + */ + assert(s->hkey); /* only KEXTYPE_GSS lets this be null */ + s->fingerprint = ssh2_fingerprint(s->hkey); + + if (s->need_gss_transient_hostkey) { + ppl_logevent(("Post-GSS rekey provided fallback host key:")); + ppl_logevent(("%s", s->fingerprint)); + ssh_store_transient_hostkey(s, s->hkey); + s->need_gss_transient_hostkey = FALSE; + } else if (!ssh_verify_transient_hostkey(s, s->hkey)) { + ppl_logevent(("Non-GSS rekey after initial GSS kex " + "used host key:")); + ppl_logevent(("%s", s->fingerprint)); + ssh_sw_abort(s->ppl.ssh, "Server's host key did not match any " + "used in previous GSS kex"); + return; + } + + sfree(s->fingerprint); + s->fingerprint = NULL; + } + } else +#endif /* NO_GSSAPI */ + if (!s->got_session_id) { + /* + * Make a note of any other host key formats that are available. + */ + { + int i, j, nkeys = 0; + char *list = NULL; + for (i = 0; i < lenof(hostkey_algs); i++) { + if (hostkey_algs[i].alg == s->hostkey_alg) + continue; + + for (j = 0; j < s->n_uncert_hostkeys; j++) + if (s->uncert_hostkeys[j] == i) + break; + + if (j < s->n_uncert_hostkeys) { + char *newlist; + if (list) + newlist = dupprintf("%s/%s", list, + hostkey_algs[i].alg->ssh_id); + else + newlist = dupprintf("%s", hostkey_algs[i].alg->ssh_id); + sfree(list); + list = newlist; + nkeys++; + } + } + if (list) { + ppl_logevent(("Server also has %s host key%s, but we " + "don't know %s", list, + nkeys > 1 ? "s" : "", + nkeys > 1 ? "any of them" : "it")); + sfree(list); + } + } + + /* + * Authenticate remote host: verify host key. (We've already + * checked the signature of the exchange hash.) + */ + s->fingerprint = ssh2_fingerprint(s->hkey); + ppl_logevent(("Host key fingerprint is:")); + ppl_logevent(("%s", s->fingerprint)); + /* First check against manually configured host keys. */ + s->dlgret = verify_ssh_manual_host_key( + s->conf, s->fingerprint, s->hkey); + if (s->dlgret == 0) { /* did not match */ + ssh_sw_abort(s->ppl.ssh, "Host key did not appear in manually " + "configured list"); + return; + } else if (s->dlgret < 0) { /* none configured; use standard handling */ + s->dlgret = verify_ssh_host_key(s->ppl.frontend, + s->savedhost, s->savedport, + ssh_key_cache_id(s->hkey), + s->keystr, s->fingerprint, + ssh2_transport_dialog_callback, s); +#ifdef FUZZING + s->dlgret = 1; +#endif + crMaybeWaitUntilV(s->dlgret >= 0); + if (s->dlgret == 0) { + ssh_user_close(s->ppl.ssh, + "User aborted at host key verification"); + return; + } + } + sfree(s->fingerprint); + s->fingerprint = NULL; + /* + * Save this host key, to check against the one presented in + * subsequent rekeys. + */ + s->hostkey_str = s->keystr; + s->keystr = NULL; + } else if (s->cross_certifying) { + s->fingerprint = ssh2_fingerprint(s->hkey); + ppl_logevent(("Storing additional host key for this host:")); + ppl_logevent(("%s", s->fingerprint)); + sfree(s->fingerprint); + s->fingerprint = NULL; + store_host_key(s->savedhost, s->savedport, + ssh_key_cache_id(s->hkey), s->keystr); + s->cross_certifying = FALSE; + /* + * Don't forget to store the new key as the one we'll be + * re-checking in future normal rekeys. + */ + s->hostkey_str = s->keystr; + s->keystr = NULL; + } else { + /* + * In a rekey, we never present an interactive host key + * verification request to the user. Instead, we simply + * enforce that the key we're seeing this time is identical to + * the one we saw before. + */ + if (strcmp(s->hostkey_str, s->keystr)) { +#ifndef FUZZING + ssh_sw_abort(s->ppl.ssh, + "Host key was different in repeat key exchange"); + return; +#endif + } + } + sfree(s->keystr); + s->keystr = NULL; + if (s->hkey) { + ssh_key_free(s->hkey); + s->hkey = NULL; + } + + /* + * The exchange hash from the very first key exchange is also + * the session id, used in session key construction and + * authentication. + */ + if (!s->got_session_id) { + assert(sizeof(s->exchange_hash) <= sizeof(s->session_id)); + memcpy(s->session_id, s->exchange_hash, sizeof(s->exchange_hash)); + s->session_id_len = s->kex_alg->hash->hlen; + assert(s->session_id_len <= sizeof(s->session_id)); + s->got_session_id = TRUE; + } + + /* + * Send SSH2_MSG_NEWKEYS. + */ + pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH2_MSG_NEWKEYS); + pq_push(s->ppl.out_pq, pktout); + /* Start counting down the outgoing-data limit for these cipher keys. */ + s->stats->out.running = TRUE; + s->stats->out.remaining = s->max_data_size; + + /* + * Force the BPP to synchronously marshal all packets up to and + * including that NEWKEYS into wire format, before we switch over + * to new crypto. + */ + ssh_bpp_handle_output(s->ppl.bpp); + + /* + * We've sent client NEWKEYS, so create and initialise + * client-to-server session keys. + */ + { + strbuf *cipher_key = strbuf_new(); + strbuf *cipher_iv = strbuf_new(); + strbuf *mac_key = strbuf_new(); + + if (s->out.cipher) { + ssh2_mkkey(s, cipher_iv, s->K, s->exchange_hash, 'A', + s->out.cipher->blksize); + ssh2_mkkey(s, cipher_key, s->K, s->exchange_hash, 'C', + s->out.cipher->padded_keybytes); + } + if (s->out.mac) { + ssh2_mkkey(s, mac_key, s->K, s->exchange_hash, 'E', + s->out.mac->keylen); + } + + ssh2_bpp_new_outgoing_crypto( + s->ppl.bpp, + s->out.cipher, cipher_key->u, cipher_iv->u, + s->out.mac, s->out.etm_mode, mac_key->u, + s->out.comp); + + strbuf_free(cipher_key); + strbuf_free(cipher_iv); + strbuf_free(mac_key); + } + + if (s->out.cipher) + ppl_logevent(("Initialised %.200s client->server encryption", + s->out.cipher->text_name)); + if (s->out.mac) + ppl_logevent(("Initialised %.200s client->server" + " MAC algorithm%s%s", + s->out.mac->text_name, + s->out.etm_mode ? " (in ETM mode)" : "", + (s->out.cipher->required_mac ? + " (required by cipher)" : ""))); + if (s->out.comp->text_name) + ppl_logevent(("Initialised %s compression", + s->out.comp->text_name)); + + /* + * Now our end of the key exchange is complete, we can send all + * our queued higher-layer packets. Transfer the whole of the next + * layer's outgoing queue on to our own. + */ + pq_concatenate(s->ppl.out_pq, s->ppl.out_pq, &s->pq_out_higher); + + /* + * Expect SSH2_MSG_NEWKEYS from server. + */ + crMaybeWaitUntilV((pktin = ssh2_transport_pop(s)) != NULL); + if (pktin->type != SSH2_MSG_NEWKEYS) { + ssh_proto_error(s->ppl.ssh, "Received unexpected packet when " + "expecting SSH_MSG_NEWKEYS, type %d (%s)", + pktin->type, + ssh2_pkt_type(s->ppl.bpp->pls->kctx, + s->ppl.bpp->pls->actx, + pktin->type)); + return; + } + /* Start counting down the incoming-data limit for these cipher keys. */ + s->stats->in.running = TRUE; + s->stats->in.remaining = s->max_data_size; + + /* + * We've seen server NEWKEYS, so create and initialise + * server-to-client session keys. + */ + { + strbuf *cipher_key = strbuf_new(); + strbuf *cipher_iv = strbuf_new(); + strbuf *mac_key = strbuf_new(); + + if (s->in.cipher) { + ssh2_mkkey(s, cipher_iv, s->K, s->exchange_hash, 'B', + s->in.cipher->blksize); + ssh2_mkkey(s, cipher_key, s->K, s->exchange_hash, 'D', + s->in.cipher->padded_keybytes); + } + if (s->in.mac) { + ssh2_mkkey(s, mac_key, s->K, s->exchange_hash, 'F', + s->in.mac->keylen); + } + + ssh2_bpp_new_incoming_crypto( + s->ppl.bpp, + s->in.cipher, cipher_key->u, cipher_iv->u, + s->in.mac, s->in.etm_mode, mac_key->u, + s->in.comp); + + strbuf_free(cipher_key); + strbuf_free(cipher_iv); + strbuf_free(mac_key); + } + + if (s->in.cipher) + ppl_logevent(("Initialised %.200s server->client encryption", + s->in.cipher->text_name)); + if (s->in.mac) + ppl_logevent(("Initialised %.200s server->client MAC algorithm%s%s", + s->in.mac->text_name, + s->in.etm_mode ? " (in ETM mode)" : "", + (s->in.cipher->required_mac ? + " (required by cipher)" : ""))); + if (s->in.comp->text_name) + ppl_logevent(("Initialised %s decompression", + s->in.comp->text_name)); + + /* + * Free shared secret. + */ + freebn(s->K); s->K = NULL; + + /* + * Update the specials menu to list the remaining uncertified host + * keys. + */ + update_specials_menu(s->ppl.frontend); + + /* + * Key exchange is over. Loop straight back round if we have a + * deferred rekey reason. + */ + if (s->deferred_rekey_reason) { + ppl_logevent(("%s", s->deferred_rekey_reason)); + pktin = NULL; + s->deferred_rekey_reason = NULL; + goto begin_key_exchange; + } + + /* + * Otherwise, schedule a timer for our next rekey. + */ + s->kex_in_progress = FALSE; + s->last_rekey = GETTICKCOUNT(); + (void) ssh2_transport_timer_update(s, 0); + + /* + * Now we're encrypting. Get the next-layer protocol started if it + * hasn't already, and then sit here waiting for reasons to go + * back to the start and do a repeat key exchange. One of those + * reasons is that we receive KEXINIT from the other end; the + * other is if we find rekey_reason is non-NULL, i.e. we've + * decided to initiate a rekey ourselves for some reason. + */ + if (!s->higher_layer_ok) { + pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH2_MSG_SERVICE_REQUEST); + put_stringz(pktout, s->higher_layer->vt->name); + pq_push(s->ppl.out_pq, pktout); + crMaybeWaitUntilV((pktin = ssh2_transport_pop(s)) != NULL); + if (pktin->type != SSH2_MSG_SERVICE_ACCEPT) { + ssh_sw_abort(s->ppl.ssh, "Server refused request to start " + "'%s' protocol", s->higher_layer->vt->name); + return; + } + + s->higher_layer_ok = TRUE; + queue_idempotent_callback(&s->higher_layer->ic_process_queue); + } + + s->rekey_class = RK_NONE; + do { + crReturnV; + + /* Pass through outgoing packets from the higher layer. */ + pq_concatenate(s->ppl.out_pq, s->ppl.out_pq, &s->pq_out_higher); + + /* Wait for either a KEXINIT, or something setting + * s->rekey_class. This call to ssh2_transport_pop also has + * the side effect of transferring incoming packets _to_ the + * higher layer (via filter_queue). */ + if ((pktin = ssh2_transport_pop(s)) != NULL) { + if (pktin->type != SSH2_MSG_KEXINIT) { + ssh_proto_error(s->ppl.ssh, "Received unexpected transport-" + "layer packet outside a key exchange, " + "type %d (%s)", pktin->type, + ssh2_pkt_type(s->ppl.bpp->pls->kctx, + s->ppl.bpp->pls->actx, + pktin->type)); + return; + } + pq_push_front(s->ppl.in_pq, pktin); + ppl_logevent(("Server initiated key re-exchange")); + s->rekey_class = RK_SERVER; + } + + if (s->rekey_class == RK_POST_USERAUTH) { + /* + * userauth has seen a USERAUTH_SUCCEEDED. For a couple of + * reasons, this may be the moment to do an immediate + * rekey with different parameters. But it may not; so + * here we turn that rekey class into either RK_NONE or + * RK_NORMAL. + * + * One is to turn on delayed compression. We do this by a + * rekey to work around a protocol design bug: + * draft-miller-secsh-compression-delayed-00 says that you + * negotiate delayed compression in the first key + * exchange, and both sides start compressing when the + * server has sent USERAUTH_SUCCESS. This has a race + * condition -- the server can't know when the client has + * seen it, and thus which incoming packets it should + * treat as compressed. + * + * Instead, we do the initial key exchange without + * offering the delayed methods, but note if the server + * offers them; when we get here, if a delayed method was + * available that was higher on our list than what we got, + * we initiate a rekey in which we _do_ list the delayed + * methods (and hopefully get it as a result). Subsequent + * rekeys will do the same. + * + * Another reason for a rekey at this point is if we've + * done a GSS key exchange and don't have anything in our + * transient hostkey cache, in which case we should make + * an attempt to populate the cache now. + */ + assert(!s->userauth_succeeded); /* should only happen once */ + s->userauth_succeeded = TRUE; + if (s->pending_compression) { + s->rekey_reason = "enabling delayed compression"; + s->rekey_class = RK_NORMAL; + } else if (s->need_gss_transient_hostkey) { + s->rekey_reason = "populating transient host key cache"; + s->rekey_class = RK_NORMAL; + } else { + /* No need to rekey at this time. */ + s->rekey_class = RK_NONE; + } + } + + if (!s->rekey_class) { + /* If we don't yet have any other reason to rekey, check + * if we've hit our data limit in either direction. */ + if (!s->stats->in.running) { + s->rekey_reason = "too much data received"; + s->rekey_class = RK_NORMAL; + } else if (!s->stats->out.running) { + s->rekey_reason = "too much data sent"; + s->rekey_class = RK_NORMAL; + } + } + + if (s->rekey_class != RK_NONE && s->rekey_class != RK_SERVER) { + /* + * Special case: if the server bug is set that doesn't + * allow rekeying, we give a different log message and + * continue waiting. (If such a server _initiates_ a + * rekey, we process it anyway!) + */ + if ((s->ppl.remote_bugs & BUG_SSH2_REKEY)) { + ppl_logevent(("Server bug prevents key re-exchange (%s)", + s->rekey_reason)); + /* Reset the counters, so that at least this message doesn't + * hit the event log _too_ often. */ + s->stats->in.running = s->stats->out.running = TRUE; + s->stats->in.remaining = s->stats->out.remaining = + s->max_data_size; + (void) ssh2_transport_timer_update(s, 0); + s->rekey_class = RK_NONE; + } else { + ppl_logevent(("Initiating key re-exchange (%s)", + s->rekey_reason)); + } + } + } while (s->rekey_reason == RK_NONE); + + /* Once we exit the above loop, we really are rekeying. */ + goto begin_key_exchange; + + crFinishV; +} + +static void ssh2_transport_higher_layer_packet_callback(void *context) +{ + PacketProtocolLayer *ppl = (PacketProtocolLayer *)context; + ssh_ppl_process_queue(ppl); +} + +static void ssh2_transport_timer(void *ctx, unsigned long now) +{ + struct ssh2_transport_state *s = (struct ssh2_transport_state *)ctx; + unsigned long mins; + unsigned long ticks; + + if (s->kex_in_progress || now != s->next_rekey) + return; + + mins = sanitise_rekey_time(conf_get_int(s->conf, CONF_ssh_rekey_time), 60); + if (mins == 0) + return; + + /* Rekey if enough time has elapsed */ + ticks = mins * 60 * TICKSPERSEC; + if (now - s->last_rekey > ticks - 30*TICKSPERSEC) { + s->rekey_reason = "timeout"; + s->rekey_class = RK_NORMAL; + queue_idempotent_callback(&s->ppl.ic_process_queue); + return; + } + +#ifndef NO_GSSAPI + /* + * Rekey now if we have a new cred or context expires this cycle, + * but not if this is unsafe. + */ + if (conf_get_int(s->conf, CONF_gssapirekey)) { + ssh2_transport_gss_update(s, FALSE); + if ((s->gss_status & GSS_KEX_CAPABLE) != 0 && + (s->gss_status & GSS_CTXT_MAYFAIL) == 0 && + (s->gss_status & (GSS_CRED_UPDATED|GSS_CTXT_EXPIRES)) != 0) { + s->rekey_reason = "GSS credentials updated"; + s->rekey_class = RK_GSS_UPDATE; + queue_idempotent_callback(&s->ppl.ic_process_queue); + return; + } + } +#endif + + /* Try again later. */ + (void) ssh2_transport_timer_update(s, 0); +} + +/* + * The rekey_time is zero except when re-configuring. + * + * We either schedule the next timer and return 0, or return 1 to run the + * callback now, which will call us again to re-schedule on completion. + */ +static int ssh2_transport_timer_update(struct ssh2_transport_state *s, + unsigned long rekey_time) +{ + unsigned long mins; + unsigned long ticks; + + mins = sanitise_rekey_time(conf_get_int(s->conf, CONF_ssh_rekey_time), 60); + ticks = mins * 60 * TICKSPERSEC; + + /* Handle change from previous setting */ + if (rekey_time != 0 && rekey_time != mins) { + unsigned long next; + unsigned long now = GETTICKCOUNT(); + + mins = rekey_time; + ticks = mins * 60 * TICKSPERSEC; + next = s->last_rekey + ticks; + + /* If overdue, caller will rekey synchronously now */ + if (now - s->last_rekey > ticks) + return 1; + ticks = next - now; + } + +#ifndef NO_GSSAPI + if (s->gss_kex_used) { + /* + * If we've used GSSAPI key exchange, then we should + * periodically check whether we need to do another one to + * pass new credentials to the server. + */ + unsigned long gssmins; + + /* Check cascade conditions more frequently if configured */ + gssmins = sanitise_rekey_time( + conf_get_int(s->conf, CONF_gssapirekey), GSS_DEF_REKEY_MINS); + if (gssmins > 0) { + if (gssmins < mins) + ticks = (mins = gssmins) * 60 * TICKSPERSEC; + + if ((s->gss_status & GSS_KEX_CAPABLE) != 0) { + /* + * Run next timer even sooner if it would otherwise be + * too close to the context expiration time + */ + if ((s->gss_status & GSS_CTXT_EXPIRES) == 0 && + s->gss_ctxt_lifetime - mins * 60 < 2 * MIN_CTXT_LIFETIME) + ticks -= 2 * MIN_CTXT_LIFETIME * TICKSPERSEC; + } + } + } +#endif + + /* Schedule the next timer */ + s->next_rekey = schedule_timer(ticks, ssh2_transport_timer, s); + return 0; +} + +static void ssh2_transport_dialog_callback(void *loginv, int ret) +{ + struct ssh2_transport_state *s = (struct ssh2_transport_state *)loginv; + s->dlgret = ret; + ssh_ppl_process_queue(&s->ppl); +} + +#ifndef NO_GSSAPI +/* + * This is called at the beginning of each SSH rekey to determine + * whether we are GSS capable, and if we did GSS key exchange, and are + * delegating credentials, it is also called periodically to determine + * whether we should rekey in order to delegate (more) fresh + * credentials. This is called "credential cascading". + * + * On Windows, with SSPI, we may not get the credential expiration, as + * Windows automatically renews from cached passwords, so the + * credential effectively never expires. Since we still want to + * cascade when the local TGT is updated, we use the expiration of a + * newly obtained context as a proxy for the expiration of the TGT. + */ +static void ssh2_transport_gss_update(struct ssh2_transport_state *s, + int definitely_rekeying) +{ + PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */ + int gss_stat; + time_t gss_cred_expiry; + unsigned long mins; + Ssh_gss_buf gss_sndtok; + Ssh_gss_buf gss_rcvtok; + Ssh_gss_ctx gss_ctx; + + s->gss_status = 0; + + /* + * Nothing to do if no GSSAPI libraries are configured or GSSAPI + * auth is not enabled. + */ + if (s->shgss->libs->nlibraries == 0) + return; + if (!conf_get_int(s->conf, CONF_try_gssapi_auth) && + !conf_get_int(s->conf, CONF_try_gssapi_kex)) + return; + + /* Import server name and cache it */ + if (s->shgss->srv_name == GSS_C_NO_NAME) { + gss_stat = s->shgss->lib->import_name( + s->shgss->lib, s->fullhostname, &s->shgss->srv_name); + if (gss_stat != SSH_GSS_OK) { + if (gss_stat == SSH_GSS_BAD_HOST_NAME) + ppl_logevent(("GSSAPI import name failed - Bad service name;" + " won't use GSS key exchange")); + else + ppl_logevent(("GSSAPI import name failed;" + " won't use GSS key exchange")); + return; + } + } + + /* + * Do we (still) have credentials? Capture the credential + * expiration when available + */ + gss_stat = s->shgss->lib->acquire_cred( + s->shgss->lib, &gss_ctx, &gss_cred_expiry); + if (gss_stat != SSH_GSS_OK) + return; + + SSH_GSS_CLEAR_BUF(&gss_sndtok); + SSH_GSS_CLEAR_BUF(&gss_rcvtok); + + /* + * When acquire_cred yields no useful expiration, get a proxy for + * the cred expiration from the context expiration. + */ + gss_stat = s->shgss->lib->init_sec_context( + s->shgss->lib, &gss_ctx, s->shgss->srv_name, + 0 /* don't delegate */, &gss_rcvtok, &gss_sndtok, + (gss_cred_expiry == GSS_NO_EXPIRATION ? &gss_cred_expiry : NULL), + &s->gss_ctxt_lifetime); + + /* This context was for testing only. */ + if (gss_ctx) + s->shgss->lib->release_cred(s->shgss->lib, &gss_ctx); + + if (gss_stat != SSH_GSS_OK && + gss_stat != SSH_GSS_S_CONTINUE_NEEDED) { + /* + * No point in verbosely interrupting the user to tell them we + * couldn't get GSS credentials, if this was only a check + * between key exchanges to see if fresh ones were available. + * When we do do a rekey, this message (if displayed) will + * appear among the standard rekey blurb, but when we're not, + * it shouldn't pop up all the time regardless. + */ + if (definitely_rekeying) + ppl_logevent(("No GSSAPI security context available")); + + return; + } + + if (gss_sndtok.length) + s->shgss->lib->free_tok(s->shgss->lib, &gss_sndtok); + + s->gss_status |= GSS_KEX_CAPABLE; + + /* + * When rekeying to cascade, avoding doing this too close to the + * context expiration time, since the key exchange might fail. + */ + if (s->gss_ctxt_lifetime < MIN_CTXT_LIFETIME) + s->gss_status |= GSS_CTXT_MAYFAIL; + + /* + * If we're not delegating credentials, rekeying is not used to + * refresh them. We must avoid setting GSS_CRED_UPDATED or + * GSS_CTXT_EXPIRES when credential delegation is disabled. + */ + if (conf_get_int(s->conf, CONF_gssapifwd) == 0) + return; + + if (s->gss_cred_expiry != GSS_NO_EXPIRATION && + difftime(gss_cred_expiry, s->gss_cred_expiry) > 0) + s->gss_status |= GSS_CRED_UPDATED; + + mins = sanitise_rekey_time( + conf_get_int(s->conf, CONF_gssapirekey), GSS_DEF_REKEY_MINS); + if (mins > 0 && s->gss_ctxt_lifetime <= mins * 60) + s->gss_status |= GSS_CTXT_EXPIRES; +} + +/* + * Data structure managing host keys in sessions based on GSSAPI KEX. + * + * In a session we started with a GSSAPI key exchange, the concept of + * 'host key' has completely different lifetime and security semantics + * from the usual ones. Per RFC 4462 section 2.1, we assume that any + * host key delivered to us in the course of a GSSAPI key exchange is + * _solely_ there to use as a transient fallback within the same + * session, if at the time of a subsequent rekey the GSS credentials + * are temporarily invalid and so a non-GSS KEX method has to be used. + * + * In particular, in a GSS-based SSH deployment, host keys may not + * even _be_ persistent identities for the server; it would be + * legitimate for a server to generate a fresh one routinely if it + * wanted to, like SSH-1 server keys. + * + * So, in this mode, we never touch the persistent host key cache at + * all, either to check keys against it _or_ to store keys in it. + * Instead, we maintain an in-memory cache of host keys that have been + * mentioned in GSS key exchanges within this particular session, and + * we permit precisely those host keys in non-GSS rekeys. + */ +struct ssh_transient_hostkey_cache_entry { + const ssh_keyalg *alg; + strbuf *pub_blob; +}; + +static int ssh_transient_hostkey_cache_cmp(void *av, void *bv) +{ + const struct ssh_transient_hostkey_cache_entry + *a = (const struct ssh_transient_hostkey_cache_entry *)av, + *b = (const struct ssh_transient_hostkey_cache_entry *)bv; + return strcmp(a->alg->ssh_id, b->alg->ssh_id); +} + +static int ssh_transient_hostkey_cache_find(void *av, void *bv) +{ + const ssh_keyalg *aalg = (const ssh_keyalg *)av; + const struct ssh_transient_hostkey_cache_entry + *b = (const struct ssh_transient_hostkey_cache_entry *)bv; + return strcmp(aalg->ssh_id, b->alg->ssh_id); +} + +static void ssh_init_transient_hostkey_store( + struct ssh2_transport_state *s) +{ + s->transient_hostkey_cache = + newtree234(ssh_transient_hostkey_cache_cmp); +} + +static void ssh_cleanup_transient_hostkey_store( + struct ssh2_transport_state *s) +{ + struct ssh_transient_hostkey_cache_entry *ent; + while ((ent = delpos234(s->transient_hostkey_cache, 0)) != NULL) { + strbuf_free(ent->pub_blob); + sfree(ent); + } + freetree234(s->transient_hostkey_cache); +} + +static void ssh_store_transient_hostkey( + struct ssh2_transport_state *s, ssh_key *key) +{ + struct ssh_transient_hostkey_cache_entry *ent, *retd; + + if ((ent = find234(s->transient_hostkey_cache, (void *)ssh_key_alg(key), + ssh_transient_hostkey_cache_find)) != NULL) { + strbuf_free(ent->pub_blob); + sfree(ent); + } + + ent = snew(struct ssh_transient_hostkey_cache_entry); + ent->alg = ssh_key_alg(key); + ent->pub_blob = strbuf_new(); + ssh_key_public_blob(key, BinarySink_UPCAST(ent->pub_blob)); + retd = add234(s->transient_hostkey_cache, ent); + assert(retd == ent); +} + +static int ssh_verify_transient_hostkey( + struct ssh2_transport_state *s, ssh_key *key) +{ + struct ssh_transient_hostkey_cache_entry *ent; + int toret = FALSE; + + if ((ent = find234(s->transient_hostkey_cache, (void *)ssh_key_alg(key), + ssh_transient_hostkey_cache_find)) != NULL) { + strbuf *this_blob = strbuf_new(); + ssh_key_public_blob(key, BinarySink_UPCAST(this_blob)); + + if (this_blob->len == ent->pub_blob->len && + !memcmp(this_blob->s, ent->pub_blob->s, + this_blob->len)) + toret = TRUE; + + strbuf_free(this_blob); + } + + return toret; +} + +static int ssh_have_transient_hostkey( + struct ssh2_transport_state *s, const ssh_keyalg *alg) +{ + struct ssh_transient_hostkey_cache_entry *ent = + find234(s->transient_hostkey_cache, (void *)alg, + ssh_transient_hostkey_cache_find); + return ent != NULL; +} + +static int ssh_have_any_transient_hostkey( + struct ssh2_transport_state *s) +{ + return count234(s->transient_hostkey_cache) > 0; +} + +ptrlen ssh2_transport_get_session_id(PacketProtocolLayer *ppl) +{ + struct ssh2_transport_state *s; + + assert(ppl->vt == &ssh2_transport_vtable); + s = FROMFIELD(ppl, struct ssh2_transport_state, ppl); + + assert(s->got_session_id); + return make_ptrlen(s->session_id, s->session_id_len); +} + +void ssh2_transport_notify_auth_done(PacketProtocolLayer *ppl) +{ + struct ssh2_transport_state *s; + + assert(ppl->vt == &ssh2_transport_vtable); + s = FROMFIELD(ppl, struct ssh2_transport_state, ppl); + + s->rekey_reason = NULL; /* will be filled in later */ + s->rekey_class = RK_POST_USERAUTH; + queue_idempotent_callback(&s->ppl.ic_process_queue); +} + +#endif /* NO_GSSAPI */ + +static int ssh2_transport_get_specials( + PacketProtocolLayer *ppl, add_special_fn_t add_special, void *ctx) +{ + struct ssh2_transport_state *s = + FROMFIELD(ppl, struct ssh2_transport_state, ppl); + int need_separator = FALSE; + int toret; + + if (ssh_ppl_get_specials(s->higher_layer, add_special, ctx)) { + need_separator = TRUE; + toret = TRUE; + } + + /* + * Don't bother offering rekey-based specials if we've decided the + * remote won't cope with it, since we wouldn't bother sending it + * if asked anyway. + */ + if (!(s->ppl.remote_bugs & BUG_SSH2_REKEY)) { + if (need_separator) { + add_special(ctx, NULL, SS_SEP, 0); + need_separator = FALSE; + } + + add_special(ctx, "Repeat key exchange", SS_REKEY, 0); + toret = TRUE; + + if (s->n_uncert_hostkeys) { + int i; + + add_special(ctx, NULL, SS_SEP, 0); + add_special(ctx, "Cache new host key type", SS_SUBMENU, 0); + for (i = 0; i < s->n_uncert_hostkeys; i++) { + const ssh_keyalg *alg = + hostkey_algs[s->uncert_hostkeys[i]].alg; + + add_special(ctx, alg->ssh_id, SS_XCERT, s->uncert_hostkeys[i]); + } + add_special(ctx, NULL, SS_EXITMENU, 0); + } + } + + return toret; +} + +static void ssh2_transport_special_cmd(PacketProtocolLayer *ppl, + SessionSpecialCode code, int arg) +{ + struct ssh2_transport_state *s = + FROMFIELD(ppl, struct ssh2_transport_state, ppl); + + if (code == SS_REKEY) { + if (!s->kex_in_progress) { + s->rekey_reason = "at user request"; + s->rekey_class = RK_NORMAL; + queue_idempotent_callback(&s->ppl.ic_process_queue); + } + } else if (code == SS_XCERT) { + if (!s->kex_in_progress) { + s->hostkey_alg = hostkey_algs[arg].alg; + s->cross_certifying = TRUE; + s->rekey_reason = "cross-certifying new host key"; + s->rekey_class = RK_NORMAL; + queue_idempotent_callback(&s->ppl.ic_process_queue); + } + } else { + /* Send everything else to the next layer up. This includes + * SS_PING/SS_NOP, which we _could_ handle here - but it's + * better to put them in the connection layer, so they'll + * still work in bare connection mode. */ + ssh_ppl_special_cmd(s->higher_layer, code, arg); + } +} + +/* Safely convert rekey_time to unsigned long minutes */ +static unsigned long sanitise_rekey_time(int rekey_time, unsigned long def) +{ + if (rekey_time < 0 || rekey_time > MAX_TICK_MINS) + rekey_time = def; + return (unsigned long)rekey_time; +} + +static void ssh2_transport_set_max_data_size(struct ssh2_transport_state *s) +{ + s->max_data_size = parse_blocksize( + conf_get_str(s->conf, CONF_ssh_rekey_data)); +} + +static void ssh2_transport_reconfigure(PacketProtocolLayer *ppl, Conf *conf) +{ + struct ssh2_transport_state *s; + const char *rekey_reason = NULL; + int rekey_mandatory = FALSE; + unsigned long old_max_data_size, rekey_time; + int i; + + assert(ppl->vt == &ssh2_transport_vtable); + s = FROMFIELD(ppl, struct ssh2_transport_state, ppl); + + rekey_time = sanitise_rekey_time( + conf_get_int(conf, CONF_ssh_rekey_time), 60); + if (ssh2_transport_timer_update(s, rekey_time)) + rekey_reason = "timeout shortened"; + + old_max_data_size = s->max_data_size; + ssh2_transport_set_max_data_size(s); + if (old_max_data_size != s->max_data_size && + s->max_data_size != 0) { + if (s->max_data_size < old_max_data_size) { + unsigned long diff = old_max_data_size - s->max_data_size; + + /* Intentionally use bitwise OR instead of logical, so + * that we decrement both counters even if the first one + * runs out */ + if ((DTS_CONSUME(s->stats, out, diff) != 0) | + (DTS_CONSUME(s->stats, in, diff) != 0)) + rekey_reason = "data limit lowered"; + } else { + unsigned long diff = s->max_data_size - old_max_data_size; + if (s->stats->out.running) + s->stats->out.remaining += diff; + if (s->stats->in.running) + s->stats->in.remaining += diff; + } + } + + if (conf_get_int(s->conf, CONF_compression) != + conf_get_int(conf, CONF_compression)) { + rekey_reason = "compression setting changed"; + rekey_mandatory = TRUE; + } + + for (i = 0; i < CIPHER_MAX; i++) + if (conf_get_int_int(s->conf, CONF_ssh_cipherlist, i) != + conf_get_int_int(conf, CONF_ssh_cipherlist, i)) { + rekey_reason = "cipher settings changed"; + rekey_mandatory = TRUE; + } + if (conf_get_int(s->conf, CONF_ssh2_des_cbc) != + conf_get_int(conf, CONF_ssh2_des_cbc)) { + rekey_reason = "cipher settings changed"; + rekey_mandatory = TRUE; + } + + conf_free(s->conf); + s->conf = conf_copy(conf); + + if (rekey_reason) { + if (!s->kex_in_progress) { + s->rekey_reason = rekey_reason; + s->rekey_class = RK_NORMAL; + queue_idempotent_callback(&s->ppl.ic_process_queue); + } else if (rekey_mandatory) { + s->deferred_rekey_reason = rekey_reason; + } + } + + /* Also pass the configuration along to our higher layer */ + ssh_ppl_reconfigure(s->higher_layer, conf); +} + +static int ssh2_transport_want_user_input(PacketProtocolLayer *ppl) +{ + struct ssh2_transport_state *s = + FROMFIELD(ppl, struct ssh2_transport_state, ppl); + + /* Just delegate this to the higher layer */ + return ssh_ppl_want_user_input(s->higher_layer); +} + +static void ssh2_transport_got_user_input(PacketProtocolLayer *ppl) +{ + struct ssh2_transport_state *s = + FROMFIELD(ppl, struct ssh2_transport_state, ppl); + + /* Just delegate this to the higher layer */ + ssh_ppl_got_user_input(s->higher_layer); +} diff --git a/ssh2userauth.c b/ssh2userauth.c new file mode 100644 index 00000000..1e5a1207 --- /dev/null +++ b/ssh2userauth.c @@ -0,0 +1,1673 @@ +/* + * Packet protocol layer for the SSH-2 userauth protocol (RFC 4252). + */ + +#include + +#include "putty.h" +#include "ssh.h" +#include "sshbpp.h" +#include "sshppl.h" +#include "sshcr.h" + +#ifndef NO_GSSAPI +#include "sshgssc.h" +#include "sshgss.h" +#endif + +#define BANNER_LIMIT 131072 + +struct ssh2_userauth_state { + int crState; + + PacketProtocolLayer *transport_layer, *successor_layer; + Filename *keyfile; + int tryagent, change_username; + char *hostname, *fullhostname; + char *default_username; + int try_ki_auth, try_gssapi_auth, try_gssapi_kex_auth, gssapi_fwd; + + ptrlen session_id; + enum { + AUTH_TYPE_NONE, + AUTH_TYPE_PUBLICKEY, + AUTH_TYPE_PUBLICKEY_OFFER_LOUD, + AUTH_TYPE_PUBLICKEY_OFFER_QUIET, + AUTH_TYPE_PASSWORD, + AUTH_TYPE_GSSAPI, /* always QUIET */ + AUTH_TYPE_KEYBOARD_INTERACTIVE, + AUTH_TYPE_KEYBOARD_INTERACTIVE_QUIET + } type; + int done_service_req; + int need_pw, can_pubkey, can_passwd, can_keyb_inter; + int userpass_ret; + int tried_pubkey_config, done_agent; + struct ssh_connection_shared_gss_state *shgss; +#ifndef NO_GSSAPI + int can_gssapi; + int can_gssapi_keyex_auth; + int tried_gssapi; + int tried_gssapi_keyex_auth; + time_t gss_cred_expiry; + Ssh_gss_buf gss_buf; + Ssh_gss_buf gss_rcvtok, gss_sndtok; + Ssh_gss_stat gss_stat; +#endif + int kbd_inter_refused; + prompts_t *cur_prompt; + int num_prompts; + char *username; + char *password; + int got_username; + strbuf *publickey_blob; + int privatekey_available, privatekey_encrypted; + char *publickey_algorithm; + char *publickey_comment; + void *agent_response_to_free; + ptrlen agent_response; + BinarySource asrc[1]; /* for reading SSH agent response */ + size_t pkblob_pos_in_agent; + int keyi, nkeys; + ptrlen pk, alg, comment; + int len; + PktOut *pktout; + int want_user_input; + + agent_pending_query *auth_agent_query; + bufchain banner; + + PacketProtocolLayer ppl; +}; + +static void ssh2_userauth_free(PacketProtocolLayer *); +static void ssh2_userauth_process_queue(PacketProtocolLayer *); +static int ssh2_userauth_get_specials( + PacketProtocolLayer *ppl, add_special_fn_t add_special, void *ctx); +static void ssh2_userauth_special_cmd(PacketProtocolLayer *ppl, + SessionSpecialCode code, int arg); +static int ssh2_userauth_want_user_input(PacketProtocolLayer *ppl); +static void ssh2_userauth_got_user_input(PacketProtocolLayer *ppl); +static void ssh2_userauth_reconfigure(PacketProtocolLayer *ppl, Conf *conf); + +static void ssh2_userauth_agent_query(struct ssh2_userauth_state *, strbuf *); +static void ssh2_userauth_agent_callback(void *, void *, int); +static void ssh2_userauth_add_sigblob( + struct ssh2_userauth_state *s, PktOut *pkt, ptrlen pkblob, ptrlen sigblob); +static void ssh2_userauth_add_session_id( + struct ssh2_userauth_state *s, strbuf *sigdata); +#ifndef NO_GSSAPI +static PktOut *ssh2_userauth_gss_packet( + struct ssh2_userauth_state *s, const char *authtype); +#endif + +static const struct PacketProtocolLayerVtable ssh2_userauth_vtable = { + ssh2_userauth_free, + ssh2_userauth_process_queue, + ssh2_userauth_get_specials, + ssh2_userauth_special_cmd, + ssh2_userauth_want_user_input, + ssh2_userauth_got_user_input, + ssh2_userauth_reconfigure, + "ssh-userauth", +}; + +PacketProtocolLayer *ssh2_userauth_new( + PacketProtocolLayer *successor_layer, + const char *hostname, const char *fullhostname, + Filename *keyfile, int tryagent, + const char *default_username, int change_username, + int try_ki_auth, + int try_gssapi_auth, int try_gssapi_kex_auth, + int gssapi_fwd, struct ssh_connection_shared_gss_state *shgss) +{ + struct ssh2_userauth_state *s = snew(struct ssh2_userauth_state); + memset(s, 0, sizeof(*s)); + s->ppl.vt = &ssh2_userauth_vtable; + + s->successor_layer = successor_layer; + s->hostname = dupstr(hostname); + s->fullhostname = dupstr(fullhostname); + s->keyfile = filename_copy(keyfile); + s->tryagent = tryagent; + s->default_username = dupstr(default_username); + s->change_username = change_username; + s->try_ki_auth = try_ki_auth; + s->try_gssapi_auth = try_gssapi_auth; + s->try_gssapi_kex_auth = try_gssapi_kex_auth; + s->gssapi_fwd = gssapi_fwd; + s->shgss = shgss; + bufchain_init(&s->banner); + + return &s->ppl; +} + +void ssh2_userauth_set_transport_layer(PacketProtocolLayer *userauth, + PacketProtocolLayer *transport) +{ + struct ssh2_userauth_state *s = + FROMFIELD(userauth, struct ssh2_userauth_state, ppl); + s->transport_layer = transport; +} + +static void ssh2_userauth_free(PacketProtocolLayer *ppl) +{ + struct ssh2_userauth_state *s = + FROMFIELD(ppl, struct ssh2_userauth_state, ppl); + bufchain_clear(&s->banner); + + if (s->successor_layer) + ssh_ppl_free(s->successor_layer); + + sfree(s->agent_response_to_free); + if (s->auth_agent_query) + agent_cancel_query(s->auth_agent_query); + filename_free(s->keyfile); + sfree(s->default_username); + sfree(s->hostname); + sfree(s->fullhostname); + sfree(s); +} + +static void ssh2_userauth_filter_queue(struct ssh2_userauth_state *s) +{ + PktIn *pktin; + ptrlen string; + + while ((pktin = pq_peek(s->ppl.in_pq)) != NULL) { + switch (pktin->type) { + case SSH2_MSG_USERAUTH_BANNER: + string = get_string(pktin); + if (string.len > BANNER_LIMIT - bufchain_size(&s->banner)) + string.len = BANNER_LIMIT - bufchain_size(&s->banner); + sanitise_term_data(&s->banner, string.ptr, string.len); + pq_pop(s->ppl.in_pq); + break; + + default: + return; + } + } +} + +static PktIn *ssh2_userauth_pop(struct ssh2_userauth_state *s) +{ + ssh2_userauth_filter_queue(s); + return pq_pop(s->ppl.in_pq); +} + +static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) +{ + struct ssh2_userauth_state *s = + FROMFIELD(ppl, struct ssh2_userauth_state, ppl); + PktIn *pktin; + + ssh2_userauth_filter_queue(s); /* no matter why we were called */ + + crBegin(s->crState); + + s->done_service_req = FALSE; +#ifndef NO_GSSAPI + s->tried_gssapi = FALSE; + s->tried_gssapi_keyex_auth = FALSE; +#endif + + /* + * Misc one-time setup for authentication. + */ + s->publickey_blob = NULL; + s->session_id = ssh2_transport_get_session_id(s->transport_layer); + + /* + * Load the public half of any configured public key file for + * later use. + */ + if (!filename_is_null(s->keyfile)) { + int keytype; + ppl_logevent(("Reading key file \"%.150s\"", + filename_to_str(s->keyfile))); + keytype = key_type(s->keyfile); + if (keytype == SSH_KEYTYPE_SSH2 || + keytype == SSH_KEYTYPE_SSH2_PUBLIC_RFC4716 || + keytype == SSH_KEYTYPE_SSH2_PUBLIC_OPENSSH) { + const char *error; + s->publickey_blob = strbuf_new(); + if (ssh2_userkey_loadpub(s->keyfile, + &s->publickey_algorithm, + BinarySink_UPCAST(s->publickey_blob), + &s->publickey_comment, &error)) { + s->privatekey_available = (keytype == SSH_KEYTYPE_SSH2); + if (!s->privatekey_available) + ppl_logevent(("Key file contains public key only")); + s->privatekey_encrypted = + ssh2_userkey_encrypted(s->keyfile, NULL); + } else { + ppl_logevent(("Unable to load key (%s)", error)); + ppl_printf(("Unable to load key file \"%s\" (%s)\r\n", + filename_to_str(s->keyfile), error)); + strbuf_free(s->publickey_blob); + s->publickey_blob = NULL; + } + } else { + ppl_logevent(("Unable to use this key file (%s)", + key_type_to_str(keytype))); + ppl_printf(("Unable to use key file \"%s\" (%s)\r\n", + filename_to_str(s->keyfile), + key_type_to_str(keytype))); + s->publickey_blob = NULL; + } + } + + /* + * Find out about any keys Pageant has (but if there's a public + * key configured, filter out all others). + */ + s->nkeys = 0; + s->pkblob_pos_in_agent = 0; + if (s->tryagent && agent_exists()) { + ppl_logevent(("Pageant is running. Requesting keys.")); + + /* Request the keys held by the agent. */ + { + strbuf *request = strbuf_new_for_agent_query(); + put_byte(request, SSH2_AGENTC_REQUEST_IDENTITIES); + ssh2_userauth_agent_query(s, request); + strbuf_free(request); + crWaitUntilV(!s->auth_agent_query); + } + BinarySource_BARE_INIT( + s->asrc, s->agent_response.ptr, s->agent_response.len); + + get_uint32(s->asrc); /* skip length field */ + if (get_byte(s->asrc) == SSH2_AGENT_IDENTITIES_ANSWER) { + int keyi; + + s->nkeys = toint(get_uint32(s->asrc)); + + /* + * Vet the Pageant response to ensure that the key count + * and blob lengths make sense. + */ + if (s->nkeys < 0) { + ppl_logevent(("Pageant response contained a negative" + " key count %d", s->nkeys)); + s->nkeys = 0; + goto done_agent_query; + } else { + ppl_logevent(("Pageant has %d SSH-2 keys", s->nkeys)); + + /* See if configured key is in agent. */ + for (keyi = 0; keyi < s->nkeys; keyi++) { + size_t pos = s->asrc->pos; + ptrlen blob = get_string(s->asrc); + get_string(s->asrc); /* skip comment */ + if (get_err(s->asrc)) { + ppl_logevent(("Pageant response was truncated")); + s->nkeys = 0; + goto done_agent_query; + } + + if (s->publickey_blob && + blob.len == s->publickey_blob->len && + !memcmp(blob.ptr, s->publickey_blob->s, + s->publickey_blob->len)) { + ppl_logevent(("Pageant key #%d matches " + "configured key file", keyi)); + s->keyi = keyi; + s->pkblob_pos_in_agent = pos; + break; + } + } + if (s->publickey_blob && !s->pkblob_pos_in_agent) { + ppl_logevent(("Configured key file not in Pageant")); + s->nkeys = 0; + } + } + } else { + ppl_logevent(("Failed to get reply from Pageant")); + } + done_agent_query:; + } + + /* + * We repeat this whole loop, including the username prompt, + * until we manage a successful authentication. If the user + * types the wrong _password_, they can be sent back to the + * beginning to try another username, if this is configured on. + * (If they specify a username in the config, they are never + * asked, even if they do give a wrong password.) + * + * I think this best serves the needs of + * + * - the people who have no configuration, no keys, and just + * want to try repeated (username,password) pairs until they + * type both correctly + * + * - people who have keys and configuration but occasionally + * need to fall back to passwords + * + * - people with a key held in Pageant, who might not have + * logged in to a particular machine before; so they want to + * type a username, and then _either_ their key will be + * accepted, _or_ they will type a password. If they mistype + * the username they will want to be able to get back and + * retype it! + */ + s->got_username = FALSE; + while (1) { + /* + * Get a username. + */ + if (s->got_username && s->change_username) { + /* + * We got a username last time round this loop, and + * with change_username turned off we don't try to get + * it again. + */ + } else if ((s->username = s->default_username) == NULL) { + s->cur_prompt = new_prompts(s->ppl.frontend); + s->cur_prompt->to_server = TRUE; + s->cur_prompt->name = dupstr("SSH login name"); + add_prompt(s->cur_prompt, dupstr("login as: "), TRUE); + s->userpass_ret = get_userpass_input(s->cur_prompt, NULL); + while (1) { + while (s->userpass_ret < 0 && + bufchain_size(s->ppl.user_input) > 0) + s->userpass_ret = get_userpass_input( + s->cur_prompt, s->ppl.user_input); + + if (s->userpass_ret >= 0) + break; + + s->want_user_input = TRUE; + crReturnV; + s->want_user_input = FALSE; + } + if (!s->userpass_ret) { + /* + * get_userpass_input() failed to get a username. + * Terminate. + */ + free_prompts(s->cur_prompt); + ssh_user_close(s->ppl.ssh, "No username provided"); + return; + } + s->username = dupstr(s->cur_prompt->prompts[0]->result); + free_prompts(s->cur_prompt); + } else { + if ((flags & FLAG_VERBOSE) || (flags & FLAG_INTERACTIVE)) + ppl_printf(("Using username \"%s\".\r\n", s->username)); + } + s->got_username = TRUE; + + /* + * Send an authentication request using method "none": (a) + * just in case it succeeds, and (b) so that we know what + * authentication methods we can usefully try next. + */ + s->ppl.bpp->pls->actx = SSH2_PKTCTX_NOAUTH; + + s->pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH2_MSG_USERAUTH_REQUEST); + put_stringz(s->pktout, s->username); + put_stringz(s->pktout, "ssh-connection");/* service requested */ + put_stringz(s->pktout, "none"); /* method */ + pq_push(s->ppl.out_pq, s->pktout); + s->type = AUTH_TYPE_NONE; + + s->tried_pubkey_config = FALSE; + s->kbd_inter_refused = FALSE; + + /* Reset agent request state. */ + s->done_agent = FALSE; + if (s->agent_response.ptr) { + if (s->pkblob_pos_in_agent) { + s->asrc->pos = s->pkblob_pos_in_agent; + } else { + s->asrc->pos = 9; /* skip length + type + key count */ + s->keyi = 0; + } + } + + while (1) { + ptrlen methods; + + methods.ptr = ""; + methods.len = 0; + + /* + * Wait for the result of the last authentication request. + */ + crMaybeWaitUntilV((pktin = ssh2_userauth_pop(s)) != NULL); + + /* + * Now is a convenient point to spew any banner material + * that we've accumulated. (This should ensure that when + * we exit the auth loop, we haven't any left to deal + * with.) + */ + { + /* + * Don't show the banner if we're operating in + * non-verbose non-interactive mode. (It's probably + * a script, which means nobody will read the + * banner _anyway_, and moreover the printing of + * the banner will screw up processing on the + * output of (say) plink.) + * + * The banner data has been sanitised already by this + * point, so we can safely pass it straight to + * from_backend. + */ + if (bufchain_size(&s->banner) && + (flags & (FLAG_VERBOSE | FLAG_INTERACTIVE))) { + while (bufchain_size(&s->banner) > 0) { + void *data; + int len; + bufchain_prefix(&s->banner, &data, &len); + from_backend(s->ppl.frontend, TRUE, data, len); + bufchain_consume(&s->banner, len); + } + } + bufchain_clear(&s->banner); + } + if (pktin->type == SSH2_MSG_USERAUTH_SUCCESS) { + ppl_logevent(("Access granted")); + goto userauth_success; + } + + if (pktin->type != SSH2_MSG_USERAUTH_FAILURE && + s->type != AUTH_TYPE_GSSAPI) { + ssh_proto_error(s->ppl.ssh, "Received unexpected packet " + "in response to authentication request, " + "type %d (%s)", pktin->type, + ssh2_pkt_type(s->ppl.bpp->pls->kctx, + s->ppl.bpp->pls->actx, + pktin->type)); + return; + } + + /* + * OK, we're now sitting on a USERAUTH_FAILURE message, so + * we can look at the string in it and know what we can + * helpfully try next. + */ + if (pktin->type == SSH2_MSG_USERAUTH_FAILURE) { + methods = get_string(pktin); + if (!get_bool(pktin)) { + /* + * We have received an unequivocal Access + * Denied. This can translate to a variety of + * messages, or no message at all. + * + * For forms of authentication which are attempted + * implicitly, by which I mean without printing + * anything in the window indicating that we're + * trying them, we should never print 'Access + * denied'. + * + * If we do print a message saying that we're + * attempting some kind of authentication, it's OK + * to print a followup message saying it failed - + * but the message may sometimes be more specific + * than simply 'Access denied'. + * + * Additionally, if we'd just tried password + * authentication, we should break out of this + * whole loop so as to go back to the username + * prompt (iff we're configured to allow + * username change attempts). + */ + if (s->type == AUTH_TYPE_NONE) { + /* do nothing */ + } else if (s->type == AUTH_TYPE_PUBLICKEY_OFFER_LOUD || + s->type == AUTH_TYPE_PUBLICKEY_OFFER_QUIET) { + if (s->type == AUTH_TYPE_PUBLICKEY_OFFER_LOUD) + ppl_printf(("Server refused our key\r\n")); + ppl_logevent(("Server refused our key")); + } else if (s->type == AUTH_TYPE_PUBLICKEY) { + /* This _shouldn't_ happen except by a + * protocol bug causing client and server to + * disagree on what is a correct signature. */ + ppl_printf(("Server refused public-key signature" + " despite accepting key!\r\n")); + ppl_logevent(("Server refused public-key signature" + " despite accepting key!")); + } else if (s->type==AUTH_TYPE_KEYBOARD_INTERACTIVE_QUIET) { + /* quiet, so no ppl_printf */ + ppl_logevent(("Server refused keyboard-interactive " + "authentication")); + } else if (s->type==AUTH_TYPE_GSSAPI) { + /* always quiet, so no ppl_printf */ + /* also, the code down in the GSSAPI block has + * already logged this in the Event Log */ + } else if (s->type == AUTH_TYPE_KEYBOARD_INTERACTIVE) { + ppl_logevent(("Keyboard-interactive authentication " + "failed")); + ppl_printf(("Access denied\r\n")); + } else { + assert(s->type == AUTH_TYPE_PASSWORD); + ppl_logevent(("Password authentication failed")); + ppl_printf(("Access denied\r\n")); + + if (s->change_username) { + /* XXX perhaps we should allow + * keyboard-interactive to do this too? */ + goto try_new_username; + } + } + } else { + ppl_printf(("Further authentication required\r\n")); + ppl_logevent(("Further authentication required")); + } + + s->can_pubkey = + in_commasep_string("publickey", methods.ptr, methods.len); + s->can_passwd = + in_commasep_string("password", methods.ptr, methods.len); + s->can_keyb_inter = + s->try_ki_auth && + in_commasep_string("keyboard-interactive", + methods.ptr, methods.len); +#ifndef NO_GSSAPI + s->can_gssapi = + s->try_gssapi_auth && + in_commasep_string("gssapi-with-mic", + methods.ptr, methods.len) && + s->shgss->libs->nlibraries > 0; + s->can_gssapi_keyex_auth = + s->try_gssapi_kex_auth && + in_commasep_string("gssapi-keyex", + methods.ptr, methods.len) && + s->shgss->libs->nlibraries > 0 && + s->shgss->ctx; +#endif + } + + s->ppl.bpp->pls->actx = SSH2_PKTCTX_NOAUTH; + +#ifndef NO_GSSAPI + if (s->can_gssapi_keyex_auth && !s->tried_gssapi_keyex_auth) { + + /* gssapi-keyex authentication */ + + s->type = AUTH_TYPE_GSSAPI; + s->tried_gssapi_keyex_auth = TRUE; + s->ppl.bpp->pls->actx = SSH2_PKTCTX_GSSAPI; + + if (s->shgss->lib->gsslogmsg) + ppl_logevent(("%s", s->shgss->lib->gsslogmsg)); + + ppl_logevent(("Trying gssapi-keyex...")); + s->pktout = ssh2_userauth_gss_packet(s, "gssapi-keyex"); + pq_push(s->ppl.out_pq, s->pktout); + s->shgss->lib->release_cred(s->shgss->lib, &s->shgss->ctx); + s->shgss->ctx = NULL; + + continue; + } else +#endif /* NO_GSSAPI */ + + if (s->can_pubkey && !s->done_agent && s->nkeys) { + + /* + * Attempt public-key authentication using a key from Pageant. + */ + + s->ppl.bpp->pls->actx = SSH2_PKTCTX_PUBLICKEY; + + ppl_logevent(("Trying Pageant key #%d", s->keyi)); + + /* Unpack key from agent response */ + s->pk = get_string(s->asrc); + s->comment = get_string(s->asrc); + { + BinarySource src[1]; + BinarySource_BARE_INIT(src, s->pk.ptr, s->pk.len); + s->alg = get_string(src); + } + + /* See if server will accept it */ + s->pktout = ssh_bpp_new_pktout( + s->ppl.bpp, SSH2_MSG_USERAUTH_REQUEST); + put_stringz(s->pktout, s->username); + put_stringz(s->pktout, "ssh-connection"); + /* service requested */ + put_stringz(s->pktout, "publickey"); + /* method */ + put_bool(s->pktout, FALSE); /* no signature included */ + put_stringpl(s->pktout, s->alg); + put_stringpl(s->pktout, s->pk); + pq_push(s->ppl.out_pq, s->pktout); + s->type = AUTH_TYPE_PUBLICKEY_OFFER_QUIET; + + crMaybeWaitUntilV((pktin = ssh2_userauth_pop(s)) != NULL); + if (pktin->type != SSH2_MSG_USERAUTH_PK_OK) { + + /* Offer of key refused, presumably via + * USERAUTH_FAILURE. Requeue for the next iteration. */ + pq_push_front(s->ppl.in_pq, pktin); + + } else { + strbuf *agentreq, *sigdata; + + if (flags & FLAG_VERBOSE) + ppl_printf(("Authenticating with public key " + "\"%.*s\" from agent\r\n", + PTRLEN_PRINTF(s->comment))); + + /* + * Server is willing to accept the key. + * Construct a SIGN_REQUEST. + */ + s->pktout = ssh_bpp_new_pktout( + s->ppl.bpp, SSH2_MSG_USERAUTH_REQUEST); + put_stringz(s->pktout, s->username); + put_stringz(s->pktout, "ssh-connection"); + /* service requested */ + put_stringz(s->pktout, "publickey"); + /* method */ + put_bool(s->pktout, TRUE); /* signature included */ + put_stringpl(s->pktout, s->alg); + put_stringpl(s->pktout, s->pk); + + /* Ask agent for signature. */ + agentreq = strbuf_new_for_agent_query(); + put_byte(agentreq, SSH2_AGENTC_SIGN_REQUEST); + put_stringpl(agentreq, s->pk); + /* Now the data to be signed... */ + sigdata = strbuf_new(); + ssh2_userauth_add_session_id(s, sigdata); + put_data(sigdata, s->pktout->data + 5, + s->pktout->length - 5); + put_stringsb(agentreq, sigdata); + /* And finally the (zero) flags word. */ + put_uint32(agentreq, 0); + ssh2_userauth_agent_query(s, agentreq); + strbuf_free(agentreq); + crWaitUntilV(!s->auth_agent_query); + + if (s->agent_response.ptr) { + ptrlen sigblob; + BinarySource src[1]; + BinarySource_BARE_INIT(src, s->agent_response.ptr, + s->agent_response.len); + get_uint32(src); /* skip length field */ + if (get_byte(src) == SSH2_AGENT_SIGN_RESPONSE && + (sigblob = get_string(src), !get_err(src))) { + ppl_logevent(("Sending Pageant's response")); + ssh2_userauth_add_sigblob(s, s->pktout, + s->pk, sigblob); + pq_push(s->ppl.out_pq, s->pktout); + s->type = AUTH_TYPE_PUBLICKEY; + } else { + /* FIXME: less drastic response */ + ssh_sw_abort(s->ppl.ssh, "Pageant failed to " + "provide a signature"); + return; + } + } + } + + /* Do we have any keys left to try? */ + if (s->pkblob_pos_in_agent) { + s->done_agent = TRUE; + s->tried_pubkey_config = TRUE; + } else { + s->keyi++; + if (s->keyi >= s->nkeys) + s->done_agent = TRUE; + } + + } else if (s->can_pubkey && s->publickey_blob && + s->privatekey_available && !s->tried_pubkey_config) { + + struct ssh2_userkey *key; /* not live over crReturn */ + char *passphrase; /* not live over crReturn */ + + s->ppl.bpp->pls->actx = SSH2_PKTCTX_PUBLICKEY; + + s->tried_pubkey_config = TRUE; + + /* + * Try the public key supplied in the configuration. + * + * First, offer the public blob to see if the server is + * willing to accept it. + */ + s->pktout = ssh_bpp_new_pktout( + s->ppl.bpp, SSH2_MSG_USERAUTH_REQUEST); + put_stringz(s->pktout, s->username); + put_stringz(s->pktout, "ssh-connection"); + /* service requested */ + put_stringz(s->pktout, "publickey"); /* method */ + put_bool(s->pktout, FALSE); + /* no signature included */ + put_stringz(s->pktout, s->publickey_algorithm); + put_string(s->pktout, s->publickey_blob->s, + s->publickey_blob->len); + pq_push(s->ppl.out_pq, s->pktout); + ppl_logevent(("Offered public key")); + + crMaybeWaitUntilV((pktin = ssh2_userauth_pop(s)) != NULL); + if (pktin->type != SSH2_MSG_USERAUTH_PK_OK) { + /* Key refused. Give up. */ + pq_push_front(s->ppl.in_pq, pktin); + s->type = AUTH_TYPE_PUBLICKEY_OFFER_LOUD; + continue; /* process this new message */ + } + ppl_logevent(("Offer of public key accepted")); + + /* + * Actually attempt a serious authentication using + * the key. + */ + if (flags & FLAG_VERBOSE) + ppl_printf(("Authenticating with public key \"%s\"\r\n", + s->publickey_comment)); + + key = NULL; + while (!key) { + const char *error; /* not live over crReturn */ + if (s->privatekey_encrypted) { + /* + * Get a passphrase from the user. + */ + s->cur_prompt = new_prompts(s->ppl.frontend); + s->cur_prompt->to_server = FALSE; + s->cur_prompt->name = dupstr("SSH key passphrase"); + add_prompt(s->cur_prompt, + dupprintf("Passphrase for key \"%.100s\": ", + s->publickey_comment), + FALSE); + s->userpass_ret = get_userpass_input( + s->cur_prompt, NULL); + while (1) { + while (s->userpass_ret < 0 && + bufchain_size(s->ppl.user_input) > 0) + s->userpass_ret = get_userpass_input( + s->cur_prompt, s->ppl.user_input); + + if (s->userpass_ret >= 0) + break; + + s->want_user_input = TRUE; + crReturnV; + s->want_user_input = FALSE; + } + if (!s->userpass_ret) { + /* Failed to get a passphrase. Terminate. */ + free_prompts(s->cur_prompt); + ssh_bpp_queue_disconnect( + s->ppl.bpp, "Unable to authenticate", + SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER); + ssh_user_close(s->ppl.ssh, "User aborted at " + "passphrase prompt"); + return; + } + passphrase = + dupstr(s->cur_prompt->prompts[0]->result); + free_prompts(s->cur_prompt); + } else { + passphrase = NULL; /* no passphrase needed */ + } + + /* + * Try decrypting the key. + */ + key = ssh2_load_userkey(s->keyfile, passphrase, &error); + if (passphrase) { + /* burn the evidence */ + smemclr(passphrase, strlen(passphrase)); + sfree(passphrase); + } + if (key == SSH2_WRONG_PASSPHRASE || key == NULL) { + if (passphrase && + (key == SSH2_WRONG_PASSPHRASE)) { + ppl_printf(("Wrong passphrase\r\n")); + key = NULL; + /* and loop again */ + } else { + ppl_printf(("Unable to load private key (%s)\r\n", + error)); + key = NULL; + break; /* try something else */ + } + } + } + + if (key) { + strbuf *pkblob, *sigdata, *sigblob; + + /* + * We have loaded the private key and the server + * has announced that it's willing to accept it. + * Hallelujah. Generate a signature and send it. + */ + s->pktout = ssh_bpp_new_pktout( + s->ppl.bpp, SSH2_MSG_USERAUTH_REQUEST); + put_stringz(s->pktout, s->username); + put_stringz(s->pktout, "ssh-connection"); + /* service requested */ + put_stringz(s->pktout, "publickey"); /* method */ + put_bool(s->pktout, TRUE); /* signature follows */ + put_stringz(s->pktout, ssh_key_ssh_id(key->key)); + pkblob = strbuf_new(); + ssh_key_public_blob(key->key, BinarySink_UPCAST(pkblob)); + put_string(s->pktout, pkblob->s, pkblob->len); + + /* + * The data to be signed is: + * + * string session-id + * + * followed by everything so far placed in the + * outgoing packet. + */ + sigdata = strbuf_new(); + ssh2_userauth_add_session_id(s, sigdata); + put_data(sigdata, s->pktout->data + 5, + s->pktout->length - 5); + sigblob = strbuf_new(); + ssh_key_sign(key->key, sigdata->s, sigdata->len, + BinarySink_UPCAST(sigblob)); + strbuf_free(sigdata); + ssh2_userauth_add_sigblob( + s, s->pktout, make_ptrlen(pkblob->s, pkblob->len), + make_ptrlen(sigblob->s, sigblob->len)); + strbuf_free(pkblob); + strbuf_free(sigblob); + + pq_push(s->ppl.out_pq, s->pktout); + ppl_logevent(("Sent public key signature")); + s->type = AUTH_TYPE_PUBLICKEY; + ssh_key_free(key->key); + sfree(key->comment); + sfree(key); + } + +#ifndef NO_GSSAPI + } else if (s->can_gssapi && !s->tried_gssapi) { + + /* gssapi-with-mic authentication */ + + ptrlen data; + + s->type = AUTH_TYPE_GSSAPI; + s->tried_gssapi = TRUE; + s->ppl.bpp->pls->actx = SSH2_PKTCTX_GSSAPI; + + if (s->shgss->lib->gsslogmsg) + ppl_logevent(("%s", s->shgss->lib->gsslogmsg)); + + /* Sending USERAUTH_REQUEST with "gssapi-with-mic" method */ + ppl_logevent(("Trying gssapi-with-mic...")); + s->pktout = ssh_bpp_new_pktout( + s->ppl.bpp, SSH2_MSG_USERAUTH_REQUEST); + put_stringz(s->pktout, s->username); + put_stringz(s->pktout, "ssh-connection"); + put_stringz(s->pktout, "gssapi-with-mic"); + ppl_logevent(("Attempting GSSAPI authentication")); + + /* add mechanism info */ + s->shgss->lib->indicate_mech(s->shgss->lib, &s->gss_buf); + + /* number of GSSAPI mechanisms */ + put_uint32(s->pktout, 1); + + /* length of OID + 2 */ + put_uint32(s->pktout, s->gss_buf.length + 2); + put_byte(s->pktout, SSH2_GSS_OIDTYPE); + + /* length of OID */ + put_byte(s->pktout, s->gss_buf.length); + + put_data(s->pktout, s->gss_buf.value, s->gss_buf.length); + pq_push(s->ppl.out_pq, s->pktout); + crMaybeWaitUntilV((pktin = ssh2_userauth_pop(s)) != NULL); + if (pktin->type != SSH2_MSG_USERAUTH_GSSAPI_RESPONSE) { + ppl_logevent(("GSSAPI authentication request refused")); + pq_push_front(s->ppl.in_pq, pktin); + continue; + } + + /* check returned packet ... */ + + data = get_string(pktin); + s->gss_rcvtok.value = (char *)data.ptr; + s->gss_rcvtok.length = data.len; + if (s->gss_rcvtok.length != s->gss_buf.length + 2 || + ((char *)s->gss_rcvtok.value)[0] != SSH2_GSS_OIDTYPE || + ((char *)s->gss_rcvtok.value)[1] != s->gss_buf.length || + memcmp((char *)s->gss_rcvtok.value + 2, + s->gss_buf.value,s->gss_buf.length) ) { + ppl_logevent(("GSSAPI authentication - wrong response " + "from server")); + continue; + } + + /* Import server name if not cached from KEX */ + if (s->shgss->srv_name == GSS_C_NO_NAME) { + s->gss_stat = s->shgss->lib->import_name( + s->shgss->lib, s->fullhostname, &s->shgss->srv_name); + if (s->gss_stat != SSH_GSS_OK) { + if (s->gss_stat == SSH_GSS_BAD_HOST_NAME) + ppl_logevent(("GSSAPI import name failed -" + " Bad service name")); + else + ppl_logevent(("GSSAPI import name failed")); + continue; + } + } + + /* Allocate our gss_ctx */ + s->gss_stat = s->shgss->lib->acquire_cred( + s->shgss->lib, &s->shgss->ctx, NULL); + if (s->gss_stat != SSH_GSS_OK) { + ppl_logevent(("GSSAPI authentication failed to get " + "credentials")); + continue; + } + + /* initial tokens are empty */ + SSH_GSS_CLEAR_BUF(&s->gss_rcvtok); + SSH_GSS_CLEAR_BUF(&s->gss_sndtok); + + /* now enter the loop */ + do { + /* + * When acquire_cred yields no useful expiration, go with + * the service ticket expiration. + */ + s->gss_stat = s->shgss->lib->init_sec_context + (s->shgss->lib, + &s->shgss->ctx, + s->shgss->srv_name, + s->gssapi_fwd, + &s->gss_rcvtok, + &s->gss_sndtok, + NULL, + NULL); + + if (s->gss_stat!=SSH_GSS_S_COMPLETE && + s->gss_stat!=SSH_GSS_S_CONTINUE_NEEDED) { + ppl_logevent(("GSSAPI authentication initialisation " + "failed")); + + if (s->shgss->lib->display_status(s->shgss->lib, + s->shgss->ctx, &s->gss_buf) == SSH_GSS_OK) { + ppl_logevent(("%s", (char *)s->gss_buf.value)); + sfree(s->gss_buf.value); + } + + pq_push_front(s->ppl.in_pq, pktin); + break; + } + ppl_logevent(("GSSAPI authentication initialised")); + + /* + * Client and server now exchange tokens until GSSAPI + * no longer says CONTINUE_NEEDED + */ + if (s->gss_sndtok.length != 0) { + s->pktout = + ssh_bpp_new_pktout( + s->ppl.bpp, SSH2_MSG_USERAUTH_GSSAPI_TOKEN); + put_string(s->pktout, + s->gss_sndtok.value, s->gss_sndtok.length); + pq_push(s->ppl.out_pq, s->pktout); + s->shgss->lib->free_tok(s->shgss->lib, &s->gss_sndtok); + } + + if (s->gss_stat == SSH_GSS_S_CONTINUE_NEEDED) { + crMaybeWaitUntilV((pktin = ssh2_userauth_pop(s)) != NULL); + if (pktin->type != SSH2_MSG_USERAUTH_GSSAPI_TOKEN) { + ppl_logevent(("GSSAPI authentication -" + " bad server response")); + s->gss_stat = SSH_GSS_FAILURE; + pq_push_front(s->ppl.in_pq, pktin); + break; + } + data = get_string(pktin); + s->gss_rcvtok.value = (char *)data.ptr; + s->gss_rcvtok.length = data.len; + } + } while (s-> gss_stat == SSH_GSS_S_CONTINUE_NEEDED); + + if (s->gss_stat != SSH_GSS_OK) { + s->shgss->lib->release_cred(s->shgss->lib, &s->shgss->ctx); + continue; + } + ppl_logevent(("GSSAPI authentication loop finished OK")); + + /* Now send the MIC */ + + s->pktout = ssh2_userauth_gss_packet(s, "gssapi-with-mic"); + pq_push(s->ppl.out_pq, s->pktout); + + s->shgss->lib->release_cred(s->shgss->lib, &s->shgss->ctx); + continue; +#endif + } else if (s->can_keyb_inter && !s->kbd_inter_refused) { + + /* + * Keyboard-interactive authentication. + */ + + s->type = AUTH_TYPE_KEYBOARD_INTERACTIVE; + + s->ppl.bpp->pls->actx = SSH2_PKTCTX_KBDINTER; + + s->pktout = ssh_bpp_new_pktout( + s->ppl.bpp, SSH2_MSG_USERAUTH_REQUEST); + put_stringz(s->pktout, s->username); + put_stringz(s->pktout, "ssh-connection"); + /* service requested */ + put_stringz(s->pktout, "keyboard-interactive"); + /* method */ + put_stringz(s->pktout, ""); /* lang */ + put_stringz(s->pktout, ""); /* submethods */ + pq_push(s->ppl.out_pq, s->pktout); + + ppl_logevent(("Attempting keyboard-interactive authentication")); + + crMaybeWaitUntilV((pktin = ssh2_userauth_pop(s)) != NULL); + if (pktin->type != SSH2_MSG_USERAUTH_INFO_REQUEST) { + /* Server is not willing to do keyboard-interactive + * at all (or, bizarrely but legally, accepts the + * user without actually issuing any prompts). + * Give up on it entirely. */ + pq_push_front(s->ppl.in_pq, pktin); + s->type = AUTH_TYPE_KEYBOARD_INTERACTIVE_QUIET; + s->kbd_inter_refused = TRUE; /* don't try it again */ + continue; + } + + /* + * Loop while the server continues to send INFO_REQUESTs. + */ + while (pktin->type == SSH2_MSG_USERAUTH_INFO_REQUEST) { + + ptrlen name, inst; + int i; + + /* + * We've got a fresh USERAUTH_INFO_REQUEST. + * Get the preamble and start building a prompt. + */ + name = get_string(pktin); + inst = get_string(pktin); + get_string(pktin); /* skip language tag */ + s->cur_prompt = new_prompts(s->ppl.frontend); + s->cur_prompt->to_server = TRUE; + + /* + * Get any prompt(s) from the packet. + */ + s->num_prompts = get_uint32(pktin); + for (i = 0; i < s->num_prompts; i++) { + ptrlen prompt; + int echo; + static char noprompt[] = + ": "; + + prompt = get_string(pktin); + echo = get_bool(pktin); + if (!prompt.len) { + prompt.ptr = noprompt; + prompt.len = lenof(noprompt)-1; + } + add_prompt(s->cur_prompt, mkstr(prompt), echo); + } + + if (name.len) { + /* FIXME: better prefix to distinguish from + * local prompts? */ + s->cur_prompt->name = + dupprintf("SSH server: %.*s", PTRLEN_PRINTF(name)); + s->cur_prompt->name_reqd = TRUE; + } else { + s->cur_prompt->name = + dupstr("SSH server authentication"); + s->cur_prompt->name_reqd = FALSE; + } + /* We add a prefix to try to make it clear that a prompt + * has come from the server. + * FIXME: ugly to print "Using..." in prompt _every_ + * time round. Can this be done more subtly? */ + /* Special case: for reasons best known to themselves, + * some servers send k-i requests with no prompts and + * nothing to display. Keep quiet in this case. */ + if (s->num_prompts || name.len || inst.len) { + s->cur_prompt->instruction = + dupprintf("Using keyboard-interactive " + "authentication.%s%.*s", + inst.len ? "\n" : "", + PTRLEN_PRINTF(inst)); + s->cur_prompt->instr_reqd = TRUE; + } else { + s->cur_prompt->instr_reqd = FALSE; + } + + /* + * Display any instructions, and get the user's + * response(s). + */ + s->userpass_ret = get_userpass_input(s->cur_prompt, NULL); + while (1) { + while (s->userpass_ret < 0 && + bufchain_size(s->ppl.user_input) > 0) + s->userpass_ret = get_userpass_input( + s->cur_prompt, s->ppl.user_input); + + if (s->userpass_ret >= 0) + break; + + s->want_user_input = TRUE; + crReturnV; + s->want_user_input = FALSE; + } + if (!s->userpass_ret) { + /* + * Failed to get responses. Terminate. + */ + free_prompts(s->cur_prompt); + ssh_bpp_queue_disconnect( + s->ppl.bpp, "Unable to authenticate", + SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER); + ssh_user_close(s->ppl.ssh, "User aborted during " + "keyboard-interactive authentication"); + return; + } + + /* + * Send the response(s) to the server. + */ + s->pktout = ssh_bpp_new_pktout( + s->ppl.bpp, SSH2_MSG_USERAUTH_INFO_RESPONSE); + put_uint32(s->pktout, s->num_prompts); + for (i=0; i < s->num_prompts; i++) { + put_stringz(s->pktout, + s->cur_prompt->prompts[i]->result); + } + s->pktout->minlen = 256; + pq_push(s->ppl.out_pq, s->pktout); + + /* + * Free the prompts structure from this iteration. + * If there's another, a new one will be allocated + * when we return to the top of this while loop. + */ + free_prompts(s->cur_prompt); + + /* + * Get the next packet in case it's another + * INFO_REQUEST. + */ + crMaybeWaitUntilV((pktin = ssh2_userauth_pop(s)) != NULL); + + } + + /* + * We should have SUCCESS or FAILURE now. + */ + pq_push_front(s->ppl.in_pq, pktin); + + } else if (s->can_passwd) { + + /* + * Plain old password authentication. + */ + int changereq_first_time; /* not live over crReturn */ + + s->ppl.bpp->pls->actx = SSH2_PKTCTX_PASSWORD; + + s->cur_prompt = new_prompts(s->ppl.frontend); + s->cur_prompt->to_server = TRUE; + s->cur_prompt->name = dupstr("SSH password"); + add_prompt(s->cur_prompt, dupprintf("%s@%s's password: ", + s->username, s->hostname), + FALSE); + + s->userpass_ret = get_userpass_input(s->cur_prompt, NULL); + while (1) { + while (s->userpass_ret < 0 && + bufchain_size(s->ppl.user_input) > 0) + s->userpass_ret = get_userpass_input( + s->cur_prompt, s->ppl.user_input); + + if (s->userpass_ret >= 0) + break; + + s->want_user_input = TRUE; + crReturnV; + s->want_user_input = FALSE; + } + if (!s->userpass_ret) { + /* + * Failed to get responses. Terminate. + */ + free_prompts(s->cur_prompt); + ssh_bpp_queue_disconnect( + s->ppl.bpp, "Unable to authenticate", + SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER); + ssh_user_close(s->ppl.ssh, "User aborted during password " + "authentication"); + return; + } + /* + * Squirrel away the password. (We may need it later if + * asked to change it.) + */ + s->password = dupstr(s->cur_prompt->prompts[0]->result); + free_prompts(s->cur_prompt); + + /* + * Send the password packet. + * + * We pad out the password packet to 256 bytes to make + * it harder for an attacker to find the length of the + * user's password. + * + * Anyone using a password longer than 256 bytes + * probably doesn't have much to worry about from + * people who find out how long their password is! + */ + s->pktout = ssh_bpp_new_pktout( + s->ppl.bpp, SSH2_MSG_USERAUTH_REQUEST); + put_stringz(s->pktout, s->username); + put_stringz(s->pktout, "ssh-connection"); + /* service requested */ + put_stringz(s->pktout, "password"); + put_bool(s->pktout, FALSE); + put_stringz(s->pktout, s->password); + s->pktout->minlen = 256; + pq_push(s->ppl.out_pq, s->pktout); + ppl_logevent(("Sent password")); + s->type = AUTH_TYPE_PASSWORD; + + /* + * Wait for next packet, in case it's a password change + * request. + */ + crMaybeWaitUntilV((pktin = ssh2_userauth_pop(s)) != NULL); + changereq_first_time = TRUE; + + while (pktin->type == SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ) { + + /* + * We're being asked for a new password + * (perhaps not for the first time). + * Loop until the server accepts it. + */ + + int got_new = FALSE; /* not live over crReturn */ + ptrlen prompt; /* not live over crReturn */ + + { + const char *msg; + if (changereq_first_time) + msg = "Server requested password change"; + else + msg = "Server rejected new password"; + ppl_logevent(("%s", msg)); + ppl_printf(("%s\r\n", msg)); + } + + prompt = get_string(pktin); + + s->cur_prompt = new_prompts(s->ppl.frontend); + s->cur_prompt->to_server = TRUE; + s->cur_prompt->name = dupstr("New SSH password"); + s->cur_prompt->instruction = mkstr(prompt); + s->cur_prompt->instr_reqd = TRUE; + /* + * There's no explicit requirement in the protocol + * for the "old" passwords in the original and + * password-change messages to be the same, and + * apparently some Cisco kit supports password change + * by the user entering a blank password originally + * and the real password subsequently, so, + * reluctantly, we prompt for the old password again. + * + * (On the other hand, some servers don't even bother + * to check this field.) + */ + add_prompt(s->cur_prompt, + dupstr("Current password (blank for previously entered password): "), + FALSE); + add_prompt(s->cur_prompt, dupstr("Enter new password: "), + FALSE); + add_prompt(s->cur_prompt, dupstr("Confirm new password: "), + FALSE); + + /* + * Loop until the user manages to enter the same + * password twice. + */ + while (!got_new) { + s->userpass_ret = get_userpass_input( + s->cur_prompt, NULL); + while (1) { + while (s->userpass_ret < 0 && + bufchain_size(s->ppl.user_input) > 0) + s->userpass_ret = get_userpass_input( + s->cur_prompt, s->ppl.user_input); + + if (s->userpass_ret >= 0) + break; + + s->want_user_input = TRUE; + crReturnV; + s->want_user_input = FALSE; + } + if (!s->userpass_ret) { + /* + * Failed to get responses. Terminate. + */ + /* burn the evidence */ + free_prompts(s->cur_prompt); + smemclr(s->password, strlen(s->password)); + sfree(s->password); + ssh_bpp_queue_disconnect( + s->ppl.bpp, "Unable to authenticate", + SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER); + ssh_user_close(s->ppl.ssh, "User aborted during " + "password changing"); + return; + } + + /* + * If the user specified a new original password + * (IYSWIM), overwrite any previously specified + * one. + * (A side effect is that the user doesn't have to + * re-enter it if they louse up the new password.) + */ + if (s->cur_prompt->prompts[0]->result[0]) { + smemclr(s->password, strlen(s->password)); + /* burn the evidence */ + sfree(s->password); + s->password = + dupstr(s->cur_prompt->prompts[0]->result); + } + + /* + * Check the two new passwords match. + */ + got_new = (strcmp(s->cur_prompt->prompts[1]->result, + s->cur_prompt->prompts[2]->result) + == 0); + if (!got_new) + /* They don't. Silly user. */ + ppl_printf(("Passwords do not match\r\n")); + + } + + /* + * Send the new password (along with the old one). + * (see above for padding rationale) + */ + s->pktout = ssh_bpp_new_pktout( + s->ppl.bpp, SSH2_MSG_USERAUTH_REQUEST); + put_stringz(s->pktout, s->username); + put_stringz(s->pktout, "ssh-connection"); + /* service requested */ + put_stringz(s->pktout, "password"); + put_bool(s->pktout, TRUE); + put_stringz(s->pktout, s->password); + put_stringz(s->pktout, + s->cur_prompt->prompts[1]->result); + free_prompts(s->cur_prompt); + s->pktout->minlen = 256; + pq_push(s->ppl.out_pq, s->pktout); + ppl_logevent(("Sent new password")); + + /* + * Now see what the server has to say about it. + * (If it's CHANGEREQ again, it's not happy with the + * new password.) + */ + crMaybeWaitUntilV((pktin = ssh2_userauth_pop(s)) != NULL); + changereq_first_time = FALSE; + + } + + /* + * We need to reexamine the current pktin at the top + * of the loop. Either: + * - we weren't asked to change password at all, in + * which case it's a SUCCESS or FAILURE with the + * usual meaning + * - we sent a new password, and the server was + * either OK with it (SUCCESS or FAILURE w/partial + * success) or unhappy with the _old_ password + * (FAILURE w/o partial success) + * In any of these cases, we go back to the top of + * the loop and start again. + */ + pq_push_front(s->ppl.in_pq, pktin); + + /* + * We don't need the old password any more, in any + * case. Burn the evidence. + */ + smemclr(s->password, strlen(s->password)); + sfree(s->password); + + } else { + ssh_bpp_queue_disconnect( + s->ppl.bpp, + "No supported authentication methods available", + SSH2_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE); + ssh_sw_abort(s->ppl.ssh, "No supported authentication methods " + "available (server sent: %.*s)", + PTRLEN_PRINTF(methods)); + return; + } + + } + try_new_username:; + } + + userauth_success: + /* + * We've just received USERAUTH_SUCCESS, and we haven't sent + * any packets since. Signal the transport layer to consider + * doing an immediate rekey, if it has any reason to want to. + */ + ssh2_transport_notify_auth_done(s->transport_layer); + + /* + * Finally, hand over to our successor layer, and return + * immediately without reaching the crFinishV: ssh_ppl_replace + * will have freed us, so crFinishV's zeroing-out of crState would + * be a use-after-free bug. + */ + { + PacketProtocolLayer *successor = s->successor_layer; + s->successor_layer = NULL; /* avoid freeing it ourself */ + ssh_ppl_replace(&s->ppl, successor); + return; /* we've just freed s, so avoid even touching s->crState */ + } + + crFinishV; +} + +static void ssh2_userauth_add_session_id( + struct ssh2_userauth_state *s, strbuf *sigdata) +{ + if (s->ppl.remote_bugs & BUG_SSH2_PK_SESSIONID) { + put_data(sigdata, s->session_id.ptr, s->session_id.len); + } else { + put_stringpl(sigdata, s->session_id); + } +} + +static void ssh2_userauth_agent_query( + struct ssh2_userauth_state *s, strbuf *req) +{ + void *response; + int response_len; + + sfree(s->agent_response_to_free); + s->agent_response_to_free = NULL; + + s->auth_agent_query = agent_query(req, &response, &response_len, + ssh2_userauth_agent_callback, s); + if (!s->auth_agent_query) + ssh2_userauth_agent_callback(s, response, response_len); +} + +static void ssh2_userauth_agent_callback(void *uav, void *reply, int replylen) +{ + struct ssh2_userauth_state *s = (struct ssh2_userauth_state *)uav; + + s->auth_agent_query = NULL; + s->agent_response_to_free = reply; + s->agent_response = make_ptrlen(reply, replylen); + + queue_idempotent_callback(&s->ppl.ic_process_queue); +} + +/* + * Helper function to add an SSH-2 signature blob to a packet. Expects + * to be shown the public key blob as well as the signature blob. + * Normally just appends the sig blob unmodified as a string, except + * that it optionally breaks it open and fiddle with it to work around + * BUG_SSH2_RSA_PADDING. + */ +static void ssh2_userauth_add_sigblob( + struct ssh2_userauth_state *s, PktOut *pkt, ptrlen pkblob, ptrlen sigblob) +{ + BinarySource pk[1], sig[1]; + BinarySource_BARE_INIT(pk, pkblob.ptr, pkblob.len); + BinarySource_BARE_INIT(sig, sigblob.ptr, sigblob.len); + + /* dmemdump(pkblob, pkblob_len); */ + /* dmemdump(sigblob, sigblob_len); */ + + /* + * See if this is in fact an ssh-rsa signature and a buggy + * server; otherwise we can just do this the easy way. + */ + if ((s->ppl.remote_bugs & BUG_SSH2_RSA_PADDING) && + ptrlen_eq_string(get_string(pk), "ssh-rsa") && + ptrlen_eq_string(get_string(sig), "ssh-rsa")) { + ptrlen mod_mp, sig_mp; + size_t sig_prefix_len; + + /* + * Find the modulus and signature integers. + */ + get_string(pk); /* skip over exponent */ + mod_mp = get_string(pk); /* remember modulus */ + sig_prefix_len = sig->pos; + sig_mp = get_string(sig); + if (get_err(pk) || get_err(sig)) + goto give_up; + + /* + * Find the byte length of the modulus, not counting leading + * zeroes. + */ + while (mod_mp.len > 0 && *(const char *)mod_mp.ptr == 0) { + mod_mp.len--; + mod_mp.ptr = (const char *)mod_mp.ptr + 1; + } + + /* debug(("modulus length is %d\n", len)); */ + /* debug(("signature length is %d\n", siglen)); */ + + if (mod_mp.len != sig_mp.len) { + strbuf *substr = strbuf_new(); + put_data(substr, sigblob.ptr, sig_prefix_len); + put_uint32(substr, mod_mp.len); + put_padding(substr, mod_mp.len - sig_mp.len, 0); + put_data(substr, sig_mp.ptr, sig_mp.len); + put_stringsb(pkt, substr); + return; + } + + /* Otherwise fall through and do it the easy way. We also come + * here as a fallback if we discover above that the key blob + * is misformatted in some way. */ + give_up:; + } + + put_stringpl(pkt, sigblob); +} + +#ifndef NO_GSSAPI +static PktOut *ssh2_userauth_gss_packet( + struct ssh2_userauth_state *s, const char *authtype) +{ + strbuf *sb; + PktOut *p; + Ssh_gss_buf buf; + Ssh_gss_buf mic; + + /* + * The mic is computed over the session id + intended + * USERAUTH_REQUEST packet. + */ + sb = strbuf_new(); + put_stringpl(sb, s->session_id); + put_byte(sb, SSH2_MSG_USERAUTH_REQUEST); + put_stringz(sb, s->username); + put_stringz(sb, "ssh-connection"); + put_stringz(sb, authtype); + + /* Compute the mic */ + buf.value = sb->s; + buf.length = sb->len; + s->shgss->lib->get_mic(s->shgss->lib, s->shgss->ctx, &buf, &mic); + strbuf_free(sb); + + /* Now we can build the real packet */ + if (strcmp(authtype, "gssapi-with-mic") == 0) { + p = ssh_bpp_new_pktout(s->ppl.bpp, SSH2_MSG_USERAUTH_GSSAPI_MIC); + } else { + p = ssh_bpp_new_pktout(s->ppl.bpp, SSH2_MSG_USERAUTH_REQUEST); + put_stringz(p, s->username); + put_stringz(p, "ssh-connection"); + put_stringz(p, authtype); + } + put_string(p, mic.value, mic.length); + + return p; +} +#endif + +static int ssh2_userauth_get_specials( + PacketProtocolLayer *ppl, add_special_fn_t add_special, void *ctx) +{ + /* No specials provided by this layer. */ + return FALSE; +} + +static void ssh2_userauth_special_cmd(PacketProtocolLayer *ppl, + SessionSpecialCode code, int arg) +{ + /* No specials provided by this layer. */ +} + +static int ssh2_userauth_want_user_input(PacketProtocolLayer *ppl) +{ + struct ssh2_userauth_state *s = + FROMFIELD(ppl, struct ssh2_userauth_state, ppl); + return s->want_user_input; +} + +static void ssh2_userauth_got_user_input(PacketProtocolLayer *ppl) +{ + struct ssh2_userauth_state *s = + FROMFIELD(ppl, struct ssh2_userauth_state, ppl); + if (s->want_user_input) + queue_idempotent_callback(&s->ppl.ic_process_queue); +} + +static void ssh2_userauth_reconfigure(PacketProtocolLayer *ppl, Conf *conf) +{ + struct ssh2_userauth_state *s = + FROMFIELD(ppl, struct ssh2_userauth_state, ppl); + ssh_ppl_reconfigure(s->successor_layer, conf); +} diff --git a/sshbpp.h b/sshbpp.h index b3eb9985..831145e6 100644 --- a/sshbpp.h +++ b/sshbpp.h @@ -17,6 +17,7 @@ struct BinaryPacketProtocolVtable { struct BinaryPacketProtocol { const struct BinaryPacketProtocolVtable *vt; bufchain *in_raw, *out_raw; + int input_eof; /* set this if in_raw will never be added to again */ PktInQueue in_pq; PktOutQueue out_pq; PacketLogSettings *pls; @@ -34,8 +35,11 @@ struct BinaryPacketProtocol { int remote_bugs; - int seen_disconnect; - char *error; + /* Set this if remote connection closure should not generate an + * error message (either because it's not to be treated as an + * error at all, or because some other error message has already + * been emitted). */ + int expect_close; }; #define ssh_bpp_handle_input(bpp) ((bpp)->vt->handle_input(bpp)) diff --git a/sshcommon.c b/sshcommon.c index 5a2270b4..ac4a6715 100644 --- a/sshcommon.c +++ b/sshcommon.c @@ -9,6 +9,7 @@ #include "putty.h" #include "ssh.h" #include "sshbpp.h" +#include "sshppl.h" #include "sshchan.h" /* ---------------------------------------------------------------------- @@ -630,6 +631,72 @@ const char *ssh2_pkt_type(Pkt_KCtx pkt_kctx, Pkt_ACtx pkt_actx, int type) #undef TRANSLATE_KEX #undef TRANSLATE_AUTH +/* ---------------------------------------------------------------------- + * Common helper function for clients and implementations of + * PacketProtocolLayer. + */ + +void ssh_logevent_and_free(void *frontend, char *message) +{ + logevent(frontend, message); + sfree(message); +} + +void ssh_ppl_replace(PacketProtocolLayer *old, PacketProtocolLayer *new) +{ + new->bpp = old->bpp; + ssh_ppl_setup_queues(new, old->in_pq, old->out_pq); + new->selfptr = old->selfptr; + new->user_input = old->user_input; + new->frontend = old->frontend; + new->ssh = old->ssh; + + *new->selfptr = new; + ssh_ppl_free(old); + + /* The new layer might need to be the first one that sends a + * packet, so trigger a call to its main coroutine immediately. If + * it doesn't need to go first, the worst that will do is return + * straight away. */ + queue_idempotent_callback(&new->ic_process_queue); +} + +void ssh_ppl_free(PacketProtocolLayer *ppl) +{ + delete_callbacks_for_context(ppl); + ppl->vt->free(ppl); +} + +static void ssh_ppl_ic_process_queue_callback(void *context) +{ + PacketProtocolLayer *ppl = (PacketProtocolLayer *)context; + ssh_ppl_process_queue(ppl); +} + +void ssh_ppl_setup_queues(PacketProtocolLayer *ppl, + PktInQueue *inq, PktOutQueue *outq) +{ + ppl->in_pq = inq; + ppl->out_pq = outq; + ppl->in_pq->pqb.ic = &ppl->ic_process_queue; + ppl->ic_process_queue.fn = ssh_ppl_ic_process_queue_callback; + ppl->ic_process_queue.ctx = ppl; + + /* If there's already something on the input queue, it will want + * handling immediately. */ + if (pq_peek(ppl->in_pq)) + queue_idempotent_callback(&ppl->ic_process_queue); +} + +void ssh_ppl_user_output_string_and_free(PacketProtocolLayer *ppl, char *text) +{ + /* Messages sent via this function are from the SSH layer, not + * from the server-side process, so they always have the stderr + * flag set. */ + from_backend(ppl->frontend, TRUE, text, strlen(text)); + sfree(text); +} + /* ---------------------------------------------------------------------- * Common helper functions for clients and implementations of * BinaryPacketProtocol. @@ -651,6 +718,7 @@ void ssh_bpp_common_setup(BinaryPacketProtocol *bpp) { pq_in_init(&bpp->in_pq); pq_out_init(&bpp->out_pq); + bpp->input_eof = FALSE; bpp->ic_in_raw.fn = ssh_bpp_input_raw_data_callback; bpp->ic_in_raw.ctx = bpp; bpp->ic_out_pq.fn = ssh_bpp_output_packet_callback; @@ -764,3 +832,37 @@ int verify_ssh_manual_host_key( return 0; } + +/* ---------------------------------------------------------------------- + * Common get_specials function for the two SSH-1 layers. + */ + +int ssh1_common_get_specials( + PacketProtocolLayer *ppl, add_special_fn_t add_special, void *ctx) +{ + /* + * Don't bother offering IGNORE if we've decided the remote + * won't cope with it, since we wouldn't bother sending it if + * asked anyway. + */ + if (!(ppl->remote_bugs & BUG_CHOKES_ON_SSH1_IGNORE)) { + add_special(ctx, "IGNORE message", SS_NOP, 0); + return TRUE; + } + + return FALSE; +} + +/* ---------------------------------------------------------------------- + * Other miscellaneous utility functions. + */ + +void free_rportfwd(struct ssh_rportfwd *rpf) +{ + if (rpf) { + sfree(rpf->log_description); + sfree(rpf->shost); + sfree(rpf->dhost); + sfree(rpf); + } +} diff --git a/sshgss.h b/sshgss.h index 7b2ed323..b1c04a35 100644 --- a/sshgss.h +++ b/sshgss.h @@ -200,6 +200,18 @@ struct ssh_gss_library { void *handle; }; +/* + * State that has to be shared between all GSSAPI-using parts of the + * same SSH connection, in particular between GSS key exchange and the + * subsequent trivial userauth method that reuses its output. + */ +struct ssh_connection_shared_gss_state { + struct ssh_gss_liblist *libs; + struct ssh_gss_library *lib; + Ssh_gss_name srv_name; + Ssh_gss_ctx ctx; +}; + #endif /* NO_GSSAPI */ #endif /*PUTTY_SSHGSS_H*/ diff --git a/sshppl.h b/sshppl.h new file mode 100644 index 00000000..29944df3 --- /dev/null +++ b/sshppl.h @@ -0,0 +1,144 @@ +/* + * Abstraction of the various layers of SSH packet-level protocol, + * general enough to take in all three of the main SSH-2 layers and + * both of the SSH-1 phases. + */ + +#ifndef PUTTY_SSHPPL_H +#define PUTTY_SSHPPL_H + +typedef void (*packet_handler_fn_t)(PacketProtocolLayer *ppl, PktIn *pktin); +typedef void (*add_special_fn_t)( + void *ctx, const char *text, SessionSpecialCode code, int arg); + +struct PacketProtocolLayerVtable { + void (*free)(PacketProtocolLayer *); + void (*process_queue)(PacketProtocolLayer *ppl); + int (*get_specials)( + PacketProtocolLayer *ppl, add_special_fn_t add_special, void *ctx); + void (*special_cmd)( + PacketProtocolLayer *ppl, SessionSpecialCode code, int arg); + int (*want_user_input)(PacketProtocolLayer *ppl); + void (*got_user_input)(PacketProtocolLayer *ppl); + void (*reconfigure)(PacketProtocolLayer *ppl, Conf *conf); + + /* Protocol-level name of this layer. */ + const char *name; +}; + +struct PacketProtocolLayer { + const struct PacketProtocolLayerVtable *vt; + + /* Link to the underlying SSH BPP. */ + BinaryPacketProtocol *bpp; + + /* Queue from which the layer receives its input packets, and one + * to put its output packets on. */ + PktInQueue *in_pq; + PktOutQueue *out_pq; + + /* Idempotent callback that in_pq will be linked to, causing a + * call to the process_queue method. in_pq points to this, so it + * will be automatically triggered by pushing things on the + * layer's input queue, but it can also be triggered on purpose. */ + IdempotentCallback ic_process_queue; + + /* Owner's pointer to this layer. Permits a layer to unilaterally + * abdicate in favour of a replacement, by overwriting this + * pointer and then freeing itself. */ + PacketProtocolLayer **selfptr; + + /* Bufchain of keyboard input from the user, for login prompts and + * similar. */ + bufchain *user_input; + + /* Logging and error-reporting facilities. */ + void *frontend; /* for logevent, dialog boxes etc */ + Ssh ssh; /* for session termination + assorted connection-layer ops */ + + /* Known bugs in the remote implementation. */ + unsigned remote_bugs; +}; + +#define ssh_ppl_process_queue(ppl) ((ppl)->vt->process_queue(ppl)) +#define ssh_ppl_get_specials(ppl, add, ctx) \ + ((ppl)->vt->get_specials(ppl, add, ctx)) +#define ssh_ppl_special_cmd(ppl, code, arg) \ + ((ppl)->vt->special_cmd(ppl, code, arg)) +#define ssh_ppl_want_user_input(ppl) ((ppl)->vt->want_user_input(ppl)) +#define ssh_ppl_got_user_input(ppl) ((ppl)->vt->got_user_input(ppl)) +#define ssh_ppl_reconfigure(ppl, conf) ((ppl)->vt->reconfigure(ppl, conf)) + +/* ssh_ppl_free is more than just a macro wrapper on the vtable; it + * does centralised parts of the freeing too. */ +void ssh_ppl_free(PacketProtocolLayer *ppl); + +/* Helper routine to point a PPL at its input and output queues. Also + * sets up the IdempotentCallback on the input queue to trigger a call + * to process_queue whenever packets are added to it. */ +void ssh_ppl_setup_queues(PacketProtocolLayer *ppl, + PktInQueue *inq, PktOutQueue *outq); + +/* Routine a PPL can call to abdicate in favour of a replacement, by + * overwriting ppl->selfptr. Has the side effect of freeing 'old', so + * if 'old' actually called this (which is likely) then it should + * avoid dereferencing itself on return from this function! */ +void ssh_ppl_replace(PacketProtocolLayer *old, PacketProtocolLayer *new); + +PacketProtocolLayer *ssh1_login_new( + Conf *conf, const char *host, int port, + PacketProtocolLayer *successor_layer); +PacketProtocolLayer *ssh1_connection_new( + Ssh ssh, Conf *conf, ConnectionLayer **cl_out); + +struct DataTransferStats; +struct ssh_connection_shared_gss_state; +PacketProtocolLayer *ssh2_transport_new( + Conf *conf, const char *host, int port, const char *fullhostname, + const char *client_greeting, const char *server_greeting, + struct ssh_connection_shared_gss_state *shgss, + struct DataTransferStats *stats, + PacketProtocolLayer *higher_layer); +PacketProtocolLayer *ssh2_userauth_new( + PacketProtocolLayer *successor_layer, + const char *hostname, const char *fullhostname, + Filename *keyfile, int tryagent, + const char *default_username, int change_username, + int try_ki_auth, + int try_gssapi_auth, int try_gssapi_kex_auth, + int gssapi_fwd, struct ssh_connection_shared_gss_state *shgss); +PacketProtocolLayer *ssh2_connection_new( + Ssh ssh, ssh_sharing_state *connshare, int is_simple, + Conf *conf, const char *peer_verstring, ConnectionLayer **cl_out); + +/* Can't put this in the userauth constructor without having a + * dependency loop at setup time (transport and userauth can't _both_ + * be constructed second and given a pointer to the other). */ +void ssh2_userauth_set_transport_layer(PacketProtocolLayer *userauth, + PacketProtocolLayer *transport); + +/* Convenience macro for protocol layers to send formatted strings to + * the Event Log. Assumes a function parameter called 'ppl' is in + * scope, and takes a double pair of parens because it passes a whole + * argument list to dupprintf. */ +#define ppl_logevent(params) ( \ + logevent_and_free((ppl)->frontend, dupprintf params)) + +/* Convenience macro for protocol layers to send formatted strings to + * the terminal. Also expects 'ppl' to be in scope and takes double + * parens. */ +#define ppl_printf(params) \ + ssh_ppl_user_output_string_and_free(ppl, dupprintf params) +void ssh_ppl_user_output_string_and_free(PacketProtocolLayer *ppl, char *text); + +/* Methods for userauth to communicate back to the transport layer */ +ptrlen ssh2_transport_get_session_id(PacketProtocolLayer *ssh2_transport_ptr); +void ssh2_transport_notify_auth_done(PacketProtocolLayer *ssh2_transport_ptr); + +/* Methods for ssh1login to pass protocol flags to ssh1connection */ +void ssh1_connection_set_local_protoflags(PacketProtocolLayer *ppl, int flags); + +/* Shared get_specials method between the two ssh1 layers */ +int ssh1_common_get_specials(PacketProtocolLayer *, add_special_fn_t, void *); + +#endif /* PUTTY_SSHPPL_H */ diff --git a/sshverstring.c b/sshverstring.c index ffead60c..612c3194 100644 --- a/sshverstring.c +++ b/sshverstring.c @@ -204,7 +204,10 @@ static void ssh_verstring_send(struct ssh_verstring_state *s) #define BPP_WAITFOR(minlen) do \ { \ crMaybeWaitUntilV( \ + s->bpp.input_eof || \ bufchain_size(s->bpp.in_raw) >= (minlen)); \ + if (s->bpp.input_eof) \ + goto eof; \ } while (0) void ssh_verstring_handle_input(BinaryPacketProtocol *bpp) @@ -359,13 +362,14 @@ void ssh_verstring_handle_input(BinaryPacketProtocol *bpp) * Unable to agree on a major protocol version at all. */ if (!ssh_version_includes_v2(s->our_protoversion)) { - s->bpp.error = dupstr( - "SSH protocol version 1 required by our configuration " - "but not provided by remote"); + ssh_sw_abort(s->bpp.ssh, + "SSH protocol version 1 required by our " + "configuration but not provided by remote"); } else { - s->bpp.error = dupstr( - "SSH protocol version 2 required by our configuration " - "but remote only provides (old, insecure) SSH-1"); + ssh_sw_abort(s->bpp.ssh, + "SSH protocol version 2 required by our " + "configuration but remote only provides " + "(old, insecure) SSH-1"); } crStopV; } @@ -387,6 +391,11 @@ void ssh_verstring_handle_input(BinaryPacketProtocol *bpp) * done. */ s->receiver->got_ssh_version(s->receiver, s->major_protoversion); + return; + + eof: + ssh_remote_error(s->bpp.ssh, + "Server unexpectedly closed network connection"); crFinishV; } From cb6fa5fff65bf7f7550cddd836c97b551b7bc7f1 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Tue, 25 Sep 2018 08:55:54 +0100 Subject: [PATCH 458/607] Fix minor mishandling of session typeahead. When the connection layer is ready to receive user input, it sets the flag causing ssh_ppl_want_user_input to return true. But one thing it _didn't_ do was to check whether the user input bufchain already had some data in it because the user had typed ahead of the session setup, and send that input immediately if so. Now it does. --- ssh1connection.c | 1 + ssh2connection.c | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/ssh1connection.c b/ssh1connection.c index cf1616d6..3ae36bd3 100644 --- a/ssh1connection.c +++ b/ssh1connection.c @@ -751,6 +751,7 @@ static void ssh1_connection_process_queue(PacketProtocolLayer *ppl) } s->session_ready = TRUE; + ssh_ppl_got_user_input(&s->ppl); /* in case any input is already queued */ /* If an EOF or a window-size change arrived before we were ready * to handle either one, handle them now. */ diff --git a/ssh2connection.c b/ssh2connection.c index 38566dc0..ea03f575 100644 --- a/ssh2connection.c +++ b/ssh2connection.c @@ -1335,8 +1335,10 @@ static void ssh2_connection_process_queue(PacketProtocolLayer *ppl) } s->mainchan_ready = TRUE; - if (s->mainchan) + if (s->mainchan) { s->want_user_input = TRUE; + ssh_ppl_got_user_input(&s->ppl); /* in case any is already queued */ + } /* If an EOF or a window-size change arrived before we were ready * to handle either one, handle them now. */ From f22d442003900ebed2d3322d4c258d73d5c6cc1c Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Tue, 25 Sep 2018 08:58:46 +0100 Subject: [PATCH 459/607] Fix mishandling of user abort during SSH-1 auth. If the user presses ^C or ^D at an authentication prompt, I meant to handle that by calling ssh_user_close, i.e. treat the closure as being intentionally directed _by_ the user, and hence don't bother putting up a warning box telling the user it had happened. I got this right in ssh2userauth, but in ssh1login I mistakenly called ssh_sw_abort instead. That's what I get for going through all the subtly different session closures in a hurry trying to decide which of five categories each one falls into... --- ssh1login.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ssh1login.c b/ssh1login.c index f676a6eb..d2404fc5 100644 --- a/ssh1login.c +++ b/ssh1login.c @@ -712,7 +712,8 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl) } if (!s->userpass_ret) { /* Failed to get a passphrase. Terminate. */ - ssh_sw_abort(s->ppl.ssh, "Unable to authenticate"); + ssh_user_close(s->ppl.ssh, + "User aborted at passphrase prompt"); return; } passphrase = dupstr(s->cur_prompt->prompts[0]->result); @@ -968,7 +969,7 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl) * because one was supplied on the command line * which has already failed to work). Terminate. */ - ssh_sw_abort(s->ppl.ssh, "Unable to authenticate"); + ssh_user_close(s->ppl.ssh, "User aborted at password prompt"); return; } From e4ee11d4c2258974a871c2e06fdf65f40b8a42eb Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Tue, 25 Sep 2018 17:12:22 +0100 Subject: [PATCH 460/607] Fix accidental termination of wait-for-rekey loop. When I separated out the transport layer into its own source file, I also reworked the logic deciding when to rekey, and apparently that rework introduced a braino in which I compared rekey_reason (which is a pointer) to RK_NONE (which is a value of the enumerated type that lives in the similarly named variable rekey_class). Oops. The result was that after the first rekey, the loop would terminate the next time the transport coroutine got called, because the code just before the loop had zeroed out rekey_class but not rekey_reason. So there'd be a rekey on every keypress, or similar. --- ssh2transport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssh2transport.c b/ssh2transport.c index 1dcd4a8c..9a5a970d 100644 --- a/ssh2transport.c +++ b/ssh2transport.c @@ -2392,7 +2392,7 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) s->rekey_reason)); } } - } while (s->rekey_reason == RK_NONE); + } while (s->rekey_class == RK_NONE); /* Once we exit the above loop, we really are rekeying. */ goto begin_key_exchange; From da1e560b42db03e6cf8bd49866975d63d4e9da84 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Tue, 25 Sep 2018 17:18:54 +0100 Subject: [PATCH 461/607] Fix failure to display the specials menu. I reworked the code for this at the last moment while preparing the Big Refactoring, having decided my previous design was overcomplicated and introducing an argument parameter (commit f4fbaa1bd) would be simpler. I carefully checked after the rework that specials manufactured by the code itself (e.g. SS_PING) came through OK, but apparently the one thing I _didn't_ test after the rework was that the specials list was actually returned correctly from ssh_get_specials to be incorporated into the GUI. In fact one stray if statement - both redundant even if it had been right, and also tested the wrong pointer - managed to arrange that when ssh->specials is NULL, it could never be overwritten by anything non-NULL. And of course it starts off initialised to NULL. Oops. --- ssh.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/ssh.c b/ssh.c index 033c236a..e52b230f 100644 --- a/ssh.c +++ b/ssh.c @@ -966,9 +966,6 @@ static const SessionSpecial *ssh_get_specials(Backend *be) if (ssh->base_layer) ssh_ppl_get_specials(ssh->base_layer, ssh_add_special, &ctx); - if (!ssh->specials) - return NULL; - if (ctx.specials) { /* If the list is non-empty, terminate it with a SS_EXITMENU. */ ssh_add_special(&ctx, NULL, SS_EXITMENU, 0); From 0bdda64724c2a897872ff394dc215c823899d7bd Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Tue, 25 Sep 2018 23:38:49 +0100 Subject: [PATCH 462/607] Fix paste error in packet-type list macro. In commit 8cb68390e I managed to copy the packet contexts inaccurately from the old implementation of ssh2_pkt_type, and listed the ECDH KEX packets against SSH2_PKTCTX_DHGEX instead of SSH2_PKTCTX_ECDHKEX, which led to them appearing as "unknown" in packet log files. --- ssh.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ssh.h b/ssh.h index 797b40c9..c5c8cdb9 100644 --- a/ssh.h +++ b/ssh.h @@ -1247,8 +1247,8 @@ void platform_ssh_share_cleanup(const char *name); K(y, SSH2_MSG_KEXRSA_PUBKEY, 30, SSH2_PKTCTX_RSAKEX) \ K(y, SSH2_MSG_KEXRSA_SECRET, 31, SSH2_PKTCTX_RSAKEX) \ K(y, SSH2_MSG_KEXRSA_DONE, 32, SSH2_PKTCTX_RSAKEX) \ - K(y, SSH2_MSG_KEX_ECDH_INIT, 30, SSH2_PKTCTX_DHGEX) \ - K(y, SSH2_MSG_KEX_ECDH_REPLY, 31, SSH2_PKTCTX_DHGEX) \ + K(y, SSH2_MSG_KEX_ECDH_INIT, 30, SSH2_PKTCTX_ECDHKEX) \ + K(y, SSH2_MSG_KEX_ECDH_REPLY, 31, SSH2_PKTCTX_ECDHKEX) \ X(y, SSH2_MSG_USERAUTH_REQUEST, 50) \ X(y, SSH2_MSG_USERAUTH_FAILURE, 51) \ X(y, SSH2_MSG_USERAUTH_SUCCESS, 52) \ From 686e78e66b5f1db67ff7b2687e291fdb2c169e6a Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Wed, 26 Sep 2018 07:39:04 +0100 Subject: [PATCH 463/607] Fix log-censoring of incoming SSH-2 session data. The call to ssh2_censor_packet for incoming packets in ssh2bpp was passing the wrong starting position in the packet data - in particular, not the same starting position as the adjacent call to log_packet - so the censor couldn't parse SSH2_MSG_CHANNEL_DATA to identify the string of session data that it should be bleeping out. --- ssh2bpp.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ssh2bpp.c b/ssh2bpp.c index 8ddb49f7..c81e0f59 100644 --- a/ssh2bpp.c +++ b/ssh2bpp.c @@ -463,13 +463,14 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp) * SSH_MSG_UNIMPLEMENTED. */ s->pktin->type = SSH_MSG_NO_TYPE_CODE; + s->data += 5; s->length = 0; - BinarySource_INIT(s->pktin, s->data + 5, 0); } else { s->pktin->type = s->data[5]; + s->data += 6; s->length -= 6; - BinarySource_INIT(s->pktin, s->data + 6, s->length); } + BinarySource_INIT(s->pktin, s->data, s->length); if (s->bpp.logctx) { logblank_t blanks[MAX_BLANKS]; @@ -479,7 +480,7 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp) log_packet(s->bpp.logctx, PKT_INCOMING, s->pktin->type, ssh2_pkt_type(s->bpp.pls->kctx, s->bpp.pls->actx, s->pktin->type), - get_ptr(s->pktin), get_avail(s->pktin), nblanks, blanks, + s->data, s->length, nblanks, blanks, &s->pktin->sequence, 0, NULL); } From 822d2fd4c3239b818bcb697f0905a217d6c783a9 Mon Sep 17 00:00:00 2001 From: Jonathan Liu Date: Wed, 26 Sep 2018 20:48:11 +1000 Subject: [PATCH 464/607] Add option whether to include header when logging. It is useful to be able to exclude the header so that the log file can be used for realtime input to other programs such as Kst for plotting live data from sensors. --- config.c | 3 +++ doc/config.but | 9 +++++++++ logging.c | 2 +- putty.h | 1 + settings.c | 2 ++ windows/winhelp.h | 1 + 6 files changed, 17 insertions(+), 1 deletion(-) diff --git a/config.c b/config.c index bdffd6bb..26d57acc 100644 --- a/config.c +++ b/config.c @@ -1628,6 +1628,9 @@ void setup_config_box(struct controlbox *b, int midsession, ctrl_checkbox(s, "Flush log file frequently", 'u', HELPCTX(logging_flush), conf_checkbox_handler, I(CONF_logflush)); + ctrl_checkbox(s, "Include header", 'h', + HELPCTX(logging_header), + conf_checkbox_handler, I(CONF_logheader)); if ((midsession && protocol == PROT_SSH) || (!midsession && backend_vt_from_proto(PROT_SSH))) { diff --git a/doc/config.but b/doc/config.but index c76e1847..96323ce6 100644 --- a/doc/config.but +++ b/doc/config.but @@ -246,6 +246,15 @@ warned that the log file may not always be up to date as a result (although it will of course be flushed when it is closed, for instance at the end of a session). +\S{config-logheader} \I{log file, header}\q{Include header} + +\cfg{winhelp-topic}{logging.header} + +This option allows you to choose whether to include a header line +with the date and time when the log file is opened. It may be useful to +disable this if the log file is being used as realtime input to other +programs that don't expect the header line. + \S{config-logssh} Options specific to \i{SSH packet log}ging These options only apply if SSH packet data is being logged. diff --git a/logging.c b/logging.c index 0393b7bf..da502c86 100644 --- a/logging.c +++ b/logging.c @@ -103,7 +103,7 @@ static void logfopen_callback(void *vctx, int mode) } } - if (ctx->state == L_OPEN) { + if (ctx->state == L_OPEN && conf_get_int(ctx->conf, CONF_logheader)) { /* Write header line into log file. */ tm = ltime(); strftime(buf, 24, "%Y.%m.%d %H:%M:%S", &tm); diff --git a/putty.h b/putty.h index 3963e48e..1a0d1ca2 100644 --- a/putty.h +++ b/putty.h @@ -931,6 +931,7 @@ void cleanup_exit(int); X(INT, NONE, logtype) \ X(INT, NONE, logxfovr) \ X(INT, NONE, logflush) \ + X(INT, NONE, logheader) \ X(INT, NONE, logomitpass) \ X(INT, NONE, logomitdata) \ X(INT, NONE, hide_mouseptr) \ diff --git a/settings.c b/settings.c index ab735488..5b613b66 100644 --- a/settings.c +++ b/settings.c @@ -524,6 +524,7 @@ void save_open_settings(settings_w *sesskey, Conf *conf) write_setting_i(sesskey, "LogType", conf_get_int(conf, CONF_logtype)); write_setting_i(sesskey, "LogFileClash", conf_get_int(conf, CONF_logxfovr)); write_setting_i(sesskey, "LogFlush", conf_get_int(conf, CONF_logflush)); + write_setting_i(sesskey, "LogHeader", conf_get_int(conf, CONF_logheader)); write_setting_i(sesskey, "SSHLogOmitPasswords", conf_get_int(conf, CONF_logomitpass)); write_setting_i(sesskey, "SSHLogOmitData", conf_get_int(conf, CONF_logomitdata)); p = "raw"; @@ -785,6 +786,7 @@ void load_open_settings(settings_r *sesskey, Conf *conf) gppi(sesskey, "LogType", 0, conf, CONF_logtype); gppi(sesskey, "LogFileClash", LGXF_ASK, conf, CONF_logxfovr); gppi(sesskey, "LogFlush", 1, conf, CONF_logflush); + gppi(sesskey, "LogHeader", 1, conf, CONF_logheader); gppi(sesskey, "SSHLogOmitPasswords", 1, conf, CONF_logomitpass); gppi(sesskey, "SSHLogOmitData", 0, conf, CONF_logomitdata); diff --git a/windows/winhelp.h b/windows/winhelp.h index c9be5f44..2ecb537a 100644 --- a/windows/winhelp.h +++ b/windows/winhelp.h @@ -23,6 +23,7 @@ #define WINHELP_CTX_logging_filename "logging.filename:config-logfilename" #define WINHELP_CTX_logging_exists "logging.exists:config-logfileexists" #define WINHELP_CTX_logging_flush "logging.flush:config-logflush" +#define WINHELP_CTX_logging_header "logging.header:config-logheader" #define WINHELP_CTX_logging_ssh_omit_password "logging.ssh.omitpassword:config-logssh" #define WINHELP_CTX_logging_ssh_omit_data "logging.ssh.omitdata:config-logssh" #define WINHELP_CTX_keyboard_backspace "keyboard.backspace:config-backspace" From b5c840431a0bf443ff81d8cc32458d52774512f2 Mon Sep 17 00:00:00 2001 From: Jonathan Liu Date: Wed, 26 Sep 2018 23:20:25 +1000 Subject: [PATCH 465/607] Suppress strncpy truncation warnings with GCC 8 and later. These warnings are bogus as the code is correct so we suppress them in the places they occur. --- unix/uxnet.c | 7 +++++++ unix/uxpty.c | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/unix/uxnet.c b/unix/uxnet.c index e13b9485..e0a7cb77 100644 --- a/unix/uxnet.c +++ b/unix/uxnet.c @@ -1678,7 +1678,14 @@ Socket new_unix_listener(SockAddr listenaddr, Plug plug) memset(&u, '\0', sizeof(u)); u.su.sun_family = AF_UNIX; +#if __GNUC__ >= 8 +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wstringop-truncation" +#endif // __GNUC__ >= 8 strncpy(u.su.sun_path, listenaddr->hostname, sizeof(u.su.sun_path)-1); +#if __GNUC__ >= 8 +# pragma GCC diagnostic pop +#endif // __GNUC__ >= 8 addr = &u; addrlen = sizeof(u.su); diff --git a/unix/uxpty.c b/unix/uxpty.c index a8429d76..41a96747 100644 --- a/unix/uxpty.c +++ b/unix/uxpty.c @@ -193,10 +193,17 @@ static void setup_utmp(char *ttyname, char *location) memset(&utmp_entry, 0, sizeof(utmp_entry)); utmp_entry.ut_type = USER_PROCESS; utmp_entry.ut_pid = getpid(); +#if __GNUC__ >= 8 +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wstringop-truncation" +#endif // __GNUC__ >= 8 strncpy(utmp_entry.ut_line, ttyname+5, lenof(utmp_entry.ut_line)); strncpy(utmp_entry.ut_id, ttyname+8, lenof(utmp_entry.ut_id)); strncpy(utmp_entry.ut_user, pw->pw_name, lenof(utmp_entry.ut_user)); strncpy(utmp_entry.ut_host, location, lenof(utmp_entry.ut_host)); +#if __GNUC__ >= 8 +# pragma GCC diagnostic pop +#endif // __GNUC__ >= 8 /* * Apparently there are some architectures where (struct * utmpx).ut_tv is not essentially struct timeval (e.g. Linux From 07313e94661071fa252c1db80806f225d2012995 Mon Sep 17 00:00:00 2001 From: Jacob Nevins Date: Wed, 26 Sep 2018 23:38:56 +0100 Subject: [PATCH 466/607] Fix shortcut clash in Windows builds. The 'Include header' option added in 822d2fd4c3 used the shortcut 'h', which clashed with the 'Help' button, causing an assertion failure. --- config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.c b/config.c index 26d57acc..caab152c 100644 --- a/config.c +++ b/config.c @@ -1628,7 +1628,7 @@ void setup_config_box(struct controlbox *b, int midsession, ctrl_checkbox(s, "Flush log file frequently", 'u', HELPCTX(logging_flush), conf_checkbox_handler, I(CONF_logflush)); - ctrl_checkbox(s, "Include header", 'h', + ctrl_checkbox(s, "Include header", 'i', HELPCTX(logging_header), conf_checkbox_handler, I(CONF_logheader)); From c912d0936d94c7aacf8698965562743f5f5fa933 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Thu, 27 Sep 2018 17:47:55 +0100 Subject: [PATCH 467/607] Handle error messages even before session startup. I carefully put a flag in the new Ssh structure so that I could tell the difference between ssh->base_layer being NULL because it hasn't been set up yet, and being NULL because it's been and gone and the session is terminated. And did I check that flag in all the error routines? I did not. Result: an early socket error, while we're still in the verstring BPP, doesn't get reported as an error message and doesn't cause the socket to be cleaned up. --- ssh.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ssh.c b/ssh.c index e52b230f..20e9bff7 100644 --- a/ssh.c +++ b/ssh.c @@ -387,7 +387,7 @@ static void ssh_initiate_connection_close(Ssh ssh) void ssh_remote_error(Ssh ssh, const char *fmt, ...) { - if (ssh->base_layer) { + if (ssh->base_layer || !ssh->session_started) { GET_FORMATTED_MSG; /* Error messages sent by the remote don't count as clean exits */ @@ -405,7 +405,7 @@ void ssh_remote_error(Ssh ssh, const char *fmt, ...) void ssh_remote_eof(Ssh ssh, const char *fmt, ...) { - if (ssh->base_layer) { + if (ssh->base_layer || !ssh->session_started) { GET_FORMATTED_MSG; /* EOF from the remote, if we were expecting it, does count as @@ -428,7 +428,7 @@ void ssh_remote_eof(Ssh ssh, const char *fmt, ...) void ssh_proto_error(Ssh ssh, const char *fmt, ...) { - if (ssh->base_layer) { + if (ssh->base_layer || !ssh->session_started) { GET_FORMATTED_MSG; ssh->exitcode = 128; @@ -445,7 +445,7 @@ void ssh_proto_error(Ssh ssh, const char *fmt, ...) void ssh_sw_abort(Ssh ssh, const char *fmt, ...) { - if (ssh->base_layer) { + if (ssh->base_layer || !ssh->session_started) { GET_FORMATTED_MSG; ssh->exitcode = 128; @@ -462,7 +462,7 @@ void ssh_sw_abort(Ssh ssh, const char *fmt, ...) void ssh_user_close(Ssh ssh, const char *fmt, ...) { - if (ssh->base_layer) { + if (ssh->base_layer || !ssh->session_started) { GET_FORMATTED_MSG; /* Closing the connection due to user action, even if the From ed0104c2feae935271a12af7a9175b81527fe96e Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Thu, 27 Sep 2018 18:06:16 +0100 Subject: [PATCH 468/607] ssh_closing: distinguish socket errors from EOF. I forgot to check the error_msg parameter at all. --- ssh.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ssh.c b/ssh.c index 20e9bff7..0e01b690 100644 --- a/ssh.c +++ b/ssh.c @@ -507,7 +507,9 @@ static void ssh_closing(Plug plug, const char *error_msg, int error_code, int calling_back) { Ssh ssh = FROMFIELD(plug, struct ssh_tag, plugvt); - if (ssh->bpp) { + if (error_msg) { + ssh_remote_error(ssh, "Network error: %s", error_msg); + } else if (ssh->bpp) { ssh->bpp->input_eof = TRUE; queue_idempotent_callback(&ssh->bpp->ic_in_raw); } From e857e43361def326df7203e0be5c4feaf7824a05 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Fri, 28 Sep 2018 11:26:26 +0100 Subject: [PATCH 469/607] Fix use-after-free on a network error. When any BPP calls ssh_remote_error or ssh_remote_eof, it triggers an immediate cleanup of the BPP itself - so on return from one of those functions we should avoid going straight to the crFinish macro, because that will write to s->crState, which no longer exists. --- ssh1bpp.c | 1 + ssh2bpp-bare.c | 1 + ssh2bpp.c | 1 + sshverstring.c | 1 + 4 files changed, 4 insertions(+) diff --git a/ssh1bpp.c b/ssh1bpp.c index e57676cc..98763e03 100644 --- a/ssh1bpp.c +++ b/ssh1bpp.c @@ -245,6 +245,7 @@ static void ssh1_bpp_handle_input(BinaryPacketProtocol *bpp) } else { ssh_remote_eof(s->bpp.ssh, "Server closed network connection"); } + return; /* avoid touching s now it's been freed */ crFinishV; } diff --git a/ssh2bpp-bare.c b/ssh2bpp-bare.c index 49689c3b..ba40e7ab 100644 --- a/ssh2bpp-bare.c +++ b/ssh2bpp-bare.c @@ -136,6 +136,7 @@ static void ssh2_bare_bpp_handle_input(BinaryPacketProtocol *bpp) } else { ssh_remote_eof(s->bpp.ssh, "Server closed network connection"); } + return; /* avoid touching s now it's been freed */ crFinishV; } diff --git a/ssh2bpp.c b/ssh2bpp.c index c81e0f59..6bda41d0 100644 --- a/ssh2bpp.c +++ b/ssh2bpp.c @@ -516,6 +516,7 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp) } else { ssh_remote_eof(s->bpp.ssh, "Server closed network connection"); } + return; /* avoid touching s now it's been freed */ crFinishV; } diff --git a/sshverstring.c b/sshverstring.c index 612c3194..d9bc8077 100644 --- a/sshverstring.c +++ b/sshverstring.c @@ -396,6 +396,7 @@ void ssh_verstring_handle_input(BinaryPacketProtocol *bpp) eof: ssh_remote_error(s->bpp.ssh, "Server unexpectedly closed network connection"); + return; /* avoid touching s now it's been freed */ crFinishV; } From 32a0de93bcdb041aa96e7f61cc832a61b0a01f7e Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Fri, 28 Sep 2018 19:06:07 +0100 Subject: [PATCH 470/607] Defer error callback from localproxy_try_send. If you call plug_closing directly from localproxy_try_send, which can in turn be called directly from sk_write, then the plug's implementation of plug_closing may well free things that the caller of sk_write expected not to have vanished. The corresponding routine in uxnet.c pushes that call to plug_closing into a toplevel callback, so let's do that here too. --- unix/uxproxy.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/unix/uxproxy.c b/unix/uxproxy.c index bd702f29..fdf8bce7 100644 --- a/unix/uxproxy.c +++ b/unix/uxproxy.c @@ -27,6 +27,8 @@ typedef struct LocalProxySocket { bufchain pending_error_data; enum { EOF_NO, EOF_PENDING, EOF_SENT } outgoingeof; + int pending_error; + const Socket_vtable *sockvt; } LocalProxySocket; @@ -132,9 +134,28 @@ static void sk_localproxy_close (Socket s) bufchain_clear(&ps->pending_output_data); bufchain_clear(&ps->pending_error_data); + delete_callbacks_for_context(ps); + sfree(ps); } +static void localproxy_error_callback(void *vs) +{ + LocalProxySocket *ps = (LocalProxySocket *)vs; + + /* + * Just in case other socket work has caused this socket to vanish + * or become somehow non-erroneous before this callback arrived... + */ + if (!ps->pending_error) + return; + + /* + * An error has occurred on this socket. Pass it to the plug. + */ + plug_closing(ps->plug, strerror(ps->pending_error), ps->pending_error, 0); +} + static int localproxy_try_send(LocalProxySocket *ps) { int sent = 0; @@ -146,7 +167,10 @@ static int localproxy_try_send(LocalProxySocket *ps) bufchain_prefix(&ps->pending_output_data, &data, &len); ret = write(ps->to_cmd, data, len); if (ret < 0 && errno != EWOULDBLOCK) { - plug_closing(ps->plug, strerror(errno), errno, 0); + if (!ps->pending_error) { + ps->pending_error = errno; + queue_toplevel_callback(localproxy_error_callback, ps); + } return 0; } else if (ret <= 0) { break; @@ -291,6 +315,7 @@ Socket platform_new_connection(SockAddr addr, const char *hostname, ret->plug = plug; ret->error = NULL; ret->outgoingeof = EOF_NO; + ret->pending_error = 0; bufchain_init(&ret->pending_input_data); bufchain_init(&ret->pending_output_data); From 3085e748070a82987620a3eb5945b307cb56ee32 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Fri, 28 Sep 2018 19:20:50 +0100 Subject: [PATCH 471/607] GTK uxsel handling: lump G_IO_HUP into G_IO_IN. Without this, we don't receive EOF notifications on pipes, because gtk uses poll rather than select, which separates those out into distinct event types. --- unix/gtkcomm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/unix/gtkcomm.c b/unix/gtkcomm.c index 6b6d19bb..b29bd7ed 100644 --- a/unix/gtkcomm.c +++ b/unix/gtkcomm.c @@ -83,7 +83,7 @@ gboolean fd_input_func(GIOChannel *source, GIOCondition condition, */ if (condition & G_IO_PRI) select_result(sourcefd, 4); - if (condition & G_IO_IN) + if (condition & (G_IO_IN | G_IO_HUP)) select_result(sourcefd, 1); if (condition & G_IO_OUT) select_result(sourcefd, 2); @@ -107,7 +107,7 @@ uxsel_id *uxsel_input_add(int fd, int rwx) { #if GTK_CHECK_VERSION(2,0,0) int flags = 0; - if (rwx & 1) flags |= G_IO_IN; + if (rwx & 1) flags |= G_IO_IN | G_IO_HUP; if (rwx & 2) flags |= G_IO_OUT; if (rwx & 4) flags |= G_IO_PRI; id->chan = g_io_channel_unix_new(fd); From 7cd425abab020968bb6a8e6d3521b6cf915a24cc Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Fri, 28 Sep 2018 19:21:37 +0100 Subject: [PATCH 472/607] uxproxy: close input pipes that have seen EOF on read. Otherwise we loop round repeatedly with the event loop continuing to report the same EOF condition on them over and over again, consuming CPU pointlessly and probably causing other knock-on trouble too. --- unix/uxproxy.c | 45 ++++++++++++++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/unix/uxproxy.c b/unix/uxproxy.c index fdf8bce7..c6708343 100644 --- a/unix/uxproxy.c +++ b/unix/uxproxy.c @@ -122,13 +122,17 @@ static void sk_localproxy_close (Socket s) close(ps->to_cmd); } - del234(localproxy_by_fromfd, ps); - uxsel_del(ps->from_cmd); - close(ps->from_cmd); + if (ps->from_cmd >= 0) { + del234(localproxy_by_fromfd, ps); + uxsel_del(ps->from_cmd); + close(ps->from_cmd); + } - del234(localproxy_by_errfd, ps); - uxsel_del(ps->cmd_err); - close(ps->cmd_err); + if (ps->cmd_err >= 0) { + del234(localproxy_by_errfd, ps); + uxsel_del(ps->cmd_err); + close(ps->cmd_err); + } bufchain_clear(&ps->pending_input_data); bufchain_clear(&ps->pending_output_data); @@ -238,6 +242,9 @@ static void sk_localproxy_set_frozen (Socket s, int is_frozen) { LocalProxySocket *ps = FROMFIELD(s, LocalProxySocket, sockvt); + if (ps->from_cmd < 0) + return; + if (is_frozen) uxsel_del(ps->from_cmd); else @@ -257,24 +264,36 @@ static void localproxy_select_result(int fd, int event) int ret; if (!(s = find234(localproxy_by_fromfd, &fd, localproxy_fromfd_find)) && - !(s = find234(localproxy_by_fromfd, &fd, localproxy_errfd_find)) && + !(s = find234(localproxy_by_errfd, &fd, localproxy_errfd_find)) && !(s = find234(localproxy_by_tofd, &fd, localproxy_tofd_find)) ) return; /* boggle */ if (event == 1) { if (fd == s->cmd_err) { ret = read(fd, buf, sizeof(buf)); - if (ret > 0) + if (ret > 0) { log_proxy_stderr(s->plug, &s->pending_error_data, buf, ret); + } else { + del234(localproxy_by_errfd, s); + uxsel_del(s->cmd_err); + close(s->cmd_err); + s->cmd_err = -1; + } } else { assert(fd == s->from_cmd); ret = read(fd, buf, sizeof(buf)); - if (ret < 0) { - plug_closing(s->plug, strerror(errno), errno, 0); - } else if (ret == 0) { - plug_closing(s->plug, NULL, 0, 0); - } else { + if (ret > 0) { plug_receive(s->plug, 0, buf, ret); + } else { + if (ret < 0) { + plug_closing(s->plug, strerror(errno), errno, 0); + } else { + plug_closing(s->plug, NULL, 0, 0); + } + del234(localproxy_by_fromfd, s); + uxsel_del(s->from_cmd); + close(s->from_cmd); + s->from_cmd = -1; } } } else if (event == 2) { From 5a6608bda8b13dcb67da122b05b65b2eb1d50725 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Fri, 28 Sep 2018 18:28:24 +0100 Subject: [PATCH 473/607] Unix GUI: honour 'no close on exit' for connection_fatal. It was being treated like an application-fatal message box even if you'd configured the window not to close on an unclean exit. --- unix/gtkwin.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/unix/gtkwin.c b/unix/gtkwin.c index a391f361..ee492d02 100644 --- a/unix/gtkwin.c +++ b/unix/gtkwin.c @@ -224,23 +224,35 @@ static void post_fatal_message_box(void *vctx, int result) queue_toplevel_callback(post_fatal_message_box_toplevel, inst); } -void fatal_message_box(Frontend *inst, const char *msg) +static void common_connfatal_message_box( + Frontend *inst, const char *msg, post_dialog_fn_t postfn) { char *title = dupcat(appname, " Fatal Error", NULL); GtkWidget *dialog = create_message_box( inst->window, title, msg, string_width("REASONABLY LONG LINE OF TEXT FOR BASIC SANITY"), - FALSE, &buttons_ok, post_fatal_message_box, inst); + FALSE, &buttons_ok, postfn, inst); register_dialog(inst, DIALOG_SLOT_CONNECTION_FATAL, dialog); sfree(title); } +void fatal_message_box(Frontend *inst, const char *msg) +{ + common_connfatal_message_box(inst, msg, post_fatal_message_box); +} + static void connection_fatal_callback(void *vctx) { Frontend *inst = (Frontend *)vctx; destroy_inst_connection(inst); } +static void post_nonfatal_message_box(void *vctx, int result) +{ + Frontend *inst = (Frontend *)vctx; + unregister_dialog(inst, DIALOG_SLOT_CONNECTION_FATAL); +} + void connection_fatal(Frontend *inst, const char *p, ...) { va_list ap; @@ -248,7 +260,11 @@ void connection_fatal(Frontend *inst, const char *p, ...) va_start(ap, p); msg = dupvprintf(p, ap); va_end(ap); - fatal_message_box(inst, msg); + if (conf_get_int(inst->conf, CONF_close_on_exit) == FORCE_ON) { + fatal_message_box(inst, msg); + } else { + common_connfatal_message_box(inst, msg, post_nonfatal_message_box); + } sfree(msg); inst->exited = TRUE; /* suppress normal exit handling */ From 57553bdaaca9a85e6dbee255f5d121a506b6b085 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Fri, 28 Sep 2018 20:52:36 +0100 Subject: [PATCH 474/607] sshshare: notify cl when last downstream goes away. The check_termination function in ssh2connection is supposed to be called whenever it's possible that we've run out of (a) channels, and (b) sharing downstreams. I've been calling it on every channel close, but apparently completely forgot to add a callback from sshshare.c that also arranges to call it when we run out of downstreams. --- ssh.h | 5 +++++ ssh1connection.c | 1 + ssh2connection.c | 9 +++++++++ sshshare.c | 12 +++++++++++- 4 files changed, 26 insertions(+), 1 deletion(-) diff --git a/ssh.h b/ssh.h index c5c8cdb9..2858a14a 100644 --- a/ssh.h +++ b/ssh.h @@ -236,6 +236,9 @@ struct ConnectionLayerVtable { void (*sharing_queue_global_request)( ConnectionLayer *cl, ssh_sharing_connstate *connstate); + /* Indicate that the last downstream has disconnected */ + void (*sharing_no_more_downstreams)(ConnectionLayer *cl); + /* Query whether the connection layer is doing agent forwarding */ int (*agent_forwarding_permitted)(ConnectionLayer *cl); @@ -281,6 +284,8 @@ struct ConnectionLayer { ((cl)->vt->delete_sharing_channel(cl, ch)) #define ssh_sharing_queue_global_request(cl, cs) \ ((cl)->vt->sharing_queue_global_request(cl, cs)) +#define ssh_sharing_no_more_downstreams(cl) \ + ((cl)->vt->sharing_no_more_downstreams(cl)) #define ssh_agent_forwarding_permitted(cl) \ ((cl)->vt->agent_forwarding_permitted(cl)) #define ssh_terminal_size(cl, w, h) ((cl)->vt->terminal_size(cl, w, h)) diff --git a/ssh1connection.c b/ssh1connection.c index 3ae36bd3..86e16f90 100644 --- a/ssh1connection.c +++ b/ssh1connection.c @@ -119,6 +119,7 @@ static const struct ConnectionLayerVtable ssh1_connlayer_vtable = { NULL /* alloc_sharing_channel */, NULL /* delete_sharing_channel */, NULL /* sharing_queue_global_request */, + NULL /* sharing_no_more_downstreams */, ssh1_agent_forwarding_permitted, ssh1_terminal_size, ssh1_stdout_unthrottle, diff --git a/ssh2connection.c b/ssh2connection.c index ea03f575..71dd1007 100644 --- a/ssh2connection.c +++ b/ssh2connection.c @@ -127,6 +127,7 @@ static void ssh2_delete_sharing_channel( ConnectionLayer *cl, unsigned localid); static void ssh2_sharing_queue_global_request( ConnectionLayer *cl, ssh_sharing_connstate *share_ctx); +static void ssh2_sharing_no_more_downstreams(ConnectionLayer *cl); static int ssh2_agent_forwarding_permitted(ConnectionLayer *cl); static void ssh2_terminal_size(ConnectionLayer *cl, int width, int height); static void ssh2_stdout_unthrottle(ConnectionLayer *cl, int bufsize); @@ -144,6 +145,7 @@ static const struct ConnectionLayerVtable ssh2_connlayer_vtable = { ssh2_alloc_sharing_channel, ssh2_delete_sharing_channel, ssh2_sharing_queue_global_request, + ssh2_sharing_no_more_downstreams, ssh2_agent_forwarding_permitted, ssh2_terminal_size, ssh2_stdout_unthrottle, @@ -2096,6 +2098,13 @@ static void ssh2_sharing_queue_global_request( ssh2_queue_global_request_handler(s, ssh2_sharing_globreq_response, cs); } +static void ssh2_sharing_no_more_downstreams(ConnectionLayer *cl) +{ + struct ssh2_connection_state *s = + FROMFIELD(cl, struct ssh2_connection_state, cl); + queue_toplevel_callback(ssh2_check_termination_callback, s); +} + static struct X11FakeAuth *ssh2_add_sharing_x11_display( ConnectionLayer *cl, int authtype, ssh_sharing_connstate *share_cs, share_channel *share_chan) diff --git a/sshshare.c b/sshshare.c index 937b4da6..c425140a 100644 --- a/sshshare.c +++ b/sshshare.c @@ -905,12 +905,22 @@ static void share_try_cleanup(struct ssh_sharing_connstate *cs) if (count234(cs->halfchannels) == 0 && count234(cs->channels_by_us) == 0 && count234(cs->forwardings) == 0) { + struct ssh_sharing_state *sharestate = cs->parent; + /* * Now we're _really_ done, so we can get rid of cs completely. */ - del234(cs->parent->connections, cs); + del234(sharestate->connections, cs); log_downstream(cs, "disconnected"); share_connstate_free(cs); + + /* + * And if this was the last downstream, notify the connection + * layer, because it might now be time to wind up the whole + * SSH connection. + */ + if (count234(sharestate->connections) == 0 && sharestate->cl) + ssh_sharing_no_more_downstreams(sharestate->cl); } } From fb07fccf2dbd28ea7e3e1771d25e0378b2a28e56 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 29 Sep 2018 13:09:47 +0100 Subject: [PATCH 475/607] Fix failure to handle SSH_MSG_EXTENDED_DATA. I left this message type code out of the list in the outer switch in ssh2_connection_filter_queue for messages with the standard handling of an initial recipient channel id. The inner switch had a perfectly good handler for extended data, but the outer one didn't pass the message on to that handler, so it went back to the main coroutine and triggered a sw_abort for an unexpected packet. --- ssh2connection.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ssh2connection.c b/ssh2connection.c index 71dd1007..e49ab076 100644 --- a/ssh2connection.c +++ b/ssh2connection.c @@ -626,6 +626,7 @@ static int ssh2_connection_filter_queue(struct ssh2_connection_state *s) break; case SSH2_MSG_CHANNEL_DATA: + case SSH2_MSG_CHANNEL_EXTENDED_DATA: case SSH2_MSG_CHANNEL_WINDOW_ADJUST: case SSH2_MSG_CHANNEL_REQUEST: case SSH2_MSG_CHANNEL_EOF: From 1d162fa767151050db5ea5b84f72b9742c2f7c7d Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Mon, 1 Oct 2018 20:25:15 +0100 Subject: [PATCH 476/607] Stop sending outgoing-only EOF on SSH sockets. When PuTTY wants to cleanly close an SSH connection, my policy has been to use shutdown(SHUT_WR) (or rather, sk_write_eof, which ends up translating into that) to close just the outgoing side of the TCP connection, and then wait for the server to acknowledge that by closing its own end. Mainly the purpose of doing this rather than just immediately closing the whole socket was that I wanted to make sure any remaining outgoing packets of ours got sent before the connection was wound up. In particular, when we send SSH_MSG_DISCONNECT immediately before the close, we do want that to get through. But I now think this was a mistake, because it puts us at the mercy of the server remembering to respond by closing the other direction of the connection. It might absent-mindedly just continue to sit there holding the connection open, which would be silly, but if it did happen, we wouldn't want to sit around waiting in order to close the client application - we'd rather abandon a socket in that state and leave it to the OS's network layer to tell the server how silly it was being. So now I'm using an in-between strategy: I still wait for outgoing data to be sent before closing the socket (so the DISCONNECT should still go out), but once it's gone, I _do_ just close the whole thing instead of just sending outgoing EOF. --- ssh.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/ssh.c b/ssh.c index 0e01b690..48af9e78 100644 --- a/ssh.c +++ b/ssh.c @@ -69,7 +69,7 @@ struct ssh_tag { int term_width, term_height; bufchain in_raw, out_raw, user_input; - int send_outgoing_eof; + int pending_close; IdempotentCallback ic_out_raw; PacketLogSettings pls; @@ -313,8 +313,10 @@ static void ssh_bpp_output_raw_data_callback(void *vctx) } } - if (ssh->send_outgoing_eof) - sk_write_eof(ssh->s); + if (ssh->pending_close) { + sk_close(ssh->s); + ssh->s = NULL; + } } static void ssh_shutdown_internal(Ssh ssh) @@ -368,9 +370,9 @@ static void ssh_initiate_connection_close(Ssh ssh) ssh_shutdown_internal(ssh); /* Force any remaining queued SSH packets through the BPP, and - * schedule sending of EOF on the network socket after them. */ + * schedule closing the network socket after they go out. */ ssh_bpp_handle_output(ssh->bpp); - ssh->send_outgoing_eof = TRUE; + ssh->pending_close = TRUE; /* Now we expect the other end to close the connection too in * response, so arrange that we'll receive notification of that From db188040ea8c1a8e3f6ae581c1806fbc77f08335 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Mon, 1 Oct 2018 21:01:59 +0100 Subject: [PATCH 477/607] Fix failure to close the outgoing socket. A second bug in the area of clean SSH-connection closure: I was setting the pending_close flag (formerly send_outgoing_eof) and expecting that once the outgoing backlog was cleared it would cause a socket closure. But of course the function that does that - ssh_bpp_output_raw_data_callback() - will only get called if there _is_ any outgoing backlog to be cleared! So if there was already no backlog, I would set the pending_close flag and nothing would ever check it again. Fixed by manually re-queuing the callback that will check the backlog and the pending_close flag. --- ssh.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ssh.c b/ssh.c index 48af9e78..f4468d6b 100644 --- a/ssh.c +++ b/ssh.c @@ -373,6 +373,7 @@ static void ssh_initiate_connection_close(Ssh ssh) * schedule closing the network socket after they go out. */ ssh_bpp_handle_output(ssh->bpp); ssh->pending_close = TRUE; + queue_idempotent_callback(&ssh->ic_out_raw); /* Now we expect the other end to close the connection too in * response, so arrange that we'll receive notification of that From 5d6d052d8b28bdaf4fc0cba29234909727f46b6c Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Mon, 1 Oct 2018 21:03:34 +0100 Subject: [PATCH 478/607] Flush log file after asynchronous askappend. When I made the 'overwrite or append log file?' dialog box into a non-modal one, it exposed a bug in logging.c's handling of an asynchronous response to askappend(): we queued all the pending log data and wrote it out to the log file, but forgot the final fflush that would have made sure it all actually _went_ to the log file. So one stdio buffer's worth could still be held in the C library, to be released the next time log data shows up. Added the missing logflush(). --- logging.c | 1 + 1 file changed, 1 insertion(+) diff --git a/logging.c b/logging.c index da502c86..f07982ac 100644 --- a/logging.c +++ b/logging.c @@ -153,6 +153,7 @@ static void logfopen_callback(void *vctx, int mode) logwrite(ctx, data, len); bufchain_consume(&ctx->queue, len); } + logflush(ctx); } /* From dcb93d60e6e8d5d7aa6fef3d981fa16a7a2c96d0 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Tue, 2 Oct 2018 18:25:53 +0100 Subject: [PATCH 479/607] pscp: fix another newline problem in output. In commit 54b300f15, I managed to set the progress_bar_displayed flag just _after_, rather than before, the call to abandon_progress_bar that moves to the new line once the file has finished copying. So in the case where a file is so small that the very first displaying of the transfer statistics is already at 100% completion, the flag wouldn't be set when abandon_progress_bar checked for it, and a newline still wouldn't be printed. --- pscp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pscp.c b/pscp.c index d99c8d83..67db1e9d 100644 --- a/pscp.c +++ b/pscp.c @@ -576,11 +576,11 @@ static void print_stats(const char *name, uint64 size, uint64 done, printf("%*s", prev_stats_len - len, ""); prev_stats_len = len; + progress_bar_displayed = TRUE; + if (uint64_compare(done, size) == 0) abandon_progress_bar(); - progress_bar_displayed = TRUE; - fflush(stdout); } From ad487da0d520915aaad114921636be1ed6a4f366 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Tue, 2 Oct 2018 18:32:08 +0100 Subject: [PATCH 480/607] pscp: remove redundant progress bar indicator. Another mistake in commit 54b300f15 was to introduce a new flag 'progress_bar_displayed', when in fact we were already storing an indication of whether a set of live transfer statistics were currently on the display, in the form of prev_stats_len (which is also used to make sure each stats display overwrites all of the previous one). Removed that redundancy, and while I'm at it, renamed the new abandon_progress_bar() to match the rest of the code's general convention of calling that status display 'statistics' or 'transfer statistics' rather than a 'progress bar'. --- pscp.c | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/pscp.c b/pscp.c index 67db1e9d..70071c29 100644 --- a/pscp.c +++ b/pscp.c @@ -42,7 +42,6 @@ static int main_cmd_is_sftp = 0; static int fallback_cmd_is_sftp = 0; static int using_sftp = 0; static int uploading = 0; -static int progress_bar_displayed = FALSE; static Backend *backend; static Conf *conf; @@ -75,18 +74,18 @@ static void tell_str(FILE *stream, const char *str) tell_char(stream, str[i]); } -static void abandon_progress_bar(void) +static void abandon_stats(void) { /* * Output a \n to stdout (which is where we've been sending - * progress bars) so that the cursor will move to the next line. - * We should do this before displaying any other kind of output - * like an error message. + * transfer statistics) so that the cursor will move to the next + * line. We should do this before displaying any other kind of + * output like an error message. */ - if (progress_bar_displayed) { + if (prev_stats_len) { putchar('\n'); fflush(stdout); - progress_bar_displayed = FALSE; + prev_stats_len = 0; } } @@ -99,7 +98,7 @@ static void tell_user(FILE *stream, const char *fmt, ...) va_end(ap); str2 = dupcat(str, "\n", NULL); sfree(str); - abandon_progress_bar(); + abandon_stats(); tell_str(stream, str2); sfree(str2); } @@ -116,7 +115,7 @@ void modalfatalbox(const char *fmt, ...) str2 = dupcat("Fatal: ", str, "\n", NULL); sfree(str); va_end(ap); - abandon_progress_bar(); + abandon_stats(); tell_str(stderr, str2); sfree(str2); errs++; @@ -132,7 +131,7 @@ void nonfatal(const char *fmt, ...) str2 = dupcat("Error: ", str, "\n", NULL); sfree(str); va_end(ap); - abandon_progress_bar(); + abandon_stats(); tell_str(stderr, str2); sfree(str2); errs++; @@ -146,7 +145,7 @@ void connection_fatal(Frontend *frontend, const char *fmt, ...) str2 = dupcat("Fatal: ", str, "\n", NULL); sfree(str); va_end(ap); - abandon_progress_bar(); + abandon_stats(); tell_str(stderr, str2); sfree(str2); errs++; @@ -307,7 +306,7 @@ static void bump(const char *fmt, ...) va_end(ap); str2 = dupcat(str, "\n", NULL); sfree(str); - abandon_progress_bar(); + abandon_stats(); tell_str(stderr, str2); sfree(str2); errs++; @@ -576,10 +575,8 @@ static void print_stats(const char *name, uint64 size, uint64 done, printf("%*s", prev_stats_len - len, ""); prev_stats_len = len; - progress_bar_displayed = TRUE; - if (uint64_compare(done, size) == 0) - abandon_progress_bar(); + abandon_stats(); fflush(stdout); } @@ -1638,7 +1635,7 @@ static void run_err(const char *fmt, ...) str2 = dupcat("pscp: ", str, "\n", NULL); sfree(str); scp_send_errmsg(str2); - abandon_progress_bar(); + abandon_stats(); tell_user(stderr, "%s", str2); va_end(ap); sfree(str2); From 78e280a1cd8902271d3c0d82afa2fa6ed3315084 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Tue, 2 Oct 2018 18:34:38 +0100 Subject: [PATCH 481/607] pscp: remove a relic of GUI feedback mode. GUI feedback mode was last seen in 2006 (removed in commit 33b7caa59), so quite what a conditioned-out piece of online help text for it was doing still around here 12 years later, I have no idea. (Especially since it had been under #if 0 since 2001, and also since then its containing source file had ceased to be Windows-only so it would have been extra-wrong to reinstate it.) --- pscp.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/pscp.c b/pscp.c index 70071c29..4cc09a41 100644 --- a/pscp.c +++ b/pscp.c @@ -2257,17 +2257,6 @@ static void usage(void) printf(" -sshlog file\n"); printf(" -sshrawlog file\n"); printf(" log protocol details to a file\n"); -#if 0 - /* - * -gui is an internal option, used by GUI front ends to get - * pscp to pass progress reports back to them. It's not an - * ordinary user-accessible option, so it shouldn't be part of - * the command-line help. The only people who need to know - * about it are programmers, and they can read the source. - */ - printf - (" -gui hWnd GUI mode with the windows handle for receiving messages\n"); -#endif cleanup_exit(1); } From 72a8c8c471131c76633ab3f252a38d78b7a46388 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Tue, 2 Oct 2018 18:37:32 +0100 Subject: [PATCH 482/607] ssh2 conn: don't accept user input until mainchan is ready. s->want_user_input is set and unset in response to fluctuations of the main channel's available SSH window size. But that means it can become TRUE before a command has been successfully started, which we don't want, because pscp.c uses backend_sendok() to determine when it's safe to check the flag that tells it whether to speak the SFTP or SCP1 protocol. So we want to ensure we never return true from that backend method until we know which command we're running. --- ssh2connection.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssh2connection.c b/ssh2connection.c index e49ab076..e4a2ede0 100644 --- a/ssh2connection.c +++ b/ssh2connection.c @@ -2480,7 +2480,7 @@ static int ssh2_connection_want_user_input(PacketProtocolLayer *ppl) { struct ssh2_connection_state *s = FROMFIELD(ppl, struct ssh2_connection_state, ppl); - return s->want_user_input; + return s->mainchan_ready && s->want_user_input; } static void ssh2_connection_got_user_input(PacketProtocolLayer *ppl) From bf61af1919f22775a0a3e272893a26499feacf23 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Wed, 3 Oct 2018 20:55:01 +0100 Subject: [PATCH 483/607] ssh2 conn: don't set mainchan_eof_sent when we didn't. In mainchan_send_eof, which is the Channel method that gets called when EOF has been received from the SSH server and is now being passed on to the local endpoint, we decide whether or not to respond to the server-side EOF with a client-side EOF based on application preference. But I was doing the followup admin _outside_ that if statement, so if the server sent EOF and we _didn't_ want to send EOF in response, we still set the flag that said we'd sent it, and stopped reading from standard input. Result: if you use 'plink -nc' to talk to a remote network socket, and the server sends EOF first, Plink will never send EOF in the other direction, because it'll stop reading from standard input and never actually see the EOF that needs to be sent. --- ssh2connection.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ssh2connection.c b/ssh2connection.c index e4a2ede0..5a93a977 100644 --- a/ssh2connection.c +++ b/ssh2connection.c @@ -2267,9 +2267,9 @@ static void mainchan_send_eof(Channel *chan) */ sshfwd_write_eof(mc->sc); ppl_logevent(("Sent EOF message")); + s->mainchan_eof_sent = TRUE; + s->want_user_input = FALSE; /* now stop reading from stdin */ } - s->mainchan_eof_sent = TRUE; - s->want_user_input = FALSE; /* now stop reading from stdin */ } static void mainchan_set_input_wanted(Channel *chan, int wanted) From 96ec2c2500b82c6a354e3472decad75bba660174 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Thu, 4 Oct 2018 19:10:23 +0100 Subject: [PATCH 484/607] Get rid of lots of implicit pointer types. All the main backend structures - Ssh, Telnet, Pty, Serial etc - now describe structure types themselves rather than pointers to them. The same goes for the codebase-wide trait types Socket and Plug, and the supporting types SockAddr and Pinger. All those things that were typedefed as pointers are older types; the newer ones have the explicit * at the point of use, because that's what I now seem to be preferring. But whichever one of those is better, inconsistently using a mixture of the two styles is worse, so let's make everything consistent. A few types are still implicitly pointers, such as Bignum and some of the GSSAPI types; generally this is either because they have to be void *, or because they're typedefed differently on different platforms and aren't always pointers at all. Can't be helped. But I've got rid of the main ones, at least. --- be_misc.c | 4 +- contrib/cygtermd/main.c | 2 +- contrib/cygtermd/telnet.c | 32 +++++------ contrib/cygtermd/telnet.h | 12 ++--- defs.h | 14 ++--- errsock.c | 14 ++--- network.h | 98 +++++++++++++++++----------------- noshare.c | 2 +- nullplug.c | 10 ++-- pageant.c | 18 +++---- pageant.h | 4 +- pinger.c | 16 +++--- portfwd.c | 24 ++++----- pproxy.c | 8 +-- proxy.c | 50 +++++++++--------- proxy.h | 8 +-- putty.h | 8 +-- raw.c | 47 +++++++++-------- rlogin.c | 51 +++++++++--------- ssh.c | 106 ++++++++++++++++++------------------- ssh.h | 32 +++++------ ssh1connection.c | 4 +- ssh2connection.c | 4 +- sshbpp.h | 2 +- sshppl.h | 6 +-- sshshare.c | 24 ++++----- telnet.c | 75 +++++++++++++------------- unix/unix.h | 2 +- unix/uxnet.c | 104 ++++++++++++++++++------------------ unix/uxpgnt.c | 18 +++---- unix/uxproxy.c | 28 +++++----- unix/uxpty.c | 74 +++++++++++++------------- unix/uxser.c | 43 +++++++-------- unix/uxshare.c | 8 +-- windows/winhsock.c | 26 ++++----- windows/winnet.c | 108 +++++++++++++++++++------------------- windows/winnpc.c | 8 +-- windows/winnps.c | 24 ++++----- windows/winproxy.c | 18 +++---- windows/winser.c | 33 ++++++------ windows/winshare.c | 8 +-- x11fwd.c | 14 ++--- 42 files changed, 595 insertions(+), 596 deletions(-) diff --git a/be_misc.c b/be_misc.c index 4774bd70..42da1302 100644 --- a/be_misc.c +++ b/be_misc.c @@ -9,7 +9,7 @@ #include "putty.h" #include "network.h" -void backend_socket_log(Frontend *frontend, int type, SockAddr addr, int port, +void backend_socket_log(Frontend *frontend, int type, SockAddr *addr, int port, const char *error_msg, int error_code, Conf *conf, int session_started) { @@ -59,7 +59,7 @@ void backend_socket_log(Frontend *frontend, int type, SockAddr addr, int port, } } -void log_proxy_stderr(Plug plug, bufchain *buf, const void *vdata, int len) +void log_proxy_stderr(Plug *plug, bufchain *buf, const void *vdata, int len) { const char *data = (const char *)vdata; int pos = 0; diff --git a/contrib/cygtermd/main.c b/contrib/cygtermd/main.c index 84e6c75e..e7ed5f0a 100644 --- a/contrib/cygtermd/main.c +++ b/contrib/cygtermd/main.c @@ -24,7 +24,7 @@ sel *asel; sel_rfd *netr, *ptyr, *sigr; int ptyfd; sel_wfd *netw, *ptyw; -Telnet telnet; +Telnet *telnet; #define BUF 65536 diff --git a/contrib/cygtermd/telnet.c b/contrib/cygtermd/telnet.c index ce0bc5fb..a41e6cea 100644 --- a/contrib/cygtermd/telnet.c +++ b/contrib/cygtermd/telnet.c @@ -172,7 +172,7 @@ static const struct Opt *const opts[] = { &o_echo, &o_we_sga, &o_they_sga, &o_naws, &o_ttype, &o_oenv, &o_nenv, NULL }; -struct telnet_tag { +struct Telnet { int opt_states[NUM_OPTS]; int sb_opt, sb_len; @@ -203,7 +203,7 @@ struct telnet_tag { #define SB_DELTA 1024 -static void send_opt(Telnet telnet, int cmd, int option) +static void send_opt(Telnet *telnet, int cmd, int option) { unsigned char b[3]; @@ -213,7 +213,7 @@ static void send_opt(Telnet telnet, int cmd, int option) sel_write(telnet->net, b, 3); } -static void deactivate_option(Telnet telnet, const struct Opt *o) +static void deactivate_option(Telnet *telnet, const struct Opt *o) { if (telnet->opt_states[o->index] == REQUESTED || telnet->opt_states[o->index] == ACTIVE) @@ -224,11 +224,11 @@ static void deactivate_option(Telnet telnet, const struct Opt *o) /* * Generate side effects of enabling or disabling an option. */ -static void option_side_effects(Telnet telnet, const struct Opt *o, int enabled) +static void option_side_effects(Telnet *telnet, const struct Opt *o, int enabled) { } -static void activate_option(Telnet telnet, const struct Opt *o) +static void activate_option(Telnet *telnet, const struct Opt *o) { if (o->option == TELOPT_NEW_ENVIRON || o->option == TELOPT_OLD_ENVIRON || @@ -245,7 +245,7 @@ static void activate_option(Telnet telnet, const struct Opt *o) option_side_effects(telnet, o, 1); } -static void done_option(Telnet telnet, int option) +static void done_option(Telnet *telnet, int option) { if (option == TELOPT_OLD_ENVIRON) telnet->old_environ_done = 1; @@ -260,7 +260,7 @@ static void done_option(Telnet telnet, int option) } } -static void refused_option(Telnet telnet, const struct Opt *o) +static void refused_option(Telnet *telnet, const struct Opt *o) { done_option(telnet, o->option); if (o->send == WILL && o->option == TELOPT_NEW_ENVIRON && @@ -272,7 +272,7 @@ static void refused_option(Telnet telnet, const struct Opt *o) option_side_effects(telnet, o, 0); } -static void proc_rec_opt(Telnet telnet, int cmd, int option) +static void proc_rec_opt(Telnet *telnet, int cmd, int option) { const struct Opt *const *o; @@ -323,7 +323,7 @@ static void proc_rec_opt(Telnet telnet, int cmd, int option) send_opt(telnet, (cmd == WILL ? DONT : WONT), option); } -static void process_subneg(Telnet telnet) +static void process_subneg(Telnet *telnet) { int var, value, n; @@ -400,7 +400,7 @@ static void process_subneg(Telnet telnet) } } -void telnet_from_net(Telnet telnet, char *buf, int len) +void telnet_from_net(Telnet *telnet, char *buf, int len) { while (len--) { int c = (unsigned char) *buf++; @@ -497,11 +497,11 @@ void telnet_from_net(Telnet telnet, char *buf, int len) } } -Telnet telnet_new(sel_wfd *net, sel_wfd *pty) +Telnet *telnet_new(sel_wfd *net, sel_wfd *pty) { - Telnet telnet; + Telnet *telnet; - telnet = snew(struct telnet_tag); + telnet = snew(Telnet); telnet->sb_buf = NULL; telnet->sb_size = 0; telnet->state = TOP_LEVEL; @@ -532,13 +532,13 @@ Telnet telnet_new(sel_wfd *net, sel_wfd *pty) return telnet; } -void telnet_free(Telnet telnet) +void telnet_free(Telnet *telnet) { sfree(telnet->sb_buf); sfree(telnet); } -void telnet_from_pty(Telnet telnet, char *buf, int len) +void telnet_from_pty(Telnet *telnet, char *buf, int len) { unsigned char *p, *end; static const unsigned char iac[2] = { IAC, IAC }; @@ -563,7 +563,7 @@ void telnet_from_pty(Telnet telnet, char *buf, int len) } } -int telnet_shell_ok(Telnet telnet, struct shell_data *shdata) +int telnet_shell_ok(Telnet *telnet, struct shell_data *shdata) { if (telnet->shell_ok) *shdata = telnet->shdata; /* structure copy */ diff --git a/contrib/cygtermd/telnet.h b/contrib/cygtermd/telnet.h index 1a74cab1..40a05dd9 100644 --- a/contrib/cygtermd/telnet.h +++ b/contrib/cygtermd/telnet.h @@ -7,7 +7,7 @@ #include "sel.h" -typedef struct telnet_tag *Telnet; +typedef struct Telnet Telnet; struct shell_data { char **envvars; /* array of "VAR=value" terms */ @@ -18,24 +18,24 @@ struct shell_data { /* * Create and destroy a Telnet structure. */ -Telnet telnet_new(sel_wfd *net, sel_wfd *pty); -void telnet_free(Telnet telnet); +Telnet *telnet_new(sel_wfd *net, sel_wfd *pty); +void telnet_free(Telnet *telnet); /* * Process data read from the pty. */ -void telnet_from_pty(Telnet telnet, char *buf, int len); +void telnet_from_pty(Telnet *telnet, char *buf, int len); /* * Process Telnet protocol data received from the network. */ -void telnet_from_net(Telnet telnet, char *buf, int len); +void telnet_from_net(Telnet *telnet, char *buf, int len); /* * Return true if pre-shell-startup negotiations are complete and * it's safe to start the shell subprocess now. On a true return, * also fills in the shell_data structure. */ -int telnet_shell_ok(Telnet telnet, struct shell_data *shdata); +int telnet_shell_ok(Telnet *telnet, struct shell_data *shdata); #endif /* FIXME_TELNET_H */ diff --git a/defs.h b/defs.h index 28020964..6dc07e7d 100644 --- a/defs.h +++ b/defs.h @@ -40,7 +40,7 @@ typedef struct BinarySource BinarySource; typedef struct IdempotentCallback IdempotentCallback; -typedef struct SockAddr_tag *SockAddr; +typedef struct SockAddr SockAddr; typedef struct Socket_vtable Socket_vtable; typedef struct Plug_vtable Plug_vtable; @@ -53,7 +53,7 @@ typedef struct LogContext_tag LogContext; typedef struct Frontend Frontend; -typedef struct ssh_tag *Ssh; +typedef struct Ssh Ssh; typedef struct Channel Channel; typedef struct SshChannel SshChannel; @@ -74,14 +74,8 @@ typedef struct settings_e settings_e; typedef struct SessionSpecial SessionSpecial; -/* Note indirection: for historical reasons (it used to be closer to - * the OS socket type), the type that most code uses for a socket is - * 'Socket', not 'Socket *'. So an implementation of Socket or Plug - * has a 'const Socket *' field for the vtable pointer, and the - * 'Socket' type returned to client code is a pointer to _that_ in - * turn. */ -typedef const Socket_vtable **Socket; -typedef const Plug_vtable **Plug; +typedef const Socket_vtable *Socket; +typedef const Plug_vtable *Plug; /* * A small structure wrapping up a (pointer, length) pair so that it diff --git a/errsock.c b/errsock.c index 824cd6e8..030f5739 100644 --- a/errsock.c +++ b/errsock.c @@ -12,21 +12,21 @@ typedef struct { char *error; - Plug plug; + Plug *plug; const Socket_vtable *sockvt; } ErrorSocket; -static Plug sk_error_plug(Socket s, Plug p) +static Plug *sk_error_plug(Socket *s, Plug *p) { ErrorSocket *es = FROMFIELD(s, ErrorSocket, sockvt); - Plug ret = es->plug; + Plug *ret = es->plug; if (p) es->plug = p; return ret; } -static void sk_error_close(Socket s) +static void sk_error_close(Socket *s) { ErrorSocket *es = FROMFIELD(s, ErrorSocket, sockvt); @@ -34,13 +34,13 @@ static void sk_error_close(Socket s) sfree(es); } -static const char *sk_error_socket_error(Socket s) +static const char *sk_error_socket_error(Socket *s) { ErrorSocket *es = FROMFIELD(s, ErrorSocket, sockvt); return es->error; } -static char *sk_error_peer_info(Socket s) +static char *sk_error_peer_info(Socket *s) { return NULL; } @@ -57,7 +57,7 @@ static const Socket_vtable ErrorSocket_sockvt = { sk_error_peer_info, }; -Socket new_error_socket(const char *errmsg, Plug plug) +Socket *new_error_socket(const char *errmsg, Plug *plug) { ErrorSocket *es = snew(ErrorSocket); es->sockvt = &ErrorSocket_sockvt; diff --git a/network.h b/network.h index 79f44f5e..86c0f6b9 100644 --- a/network.h +++ b/network.h @@ -16,26 +16,26 @@ #include "defs.h" struct Socket_vtable { - Plug(*plug) (Socket s, Plug p); + Plug *(*plug) (Socket *s, Plug *p); /* use a different plug (return the old one) */ /* if p is NULL, it doesn't change the plug */ /* but it does return the one it's using */ - void (*close) (Socket s); - int (*write) (Socket s, const void *data, int len); - int (*write_oob) (Socket s, const void *data, int len); - void (*write_eof) (Socket s); - void (*flush) (Socket s); - void (*set_frozen) (Socket s, int is_frozen); + void (*close) (Socket *s); + int (*write) (Socket *s, const void *data, int len); + int (*write_oob) (Socket *s, const void *data, int len); + void (*write_eof) (Socket *s); + void (*flush) (Socket *s); + void (*set_frozen) (Socket *s, int is_frozen); /* ignored by tcp, but vital for ssl */ - const char *(*socket_error) (Socket s); - char *(*peer_info) (Socket s); + const char *(*socket_error) (Socket *s); + char *(*peer_info) (Socket *s); }; typedef union { void *p; int i; } accept_ctx_t; -typedef Socket (*accept_fn_t)(accept_ctx_t ctx, Plug plug); +typedef Socket *(*accept_fn_t)(accept_ctx_t ctx, Plug *plug); struct Plug_vtable { - void (*log)(Plug p, int type, SockAddr addr, int port, + void (*log)(Plug *p, int type, SockAddr *addr, int port, const char *error_msg, int error_code); /* * Passes the client progress reports on the process of setting @@ -55,11 +55,11 @@ struct Plug_vtable { * indicate this. */ void (*closing) - (Plug p, const char *error_msg, int error_code, int calling_back); + (Plug *p, const char *error_msg, int error_code, int calling_back); /* error_msg is NULL iff it is not an error (ie it closed normally) */ /* calling_back != 0 iff there is a Plug function */ /* currently running (would cure the fixme in try_send()) */ - void (*receive) (Plug p, int urgent, char *data, int len); + void (*receive) (Plug *p, int urgent, char *data, int len); /* * - urgent==0. `data' points to `len' bytes of perfectly * ordinary data. @@ -70,13 +70,13 @@ struct Plug_vtable { * - urgent==2. `data' points to `len' bytes of data, * the first of which was the one at the Urgent mark. */ - void (*sent) (Plug p, int bufsize); + void (*sent) (Plug *p, int bufsize); /* * The `sent' function is called when the pending send backlog * on a socket is cleared or partially cleared. The new backlog * size is passed in the `bufsize' parameter. */ - int (*accepting)(Plug p, accept_fn_t constructor, accept_ctx_t ctx); + int (*accepting)(Plug *p, accept_fn_t constructor, accept_ctx_t ctx); /* * `accepting' is called only on listener-type sockets, and is * passed a constructor function+context that will create a fresh @@ -88,55 +88,55 @@ struct Plug_vtable { /* proxy indirection layer */ /* NB, control of 'addr' is passed via new_connection, which takes * responsibility for freeing it */ -Socket new_connection(SockAddr addr, const char *hostname, - int port, int privport, - int oobinline, int nodelay, int keepalive, - Plug plug, Conf *conf); -Socket new_listener(const char *srcaddr, int port, Plug plug, - int local_host_only, Conf *conf, int addressfamily); -SockAddr name_lookup(const char *host, int port, char **canonicalname, - Conf *conf, int addressfamily, - Frontend *frontend_for_logging, - const char *lookup_reason_for_logging); -int proxy_for_destination (SockAddr addr, const char *hostname, int port, +Socket *new_connection(SockAddr *addr, const char *hostname, + int port, int privport, + int oobinline, int nodelay, int keepalive, + Plug *plug, Conf *conf); +Socket *new_listener(const char *srcaddr, int port, Plug *plug, + int local_host_only, Conf *conf, int addressfamily); +SockAddr *name_lookup(const char *host, int port, char **canonicalname, + Conf *conf, int addressfamily, + Frontend *frontend_for_logging, + const char *lookup_reason_for_logging); +int proxy_for_destination (SockAddr *addr, const char *hostname, int port, Conf *conf); /* platform-dependent callback from new_connection() */ /* (same caveat about addr as new_connection()) */ -Socket platform_new_connection(SockAddr addr, const char *hostname, - int port, int privport, - int oobinline, int nodelay, int keepalive, - Plug plug, Conf *conf); +Socket *platform_new_connection(SockAddr *addr, const char *hostname, + int port, int privport, + int oobinline, int nodelay, int keepalive, + Plug *plug, Conf *conf); /* socket functions */ void sk_init(void); /* called once at program startup */ void sk_cleanup(void); /* called just before program exit */ -SockAddr sk_namelookup(const char *host, char **canonicalname, int address_family); -SockAddr sk_nonamelookup(const char *host); -void sk_getaddr(SockAddr addr, char *buf, int buflen); -int sk_addr_needs_port(SockAddr addr); +SockAddr *sk_namelookup(const char *host, char **canonicalname, int address_family); +SockAddr *sk_nonamelookup(const char *host); +void sk_getaddr(SockAddr *addr, char *buf, int buflen); +int sk_addr_needs_port(SockAddr *addr); int sk_hostname_is_local(const char *name); -int sk_address_is_local(SockAddr addr); -int sk_address_is_special_local(SockAddr addr); -int sk_addrtype(SockAddr addr); -void sk_addrcopy(SockAddr addr, char *buf); -void sk_addr_free(SockAddr addr); +int sk_address_is_local(SockAddr *addr); +int sk_address_is_special_local(SockAddr *addr); +int sk_addrtype(SockAddr *addr); +void sk_addrcopy(SockAddr *addr, char *buf); +void sk_addr_free(SockAddr *addr); /* sk_addr_dup generates another SockAddr which contains the same data * as the original one and can be freed independently. May not actually * physically _duplicate_ it: incrementing a reference count so that * one more free is required before it disappears is an acceptable * implementation. */ -SockAddr sk_addr_dup(SockAddr addr); +SockAddr *sk_addr_dup(SockAddr *addr); /* NB, control of 'addr' is passed via sk_new, which takes responsibility * for freeing it, as for new_connection() */ -Socket sk_new(SockAddr addr, int port, int privport, int oobinline, - int nodelay, int keepalive, Plug p); +Socket *sk_new(SockAddr *addr, int port, int privport, int oobinline, + int nodelay, int keepalive, Plug *p); -Socket sk_newlistener(const char *srcaddr, int port, Plug plug, - int local_host_only, int address_family); +Socket *sk_newlistener(const char *srcaddr, int port, Plug *plug, + int local_host_only, int address_family); #define sk_plug(s,p) (((*s)->plug) (s, p)) #define sk_close(s) (((*s)->close) (s)) @@ -158,7 +158,7 @@ Socket sk_newlistener(const char *srcaddr, int port, Plug plug, * if there's a problem. These functions extract an error message, * or return NULL if there's no problem. */ -const char *sk_addr_error(SockAddr addr); +const char *sk_addr_error(SockAddr *addr); #define sk_socket_error(s) (((*s)->socket_error) (s)) /* @@ -206,12 +206,12 @@ char *get_hostname(void); * Trivial socket implementation which just stores an error. Found in * errsock.c. */ -Socket new_error_socket(const char *errmsg, Plug plug); +Socket *new_error_socket(const char *errmsg, Plug *plug); /* * Trivial plug that does absolutely nothing. Found in nullplug.c. */ -extern Plug nullplug; +extern Plug *nullplug; /* ---------------------------------------------------------------------- * Functions defined outside the network code, which have to be @@ -222,9 +222,9 @@ extern Plug nullplug; /* * Exports from be_misc.c. */ -void backend_socket_log(Frontend *frontend, int type, SockAddr addr, int port, +void backend_socket_log(Frontend *frontend, int type, SockAddr *addr, int port, const char *error_msg, int error_code, Conf *conf, int session_started); -void log_proxy_stderr(Plug plug, bufchain *buf, const void *vdata, int len); +void log_proxy_stderr(Plug *plug, bufchain *buf, const void *vdata, int len); #endif diff --git a/noshare.c b/noshare.c index 9a888454..bc6d0efc 100644 --- a/noshare.c +++ b/noshare.c @@ -13,7 +13,7 @@ #include "network.h" int platform_ssh_share(const char *name, Conf *conf, - Plug downplug, Plug upplug, Socket *sock, + Plug *downplug, Plug *upplug, Socket **sock, char **logtext, char **ds_err, char **us_err, int can_upstream, int can_downstream) { diff --git a/nullplug.c b/nullplug.c index afc1aa38..4a57f33a 100644 --- a/nullplug.c +++ b/nullplug.c @@ -7,21 +7,21 @@ #include "putty.h" -static void nullplug_socket_log(Plug plug, int type, SockAddr addr, int port, +static void nullplug_socket_log(Plug *plug, int type, SockAddr *addr, int port, const char *error_msg, int error_code) { } -static void nullplug_closing(Plug plug, const char *error_msg, int error_code, +static void nullplug_closing(Plug *plug, const char *error_msg, int error_code, int calling_back) { } -static void nullplug_receive(Plug plug, int urgent, char *data, int len) +static void nullplug_receive(Plug *plug, int urgent, char *data, int len) { } -static void nullplug_sent(Plug plug, int bufsize) +static void nullplug_sent(Plug *plug, int bufsize) { } @@ -39,4 +39,4 @@ static const Plug_vtable *nullplug_plugvt_ptr = &nullplug_plugvt; * There's a singleton instance of nullplug, because it's not * interesting enough to worry about making more than one of them. */ -Plug nullplug = &nullplug_plugvt_ptr; +Plug *nullplug = &nullplug_plugvt_ptr; diff --git a/pageant.c b/pageant.c index f12694de..270715bf 100644 --- a/pageant.c +++ b/pageant.c @@ -699,7 +699,7 @@ int pageant_delete_ssh2_key(struct ssh2_userkey *skey) } while (0) struct pageant_conn_state { - Socket connsock; + Socket *connsock; void *logctx; pageant_logfn_t logfn; unsigned char lenbuf[4], pktbuf[AGENT_MAX_MSGLEN]; @@ -710,7 +710,7 @@ struct pageant_conn_state { const Plug_vtable *plugvt; }; -static void pageant_conn_closing(Plug plug, const char *error_msg, +static void pageant_conn_closing(Plug *plug, const char *error_msg, int error_code, int calling_back) { struct pageant_conn_state *pc = FROMFIELD( @@ -723,7 +723,7 @@ static void pageant_conn_closing(Plug plug, const char *error_msg, sfree(pc); } -static void pageant_conn_sent(Plug plug, int bufsize) +static void pageant_conn_sent(Plug *plug, int bufsize) { /* struct pageant_conn_state *pc = FROMFIELD( plug, struct pageant_conn_state, plugvt); */ @@ -745,7 +745,7 @@ static void pageant_conn_log(void *logctx, const char *fmt, va_list ap) sfree(formatted); } -static void pageant_conn_receive(Plug plug, int urgent, char *data, int len) +static void pageant_conn_receive(Plug *plug, int urgent, char *data, int len) { struct pageant_conn_state *pc = FROMFIELD( plug, struct pageant_conn_state, plugvt); @@ -797,14 +797,14 @@ static void pageant_conn_receive(Plug plug, int urgent, char *data, int len) } struct pageant_listen_state { - Socket listensock; + Socket *listensock; void *logctx; pageant_logfn_t logfn; const Plug_vtable *plugvt; }; -static void pageant_listen_closing(Plug plug, const char *error_msg, +static void pageant_listen_closing(Plug *plug, const char *error_msg, int error_code, int calling_back) { struct pageant_listen_state *pl = FROMFIELD( @@ -823,7 +823,7 @@ static const Plug_vtable pageant_connection_plugvt = { NULL /* no accepting function, because we've already done it */ }; -static int pageant_listen_accepting(Plug plug, +static int pageant_listen_accepting(Plug *plug, accept_fn_t constructor, accept_ctx_t ctx) { struct pageant_listen_state *pl = FROMFIELD( @@ -866,7 +866,7 @@ static const Plug_vtable pageant_listener_plugvt = { pageant_listen_accepting }; -struct pageant_listen_state *pageant_listener_new(Plug *plug) +struct pageant_listen_state *pageant_listener_new(Plug **plug) { struct pageant_listen_state *pl = snew(struct pageant_listen_state); pl->plugvt = &pageant_listener_plugvt; @@ -877,7 +877,7 @@ struct pageant_listen_state *pageant_listener_new(Plug *plug) return pl; } -void pageant_listener_got_socket(struct pageant_listen_state *pl, Socket sock) +void pageant_listener_got_socket(struct pageant_listen_state *pl, Socket *sock) { pl->listensock = sock; } diff --git a/pageant.h b/pageant.h index 26263129..e491d4f8 100644 --- a/pageant.h +++ b/pageant.h @@ -84,8 +84,8 @@ void keylist_update(void); * to. */ struct pageant_listen_state; -struct pageant_listen_state *pageant_listener_new(Plug *plug); -void pageant_listener_got_socket(struct pageant_listen_state *pl, Socket sock); +struct pageant_listen_state *pageant_listener_new(Plug **plug); +void pageant_listener_got_socket(struct pageant_listen_state *pl, Socket *); void pageant_listener_set_logfn(struct pageant_listen_state *pl, void *logctx, pageant_logfn_t logfn); void pageant_listener_free(struct pageant_listen_state *pl); diff --git a/pinger.c b/pinger.c index 672e86f9..e14c32d1 100644 --- a/pinger.c +++ b/pinger.c @@ -5,18 +5,18 @@ #include "putty.h" -struct pinger_tag { +struct Pinger { int interval; int pending; unsigned long when_set, next; Backend *backend; }; -static void pinger_schedule(Pinger pinger); +static void pinger_schedule(Pinger *pinger); static void pinger_timer(void *ctx, unsigned long now) { - Pinger pinger = (Pinger)ctx; + Pinger *pinger = (Pinger *)ctx; if (pinger->pending && now == pinger->next) { backend_special(pinger->backend, SS_PING, 0); @@ -25,7 +25,7 @@ static void pinger_timer(void *ctx, unsigned long now) } } -static void pinger_schedule(Pinger pinger) +static void pinger_schedule(Pinger *pinger) { unsigned long next; @@ -44,9 +44,9 @@ static void pinger_schedule(Pinger pinger) } } -Pinger pinger_new(Conf *conf, Backend *backend) +Pinger *pinger_new(Conf *conf, Backend *backend) { - Pinger pinger = snew(struct pinger_tag); + Pinger *pinger = snew(Pinger); pinger->interval = conf_get_int(conf, CONF_ping_interval); pinger->pending = FALSE; @@ -56,7 +56,7 @@ Pinger pinger_new(Conf *conf, Backend *backend) return pinger; } -void pinger_reconfig(Pinger pinger, Conf *oldconf, Conf *newconf) +void pinger_reconfig(Pinger *pinger, Conf *oldconf, Conf *newconf) { int newinterval = conf_get_int(newconf, CONF_ping_interval); if (conf_get_int(oldconf, CONF_ping_interval) != newinterval) { @@ -65,7 +65,7 @@ void pinger_reconfig(Pinger pinger, Conf *oldconf, Conf *newconf) } } -void pinger_free(Pinger pinger) +void pinger_free(Pinger *pinger) { expire_timer_context(pinger); sfree(pinger); diff --git a/portfwd.c b/portfwd.c index 07210683..9c7ff137 100644 --- a/portfwd.c +++ b/portfwd.c @@ -38,7 +38,7 @@ typedef struct PortForwarding { SshChannel *c; /* channel structure held by SSH connection layer */ ConnectionLayer *cl; /* the connection layer itself */ /* Note that ssh need not be filled in if c is non-NULL */ - Socket s; + Socket *s; int input_wanted; int ready; SocksState socks_state; @@ -62,7 +62,7 @@ typedef struct PortForwarding { struct PortListener { ConnectionLayer *cl; - Socket s; + Socket *s; int is_dynamic; /* * `hostname' and `port' are the real hostname and port, for @@ -107,13 +107,13 @@ static void free_portlistener_state(struct PortListener *pl) sfree(pl); } -static void pfd_log(Plug plug, int type, SockAddr addr, int port, +static void pfd_log(Plug *plug, int type, SockAddr *addr, int port, const char *error_msg, int error_code) { /* we have to dump these since we have no interface to logging.c */ } -static void pfl_log(Plug plug, int type, SockAddr addr, int port, +static void pfl_log(Plug *plug, int type, SockAddr *addr, int port, const char *error_msg, int error_code) { /* we have to dump these since we have no interface to logging.c */ @@ -121,7 +121,7 @@ static void pfl_log(Plug plug, int type, SockAddr addr, int port, static void pfd_close(struct PortForwarding *pf); -static void pfd_closing(Plug plug, const char *error_msg, int error_code, +static void pfd_closing(Plug *plug, const char *error_msg, int error_code, int calling_back) { struct PortForwarding *pf = FROMFIELD(plug, struct PortForwarding, plugvt); @@ -153,7 +153,7 @@ static void pfd_closing(Plug plug, const char *error_msg, int error_code, static void pfl_terminate(struct PortListener *pl); -static void pfl_closing(Plug plug, const char *error_msg, int error_code, +static void pfl_closing(Plug *plug, const char *error_msg, int error_code, int calling_back) { struct PortListener *pl = (struct PortListener *) plug; @@ -162,7 +162,7 @@ static void pfl_closing(Plug plug, const char *error_msg, int error_code, static SshChannel *wrap_lportfwd_open( ConnectionLayer *cl, const char *hostname, int port, - Socket s, Channel *chan) + Socket *s, Channel *chan) { char *peerinfo, *description; SshChannel *toret; @@ -203,7 +203,7 @@ static char *ipv6_to_string(ptrlen ipv6) (unsigned)GET_16BIT_MSB_FIRST(addr + 14)); } -static void pfd_receive(Plug plug, int urgent, char *data, int len) +static void pfd_receive(Plug *plug, int urgent, char *data, int len) { struct PortForwarding *pf = FROMFIELD(plug, struct PortForwarding, plugvt); @@ -427,7 +427,7 @@ static void pfd_receive(Plug plug, int urgent, char *data, int len) sshfwd_write(pf->c, data, len); } -static void pfd_sent(Plug plug, int bufsize) +static void pfd_sent(Plug *plug, int bufsize) { struct PortForwarding *pf = FROMFIELD(plug, struct PortForwarding, plugvt); @@ -466,11 +466,11 @@ static const struct ChannelVtable PortForwarding_channelvt = { called when someone connects to the local port */ -static int pfl_accepting(Plug p, accept_fn_t constructor, accept_ctx_t ctx) +static int pfl_accepting(Plug *p, accept_fn_t constructor, accept_ctx_t ctx) { struct PortForwarding *pf; struct PortListener *pl; - Socket s; + Socket *s; const char *err; pl = FROMFIELD(p, struct PortListener, plugvt); @@ -1020,7 +1020,7 @@ char *portfwdmgr_connect(PortFwdManager *mgr, Channel **chan_ret, char *hostname, int port, SshChannel *c, int addressfamily) { - SockAddr addr; + SockAddr *addr; const char *err; char *dummy_realhost = NULL; struct PortForwarding *pf; diff --git a/pproxy.c b/pproxy.c index 34e569bc..4b08606e 100644 --- a/pproxy.c +++ b/pproxy.c @@ -8,10 +8,10 @@ #include "network.h" #include "proxy.h" -Socket platform_new_connection(SockAddr addr, const char *hostname, - int port, int privport, - int oobinline, int nodelay, int keepalive, - Plug plug, Conf *conf) +Socket *platform_new_connection(SockAddr *addr, const char *hostname, + int port, int privport, + int oobinline, int nodelay, int keepalive, + Plug *plug, Conf *conf) { return NULL; } diff --git a/proxy.c b/proxy.c index f55973fc..26c1eacb 100644 --- a/proxy.c +++ b/proxy.c @@ -78,16 +78,16 @@ void proxy_activate (ProxySocket *p) /* basic proxy socket functions */ -static Plug sk_proxy_plug (Socket s, Plug p) +static Plug *sk_proxy_plug (Socket *s, Plug *p) { ProxySocket *ps = FROMFIELD(s, ProxySocket, sockvt); - Plug ret = ps->plug; + Plug *ret = ps->plug; if (p) ps->plug = p; return ret; } -static void sk_proxy_close (Socket s) +static void sk_proxy_close (Socket *s) { ProxySocket *ps = FROMFIELD(s, ProxySocket, sockvt); @@ -96,7 +96,7 @@ static void sk_proxy_close (Socket s) sfree(ps); } -static int sk_proxy_write (Socket s, const void *data, int len) +static int sk_proxy_write (Socket *s, const void *data, int len) { ProxySocket *ps = FROMFIELD(s, ProxySocket, sockvt); @@ -107,7 +107,7 @@ static int sk_proxy_write (Socket s, const void *data, int len) return sk_write(ps->sub_socket, data, len); } -static int sk_proxy_write_oob (Socket s, const void *data, int len) +static int sk_proxy_write_oob (Socket *s, const void *data, int len) { ProxySocket *ps = FROMFIELD(s, ProxySocket, sockvt); @@ -120,7 +120,7 @@ static int sk_proxy_write_oob (Socket s, const void *data, int len) return sk_write_oob(ps->sub_socket, data, len); } -static void sk_proxy_write_eof (Socket s) +static void sk_proxy_write_eof (Socket *s) { ProxySocket *ps = FROMFIELD(s, ProxySocket, sockvt); @@ -131,7 +131,7 @@ static void sk_proxy_write_eof (Socket s) sk_write_eof(ps->sub_socket); } -static void sk_proxy_flush (Socket s) +static void sk_proxy_flush (Socket *s) { ProxySocket *ps = FROMFIELD(s, ProxySocket, sockvt); @@ -142,7 +142,7 @@ static void sk_proxy_flush (Socket s) sk_flush(ps->sub_socket); } -static void sk_proxy_set_frozen (Socket s, int is_frozen) +static void sk_proxy_set_frozen (Socket *s, int is_frozen) { ProxySocket *ps = FROMFIELD(s, ProxySocket, sockvt); @@ -181,7 +181,7 @@ static void sk_proxy_set_frozen (Socket s, int is_frozen) sk_set_frozen(ps->sub_socket, is_frozen); } -static const char * sk_proxy_socket_error (Socket s) +static const char * sk_proxy_socket_error (Socket *s) { ProxySocket *ps = FROMFIELD(s, ProxySocket, sockvt); if (ps->error != NULL || ps->sub_socket == NULL) { @@ -192,7 +192,7 @@ static const char * sk_proxy_socket_error (Socket s) /* basic proxy plug functions */ -static void plug_proxy_log(Plug plug, int type, SockAddr addr, int port, +static void plug_proxy_log(Plug *plug, int type, SockAddr *addr, int port, const char *error_msg, int error_code) { ProxySocket *ps = FROMFIELD(plug, ProxySocket, plugvt); @@ -200,7 +200,7 @@ static void plug_proxy_log(Plug plug, int type, SockAddr addr, int port, plug_log(ps->plug, type, addr, port, error_msg, error_code); } -static void plug_proxy_closing (Plug p, const char *error_msg, +static void plug_proxy_closing (Plug *p, const char *error_msg, int error_code, int calling_back) { ProxySocket *ps = FROMFIELD(p, ProxySocket, plugvt); @@ -215,7 +215,7 @@ static void plug_proxy_closing (Plug p, const char *error_msg, } } -static void plug_proxy_receive (Plug p, int urgent, char *data, int len) +static void plug_proxy_receive (Plug *p, int urgent, char *data, int len) { ProxySocket *ps = FROMFIELD(p, ProxySocket, plugvt); @@ -234,7 +234,7 @@ static void plug_proxy_receive (Plug p, int urgent, char *data, int len) } } -static void plug_proxy_sent (Plug p, int bufsize) +static void plug_proxy_sent (Plug *p, int bufsize) { ProxySocket *ps = FROMFIELD(p, ProxySocket, plugvt); @@ -246,7 +246,7 @@ static void plug_proxy_sent (Plug p, int bufsize) plug_sent(ps->plug, bufsize); } -static int plug_proxy_accepting(Plug p, +static int plug_proxy_accepting(Plug *p, accept_fn_t constructor, accept_ctx_t ctx) { ProxySocket *ps = FROMFIELD(p, ProxySocket, plugvt); @@ -263,7 +263,7 @@ static int plug_proxy_accepting(Plug p, * This function can accept a NULL pointer as `addr', in which case * it will only check the host name. */ -int proxy_for_destination (SockAddr addr, const char *hostname, +int proxy_for_destination (SockAddr *addr, const char *hostname, int port, Conf *conf) { int s = 0, e = 0; @@ -367,7 +367,7 @@ static char *dns_log_msg(const char *host, int addressfamily, ""), reason); } -SockAddr name_lookup(const char *host, int port, char **canonicalname, +SockAddr *name_lookup(const char *host, int port, char **canonicalname, Conf *conf, int addressfamily, Frontend *frontend, const char *reason) { @@ -416,19 +416,19 @@ static const struct Plug_vtable ProxySocket_plugvt = { plug_proxy_accepting }; -Socket new_connection(SockAddr addr, const char *hostname, - int port, int privport, - int oobinline, int nodelay, int keepalive, - Plug plug, Conf *conf) +Socket *new_connection(SockAddr *addr, const char *hostname, + int port, int privport, + int oobinline, int nodelay, int keepalive, + Plug *plug, Conf *conf) { if (conf_get_int(conf, CONF_proxy_type) != PROXY_NONE && proxy_for_destination(addr, hostname, port, conf)) { ProxySocket *ret; - SockAddr proxy_addr; + SockAddr *proxy_addr; char *proxy_canonical_name; const char *proxy_type; - Socket sret; + Socket *sret; int type; if ((sret = platform_new_connection(addr, hostname, port, privport, @@ -536,8 +536,8 @@ Socket new_connection(SockAddr addr, const char *hostname, return sk_new(addr, port, privport, oobinline, nodelay, keepalive, plug); } -Socket new_listener(const char *srcaddr, int port, Plug plug, - int local_host_only, Conf *conf, int addressfamily) +Socket *new_listener(const char *srcaddr, int port, Plug *plug, + int local_host_only, Conf *conf, int addressfamily) { /* TODO: SOCKS (and potentially others) support inbound * TODO: connections via the proxy. support them. @@ -1278,7 +1278,7 @@ int proxy_socks5_negotiate (ProxySocket *p, int change) * standardised or at all well-defined.) */ -char *format_telnet_command(SockAddr addr, int port, Conf *conf) +char *format_telnet_command(SockAddr *addr, int port, Conf *conf) { char *fmt = conf_get_str(conf, CONF_proxy_telnet_command); char *ret = NULL; diff --git a/proxy.h b/proxy.h index 1fae25d2..2f39139e 100644 --- a/proxy.h +++ b/proxy.h @@ -18,9 +18,9 @@ typedef struct ProxySocket ProxySocket; struct ProxySocket { const char *error; - Socket sub_socket; - Plug plug; - SockAddr remote_addr; + Socket *sub_socket; + Plug *plug; + SockAddr *remote_addr; int remote_port; bufchain pending_output_data; @@ -102,7 +102,7 @@ extern int proxy_socks5_negotiate (ProxySocket *, int); * This may be reused by local-command proxies on individual * platforms. */ -char *format_telnet_command(SockAddr addr, int port, Conf *conf); +char *format_telnet_command(SockAddr *addr, int port, Conf *conf); /* * These are implemented in cproxy.c or nocproxy.c, depending on diff --git a/putty.h b/putty.h index 1a0d1ca2..778dac35 100644 --- a/putty.h +++ b/putty.h @@ -1254,10 +1254,10 @@ void random_unref(void); /* * Exports from pinger.c. */ -typedef struct pinger_tag *Pinger; -Pinger pinger_new(Conf *conf, Backend *backend); -void pinger_reconfig(Pinger, Conf *oldconf, Conf *newconf); -void pinger_free(Pinger); +typedef struct Pinger Pinger; +Pinger *pinger_new(Conf *conf, Backend *backend); +void pinger_reconfig(Pinger *, Conf *oldconf, Conf *newconf); +void pinger_free(Pinger *); /* * Exports from misc.c. diff --git a/raw.c b/raw.c index fea38a9a..aed3f708 100644 --- a/raw.c +++ b/raw.c @@ -10,8 +10,9 @@ #define RAW_MAX_BACKLOG 4096 -typedef struct raw_backend_data { - Socket s; +typedef struct Raw Raw; +struct Raw { + Socket *s; int closed_on_socket_error; int bufsize; Frontend *frontend; @@ -21,25 +22,25 @@ typedef struct raw_backend_data { const Plug_vtable *plugvt; Backend backend; -} *Raw; +}; static void raw_size(Backend *be, int width, int height); -static void c_write(Raw raw, const void *buf, int len) +static void c_write(Raw *raw, const void *buf, int len) { int backlog = from_backend(raw->frontend, 0, buf, len); sk_set_frozen(raw->s, backlog > RAW_MAX_BACKLOG); } -static void raw_log(Plug plug, int type, SockAddr addr, int port, +static void raw_log(Plug *plug, int type, SockAddr *addr, int port, const char *error_msg, int error_code) { - Raw raw = FROMFIELD(plug, struct raw_backend_data, plugvt); + Raw *raw = FROMFIELD(plug, Raw, plugvt); backend_socket_log(raw->frontend, type, addr, port, error_msg, error_code, raw->conf, raw->session_started); } -static void raw_check_close(Raw raw) +static void raw_check_close(Raw *raw) { /* * Called after we send EOF on either the socket or the console. @@ -54,10 +55,10 @@ static void raw_check_close(Raw raw) } } -static void raw_closing(Plug plug, const char *error_msg, int error_code, +static void raw_closing(Plug *plug, const char *error_msg, int error_code, int calling_back) { - Raw raw = FROMFIELD(plug, struct raw_backend_data, plugvt); + Raw *raw = FROMFIELD(plug, Raw, plugvt); if (error_msg) { /* A socket error has occurred. */ @@ -87,18 +88,18 @@ static void raw_closing(Plug plug, const char *error_msg, int error_code, } } -static void raw_receive(Plug plug, int urgent, char *data, int len) +static void raw_receive(Plug *plug, int urgent, char *data, int len) { - Raw raw = FROMFIELD(plug, struct raw_backend_data, plugvt); + Raw *raw = FROMFIELD(plug, Raw, plugvt); c_write(raw, data, len); /* We count 'session start', for proxy logging purposes, as being * when data is received from the network and printed. */ raw->session_started = TRUE; } -static void raw_sent(Plug plug, int bufsize) +static void raw_sent(Plug *plug, int bufsize) { - Raw raw = FROMFIELD(plug, struct raw_backend_data, plugvt); + Raw *raw = FROMFIELD(plug, Raw, plugvt); raw->bufsize = bufsize; } @@ -122,13 +123,13 @@ static const char *raw_init(Frontend *frontend, Backend **backend_handle, const char *host, int port, char **realhost, int nodelay, int keepalive) { - SockAddr addr; + SockAddr *addr; const char *err; - Raw raw; + Raw *raw; int addressfamily; char *loghost; - raw = snew(struct raw_backend_data); + raw = snew(Raw); raw->plugvt = &Raw_plugvt; raw->backend.vt = &raw_backend; raw->s = NULL; @@ -180,7 +181,7 @@ static const char *raw_init(Frontend *frontend, Backend **backend_handle, static void raw_free(Backend *be) { - Raw raw = FROMFIELD(be, struct raw_backend_data, backend); + Raw *raw = FROMFIELD(be, Raw, backend); if (raw->s) sk_close(raw->s); @@ -200,7 +201,7 @@ static void raw_reconfig(Backend *be, Conf *conf) */ static int raw_send(Backend *be, const char *buf, int len) { - Raw raw = FROMFIELD(be, struct raw_backend_data, backend); + Raw *raw = FROMFIELD(be, Raw, backend); if (raw->s == NULL) return 0; @@ -215,7 +216,7 @@ static int raw_send(Backend *be, const char *buf, int len) */ static int raw_sendbuffer(Backend *be) { - Raw raw = FROMFIELD(be, struct raw_backend_data, backend); + Raw *raw = FROMFIELD(be, Raw, backend); return raw->bufsize; } @@ -233,7 +234,7 @@ static void raw_size(Backend *be, int width, int height) */ static void raw_special(Backend *be, SessionSpecialCode code, int arg) { - Raw raw = FROMFIELD(be, struct raw_backend_data, backend); + Raw *raw = FROMFIELD(be, Raw, backend); if (code == SS_EOF && raw->s) { sk_write_eof(raw->s); raw->sent_socket_eof= TRUE; @@ -254,7 +255,7 @@ static const SessionSpecial *raw_get_specials(Backend *be) static int raw_connected(Backend *be) { - Raw raw = FROMFIELD(be, struct raw_backend_data, backend); + Raw *raw = FROMFIELD(be, Raw, backend); return raw->s != NULL; } @@ -265,7 +266,7 @@ static int raw_sendok(Backend *be) static void raw_unthrottle(Backend *be, int backlog) { - Raw raw = FROMFIELD(be, struct raw_backend_data, backend); + Raw *raw = FROMFIELD(be, Raw, backend); sk_set_frozen(raw->s, backlog > RAW_MAX_BACKLOG); } @@ -288,7 +289,7 @@ static void raw_provide_logctx(Backend *be, LogContext *logctx) static int raw_exitcode(Backend *be) { - Raw raw = FROMFIELD(be, struct raw_backend_data, backend); + Raw *raw = FROMFIELD(be, Raw, backend); if (raw->s != NULL) return -1; /* still connected */ else if (raw->closed_on_socket_error) diff --git a/rlogin.c b/rlogin.c index 3055ee7f..8faf37b0 100644 --- a/rlogin.c +++ b/rlogin.c @@ -11,8 +11,9 @@ #define RLOGIN_MAX_BACKLOG 4096 -typedef struct rlogin_tag { - Socket s; +typedef struct Rlogin Rlogin; +struct Rlogin { + Socket *s; int closed_on_socket_error; int bufsize; int firstbyte; @@ -27,27 +28,27 @@ typedef struct rlogin_tag { const Plug_vtable *plugvt; Backend backend; -} *Rlogin; +}; -static void c_write(Rlogin rlogin, const void *buf, int len) +static void c_write(Rlogin *rlogin, const void *buf, int len) { int backlog = from_backend(rlogin->frontend, 0, buf, len); sk_set_frozen(rlogin->s, backlog > RLOGIN_MAX_BACKLOG); } -static void rlogin_log(Plug plug, int type, SockAddr addr, int port, +static void rlogin_log(Plug *plug, int type, SockAddr *addr, int port, const char *error_msg, int error_code) { - Rlogin rlogin = FROMFIELD(plug, struct rlogin_tag, plugvt); + Rlogin *rlogin = FROMFIELD(plug, Rlogin, plugvt); backend_socket_log(rlogin->frontend, type, addr, port, error_msg, error_code, rlogin->conf, !rlogin->firstbyte); } -static void rlogin_closing(Plug plug, const char *error_msg, int error_code, +static void rlogin_closing(Plug *plug, const char *error_msg, int error_code, int calling_back) { - Rlogin rlogin = FROMFIELD(plug, struct rlogin_tag, plugvt); + Rlogin *rlogin = FROMFIELD(plug, Rlogin, plugvt); /* * We don't implement independent EOF in each direction for Telnet @@ -69,9 +70,9 @@ static void rlogin_closing(Plug plug, const char *error_msg, int error_code, } /* Otherwise, the remote side closed the connection normally. */ } -static void rlogin_receive(Plug plug, int urgent, char *data, int len) +static void rlogin_receive(Plug *plug, int urgent, char *data, int len) { - Rlogin rlogin = FROMFIELD(plug, struct rlogin_tag, plugvt); + Rlogin *rlogin = FROMFIELD(plug, Rlogin, plugvt); if (urgent == 2) { char c; @@ -106,13 +107,13 @@ static void rlogin_receive(Plug plug, int urgent, char *data, int len) } } -static void rlogin_sent(Plug plug, int bufsize) +static void rlogin_sent(Plug *plug, int bufsize) { - Rlogin rlogin = FROMFIELD(plug, struct rlogin_tag, plugvt); + Rlogin *rlogin = FROMFIELD(plug, Rlogin, plugvt); rlogin->bufsize = bufsize; } -static void rlogin_startup(Rlogin rlogin, const char *ruser) +static void rlogin_startup(Rlogin *rlogin, const char *ruser) { char z = 0; char *p; @@ -153,14 +154,14 @@ static const char *rlogin_init(Frontend *frontend, Backend **backend_handle, const char *host, int port, char **realhost, int nodelay, int keepalive) { - SockAddr addr; + SockAddr *addr; const char *err; - Rlogin rlogin; + Rlogin *rlogin; char *ruser; int addressfamily; char *loghost; - rlogin = snew(struct rlogin_tag); + rlogin = snew(Rlogin); rlogin->plugvt = &Rlogin_plugvt; rlogin->backend.vt = &rlogin_backend; rlogin->s = NULL; @@ -235,7 +236,7 @@ static const char *rlogin_init(Frontend *frontend, Backend **backend_handle, static void rlogin_free(Backend *be) { - Rlogin rlogin = FROMFIELD(be, struct rlogin_tag, backend); + Rlogin *rlogin = FROMFIELD(be, Rlogin, backend); if (rlogin->prompt) free_prompts(rlogin->prompt); @@ -257,7 +258,7 @@ static void rlogin_reconfig(Backend *be, Conf *conf) */ static int rlogin_send(Backend *be, const char *buf, int len) { - Rlogin rlogin = FROMFIELD(be, struct rlogin_tag, backend); + Rlogin *rlogin = FROMFIELD(be, Rlogin, backend); bufchain bc; if (rlogin->s == NULL) @@ -299,7 +300,7 @@ static int rlogin_send(Backend *be, const char *buf, int len) */ static int rlogin_sendbuffer(Backend *be) { - Rlogin rlogin = FROMFIELD(be, struct rlogin_tag, backend); + Rlogin *rlogin = FROMFIELD(be, Rlogin, backend); return rlogin->bufsize; } @@ -308,7 +309,7 @@ static int rlogin_sendbuffer(Backend *be) */ static void rlogin_size(Backend *be, int width, int height) { - Rlogin rlogin = FROMFIELD(be, struct rlogin_tag, backend); + Rlogin *rlogin = FROMFIELD(be, Rlogin, backend); char b[12] = { '\xFF', '\xFF', 0x73, 0x73, 0, 0, 0, 0, 0, 0, 0, 0 }; rlogin->term_width = width; @@ -345,25 +346,25 @@ static const SessionSpecial *rlogin_get_specials(Backend *be) static int rlogin_connected(Backend *be) { - Rlogin rlogin = FROMFIELD(be, struct rlogin_tag, backend); + Rlogin *rlogin = FROMFIELD(be, Rlogin, backend); return rlogin->s != NULL; } static int rlogin_sendok(Backend *be) { - /* Rlogin rlogin = FROMFIELD(be, struct rlogin_tag, backend); */ + /* Rlogin *rlogin = FROMFIELD(be, Rlogin, backend); */ return 1; } static void rlogin_unthrottle(Backend *be, int backlog) { - Rlogin rlogin = FROMFIELD(be, struct rlogin_tag, backend); + Rlogin *rlogin = FROMFIELD(be, Rlogin, backend); sk_set_frozen(rlogin->s, backlog > RLOGIN_MAX_BACKLOG); } static int rlogin_ldisc(Backend *be, int option) { - /* Rlogin rlogin = FROMFIELD(be, struct rlogin_tag, backend); */ + /* Rlogin *rlogin = FROMFIELD(be, Rlogin, backend); */ return 0; } @@ -379,7 +380,7 @@ static void rlogin_provide_logctx(Backend *be, LogContext *logctx) static int rlogin_exitcode(Backend *be) { - Rlogin rlogin = FROMFIELD(be, struct rlogin_tag, backend); + Rlogin *rlogin = FROMFIELD(be, Rlogin, backend); if (rlogin->s != NULL) return -1; /* still connected */ else if (rlogin->closed_on_socket_error) diff --git a/ssh.c b/ssh.c index f4468d6b..d6afb259 100644 --- a/ssh.c +++ b/ssh.c @@ -29,8 +29,8 @@ #define GSS_CTXT_MAYFAIL (1<<3) /* Context may expire during handshake */ #endif -struct ssh_tag { - Socket s; +struct Ssh { + Socket *s; Frontend *frontend; Conf *conf; @@ -101,7 +101,7 @@ struct ssh_tag { */ int session_started; - Pinger pinger; + Pinger *pinger; int need_random_unref; }; @@ -109,16 +109,16 @@ struct ssh_tag { #define ssh_logevent(params) ( \ logevent_and_free((ssh)->frontend, dupprintf params)) -static void ssh_shutdown(Ssh ssh); -static void ssh_throttle_all(Ssh ssh, int enable, int bufsize); +static void ssh_shutdown(Ssh *ssh); +static void ssh_throttle_all(Ssh *ssh, int enable, int bufsize); static void ssh_bpp_output_raw_data_callback(void *vctx); -Frontend *ssh_get_frontend(Ssh ssh) +Frontend *ssh_get_frontend(Ssh *ssh) { return ssh->frontend; } -static void ssh_connect_bpp(Ssh ssh) +static void ssh_connect_bpp(Ssh *ssh) { ssh->bpp->ssh = ssh; ssh->bpp->in_raw = &ssh->in_raw; @@ -129,7 +129,7 @@ static void ssh_connect_bpp(Ssh ssh) ssh->bpp->remote_bugs = ssh->remote_bugs; } -static void ssh_connect_ppl(Ssh ssh, PacketProtocolLayer *ppl) +static void ssh_connect_ppl(Ssh *ssh, PacketProtocolLayer *ppl) { ppl->bpp = ssh->bpp; ppl->user_input = &ssh->user_input; @@ -141,7 +141,7 @@ static void ssh_connect_ppl(Ssh ssh, PacketProtocolLayer *ppl) static void ssh_got_ssh_version(struct ssh_version_receiver *rcv, int major_version) { - Ssh ssh = FROMFIELD(rcv, struct ssh_tag, version_receiver); + Ssh *ssh = FROMFIELD(rcv, Ssh, version_receiver); BinaryPacketProtocol *old_bpp; PacketProtocolLayer *connection_layer; @@ -289,7 +289,7 @@ static void ssh_got_ssh_version(struct ssh_version_receiver *rcv, static void ssh_bpp_output_raw_data_callback(void *vctx) { - Ssh ssh = (Ssh)vctx; + Ssh *ssh = (Ssh *)vctx; if (!ssh->s) return; @@ -319,7 +319,7 @@ static void ssh_bpp_output_raw_data_callback(void *vctx) } } -static void ssh_shutdown_internal(Ssh ssh) +static void ssh_shutdown_internal(Ssh *ssh) { expire_timer_context(ssh); @@ -345,7 +345,7 @@ static void ssh_shutdown_internal(Ssh ssh) ssh->cl = NULL; } -static void ssh_shutdown(Ssh ssh) +static void ssh_shutdown(Ssh *ssh) { ssh_shutdown_internal(ssh); @@ -364,7 +364,7 @@ static void ssh_shutdown(Ssh ssh) bufchain_clear(&ssh->user_input); } -static void ssh_initiate_connection_close(Ssh ssh) +static void ssh_initiate_connection_close(Ssh *ssh) { /* Wind up everything above the BPP. */ ssh_shutdown_internal(ssh); @@ -388,7 +388,7 @@ static void ssh_initiate_connection_close(Ssh ssh) msg = dupvprintf(fmt, ap); \ va_end(ap); -void ssh_remote_error(Ssh ssh, const char *fmt, ...) +void ssh_remote_error(Ssh *ssh, const char *fmt, ...) { if (ssh->base_layer || !ssh->session_started) { GET_FORMATTED_MSG; @@ -406,7 +406,7 @@ void ssh_remote_error(Ssh ssh, const char *fmt, ...) } } -void ssh_remote_eof(Ssh ssh, const char *fmt, ...) +void ssh_remote_eof(Ssh *ssh, const char *fmt, ...) { if (ssh->base_layer || !ssh->session_started) { GET_FORMATTED_MSG; @@ -429,7 +429,7 @@ void ssh_remote_eof(Ssh ssh, const char *fmt, ...) } } -void ssh_proto_error(Ssh ssh, const char *fmt, ...) +void ssh_proto_error(Ssh *ssh, const char *fmt, ...) { if (ssh->base_layer || !ssh->session_started) { GET_FORMATTED_MSG; @@ -446,7 +446,7 @@ void ssh_proto_error(Ssh ssh, const char *fmt, ...) } } -void ssh_sw_abort(Ssh ssh, const char *fmt, ...) +void ssh_sw_abort(Ssh *ssh, const char *fmt, ...) { if (ssh->base_layer || !ssh->session_started) { GET_FORMATTED_MSG; @@ -463,7 +463,7 @@ void ssh_sw_abort(Ssh ssh, const char *fmt, ...) } } -void ssh_user_close(Ssh ssh, const char *fmt, ...) +void ssh_user_close(Ssh *ssh, const char *fmt, ...) { if (ssh->base_layer || !ssh->session_started) { GET_FORMATTED_MSG; @@ -486,10 +486,10 @@ void ssh_user_close(Ssh ssh, const char *fmt, ...) } } -static void ssh_socket_log(Plug plug, int type, SockAddr addr, int port, +static void ssh_socket_log(Plug *plug, int type, SockAddr *addr, int port, const char *error_msg, int error_code) { - Ssh ssh = FROMFIELD(plug, struct ssh_tag, plugvt); + Ssh *ssh = FROMFIELD(plug, Ssh, plugvt); /* * While we're attempting connection sharing, don't loudly log @@ -506,10 +506,10 @@ static void ssh_socket_log(Plug plug, int type, SockAddr addr, int port, ssh->session_started); } -static void ssh_closing(Plug plug, const char *error_msg, int error_code, +static void ssh_closing(Plug *plug, const char *error_msg, int error_code, int calling_back) { - Ssh ssh = FROMFIELD(plug, struct ssh_tag, plugvt); + Ssh *ssh = FROMFIELD(plug, Ssh, plugvt); if (error_msg) { ssh_remote_error(ssh, "Network error: %s", error_msg); } else if (ssh->bpp) { @@ -518,9 +518,9 @@ static void ssh_closing(Plug plug, const char *error_msg, int error_code, } } -static void ssh_receive(Plug plug, int urgent, char *data, int len) +static void ssh_receive(Plug *plug, int urgent, char *data, int len) { - Ssh ssh = FROMFIELD(plug, struct ssh_tag, plugvt); + Ssh *ssh = FROMFIELD(plug, Ssh, plugvt); /* Log raw data, if we're in that mode. */ if (ssh->logctx) @@ -532,9 +532,9 @@ static void ssh_receive(Plug plug, int urgent, char *data, int len) queue_idempotent_callback(&ssh->bpp->ic_in_raw); } -static void ssh_sent(Plug plug, int bufsize) +static void ssh_sent(Plug *plug, int bufsize) { - Ssh ssh = FROMFIELD(plug, struct ssh_tag, plugvt); + Ssh *ssh = FROMFIELD(plug, Ssh, plugvt); /* * If the send backlog on the SSH socket itself clears, we should * unthrottle the whole world if it was throttled. Also trigger an @@ -613,10 +613,10 @@ static const Plug_vtable Ssh_plugvt = { * Also places the canonical host name into `realhost'. It must be * freed by the caller. */ -static const char *connect_to_host(Ssh ssh, const char *host, int port, +static const char *connect_to_host(Ssh *ssh, const char *host, int port, char **realhost, int nodelay, int keepalive) { - SockAddr addr; + SockAddr *addr; const char *err; char *loghost; int addressfamily, sshprot; @@ -725,7 +725,7 @@ static const char *connect_to_host(Ssh ssh, const char *host, int port, /* * Throttle or unthrottle the SSH connection. */ -void ssh_throttle_conn(Ssh ssh, int adjust) +void ssh_throttle_conn(Ssh *ssh, int adjust) { int old_count = ssh->conn_throttle_count; int frozen; @@ -758,7 +758,7 @@ void ssh_throttle_conn(Ssh ssh, int adjust) * Throttle or unthrottle _all_ local data streams (for when sends * on the SSH connection itself back up). */ -static void ssh_throttle_all(Ssh ssh, int enable, int bufsize) +static void ssh_throttle_all(Ssh *ssh, int enable, int bufsize) { if (enable == ssh->throttled_all) return; @@ -768,7 +768,7 @@ static void ssh_throttle_all(Ssh ssh, int enable, int bufsize) ssh_throttle_all_channels(ssh->cl, enable); } -static void ssh_cache_conf_values(Ssh ssh) +static void ssh_cache_conf_values(Ssh *ssh) { ssh->pls.omit_passwords = conf_get_int(ssh->conf, CONF_logomitpass); ssh->pls.omit_data = conf_get_int(ssh->conf, CONF_logomitdata); @@ -785,10 +785,10 @@ static const char *ssh_init(Frontend *frontend, Backend **backend_handle, int nodelay, int keepalive) { const char *p; - Ssh ssh; + Ssh *ssh; - ssh = snew(struct ssh_tag); - memset(ssh, 0, sizeof(struct ssh_tag)); + ssh = snew(Ssh); + memset(ssh, 0, sizeof(Ssh)); ssh->conf = conf_copy(conf); ssh_cache_conf_values(ssh); @@ -825,7 +825,7 @@ static const char *ssh_init(Frontend *frontend, Backend **backend_handle, static void ssh_free(Backend *be) { - Ssh ssh = FROMFIELD(be, struct ssh_tag, backend); + Ssh *ssh = FROMFIELD(be, Ssh, backend); int need_random_unref; ssh_shutdown(ssh); @@ -860,7 +860,7 @@ static void ssh_free(Backend *be) */ static void ssh_reconfig(Backend *be, Conf *conf) { - Ssh ssh = FROMFIELD(be, struct ssh_tag, backend); + Ssh *ssh = FROMFIELD(be, Ssh, backend); if (ssh->pinger) pinger_reconfig(ssh->pinger, ssh->conf, conf); @@ -877,7 +877,7 @@ static void ssh_reconfig(Backend *be, Conf *conf) */ static int ssh_send(Backend *be, const char *buf, int len) { - Ssh ssh = FROMFIELD(be, struct ssh_tag, backend); + Ssh *ssh = FROMFIELD(be, Ssh, backend); if (ssh == NULL || ssh->s == NULL) return 0; @@ -894,7 +894,7 @@ static int ssh_send(Backend *be, const char *buf, int len) */ static int ssh_sendbuffer(Backend *be) { - Ssh ssh = FROMFIELD(be, struct ssh_tag, backend); + Ssh *ssh = FROMFIELD(be, Ssh, backend); int backlog; if (!ssh || !ssh->s || !ssh->cl) @@ -919,7 +919,7 @@ static int ssh_sendbuffer(Backend *be) */ static void ssh_size(Backend *be, int width, int height) { - Ssh ssh = FROMFIELD(be, struct ssh_tag, backend); + Ssh *ssh = FROMFIELD(be, Ssh, backend); ssh->term_width = width; ssh->term_height = height; @@ -956,7 +956,7 @@ static void ssh_add_special(void *vctx, const char *text, */ static const SessionSpecial *ssh_get_specials(Backend *be) { - Ssh ssh = FROMFIELD(be, struct ssh_tag, backend); + Ssh *ssh = FROMFIELD(be, Ssh, backend); /* * Ask all our active protocol layers what specials they've got, @@ -986,7 +986,7 @@ static const SessionSpecial *ssh_get_specials(Backend *be) */ static void ssh_special(Backend *be, SessionSpecialCode code, int arg) { - Ssh ssh = FROMFIELD(be, struct ssh_tag, backend); + Ssh *ssh = FROMFIELD(be, Ssh, backend); if (ssh->base_layer) ssh_ppl_special_cmd(ssh->base_layer, code, arg); @@ -998,24 +998,24 @@ static void ssh_special(Backend *be, SessionSpecialCode code, int arg) */ static void ssh_unthrottle(Backend *be, int bufsize) { - Ssh ssh = FROMFIELD(be, struct ssh_tag, backend); + Ssh *ssh = FROMFIELD(be, Ssh, backend); ssh_stdout_unthrottle(ssh->cl, bufsize); } static int ssh_connected(Backend *be) { - Ssh ssh = FROMFIELD(be, struct ssh_tag, backend); + Ssh *ssh = FROMFIELD(be, Ssh, backend); return ssh->s != NULL; } static int ssh_sendok(Backend *be) { - Ssh ssh = FROMFIELD(be, struct ssh_tag, backend); + Ssh *ssh = FROMFIELD(be, Ssh, backend); return ssh->base_layer && ssh_ppl_want_user_input(ssh->base_layer); } -void ssh_ldisc_update(Ssh ssh) +void ssh_ldisc_update(Ssh *ssh) { /* Called when the connection layer wants to propagate an update * to the line discipline options */ @@ -1025,30 +1025,30 @@ void ssh_ldisc_update(Ssh ssh) static int ssh_ldisc(Backend *be, int option) { - Ssh ssh = FROMFIELD(be, struct ssh_tag, backend); + Ssh *ssh = FROMFIELD(be, Ssh, backend); return ssh->cl ? ssh_ldisc_option(ssh->cl, option) : FALSE; } static void ssh_provide_ldisc(Backend *be, Ldisc *ldisc) { - Ssh ssh = FROMFIELD(be, struct ssh_tag, backend); + Ssh *ssh = FROMFIELD(be, Ssh, backend); ssh->ldisc = ldisc; } static void ssh_provide_logctx(Backend *be, LogContext *logctx) { - Ssh ssh = FROMFIELD(be, struct ssh_tag, backend); + Ssh *ssh = FROMFIELD(be, Ssh, backend); ssh->logctx = logctx; } -void ssh_got_exitcode(Ssh ssh, int exitcode) +void ssh_got_exitcode(Ssh *ssh, int exitcode) { ssh->exitcode = exitcode; } static int ssh_return_exitcode(Backend *be) { - Ssh ssh = FROMFIELD(be, struct ssh_tag, backend); + Ssh *ssh = FROMFIELD(be, Ssh, backend); if (ssh->s && (!ssh->session_started || ssh->base_layer)) return -1; else @@ -1062,7 +1062,7 @@ static int ssh_return_exitcode(Backend *be) */ static int ssh_cfg_info(Backend *be) { - Ssh ssh = FROMFIELD(be, struct ssh_tag, backend); + Ssh *ssh = FROMFIELD(be, Ssh, backend); if (ssh->version == 0) return 0; /* don't know yet */ else if (ssh->bare_connection) @@ -1078,11 +1078,11 @@ static int ssh_cfg_info(Backend *be) */ extern int ssh_fallback_cmd(Backend *be) { - Ssh ssh = FROMFIELD(be, struct ssh_tag, backend); + Ssh *ssh = FROMFIELD(be, Ssh, backend); return ssh->fallback_cmd; } -void ssh_got_fallback_cmd(Ssh ssh) +void ssh_got_fallback_cmd(Ssh *ssh) { ssh->fallback_cmd = TRUE; } diff --git a/ssh.h b/ssh.h index 2858a14a..8706e9f1 100644 --- a/ssh.h +++ b/ssh.h @@ -160,9 +160,9 @@ int ssh2_censor_packet( PktOut *ssh_new_packet(void); void ssh_free_pktout(PktOut *pkt); -extern Socket ssh_connection_sharing_init( +extern Socket *ssh_connection_sharing_init( const char *host, int port, Conf *conf, Frontend *frontend, - Plug sshplug, ssh_sharing_state **state); + Plug *sshplug, ssh_sharing_state **state); void ssh_connshare_provide_connlayer(ssh_sharing_state *sharestate, ConnectionLayer *cl); int ssh_share_test_for_upstream(const char *host, int port, Conf *conf); @@ -173,7 +173,7 @@ void share_activate(ssh_sharing_state *sharestate, void sharestate_free(ssh_sharing_state *state); int share_ndownstreams(ssh_sharing_state *state); -void ssh_connshare_log(Ssh ssh, int event, const char *logtext, +void ssh_connshare_log(Ssh *ssh, int event, const char *logtext, const char *ds_err, const char *us_err); void share_setup_x11_channel(ssh_sharing_connstate *cs, share_channel *chan, unsigned upstream_id, unsigned server_id, @@ -306,20 +306,20 @@ char *portfwdmgr_connect(PortFwdManager *mgr, Channel **chan_ret, char *hostname, int port, SshChannel *c, int addressfamily); -Frontend *ssh_get_frontend(Ssh ssh); +Frontend *ssh_get_frontend(Ssh *ssh); /* Communications back to ssh.c from connection layers */ -void ssh_throttle_conn(Ssh ssh, int adjust); -void ssh_got_exitcode(Ssh ssh, int status); -void ssh_ldisc_update(Ssh ssh); -void ssh_got_fallback_cmd(Ssh ssh); +void ssh_throttle_conn(Ssh *ssh, int adjust); +void ssh_got_exitcode(Ssh *ssh, int status); +void ssh_ldisc_update(Ssh *ssh); +void ssh_got_fallback_cmd(Ssh *ssh); /* Functions to abort the connection, for various reasons. */ -void ssh_remote_error(Ssh ssh, const char *fmt, ...); -void ssh_remote_eof(Ssh ssh, const char *fmt, ...); -void ssh_proto_error(Ssh ssh, const char *fmt, ...); -void ssh_sw_abort(Ssh ssh, const char *fmt, ...); -void ssh_user_close(Ssh ssh, const char *fmt, ...); +void ssh_remote_error(Ssh *ssh, const char *fmt, ...); +void ssh_remote_eof(Ssh *ssh, const char *fmt, ...); +void ssh_proto_error(Ssh *ssh, const char *fmt, ...); +void ssh_sw_abort(Ssh *ssh, const char *fmt, ...); +void ssh_user_close(Ssh *ssh, const char *fmt, ...); #define SSH_CIPHER_IDEA 1 #define SSH_CIPHER_DES 2 @@ -875,7 +875,7 @@ struct X11Display { /* PuTTY networking SockAddr to connect to the display, and associated * gubbins */ - SockAddr addr; + SockAddr *addr; int port; char *realhost; @@ -935,7 +935,7 @@ extern void platform_get_x11_auth(struct X11Display *display, Conf *); /* examine a mostly-filled-in X11Display and fill in localauth* */ extern const int platform_uses_x11_unix_by_default; /* choose default X transport in the absence of a specified one */ -SockAddr platform_get_x11_unix_address(const char *path, int displaynum); +SockAddr *platform_get_x11_unix_address(const char *path, int displaynum); /* make up a SockAddr naming the address for displaynum */ char *platform_get_x_display(void); /* allocated local X display string, if any */ @@ -1158,7 +1158,7 @@ void invent_firstbits(unsigned *one, unsigned *two); */ enum { SHARE_NONE, SHARE_DOWNSTREAM, SHARE_UPSTREAM }; int platform_ssh_share(const char *name, Conf *conf, - Plug downplug, Plug upplug, Socket *sock, + Plug *downplug, Plug *upplug, Socket **sock, char **logtext, char **ds_err, char **us_err, int can_upstream, int can_downstream); void platform_ssh_share_cleanup(const char *name); diff --git a/ssh1connection.c b/ssh1connection.c index 86e16f90..6a02676f 100644 --- a/ssh1connection.c +++ b/ssh1connection.c @@ -19,7 +19,7 @@ struct outstanding_succfail; struct ssh1_connection_state { int crState; - Ssh ssh; + Ssh *ssh; Conf *conf; int local_protoflags; @@ -248,7 +248,7 @@ static void ssh1_channel_free(struct ssh1_channel *c) } PacketProtocolLayer *ssh1_connection_new( - Ssh ssh, Conf *conf, ConnectionLayer **cl_out) + Ssh *ssh, Conf *conf, ConnectionLayer **cl_out) { struct ssh1_connection_state *s = snew(struct ssh1_connection_state); memset(s, 0, sizeof(*s)); diff --git a/ssh2connection.c b/ssh2connection.c index 5a93a977..9aa45dc9 100644 --- a/ssh2connection.c +++ b/ssh2connection.c @@ -22,7 +22,7 @@ struct outstanding_global_request; struct ssh2_connection_state { int crState; - Ssh ssh; + Ssh *ssh; ssh_sharing_state *connshare; char *peer_verstring; @@ -370,7 +370,7 @@ static void ssh2_channel_free(struct ssh2_channel *c) } PacketProtocolLayer *ssh2_connection_new( - Ssh ssh, ssh_sharing_state *connshare, int is_simple, + Ssh *ssh, ssh_sharing_state *connshare, int is_simple, Conf *conf, const char *peer_verstring, ConnectionLayer **cl_out) { struct ssh2_connection_state *s = snew(struct ssh2_connection_state); diff --git a/sshbpp.h b/sshbpp.h index 831145e6..ee5c1c12 100644 --- a/sshbpp.h +++ b/sshbpp.h @@ -22,7 +22,7 @@ struct BinaryPacketProtocol { PktOutQueue out_pq; PacketLogSettings *pls; LogContext *logctx; - Ssh ssh; + Ssh *ssh; /* ic_in_raw is filled in by the BPP (probably by calling * ssh_bpp_common_setup). The BPP's owner triggers it when data is diff --git a/sshppl.h b/sshppl.h index 29944df3..f139263d 100644 --- a/sshppl.h +++ b/sshppl.h @@ -54,7 +54,7 @@ struct PacketProtocolLayer { /* Logging and error-reporting facilities. */ void *frontend; /* for logevent, dialog boxes etc */ - Ssh ssh; /* for session termination + assorted connection-layer ops */ + Ssh *ssh; /* for session termination + assorted connection-layer ops */ /* Known bugs in the remote implementation. */ unsigned remote_bugs; @@ -89,7 +89,7 @@ PacketProtocolLayer *ssh1_login_new( Conf *conf, const char *host, int port, PacketProtocolLayer *successor_layer); PacketProtocolLayer *ssh1_connection_new( - Ssh ssh, Conf *conf, ConnectionLayer **cl_out); + Ssh *ssh, Conf *conf, ConnectionLayer **cl_out); struct DataTransferStats; struct ssh_connection_shared_gss_state; @@ -108,7 +108,7 @@ PacketProtocolLayer *ssh2_userauth_new( int try_gssapi_auth, int try_gssapi_kex_auth, int gssapi_fwd, struct ssh_connection_shared_gss_state *shgss); PacketProtocolLayer *ssh2_connection_new( - Ssh ssh, ssh_sharing_state *connshare, int is_simple, + Ssh *ssh, ssh_sharing_state *connshare, int is_simple, Conf *conf, const char *peer_verstring, ConnectionLayer **cl_out); /* Can't put this in the userauth constructor without having a diff --git a/sshshare.c b/sshshare.c index c425140a..3de2caa8 100644 --- a/sshshare.c +++ b/sshshare.c @@ -141,7 +141,7 @@ struct ssh_sharing_state { char *sockname; /* the socket name, kept for cleanup */ - Socket listensock; /* the master listening Socket */ + Socket *listensock; /* the master listening Socket */ tree234 *connections; /* holds ssh_sharing_connstates */ unsigned nextid; /* preferred id for next connstate */ ConnectionLayer *cl; /* instance of the ssh connection layer */ @@ -155,7 +155,7 @@ struct share_globreq; struct ssh_sharing_connstate { unsigned id; /* used to identify this downstream in log messages */ - Socket sock; /* the Socket for this connection */ + Socket *sock; /* the Socket for this connection */ struct ssh_sharing_state *parent; int crLine; /* coroutine state for share_receive */ @@ -947,7 +947,7 @@ static void share_disconnect(struct ssh_sharing_connstate *cs, share_begin_cleanup(cs); } -static void share_closing(Plug plug, const char *error_msg, int error_code, +static void share_closing(Plug *plug, const char *error_msg, int error_code, int calling_back) { struct ssh_sharing_connstate *cs = FROMFIELD( @@ -1764,7 +1764,7 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs, (c) = (unsigned char)*data++; \ } while (0) -static void share_receive(Plug plug, int urgent, char *data, int len) +static void share_receive(Plug *plug, int urgent, char *data, int len) { ssh_sharing_connstate *cs = FROMFIELD( plug, ssh_sharing_connstate, plugvt); @@ -1840,7 +1840,7 @@ static void share_receive(Plug plug, int urgent, char *data, int len) crFinishV; } -static void share_sent(Plug plug, int bufsize) +static void share_sent(Plug *plug, int bufsize) { /* ssh_sharing_connstate *cs = FROMFIELD( plug, ssh_sharing_connstate, plugvt); */ @@ -1855,7 +1855,7 @@ static void share_sent(Plug plug, int bufsize) */ } -static void share_listen_closing(Plug plug, const char *error_msg, +static void share_listen_closing(Plug *plug, const char *error_msg, int error_code, int calling_back) { ssh_sharing_state *sharestate = FROMFIELD(plug, ssh_sharing_state, plugvt); @@ -1918,7 +1918,7 @@ static const Plug_vtable ssh_sharing_conn_plugvt = { NULL /* no accepting function, because we've already done it */ }; -static int share_listen_accepting(Plug plug, +static int share_listen_accepting(Plug *plug, accept_fn_t constructor, accept_ctx_t ctx) { struct ssh_sharing_state *sharestate = FROMFIELD( @@ -2030,13 +2030,13 @@ int ssh_share_test_for_upstream(const char *host, int port, Conf *conf) { char *sockname, *logtext, *ds_err, *us_err; int result; - Socket sock; + Socket *sock; sockname = ssh_share_sockname(host, port, conf); sock = NULL; logtext = ds_err = us_err = NULL; - result = platform_ssh_share(sockname, conf, nullplug, (Plug)NULL, &sock, + result = platform_ssh_share(sockname, conf, nullplug, (Plug *)NULL, &sock, &logtext, &ds_err, &us_err, FALSE, TRUE); sfree(logtext); @@ -2078,14 +2078,14 @@ void ssh_connshare_provide_connlayer(ssh_sharing_state *sharestate, * to the upstream; otherwise (whether or not we have established an * upstream) we return NULL. */ -Socket ssh_connection_sharing_init( +Socket *ssh_connection_sharing_init( const char *host, int port, Conf *conf, Frontend *frontend, - Plug sshplug, ssh_sharing_state **state) + Plug *sshplug, ssh_sharing_state **state) { int result, can_upstream, can_downstream; char *logtext, *ds_err, *us_err; char *sockname; - Socket sock, toret = NULL; + Socket *sock, *toret = NULL; struct ssh_sharing_state *sharestate; if (!conf_get_int(conf, CONF_ssh_connection_sharing)) diff --git a/telnet.c b/telnet.c index 171b4210..805cb13b 100644 --- a/telnet.c +++ b/telnet.c @@ -168,8 +168,9 @@ static const struct Opt *const opts[] = { &o_we_sga, &o_they_sga, &o_we_bin, &o_they_bin, NULL }; -typedef struct telnet_tag { - Socket s; +typedef struct Telnet Telnet; +struct Telnet { + Socket *s; int closed_on_socket_error; Frontend *frontend; @@ -194,24 +195,24 @@ typedef struct telnet_tag { Conf *conf; - Pinger pinger; + Pinger *pinger; const Plug_vtable *plugvt; Backend backend; -} *Telnet; +}; #define TELNET_MAX_BACKLOG 4096 #define SB_DELTA 1024 -static void c_write(Telnet telnet, const void *buf, int len) +static void c_write(Telnet *telnet, const void *buf, int len) { int backlog; backlog = from_backend(telnet->frontend, 0, buf, len); sk_set_frozen(telnet->s, backlog > TELNET_MAX_BACKLOG); } -static void log_option(Telnet telnet, const char *sender, int cmd, int option) +static void log_option(Telnet *telnet, const char *sender, int cmd, int option) { char *buf; /* @@ -227,7 +228,7 @@ static void log_option(Telnet telnet, const char *sender, int cmd, int option) sfree(buf); } -static void send_opt(Telnet telnet, int cmd, int option) +static void send_opt(Telnet *telnet, int cmd, int option) { unsigned char b[3]; @@ -238,7 +239,7 @@ static void send_opt(Telnet telnet, int cmd, int option) log_option(telnet, "client", cmd, option); } -static void deactivate_option(Telnet telnet, const struct Opt *o) +static void deactivate_option(Telnet *telnet, const struct Opt *o) { if (telnet->opt_states[o->index] == REQUESTED || telnet->opt_states[o->index] == ACTIVE) @@ -249,7 +250,7 @@ static void deactivate_option(Telnet telnet, const struct Opt *o) /* * Generate side effects of enabling or disabling an option. */ -static void option_side_effects(Telnet telnet, const struct Opt *o, int enabled) +static void option_side_effects(Telnet *telnet, const struct Opt *o, int enabled) { if (o->option == TELOPT_ECHO && o->send == DO) telnet->echoing = !enabled; @@ -276,7 +277,7 @@ static void option_side_effects(Telnet telnet, const struct Opt *o, int enabled) } } -static void activate_option(Telnet telnet, const struct Opt *o) +static void activate_option(Telnet *telnet, const struct Opt *o) { if (o->send == WILL && o->option == TELOPT_NAWS) backend_size(&telnet->backend, @@ -294,7 +295,7 @@ static void activate_option(Telnet telnet, const struct Opt *o) option_side_effects(telnet, o, 1); } -static void refused_option(Telnet telnet, const struct Opt *o) +static void refused_option(Telnet *telnet, const struct Opt *o) { if (o->send == WILL && o->option == TELOPT_NEW_ENVIRON && telnet->opt_states[o_oenv.index] == INACTIVE) { @@ -304,7 +305,7 @@ static void refused_option(Telnet telnet, const struct Opt *o) option_side_effects(telnet, o, 0); } -static void proc_rec_opt(Telnet telnet, int cmd, int option) +static void proc_rec_opt(Telnet *telnet, int cmd, int option) { const struct Opt *const *o; @@ -356,7 +357,7 @@ static void proc_rec_opt(Telnet telnet, int cmd, int option) send_opt(telnet, (cmd == WILL ? DONT : WONT), option); } -static void process_subneg(Telnet telnet) +static void process_subneg(Telnet *telnet) { unsigned char *b, *p, *q; int var, value, n, bsize; @@ -523,7 +524,7 @@ static void process_subneg(Telnet telnet) } } -static void do_telnet_read(Telnet telnet, char *buf, int len) +static void do_telnet_read(Telnet *telnet, char *buf, int len) { char *outbuf = NULL; int outbuflen = 0, outbufsize = 0; @@ -641,19 +642,19 @@ static void do_telnet_read(Telnet telnet, char *buf, int len) sfree(outbuf); } -static void telnet_log(Plug plug, int type, SockAddr addr, int port, +static void telnet_log(Plug *plug, int type, SockAddr *addr, int port, const char *error_msg, int error_code) { - Telnet telnet = FROMFIELD(plug, struct telnet_tag, plugvt); + Telnet *telnet = FROMFIELD(plug, Telnet, plugvt); backend_socket_log(telnet->frontend, type, addr, port, error_msg, error_code, telnet->conf, telnet->session_started); } -static void telnet_closing(Plug plug, const char *error_msg, int error_code, +static void telnet_closing(Plug *plug, const char *error_msg, int error_code, int calling_back) { - Telnet telnet = FROMFIELD(plug, struct telnet_tag, plugvt); + Telnet *telnet = FROMFIELD(plug, Telnet, plugvt); /* * We don't implement independent EOF in each direction for Telnet @@ -675,18 +676,18 @@ static void telnet_closing(Plug plug, const char *error_msg, int error_code, /* Otherwise, the remote side closed the connection normally. */ } -static void telnet_receive(Plug plug, int urgent, char *data, int len) +static void telnet_receive(Plug *plug, int urgent, char *data, int len) { - Telnet telnet = FROMFIELD(plug, struct telnet_tag, plugvt); + Telnet *telnet = FROMFIELD(plug, Telnet, plugvt); if (urgent) telnet->in_synch = TRUE; telnet->session_started = TRUE; do_telnet_read(telnet, data, len); } -static void telnet_sent(Plug plug, int bufsize) +static void telnet_sent(Plug *plug, int bufsize) { - Telnet telnet = FROMFIELD(plug, struct telnet_tag, plugvt); + Telnet *telnet = FROMFIELD(plug, Telnet, plugvt); telnet->bufsize = bufsize; } @@ -709,13 +710,13 @@ static const char *telnet_init(Frontend *frontend, Backend **backend_handle, Conf *conf, const char *host, int port, char **realhost, int nodelay, int keepalive) { - SockAddr addr; + SockAddr *addr; const char *err; - Telnet telnet; + Telnet *telnet; char *loghost; int addressfamily; - telnet = snew(struct telnet_tag); + telnet = snew(Telnet); telnet->plugvt = &Telnet_plugvt; telnet->backend.vt = &telnet_backend; telnet->conf = conf_copy(conf); @@ -808,7 +809,7 @@ static const char *telnet_init(Frontend *frontend, Backend **backend_handle, static void telnet_free(Backend *be) { - Telnet telnet = FROMFIELD(be, struct telnet_tag, backend); + Telnet *telnet = FROMFIELD(be, Telnet, backend); sfree(telnet->sb_buf); if (telnet->s) @@ -825,7 +826,7 @@ static void telnet_free(Backend *be) */ static void telnet_reconfig(Backend *be, Conf *conf) { - Telnet telnet = FROMFIELD(be, struct telnet_tag, backend); + Telnet *telnet = FROMFIELD(be, Telnet, backend); pinger_reconfig(telnet->pinger, telnet->conf, conf); conf_free(telnet->conf); telnet->conf = conf_copy(conf); @@ -836,7 +837,7 @@ static void telnet_reconfig(Backend *be, Conf *conf) */ static int telnet_send(Backend *be, const char *buf, int len) { - Telnet telnet = FROMFIELD(be, struct telnet_tag, backend); + Telnet *telnet = FROMFIELD(be, Telnet, backend); unsigned char *p, *end; static const unsigned char iac[2] = { IAC, IAC }; static const unsigned char cr[2] = { CR, NUL }; @@ -871,7 +872,7 @@ static int telnet_send(Backend *be, const char *buf, int len) */ static int telnet_sendbuffer(Backend *be) { - Telnet telnet = FROMFIELD(be, struct telnet_tag, backend); + Telnet *telnet = FROMFIELD(be, Telnet, backend); return telnet->bufsize; } @@ -880,7 +881,7 @@ static int telnet_sendbuffer(Backend *be) */ static void telnet_size(Backend *be, int width, int height) { - Telnet telnet = FROMFIELD(be, struct telnet_tag, backend); + Telnet *telnet = FROMFIELD(be, Telnet, backend); unsigned char b[24]; int n; char *logbuf; @@ -916,7 +917,7 @@ static void telnet_size(Backend *be, int width, int height) */ static void telnet_special(Backend *be, SessionSpecialCode code, int arg) { - Telnet telnet = FROMFIELD(be, struct telnet_tag, backend); + Telnet *telnet = FROMFIELD(be, Telnet, backend); unsigned char b[2]; if (telnet->s == NULL) @@ -1021,25 +1022,25 @@ static const SessionSpecial *telnet_get_specials(Backend *be) static int telnet_connected(Backend *be) { - Telnet telnet = FROMFIELD(be, struct telnet_tag, backend); + Telnet *telnet = FROMFIELD(be, Telnet, backend); return telnet->s != NULL; } static int telnet_sendok(Backend *be) { - /* Telnet telnet = FROMFIELD(be, struct telnet_tag, backend); */ + /* Telnet *telnet = FROMFIELD(be, Telnet, backend); */ return 1; } static void telnet_unthrottle(Backend *be, int backlog) { - Telnet telnet = FROMFIELD(be, struct telnet_tag, backend); + Telnet *telnet = FROMFIELD(be, Telnet, backend); sk_set_frozen(telnet->s, backlog > TELNET_MAX_BACKLOG); } static int telnet_ldisc(Backend *be, int option) { - Telnet telnet = FROMFIELD(be, struct telnet_tag, backend); + Telnet *telnet = FROMFIELD(be, Telnet, backend); if (option == LD_ECHO) return telnet->echoing; if (option == LD_EDIT) @@ -1049,7 +1050,7 @@ static int telnet_ldisc(Backend *be, int option) static void telnet_provide_ldisc(Backend *be, Ldisc *ldisc) { - Telnet telnet = FROMFIELD(be, struct telnet_tag, backend); + Telnet *telnet = FROMFIELD(be, Telnet, backend); telnet->ldisc = ldisc; } @@ -1060,7 +1061,7 @@ static void telnet_provide_logctx(Backend *be, LogContext *logctx) static int telnet_exitcode(Backend *be) { - Telnet telnet = FROMFIELD(be, struct telnet_tag, backend); + Telnet *telnet = FROMFIELD(be, Telnet, backend); if (telnet->s != NULL) return -1; /* still connected */ else if (telnet->closed_on_socket_error) diff --git a/unix/unix.h b/unix/unix.h index 9a93a059..75093668 100644 --- a/unix/unix.h +++ b/unix/unix.h @@ -314,7 +314,7 @@ int init_ucs(struct unicode_data *ucsdata, char *line_codepage, /* * Spare function exported directly from uxnet.c. */ -void *sk_getxdmdata(Socket sock, int *lenp); +void *sk_getxdmdata(Socket *sock, int *lenp); /* * General helpful Unix stuff: more helpful version of the FD_SET diff --git a/unix/uxnet.c b/unix/uxnet.c index e0a7cb77..e924f449 100644 --- a/unix/uxnet.c +++ b/unix/uxnet.c @@ -63,7 +63,7 @@ typedef struct NetSocket NetSocket; struct NetSocket { const char *error; int s; - Plug plug; + Plug *plug; bufchain output_data; int connected; /* irrelevant for listening sockets */ int writable; @@ -79,7 +79,7 @@ struct NetSocket { int listener; int nodelay, keepalive; /* for connect()-type sockets */ int privport, port; /* and again */ - SockAddr addr; + SockAddr *addr; SockAddrStep step; /* * We sometimes need pairs of Socket structures to be linked: @@ -92,7 +92,7 @@ struct NetSocket { const Socket_vtable *sockvt; }; -struct SockAddr_tag { +struct SockAddr { int refcount; const char *error; enum { UNRESOLVED, UNIX, IP } superfamily; @@ -184,9 +184,9 @@ void sk_cleanup(void) } } -SockAddr sk_namelookup(const char *host, char **canonicalname, int address_family) +SockAddr *sk_namelookup(const char *host, char **canonicalname, int address_family) { - SockAddr ret = snew(struct SockAddr_tag); + SockAddr *ret = snew(SockAddr); #ifndef NO_IPV6 struct addrinfo hints; int err; @@ -198,7 +198,7 @@ SockAddr sk_namelookup(const char *host, char **canonicalname, int address_famil char realhost[8192]; /* Clear the structure and default to IPv4. */ - memset(ret, 0, sizeof(struct SockAddr_tag)); + memset(ret, 0, sizeof(SockAddr)); ret->superfamily = UNRESOLVED; *realhost = '\0'; ret->error = NULL; @@ -277,9 +277,9 @@ SockAddr sk_namelookup(const char *host, char **canonicalname, int address_famil return ret; } -SockAddr sk_nonamelookup(const char *host) +SockAddr *sk_nonamelookup(const char *host) { - SockAddr ret = snew(struct SockAddr_tag); + SockAddr *ret = snew(SockAddr); ret->error = NULL; ret->superfamily = UNRESOLVED; strncpy(ret->hostname, host, lenof(ret->hostname)); @@ -293,7 +293,7 @@ SockAddr sk_nonamelookup(const char *host) return ret; } -static int sk_nextaddr(SockAddr addr, SockAddrStep *step) +static int sk_nextaddr(SockAddr *addr, SockAddrStep *step) { #ifndef NO_IPV6 if (step->ai && step->ai->ai_next) { @@ -311,7 +311,7 @@ static int sk_nextaddr(SockAddr addr, SockAddrStep *step) #endif } -void sk_getaddr(SockAddr addr, char *buf, int buflen) +void sk_getaddr(SockAddr *addr, char *buf, int buflen) { if (addr->superfamily == UNRESOLVED || addr->superfamily == UNIX) { strncpy(buf, addr->hostname, buflen); @@ -344,10 +344,10 @@ void sk_getaddr(SockAddr addr, char *buf, int buflen) * rather than dynamically allocated - that should clue in anyone * writing a call to it that something is weird about it.) */ -static struct SockAddr_tag sk_extractaddr_tmp( - SockAddr addr, const SockAddrStep *step) +static SockAddr sk_extractaddr_tmp( + SockAddr *addr, const SockAddrStep *step) { - struct SockAddr_tag toret; + SockAddr toret; toret = *addr; /* structure copy */ toret.refcount = 1; @@ -363,7 +363,7 @@ static struct SockAddr_tag sk_extractaddr_tmp( return toret; } -int sk_addr_needs_port(SockAddr addr) +int sk_addr_needs_port(SockAddr *addr) { if (addr->superfamily == UNRESOLVED || addr->superfamily == UNIX) { return FALSE; @@ -399,7 +399,7 @@ static int sockaddr_is_loopback(struct sockaddr *sa) } } -int sk_address_is_local(SockAddr addr) +int sk_address_is_local(SockAddr *addr) { if (addr->superfamily == UNRESOLVED) return 0; /* we don't know; assume not */ @@ -419,12 +419,12 @@ int sk_address_is_local(SockAddr addr) } } -int sk_address_is_special_local(SockAddr addr) +int sk_address_is_special_local(SockAddr *addr) { return addr->superfamily == UNIX; } -int sk_addrtype(SockAddr addr) +int sk_addrtype(SockAddr *addr) { SockAddrStep step; int family; @@ -438,7 +438,7 @@ int sk_addrtype(SockAddr addr) ADDRTYPE_NAME); } -void sk_addrcopy(SockAddr addr, char *buf) +void sk_addrcopy(SockAddr *addr, char *buf) { SockAddrStep step; int family; @@ -463,7 +463,7 @@ void sk_addrcopy(SockAddr addr, char *buf) #endif } -void sk_addr_free(SockAddr addr) +void sk_addr_free(SockAddr *addr) { if (--addr->refcount > 0) return; @@ -476,22 +476,22 @@ void sk_addr_free(SockAddr addr) sfree(addr); } -SockAddr sk_addr_dup(SockAddr addr) +SockAddr *sk_addr_dup(SockAddr *addr) { addr->refcount++; return addr; } -static Plug sk_net_plug(Socket sock, Plug p) +static Plug *sk_net_plug(Socket *sock, Plug *p) { NetSocket *s = FROMFIELD(sock, NetSocket, sockvt); - Plug ret = s->plug; + Plug *ret = s->plug; if (p) s->plug = p; return ret; } -static void sk_net_flush(Socket s) +static void sk_net_flush(Socket *s) { /* * We send data to the socket as soon as we can anyway, @@ -499,13 +499,13 @@ static void sk_net_flush(Socket s) */ } -static void sk_net_close(Socket s); -static int sk_net_write(Socket s, const void *data, int len); -static int sk_net_write_oob(Socket s, const void *data, int len); -static void sk_net_write_eof(Socket s); -static void sk_net_set_frozen(Socket s, int is_frozen); -static char *sk_net_peer_info(Socket s); -static const char *sk_net_socket_error(Socket s); +static void sk_net_close(Socket *s); +static int sk_net_write(Socket *s, const void *data, int len); +static int sk_net_write_oob(Socket *s, const void *data, int len); +static void sk_net_write_eof(Socket *s); +static void sk_net_set_frozen(Socket *s, int is_frozen); +static char *sk_net_peer_info(Socket *s); +static const char *sk_net_socket_error(Socket *s); static struct Socket_vtable NetSocket_sockvt = { sk_net_plug, @@ -519,7 +519,7 @@ static struct Socket_vtable NetSocket_sockvt = { sk_net_peer_info, }; -static Socket sk_net_accept(accept_ctx_t ctx, Plug plug) +static Socket *sk_net_accept(accept_ctx_t ctx, Plug *plug) { int sockfd = ctx.i; NetSocket *ret; @@ -581,7 +581,7 @@ static int try_connect(NetSocket *sock) close(sock->s); { - struct SockAddr_tag thisaddr = sk_extractaddr_tmp( + SockAddr thisaddr = sk_extractaddr_tmp( sock->addr, &sock->step); plug_log(sock->plug, 0, &thisaddr, sock->port, NULL, 0); } @@ -752,15 +752,15 @@ static int try_connect(NetSocket *sock) add234(sktree, sock); if (err) { - struct SockAddr_tag thisaddr = sk_extractaddr_tmp( + SockAddr thisaddr = sk_extractaddr_tmp( sock->addr, &sock->step); plug_log(sock->plug, 1, &thisaddr, sock->port, strerror(err), err); } return err; } -Socket sk_new(SockAddr addr, int port, int privport, int oobinline, - int nodelay, int keepalive, Plug plug) +Socket *sk_new(SockAddr *addr, int port, int privport, int oobinline, + int nodelay, int keepalive, Plug *plug) { NetSocket *ret; int err; @@ -804,8 +804,8 @@ Socket sk_new(SockAddr addr, int port, int privport, int oobinline, return &ret->sockvt; } -Socket sk_newlistener(const char *srcaddr, int port, Plug plug, - int local_host_only, int orig_address_family) +Socket *sk_newlistener(const char *srcaddr, int port, Plug *plug, + int local_host_only, int orig_address_family) { int s; #ifndef NO_IPV6 @@ -1009,7 +1009,7 @@ Socket sk_newlistener(const char *srcaddr, int port, Plug plug, return &ret->sockvt; } -static void sk_net_close(Socket sock) +static void sk_net_close(Socket *sock) { NetSocket *s = FROMFIELD(sock, NetSocket, sockvt); @@ -1026,7 +1026,7 @@ static void sk_net_close(Socket sock) sfree(s); } -void *sk_getxdmdata(Socket sock, int *lenp) +void *sk_getxdmdata(Socket *sock, int *lenp) { NetSocket *s; union sockaddr_union u; @@ -1184,7 +1184,7 @@ void try_send(NetSocket *s) uxsel_tell(s); } -static int sk_net_write(Socket sock, const void *buf, int len) +static int sk_net_write(Socket *sock, const void *buf, int len) { NetSocket *s = FROMFIELD(sock, NetSocket, sockvt); @@ -1210,7 +1210,7 @@ static int sk_net_write(Socket sock, const void *buf, int len) return bufchain_size(&s->output_data); } -static int sk_net_write_oob(Socket sock, const void *buf, int len) +static int sk_net_write_oob(Socket *sock, const void *buf, int len) { NetSocket *s = FROMFIELD(sock, NetSocket, sockvt); @@ -1239,7 +1239,7 @@ static int sk_net_write_oob(Socket sock, const void *buf, int len) return s->sending_oob; } -static void sk_net_write_eof(Socket sock) +static void sk_net_write_eof(Socket *sock) { NetSocket *s = FROMFIELD(sock, NetSocket, sockvt); @@ -1417,7 +1417,7 @@ static void net_select_result(int fd, int event) * with the next candidate address, if we have * more than one. */ - struct SockAddr_tag thisaddr; + SockAddr thisaddr; assert(s->addr); thisaddr = sk_extractaddr_tmp(s->addr, &s->step); @@ -1462,17 +1462,17 @@ static void net_select_result(int fd, int event) * if there's a problem. These functions extract an error message, * or return NULL if there's no problem. */ -const char *sk_addr_error(SockAddr addr) +const char *sk_addr_error(SockAddr *addr) { return addr->error; } -static const char *sk_net_socket_error(Socket sock) +static const char *sk_net_socket_error(Socket *sock) { NetSocket *s = FROMFIELD(sock, NetSocket, sockvt); return s->error; } -static void sk_net_set_frozen(Socket sock, int is_frozen) +static void sk_net_set_frozen(Socket *sock, int is_frozen) { NetSocket *s = FROMFIELD(sock, NetSocket, sockvt); if (s->frozen == is_frozen) @@ -1481,7 +1481,7 @@ static void sk_net_set_frozen(Socket sock, int is_frozen) uxsel_tell(s); } -static char *sk_net_peer_info(Socket sock) +static char *sk_net_peer_info(Socket *sock) { NetSocket *s = FROMFIELD(sock, NetSocket, sockvt); union sockaddr_union addr; @@ -1572,9 +1572,9 @@ char *get_hostname(void) return hostname; } -SockAddr platform_get_x11_unix_address(const char *sockpath, int displaynum) +SockAddr *platform_get_x11_unix_address(const char *sockpath, int displaynum) { - SockAddr ret = snew(struct SockAddr_tag); + SockAddr *ret = snew(SockAddr); int n; memset(ret, 0, sizeof *ret); @@ -1606,9 +1606,9 @@ SockAddr platform_get_x11_unix_address(const char *sockpath, int displaynum) return ret; } -SockAddr unix_sock_addr(const char *path) +SockAddr *unix_sock_addr(const char *path) { - SockAddr ret = snew(struct SockAddr_tag); + SockAddr *ret = snew(SockAddr); int n; memset(ret, 0, sizeof *ret); @@ -1631,7 +1631,7 @@ SockAddr unix_sock_addr(const char *path) return ret; } -Socket new_unix_listener(SockAddr listenaddr, Plug plug) +Socket *new_unix_listener(SockAddr *listenaddr, Plug *plug) { int s; union sockaddr_union u; diff --git a/unix/uxpgnt.c b/unix/uxpgnt.c index 1b7004f8..0a0a14ea 100644 --- a/unix/uxpgnt.c +++ b/unix/uxpgnt.c @@ -20,8 +20,8 @@ #include "misc.h" #include "pageant.h" -SockAddr unix_sock_addr(const char *path); -Socket new_unix_listener(SockAddr listenaddr, Plug plug); +SockAddr *unix_sock_addr(const char *path); +Socket *new_unix_listener(SockAddr *listenaddr, Plug *plug); void modalfatalbox(const char *p, ...) { @@ -166,11 +166,11 @@ int chan_no_eager_close(Channel *chan, int s, int r) { return FALSE; } * except that x11_closing has to signal back to the main loop that * it's time to terminate. */ -static void x11_log(Plug p, int type, SockAddr addr, int port, +static void x11_log(Plug *p, int type, SockAddr *addr, int port, const char *error_msg, int error_code) {} -static void x11_receive(Plug plug, int urgent, char *data, int len) {} -static void x11_sent(Plug plug, int bufsize) {} -static void x11_closing(Plug plug, const char *error_msg, int error_code, +static void x11_receive(Plug *plug, int urgent, char *data, int len) {} +static void x11_sent(Plug *plug, int bufsize) {} +static void x11_closing(Plug *plug, const char *error_msg, int error_code, int calling_back) { time_to_die = TRUE; @@ -741,8 +741,8 @@ void run_agent(void) const char *err; char *username, *socketdir; struct pageant_listen_state *pl; - Plug pl_plug; - Socket sock; + Plug *pl_plug; + Socket *sock; unsigned long now; int *fdlist; int fd; @@ -799,7 +799,7 @@ void run_agent(void) struct X11Display *disp; void *greeting; int greetinglen; - Socket s; + Socket *s; struct X11Connection *conn; if (!display) { diff --git a/unix/uxproxy.c b/unix/uxproxy.c index c6708343..8e121f15 100644 --- a/unix/uxproxy.c +++ b/unix/uxproxy.c @@ -20,7 +20,7 @@ typedef struct LocalProxySocket { char *error; - Plug plug; + Plug *plug; bufchain pending_output_data; bufchain pending_input_data; @@ -103,16 +103,16 @@ static int localproxy_errfd_find(void *av, void *bv) /* basic proxy socket functions */ -static Plug sk_localproxy_plug (Socket s, Plug p) +static Plug *sk_localproxy_plug (Socket *s, Plug *p) { LocalProxySocket *ps = FROMFIELD(s, LocalProxySocket, sockvt); - Plug ret = ps->plug; + Plug *ret = ps->plug; if (p) ps->plug = p; return ret; } -static void sk_localproxy_close (Socket s) +static void sk_localproxy_close (Socket *s) { LocalProxySocket *ps = FROMFIELD(s, LocalProxySocket, sockvt); @@ -200,7 +200,7 @@ static int localproxy_try_send(LocalProxySocket *ps) return sent; } -static int sk_localproxy_write (Socket s, const void *data, int len) +static int sk_localproxy_write (Socket *s, const void *data, int len) { LocalProxySocket *ps = FROMFIELD(s, LocalProxySocket, sockvt); @@ -213,7 +213,7 @@ static int sk_localproxy_write (Socket s, const void *data, int len) return bufchain_size(&ps->pending_output_data); } -static int sk_localproxy_write_oob (Socket s, const void *data, int len) +static int sk_localproxy_write_oob (Socket *s, const void *data, int len) { /* * oob data is treated as inband; nasty, but nothing really @@ -222,7 +222,7 @@ static int sk_localproxy_write_oob (Socket s, const void *data, int len) return sk_localproxy_write(s, data, len); } -static void sk_localproxy_write_eof (Socket s) +static void sk_localproxy_write_eof (Socket *s) { LocalProxySocket *ps = FROMFIELD(s, LocalProxySocket, sockvt); @@ -232,13 +232,13 @@ static void sk_localproxy_write_eof (Socket s) localproxy_try_send(ps); } -static void sk_localproxy_flush (Socket s) +static void sk_localproxy_flush (Socket *s) { /* LocalProxySocket *ps = FROMFIELD(s, LocalProxySocket, sockvt); */ /* do nothing */ } -static void sk_localproxy_set_frozen (Socket s, int is_frozen) +static void sk_localproxy_set_frozen (Socket *s, int is_frozen) { LocalProxySocket *ps = FROMFIELD(s, LocalProxySocket, sockvt); @@ -251,7 +251,7 @@ static void sk_localproxy_set_frozen (Socket s, int is_frozen) uxsel_set(ps->from_cmd, 1, localproxy_select_result); } -static const char * sk_localproxy_socket_error (Socket s) +static const char * sk_localproxy_socket_error (Socket *s) { LocalProxySocket *ps = FROMFIELD(s, LocalProxySocket, sockvt); return ps->error; @@ -315,10 +315,10 @@ static const Socket_vtable LocalProxySocket_sockvt = { NULL, /* peer_info */ }; -Socket platform_new_connection(SockAddr addr, const char *hostname, - int port, int privport, - int oobinline, int nodelay, int keepalive, - Plug plug, Conf *conf) +Socket *platform_new_connection(SockAddr *addr, const char *hostname, + int port, int privport, + int oobinline, int nodelay, int keepalive, + Plug *plug, Conf *conf) { char *cmd; diff --git a/unix/uxpty.c b/unix/uxpty.c index 41a96747..3389074c 100644 --- a/unix/uxpty.c +++ b/unix/uxpty.c @@ -60,7 +60,7 @@ #endif #endif -typedef struct pty_tag *Pty; +typedef struct Pty Pty; /* * The pty_signal_pipe, along with the SIGCHLD handler, must be @@ -68,7 +68,7 @@ typedef struct pty_tag *Pty; */ static int pty_signal_pipe[2] = { -1, -1 }; /* obviously bogus initial val */ -struct pty_tag { +struct Pty { Conf *conf; int master_fd, slave_fd; Frontend *frontend; @@ -88,8 +88,8 @@ struct pty_tag { */ static int pty_compare_by_fd(void *av, void *bv) { - Pty a = (Pty)av; - Pty b = (Pty)bv; + Pty *a = (Pty *)av; + Pty *b = (Pty *)bv; if (a->master_fd < b->master_fd) return -1; @@ -101,7 +101,7 @@ static int pty_compare_by_fd(void *av, void *bv) static int pty_find_by_fd(void *av, void *bv) { int a = *(int *)av; - Pty b = (Pty)bv; + Pty *b = (Pty *)bv; if (a < b->master_fd) return -1; @@ -119,8 +119,8 @@ static tree234 *ptys_by_fd = NULL; */ static int pty_compare_by_pid(void *av, void *bv) { - Pty a = (Pty)av; - Pty b = (Pty)bv; + Pty *a = (Pty *)av; + Pty *b = (Pty *)bv; if (a->child_pid < b->child_pid) return -1; @@ -132,7 +132,7 @@ static int pty_compare_by_pid(void *av, void *bv) static int pty_find_by_pid(void *av, void *bv) { pid_t a = *(pid_t *)av; - Pty b = (Pty)bv; + Pty *b = (Pty *)bv; if (a < b->child_pid) return -1; @@ -158,7 +158,7 @@ static tree234 *ptys_by_pid = NULL; * be single-instance, so we can declare utmp-related variables * here. */ -static Pty single_pty = NULL; +static Pty *single_pty = NULL; #ifndef OMIT_UTMP static pid_t pty_utmp_helper_pid = -1; @@ -176,8 +176,8 @@ char **pty_argv; char *pty_osx_envrestore_prefix; -static void pty_close(Pty pty); -static void pty_try_write(Pty pty); +static void pty_close(Pty *pty); +static void pty_try_write(Pty *pty); #ifndef OMIT_UTMP static void setup_utmp(char *ttyname, char *location) @@ -286,7 +286,7 @@ static void fatal_sig_handler(int signum) } #endif -static int pty_open_slave(Pty pty) +static int pty_open_slave(Pty *pty) { if (pty->slave_fd < 0) { pty->slave_fd = open(pty->name, O_RDWR); @@ -296,7 +296,7 @@ static int pty_open_slave(Pty pty) return pty->slave_fd; } -static void pty_open_master(Pty pty) +static void pty_open_master(Pty *pty) { #ifdef BSD_PTYS const char chars1[] = "pqrstuvwxyz"; @@ -405,9 +405,9 @@ static void pty_open_master(Pty pty) add234(ptys_by_fd, pty); } -static Pty new_pty_struct(void) +static Pty *new_pty_struct(void) { - Pty pty = snew(struct pty_tag); + Pty *pty = snew(Pty); pty->conf = NULL; bufchain_init(&pty->output_data); return pty; @@ -430,7 +430,7 @@ void pty_pre_init(void) { #ifndef NO_PTY_PRE_INIT - Pty pty; + Pty *pty; #ifndef OMIT_UTMP pid_t pid; @@ -580,7 +580,7 @@ void pty_pre_init(void) } -void pty_real_select_result(Pty pty, int event, int status) +void pty_real_select_result(Pty *pty, int event, int status) { char buf[4096]; int ret; @@ -684,7 +684,7 @@ void pty_real_select_result(Pty pty, int event, int status) void pty_select_result(int fd, int event) { - Pty pty; + Pty *pty; if (fd == pty_signal_pipe[0]) { pid_t pid; @@ -711,7 +711,7 @@ void pty_select_result(int fd, int event) } } -static void pty_uxsel_setup(Pty pty) +static void pty_uxsel_setup(Pty *pty) { int rwx; @@ -746,7 +746,7 @@ static const char *pty_init(Frontend *frontend, Backend **backend_handle, int got_windowid; long windowid; #endif - Pty pty; + Pty *pty; if (single_pty) { pty = single_pty; @@ -1041,7 +1041,7 @@ static const char *pty_init(Frontend *frontend, Backend **backend_handle, static void pty_reconfig(Backend *be, Conf *conf) { - Pty pty = FROMFIELD(be, struct pty_tag, backend); + Pty *pty = FROMFIELD(be, Pty, backend); /* * We don't have much need to reconfigure this backend, but * unfortunately we do need to pick up the setting of Close On @@ -1055,7 +1055,7 @@ static void pty_reconfig(Backend *be, Conf *conf) */ static void pty_free(Backend *be) { - Pty pty = FROMFIELD(be, struct pty_tag, backend); + Pty *pty = FROMFIELD(be, Pty, backend); /* Either of these may fail `not found'. That's fine with us. */ del234(ptys_by_pid, pty); @@ -1076,7 +1076,7 @@ static void pty_free(Backend *be) } } -static void pty_try_write(Pty pty) +static void pty_try_write(Pty *pty) { void *data; int len, ret; @@ -1108,7 +1108,7 @@ static void pty_try_write(Pty pty) */ static int pty_send(Backend *be, const char *buf, int len) { - Pty pty = FROMFIELD(be, struct pty_tag, backend); + Pty *pty = FROMFIELD(be, Pty, backend); if (pty->master_fd < 0) return 0; /* ignore all writes if fd closed */ @@ -1119,7 +1119,7 @@ static int pty_send(Backend *be, const char *buf, int len) return bufchain_size(&pty->output_data); } -static void pty_close(Pty pty) +static void pty_close(Pty *pty) { if (pty->master_fd >= 0) { close(pty->master_fd); @@ -1138,7 +1138,7 @@ static void pty_close(Pty pty) */ static int pty_sendbuffer(Backend *be) { - /* Pty pty = FROMFIELD(be, struct pty_tag, backend); */ + /* Pty *pty = FROMFIELD(be, Pty, backend); */ return 0; } @@ -1147,7 +1147,7 @@ static int pty_sendbuffer(Backend *be) */ static void pty_size(Backend *be, int width, int height) { - Pty pty = FROMFIELD(be, struct pty_tag, backend); + Pty *pty = FROMFIELD(be, Pty, backend); struct winsize size; pty->term_width = width; @@ -1168,7 +1168,7 @@ static void pty_size(Backend *be, int width, int height) */ static void pty_special(Backend *be, SessionSpecialCode code, int arg) { - /* Pty pty = FROMFIELD(be, struct pty_tag, backend); */ + /* Pty *pty = FROMFIELD(be, Pty, backend); */ /* Do nothing! */ return; } @@ -1179,7 +1179,7 @@ static void pty_special(Backend *be, SessionSpecialCode code, int arg) */ static const SessionSpecial *pty_get_specials(Backend *be) { - /* Pty pty = FROMFIELD(be, struct pty_tag, backend); */ + /* Pty *pty = FROMFIELD(be, Pty, backend); */ /* * Hmm. When I get round to having this actually usable, it * might be quite nice to have the ability to deliver a few @@ -1191,43 +1191,43 @@ static const SessionSpecial *pty_get_specials(Backend *be) static int pty_connected(Backend *be) { - /* Pty pty = FROMFIELD(be, struct pty_tag, backend); */ + /* Pty *pty = FROMFIELD(be, Pty, backend); */ return TRUE; } static int pty_sendok(Backend *be) { - /* Pty pty = FROMFIELD(be, struct pty_tag, backend); */ + /* Pty *pty = FROMFIELD(be, Pty, backend); */ return 1; } static void pty_unthrottle(Backend *be, int backlog) { - /* Pty pty = FROMFIELD(be, struct pty_tag, backend); */ + /* Pty *pty = FROMFIELD(be, Pty, backend); */ /* do nothing */ } static int pty_ldisc(Backend *be, int option) { - /* Pty pty = FROMFIELD(be, struct pty_tag, backend); */ + /* Pty *pty = FROMFIELD(be, Pty, backend); */ return 0; /* neither editing nor echoing */ } static void pty_provide_ldisc(Backend *be, Ldisc *ldisc) { - /* Pty pty = FROMFIELD(be, struct pty_tag, backend); */ + /* Pty *pty = FROMFIELD(be, Pty, backend); */ /* This is a stub. */ } static void pty_provide_logctx(Backend *be, LogContext *logctx) { - /* Pty pty = FROMFIELD(be, struct pty_tag, backend); */ + /* Pty *pty = FROMFIELD(be, Pty, backend); */ /* This is a stub. */ } static int pty_exitcode(Backend *be) { - Pty pty = FROMFIELD(be, struct pty_tag, backend); + Pty *pty = FROMFIELD(be, Pty, backend); if (!pty->finished) return -1; /* not dead yet */ else @@ -1236,7 +1236,7 @@ static int pty_exitcode(Backend *be) static int pty_cfg_info(Backend *be) { - /* Pty pty = FROMFIELD(be, struct pty_tag, backend); */ + /* Pty *pty = FROMFIELD(be, Pty, backend); */ return 0; } diff --git a/unix/uxser.c b/unix/uxser.c index f2064680..2db560b9 100644 --- a/unix/uxser.c +++ b/unix/uxser.c @@ -17,14 +17,15 @@ #define SERIAL_MAX_BACKLOG 4096 -typedef struct serial_backend_data { +typedef struct Serial Serial; +struct Serial { Frontend *frontend; int fd; int finished; int inbufsize; bufchain output_data; Backend backend; -} *Serial; +}; /* * We store our serial backends in a tree sorted by fd, so that @@ -33,8 +34,8 @@ typedef struct serial_backend_data { */ static int serial_compare_by_fd(void *av, void *bv) { - Serial a = (Serial)av; - Serial b = (Serial)bv; + Serial *a = (Serial *)av; + Serial *b = (Serial *)bv; if (a->fd < b->fd) return -1; @@ -46,7 +47,7 @@ static int serial_compare_by_fd(void *av, void *bv) static int serial_find_by_fd(void *av, void *bv) { int a = *(int *)av; - Serial b = (Serial)bv; + Serial *b = (Serial *)bv; if (a < b->fd) return -1; @@ -58,10 +59,10 @@ static int serial_find_by_fd(void *av, void *bv) static tree234 *serial_by_fd = NULL; static void serial_select_result(int fd, int event); -static void serial_uxsel_setup(Serial serial); -static void serial_try_write(Serial serial); +static void serial_uxsel_setup(Serial *serial); +static void serial_try_write(Serial *serial); -static const char *serial_configure(Serial serial, Conf *conf) +static const char *serial_configure(Serial *serial, Conf *conf) { struct termios options; int bflag, bval, speed, flow, parity; @@ -293,11 +294,11 @@ static const char *serial_init(Frontend *frontend, Backend **backend_handle, const char *host, int port, char **realhost, int nodelay, int keepalive) { - Serial serial; + Serial *serial; const char *err; char *line; - serial = snew(struct serial_backend_data); + serial = snew(Serial); serial->backend.vt = &serial_backend; *backend_handle = &serial->backend; @@ -339,7 +340,7 @@ static const char *serial_init(Frontend *frontend, Backend **backend_handle, return NULL; } -static void serial_close(Serial serial) +static void serial_close(Serial *serial) { if (serial->fd >= 0) { close(serial->fd); @@ -349,7 +350,7 @@ static void serial_close(Serial serial) static void serial_free(Backend *be) { - Serial serial = FROMFIELD(be, struct serial_backend_data, backend); + Serial *serial = FROMFIELD(be, Serial, backend); serial_close(serial); @@ -360,7 +361,7 @@ static void serial_free(Backend *be) static void serial_reconfig(Backend *be, Conf *conf) { - Serial serial = FROMFIELD(be, struct serial_backend_data, backend); + Serial *serial = FROMFIELD(be, Serial, backend); /* * FIXME: what should we do if this returns an error? @@ -370,7 +371,7 @@ static void serial_reconfig(Backend *be, Conf *conf) static void serial_select_result(int fd, int event) { - Serial serial; + Serial *serial; char buf[4096]; int ret; int finished = FALSE; @@ -421,7 +422,7 @@ static void serial_select_result(int fd, int event) } } -static void serial_uxsel_setup(Serial serial) +static void serial_uxsel_setup(Serial *serial) { int rwx = 0; @@ -432,7 +433,7 @@ static void serial_uxsel_setup(Serial serial) uxsel_set(serial->fd, rwx, serial_select_result); } -static void serial_try_write(Serial serial) +static void serial_try_write(Serial *serial) { void *data; int len, ret; @@ -464,7 +465,7 @@ static void serial_try_write(Serial serial) */ static int serial_send(Backend *be, const char *buf, int len) { - Serial serial = FROMFIELD(be, struct serial_backend_data, backend); + Serial *serial = FROMFIELD(be, Serial, backend); if (serial->fd < 0) return 0; @@ -480,7 +481,7 @@ static int serial_send(Backend *be, const char *buf, int len) */ static int serial_sendbuffer(Backend *be) { - Serial serial = FROMFIELD(be, struct serial_backend_data, backend); + Serial *serial = FROMFIELD(be, Serial, backend); return bufchain_size(&serial->output_data); } @@ -498,7 +499,7 @@ static void serial_size(Backend *be, int width, int height) */ static void serial_special(Backend *be, SessionSpecialCode code, int arg) { - Serial serial = FROMFIELD(be, struct serial_backend_data, backend); + Serial *serial = FROMFIELD(be, Serial, backend); if (serial->fd >= 0 && code == SS_BRK) { tcsendbreak(serial->fd, 0); @@ -533,7 +534,7 @@ static int serial_sendok(Backend *be) static void serial_unthrottle(Backend *be, int backlog) { - Serial serial = FROMFIELD(be, struct serial_backend_data, backend); + Serial *serial = FROMFIELD(be, Serial, backend); serial->inbufsize = backlog; serial_uxsel_setup(serial); } @@ -558,7 +559,7 @@ static void serial_provide_logctx(Backend *be, LogContext *logctx) static int serial_exitcode(Backend *be) { - Serial serial = FROMFIELD(be, struct serial_backend_data, backend); + Serial *serial = FROMFIELD(be, Serial, backend); if (serial->fd >= 0) return -1; /* still connected */ else diff --git a/unix/uxshare.c b/unix/uxshare.c index 93de5e66..633ed502 100644 --- a/unix/uxshare.c +++ b/unix/uxshare.c @@ -27,8 +27,8 @@ /* * Functions provided by uxnet.c to help connection sharing. */ -SockAddr unix_sock_addr(const char *path); -Socket new_unix_listener(SockAddr listenaddr, Plug plug); +SockAddr *unix_sock_addr(const char *path); +Socket *new_unix_listener(SockAddr *listenaddr, Plug *plug); static char *make_parentdir_name(void) { @@ -249,13 +249,13 @@ static char *make_dirname(const char *pi_name, char **logtext) } int platform_ssh_share(const char *pi_name, Conf *conf, - Plug downplug, Plug upplug, Socket *sock, + Plug *downplug, Plug *upplug, Socket **sock, char **logtext, char **ds_err, char **us_err, int can_upstream, int can_downstream) { char *dirname, *lockname, *sockname, *err; int lockfd; - Socket retsock; + Socket *retsock; /* * Sort out what we're going to call the directory in which we diff --git a/windows/winhsock.c b/windows/winhsock.c index c7c833e2..f8349831 100644 --- a/windows/winhsock.c +++ b/windows/winhsock.c @@ -41,7 +41,7 @@ typedef struct HandleSocket { char *error; - Plug plug; + Plug *plug; const Socket_vtable *sockvt; } HandleSocket; @@ -105,16 +105,16 @@ static void handle_sentdata(struct handle *h, int new_backlog) plug_sent(hs->plug, new_backlog); } -static Plug sk_handle_plug(Socket s, Plug p) +static Plug *sk_handle_plug(Socket *s, Plug *p) { HandleSocket *hs = FROMFIELD(s, HandleSocket, sockvt); - Plug ret = hs->plug; + Plug *ret = hs->plug; if (p) hs->plug = p; return ret; } -static void sk_handle_close(Socket s) +static void sk_handle_close(Socket *s) { HandleSocket *hs = FROMFIELD(s, HandleSocket, sockvt); @@ -134,14 +134,14 @@ static void sk_handle_close(Socket s) sfree(hs); } -static int sk_handle_write(Socket s, const void *data, int len) +static int sk_handle_write(Socket *s, const void *data, int len) { HandleSocket *hs = FROMFIELD(s, HandleSocket, sockvt); return handle_write(hs->send_h, data, len); } -static int sk_handle_write_oob(Socket s, const void *data, int len) +static int sk_handle_write_oob(Socket *s, const void *data, int len) { /* * oob data is treated as inband; nasty, but nothing really @@ -150,14 +150,14 @@ static int sk_handle_write_oob(Socket s, const void *data, int len) return sk_handle_write(s, data, len); } -static void sk_handle_write_eof(Socket s) +static void sk_handle_write_eof(Socket *s) { HandleSocket *hs = FROMFIELD(s, HandleSocket, sockvt); handle_write_eof(hs->send_h); } -static void sk_handle_flush(Socket s) +static void sk_handle_flush(Socket *s) { /* HandleSocket *hs = FROMFIELD(s, HandleSocket, sockvt); */ /* do nothing */ @@ -210,7 +210,7 @@ static void handle_socket_unfreeze(void *hsv) } } -static void sk_handle_set_frozen(Socket s, int is_frozen) +static void sk_handle_set_frozen(Socket *s, int is_frozen) { HandleSocket *hs = FROMFIELD(s, HandleSocket, sockvt); @@ -265,13 +265,13 @@ static void sk_handle_set_frozen(Socket s, int is_frozen) } } -static const char *sk_handle_socket_error(Socket s) +static const char *sk_handle_socket_error(Socket *s) { HandleSocket *hs = FROMFIELD(s, HandleSocket, sockvt); return hs->error; } -static char *sk_handle_peer_info(Socket s) +static char *sk_handle_peer_info(Socket *s) { HandleSocket *hs = FROMFIELD(s, HandleSocket, sockvt); ULONG pid; @@ -318,8 +318,8 @@ static const Socket_vtable HandleSocket_sockvt = { sk_handle_peer_info, }; -Socket make_handle_socket(HANDLE send_H, HANDLE recv_H, HANDLE stderr_H, - Plug plug, int overlapped) +Socket *make_handle_socket(HANDLE send_H, HANDLE recv_H, HANDLE stderr_H, + Plug *plug, int overlapped) { HandleSocket *hs; int flags = (overlapped ? HANDLE_FLAG_OVERLAPPED : 0); diff --git a/windows/winnet.c b/windows/winnet.c index b5efc955..454e649a 100644 --- a/windows/winnet.c +++ b/windows/winnet.c @@ -52,7 +52,7 @@ typedef struct NetSocket NetSocket; struct NetSocket { const char *error; SOCKET s; - Plug plug; + Plug *plug; bufchain output_data; int connected; int writable; @@ -64,7 +64,7 @@ struct NetSocket { int sending_oob; int oobinline, nodelay, keepalive, privport; enum { EOF_NO, EOF_PENDING, EOF_SENT } outgoingeof; - SockAddr addr; + SockAddr *addr; SockAddrStep step; int port; int pending_error; /* in case send() returns error */ @@ -79,7 +79,7 @@ struct NetSocket { const Socket_vtable *sockvt; }; -struct SockAddr_tag { +struct SockAddr { int refcount; char *error; int resolved; @@ -525,10 +525,10 @@ const char *winsock_error_string(int error) return es->text; } -SockAddr sk_namelookup(const char *host, char **canonicalname, - int address_family) +SockAddr *sk_namelookup(const char *host, char **canonicalname, + int address_family) { - SockAddr ret = snew(struct SockAddr_tag); + SockAddr *ret = snew(SockAddr); unsigned long a; char realhost[8192]; int hint_family; @@ -541,7 +541,7 @@ SockAddr sk_namelookup(const char *host, char **canonicalname, AF_UNSPEC); /* Clear the structure and default to IPv4. */ - memset(ret, 0, sizeof(struct SockAddr_tag)); + memset(ret, 0, sizeof(SockAddr)); #ifndef NO_IPV6 ret->ais = NULL; #endif @@ -650,9 +650,9 @@ SockAddr sk_namelookup(const char *host, char **canonicalname, return ret; } -SockAddr sk_nonamelookup(const char *host) +SockAddr *sk_nonamelookup(const char *host) { - SockAddr ret = snew(struct SockAddr_tag); + SockAddr *ret = snew(SockAddr); ret->error = NULL; ret->resolved = FALSE; #ifndef NO_IPV6 @@ -667,9 +667,9 @@ SockAddr sk_nonamelookup(const char *host) return ret; } -SockAddr sk_namedpipe_addr(const char *pipename) +SockAddr *sk_namedpipe_addr(const char *pipename) { - SockAddr ret = snew(struct SockAddr_tag); + SockAddr *ret = snew(SockAddr); ret->error = NULL; ret->resolved = FALSE; #ifndef NO_IPV6 @@ -684,7 +684,7 @@ SockAddr sk_namedpipe_addr(const char *pipename) return ret; } -int sk_nextaddr(SockAddr addr, SockAddrStep *step) +int sk_nextaddr(SockAddr *addr, SockAddrStep *step) { #ifndef NO_IPV6 if (step->ai) { @@ -703,7 +703,7 @@ int sk_nextaddr(SockAddr addr, SockAddrStep *step) } } -void sk_getaddr(SockAddr addr, char *buf, int buflen) +void sk_getaddr(SockAddr *addr, char *buf, int buflen) { SockAddrStep step; START_STEP(addr, step); @@ -746,10 +746,10 @@ void sk_getaddr(SockAddr addr, char *buf, int buflen) * rather than dynamically allocated - that should clue in anyone * writing a call to it that something is weird about it.) */ -static struct SockAddr_tag sk_extractaddr_tmp( - SockAddr addr, const SockAddrStep *step) +static SockAddr sk_extractaddr_tmp( + SockAddr *addr, const SockAddrStep *step) { - struct SockAddr_tag toret; + SockAddr toret; toret = *addr; /* structure copy */ toret.refcount = 1; @@ -766,7 +766,7 @@ static struct SockAddr_tag sk_extractaddr_tmp( return toret; } -int sk_addr_needs_port(SockAddr addr) +int sk_addr_needs_port(SockAddr *addr) { return addr->namedpipe ? FALSE : TRUE; } @@ -811,7 +811,7 @@ static int ipv4_is_local_addr(struct in_addr addr) return 0; /* this address is not local */ } -int sk_address_is_local(SockAddr addr) +int sk_address_is_local(SockAddr *addr) { SockAddrStep step; int family; @@ -842,12 +842,12 @@ int sk_address_is_local(SockAddr addr) } } -int sk_address_is_special_local(SockAddr addr) +int sk_address_is_special_local(SockAddr *addr) { return 0; /* no Unix-domain socket analogue here */ } -int sk_addrtype(SockAddr addr) +int sk_addrtype(SockAddr *addr) { SockAddrStep step; int family; @@ -861,7 +861,7 @@ int sk_addrtype(SockAddr addr) ADDRTYPE_NAME); } -void sk_addrcopy(SockAddr addr, char *buf) +void sk_addrcopy(SockAddr *addr, char *buf) { SockAddrStep step; int family; @@ -889,7 +889,7 @@ void sk_addrcopy(SockAddr addr, char *buf) } } -void sk_addr_free(SockAddr addr) +void sk_addr_free(SockAddr *addr) { if (--addr->refcount > 0) return; @@ -902,22 +902,22 @@ void sk_addr_free(SockAddr addr) sfree(addr); } -SockAddr sk_addr_dup(SockAddr addr) +SockAddr *sk_addr_dup(SockAddr *addr) { addr->refcount++; return addr; } -static Plug sk_net_plug(Socket sock, Plug p) +static Plug *sk_net_plug(Socket *sock, Plug *p) { NetSocket *s = FROMFIELD(sock, NetSocket, sockvt); - Plug ret = s->plug; + Plug *ret = s->plug; if (p) s->plug = p; return ret; } -static void sk_net_flush(Socket s) +static void sk_net_flush(Socket *s) { /* * We send data to the socket as soon as we can anyway, @@ -925,13 +925,13 @@ static void sk_net_flush(Socket s) */ } -static void sk_net_close(Socket s); -static int sk_net_write(Socket s, const void *data, int len); -static int sk_net_write_oob(Socket s, const void *data, int len); -static void sk_net_write_eof(Socket s); -static void sk_net_set_frozen(Socket s, int is_frozen); -static const char *sk_net_socket_error(Socket s); -static char *sk_net_peer_info(Socket s); +static void sk_net_close(Socket *s); +static int sk_net_write(Socket *s, const void *data, int len); +static int sk_net_write_oob(Socket *s, const void *data, int len); +static void sk_net_write_eof(Socket *s); +static void sk_net_set_frozen(Socket *s, int is_frozen); +static const char *sk_net_socket_error(Socket *s); +static char *sk_net_peer_info(Socket *s); extern char *do_select(SOCKET skt, int startup); @@ -947,7 +947,7 @@ static const Socket_vtable NetSocket_sockvt = { sk_net_peer_info, }; -static Socket sk_net_accept(accept_ctx_t ctx, Plug plug) +static Socket *sk_net_accept(accept_ctx_t ctx, Plug *plug) { DWORD err; char *errstr; @@ -1012,7 +1012,7 @@ static DWORD try_connect(NetSocket *sock) } { - struct SockAddr_tag thisaddr = sk_extractaddr_tmp( + SockAddr thisaddr = sk_extractaddr_tmp( sock->addr, &sock->step); plug_log(sock->plug, 0, &thisaddr, sock->port, NULL, 0); } @@ -1185,15 +1185,15 @@ static DWORD try_connect(NetSocket *sock) add234(sktree, sock); if (err) { - struct SockAddr_tag thisaddr = sk_extractaddr_tmp( + SockAddr thisaddr = sk_extractaddr_tmp( sock->addr, &sock->step); plug_log(sock->plug, 1, &thisaddr, sock->port, sock->error, err); } return err; } -Socket sk_new(SockAddr addr, int port, int privport, int oobinline, - int nodelay, int keepalive, Plug plug) +Socket *sk_new(SockAddr *addr, int port, int privport, int oobinline, + int nodelay, int keepalive, Plug *plug) { NetSocket *ret; DWORD err; @@ -1232,8 +1232,8 @@ Socket sk_new(SockAddr addr, int port, int privport, int oobinline, return &ret->sockvt; } -Socket sk_newlistener(const char *srcaddr, int port, Plug plug, - int local_host_only, int orig_address_family) +Socket *sk_newlistener(const char *srcaddr, int port, Plug *plug, + int local_host_only, int orig_address_family) { SOCKET s; #ifndef NO_IPV6 @@ -1408,8 +1408,8 @@ Socket sk_newlistener(const char *srcaddr, int port, Plug plug, * IPv6 listening socket and link it to this one. */ if (address_family == AF_INET && orig_address_family == ADDRTYPE_UNSPEC) { - Socket other = sk_newlistener(srcaddr, port, plug, - local_host_only, ADDRTYPE_IPV6); + Socket *other = sk_newlistener(srcaddr, port, plug, + local_host_only, ADDRTYPE_IPV6); if (other) { NetSocket *ns = FROMFIELD(other, NetSocket, sockvt); @@ -1426,7 +1426,7 @@ Socket sk_newlistener(const char *srcaddr, int port, Plug plug, return &ret->sockvt; } -static void sk_net_close(Socket sock) +static void sk_net_close(Socket *sock) { extern char *do_select(SOCKET skt, int startup); NetSocket *s = FROMFIELD(sock, NetSocket, sockvt); @@ -1538,7 +1538,7 @@ void try_send(NetSocket *s) } } -static int sk_net_write(Socket sock, const void *buf, int len) +static int sk_net_write(Socket *sock, const void *buf, int len) { NetSocket *s = FROMFIELD(sock, NetSocket, sockvt); @@ -1558,7 +1558,7 @@ static int sk_net_write(Socket sock, const void *buf, int len) return bufchain_size(&s->output_data); } -static int sk_net_write_oob(Socket sock, const void *buf, int len) +static int sk_net_write_oob(Socket *sock, const void *buf, int len) { NetSocket *s = FROMFIELD(sock, NetSocket, sockvt); @@ -1581,7 +1581,7 @@ static int sk_net_write_oob(Socket sock, const void *buf, int len) return s->sending_oob; } -static void sk_net_write_eof(Socket sock) +static void sk_net_write_eof(Socket *sock) { NetSocket *s = FROMFIELD(sock, NetSocket, sockvt); @@ -1622,7 +1622,7 @@ void select_result(WPARAM wParam, LPARAM lParam) * plug. */ if (s->addr) { - struct SockAddr_tag thisaddr = sk_extractaddr_tmp( + SockAddr thisaddr = sk_extractaddr_tmp( s->addr, &s->step); plug_log(s->plug, 1, &thisaddr, s->port, winsock_error_string(err), err); @@ -1780,17 +1780,17 @@ void select_result(WPARAM wParam, LPARAM lParam) * if there's a problem. These functions extract an error message, * or return NULL if there's no problem. */ -const char *sk_addr_error(SockAddr addr) +const char *sk_addr_error(SockAddr *addr) { return addr->error; } -static const char *sk_net_socket_error(Socket sock) +static const char *sk_net_socket_error(Socket *sock) { NetSocket *s = FROMFIELD(sock, NetSocket, sockvt); return s->error; } -static char *sk_net_peer_info(Socket sock) +static char *sk_net_peer_info(Socket *sock) { NetSocket *s = FROMFIELD(sock, NetSocket, sockvt); #ifdef NO_IPV6 @@ -1822,7 +1822,7 @@ static char *sk_net_peer_info(Socket sock) } } -static void sk_net_set_frozen(Socket sock, int is_frozen) +static void sk_net_set_frozen(Socket *sock, int is_frozen) { NetSocket *s = FROMFIELD(sock, NetSocket, sockvt); if (s->frozen == is_frozen) @@ -1902,11 +1902,11 @@ char *get_hostname(void) return hostname; } -SockAddr platform_get_x11_unix_address(const char *display, int displaynum, +SockAddr *platform_get_x11_unix_address(const char *display, int displaynum, char **canonicalname) { - SockAddr ret = snew(struct SockAddr_tag); - memset(ret, 0, sizeof(struct SockAddr_tag)); + SockAddr *ret = snew(SockAddr); + memset(ret, 0, sizeof(SockAddr)); ret->error = "unix sockets not supported on this platform"; ret->refcount = 1; return ret; diff --git a/windows/winnpc.c b/windows/winnpc.c index e5d1d7a6..7797ba40 100644 --- a/windows/winnpc.c +++ b/windows/winnpc.c @@ -16,16 +16,16 @@ #include "winsecur.h" -Socket make_handle_socket(HANDLE send_H, HANDLE recv_H, HANDLE stderr_H, - Plug plug, int overlapped); +Socket *make_handle_socket(HANDLE send_H, HANDLE recv_H, HANDLE stderr_H, + Plug *plug, int overlapped); -Socket new_named_pipe_client(const char *pipename, Plug plug) +Socket *new_named_pipe_client(const char *pipename, Plug *plug) { HANDLE pipehandle; PSID usersid, pipeowner; PSECURITY_DESCRIPTOR psd; char *err; - Socket ret; + Socket *ret; assert(strncmp(pipename, "\\\\.\\pipe\\", 9) == 0); assert(strchr(pipename + 9, '\\') == NULL); diff --git a/windows/winnps.c b/windows/winnps.c index ff71b0a4..e827c0a7 100644 --- a/windows/winnps.c +++ b/windows/winnps.c @@ -16,8 +16,8 @@ #include "winsecur.h" -Socket make_handle_socket(HANDLE send_H, HANDLE recv_H, HANDLE stderr_H, - Plug plug, int overlapped); +Socket *make_handle_socket(HANDLE send_H, HANDLE recv_H, HANDLE stderr_H, + Plug *plug, int overlapped); typedef struct NamedPipeServerSocket { /* Parameters for (repeated) creation of named pipe objects */ @@ -31,22 +31,22 @@ typedef struct NamedPipeServerSocket { struct handle *callback_handle; /* winhandl.c's reference */ /* PuTTY Socket machinery */ - Plug plug; + Plug *plug; char *error; const Socket_vtable *sockvt; } NamedPipeServerSocket; -static Plug sk_namedpipeserver_plug(Socket s, Plug p) +static Plug *sk_namedpipeserver_plug(Socket *s, Plug *p) { NamedPipeServerSocket *ps = FROMFIELD(s, NamedPipeServerSocket, sockvt); - Plug ret = ps->plug; + Plug *ret = ps->plug; if (p) ps->plug = p; return ret; } -static void sk_namedpipeserver_close(Socket s) +static void sk_namedpipeserver_close(Socket *s) { NamedPipeServerSocket *ps = FROMFIELD(s, NamedPipeServerSocket, sockvt); @@ -63,13 +63,13 @@ static void sk_namedpipeserver_close(Socket s) sfree(ps); } -static const char *sk_namedpipeserver_socket_error(Socket s) +static const char *sk_namedpipeserver_socket_error(Socket *s) { NamedPipeServerSocket *ps = FROMFIELD(s, NamedPipeServerSocket, sockvt); return ps->error; } -static char *sk_namedpipeserver_peer_info(Socket s) +static char *sk_namedpipeserver_peer_info(Socket *s) { return NULL; } @@ -114,7 +114,7 @@ static int create_named_pipe(NamedPipeServerSocket *ps, int first_instance) return ps->pipehandle != INVALID_HANDLE_VALUE; } -static Socket named_pipe_accept(accept_ctx_t ctx, Plug plug) +static Socket *named_pipe_accept(accept_ctx_t ctx, Plug *plug) { HANDLE conn = (HANDLE)ctx.p; @@ -122,10 +122,10 @@ static Socket named_pipe_accept(accept_ctx_t ctx, Plug plug) } /* - * Dummy SockAddr type which just holds a named pipe address. Only + * Dummy SockAddr *type which just holds a named pipe address. Only * used for calling plug_log from named_pipe_accept_loop() here. */ -SockAddr sk_namedpipe_addr(const char *pipename); +SockAddr *sk_namedpipe_addr(const char *pipename); static void named_pipe_accept_loop(NamedPipeServerSocket *ps, int got_one_already) @@ -216,7 +216,7 @@ static const Socket_vtable NamedPipeServerSocket_sockvt = { sk_namedpipeserver_peer_info, }; -Socket new_named_pipe_listener(const char *pipename, Plug plug) +Socket *new_named_pipe_listener(const char *pipename, Plug *plug) { NamedPipeServerSocket *ret = snew(NamedPipeServerSocket); ret->sockvt = &NamedPipeServerSocket_sockvt; diff --git a/windows/winproxy.c b/windows/winproxy.c index 7a313181..6868325c 100644 --- a/windows/winproxy.c +++ b/windows/winproxy.c @@ -13,13 +13,13 @@ #include "network.h" #include "proxy.h" -Socket make_handle_socket(HANDLE send_H, HANDLE recv_H, HANDLE stderr_H, - Plug plug, int overlapped); +Socket *make_handle_socket(HANDLE send_H, HANDLE recv_H, HANDLE stderr_H, + Plug *plug, int overlapped); -Socket platform_new_connection(SockAddr addr, const char *hostname, - int port, int privport, - int oobinline, int nodelay, int keepalive, - Plug plug, Conf *conf) +Socket *platform_new_connection(SockAddr *addr, const char *hostname, + int port, int privport, + int oobinline, int nodelay, int keepalive, + Plug *plug, Conf *conf) { char *cmd; HANDLE us_to_cmd, cmd_from_us; @@ -51,14 +51,14 @@ Socket platform_new_connection(SockAddr addr, const char *hostname, sa.lpSecurityDescriptor = NULL; /* default */ sa.bInheritHandle = TRUE; if (!CreatePipe(&us_from_cmd, &cmd_to_us, &sa, 0)) { - Socket ret = + Socket *ret = new_error_socket("Unable to create pipes for proxy command", plug); sfree(cmd); return ret; } if (!CreatePipe(&cmd_from_us, &us_to_cmd, &sa, 0)) { - Socket ret = + Socket *ret = new_error_socket("Unable to create pipes for proxy command", plug); sfree(cmd); CloseHandle(us_from_cmd); @@ -67,7 +67,7 @@ Socket platform_new_connection(SockAddr addr, const char *hostname, } if (!CreatePipe(&us_from_cmd_err, &cmd_err_to_us, &sa, 0)) { - Socket ret = new_error_socket + Socket *ret = new_error_socket ("Unable to create pipes for proxy command", plug); sfree(cmd); CloseHandle(us_from_cmd); diff --git a/windows/winser.c b/windows/winser.c index e427f358..5367c4a6 100644 --- a/windows/winser.c +++ b/windows/winser.c @@ -10,7 +10,8 @@ #define SERIAL_MAX_BACKLOG 4096 -typedef struct serial_backend_data { +typedef struct Serial Serial; +struct Serial { HANDLE port; struct handle *out, *in; Frontend *frontend; @@ -18,9 +19,9 @@ typedef struct serial_backend_data { long clearbreak_time; int break_in_progress; Backend backend; -} *Serial; +}; -static void serial_terminate(Serial serial) +static void serial_terminate(Serial *serial) { if (serial->out) { handle_free(serial->out); @@ -40,7 +41,7 @@ static void serial_terminate(Serial serial) static int serial_gotdata(struct handle *h, void *data, int len) { - Serial serial = (Serial)handle_get_privdata(h); + Serial *serial = (Serial *)handle_get_privdata(h); if (len <= 0) { const char *error_msg; @@ -72,7 +73,7 @@ static int serial_gotdata(struct handle *h, void *data, int len) static void serial_sentdata(struct handle *h, int new_backlog) { - Serial serial = (Serial)handle_get_privdata(h); + Serial *serial = (Serial *)handle_get_privdata(h); if (new_backlog < 0) { const char *error_msg = "Error writing to serial device"; @@ -88,7 +89,7 @@ static void serial_sentdata(struct handle *h, int new_backlog) } } -static const char *serial_configure(Serial serial, HANDLE serport, Conf *conf) +static const char *serial_configure(Serial *serial, HANDLE serport, Conf *conf) { DCB dcb; COMMTIMEOUTS timeouts; @@ -203,12 +204,12 @@ static const char *serial_init(Frontend *frontend, Backend **backend_handle, Conf *conf, const char *host, int port, char **realhost, int nodelay, int keepalive) { - Serial serial; + Serial *serial; HANDLE serport; const char *err; char *serline; - serial = snew(struct serial_backend_data); + serial = snew(Serial); serial->port = INVALID_HANDLE_VALUE; serial->out = serial->in = NULL; serial->bufsize = 0; @@ -283,7 +284,7 @@ static const char *serial_init(Frontend *frontend, Backend **backend_handle, static void serial_free(Backend *be) { - Serial serial = FROMFIELD(be, struct serial_backend_data, backend); + Serial *serial = FROMFIELD(be, Serial, backend); serial_terminate(serial); expire_timer_context(serial); @@ -292,7 +293,7 @@ static void serial_free(Backend *be) static void serial_reconfig(Backend *be, Conf *conf) { - Serial serial = FROMFIELD(be, struct serial_backend_data, backend); + Serial *serial = FROMFIELD(be, Serial, backend); serial_configure(serial, serial->port, conf); @@ -307,7 +308,7 @@ static void serial_reconfig(Backend *be, Conf *conf) */ static int serial_send(Backend *be, const char *buf, int len) { - Serial serial = FROMFIELD(be, struct serial_backend_data, backend); + Serial *serial = FROMFIELD(be, Serial, backend); if (serial->out == NULL) return 0; @@ -321,7 +322,7 @@ static int serial_send(Backend *be, const char *buf, int len) */ static int serial_sendbuffer(Backend *be) { - Serial serial = FROMFIELD(be, struct serial_backend_data, backend); + Serial *serial = FROMFIELD(be, Serial, backend); return serial->bufsize; } @@ -336,7 +337,7 @@ static void serial_size(Backend *be, int width, int height) static void serbreak_timer(void *ctx, unsigned long now) { - Serial serial = (Serial)ctx; + Serial *serial = (Serial *)ctx; if (now == serial->clearbreak_time && serial->port) { ClearCommBreak(serial->port); @@ -350,7 +351,7 @@ static void serbreak_timer(void *ctx, unsigned long now) */ static void serial_special(Backend *be, SessionSpecialCode code, int arg) { - Serial serial = FROMFIELD(be, struct serial_backend_data, backend); + Serial *serial = FROMFIELD(be, Serial, backend); if (serial->port && code == SS_BRK) { logevent(serial->frontend, "Starting serial break at user request"); @@ -398,7 +399,7 @@ static int serial_sendok(Backend *be) static void serial_unthrottle(Backend *be, int backlog) { - Serial serial = FROMFIELD(be, struct serial_backend_data, backend); + Serial *serial = FROMFIELD(be, Serial, backend); if (serial->in) handle_unthrottle(serial->in, backlog); } @@ -423,7 +424,7 @@ static void serial_provide_logctx(Backend *be, LogContext *logctx) static int serial_exitcode(Backend *be) { - Serial serial = FROMFIELD(be, struct serial_backend_data, backend); + Serial *serial = FROMFIELD(be, Serial, backend); if (serial->port != INVALID_HANDLE_VALUE) return -1; /* still connected */ else diff --git a/windows/winshare.c b/windows/winshare.c index 3b81d06c..5b7f93ad 100644 --- a/windows/winshare.c +++ b/windows/winshare.c @@ -116,17 +116,17 @@ static char *make_name(const char *prefix, const char *name) return retname; } -Socket new_named_pipe_client(const char *pipename, Plug plug); -Socket new_named_pipe_listener(const char *pipename, Plug plug); +Socket *new_named_pipe_client(const char *pipename, Plug *plug); +Socket *new_named_pipe_listener(const char *pipename, Plug *plug); int platform_ssh_share(const char *pi_name, Conf *conf, - Plug downplug, Plug upplug, Socket *sock, + Plug *downplug, Plug *upplug, Socket **sock, char **logtext, char **ds_err, char **us_err, int can_upstream, int can_downstream) { char *name, *mutexname, *pipename; HANDLE mutex; - Socket retsock; + Socket *retsock; PSECURITY_DESCRIPTOR psd; PACL acl; diff --git a/x11fwd.c b/x11fwd.c index ed2f3b60..658008d9 100644 --- a/x11fwd.c +++ b/x11fwd.c @@ -40,7 +40,7 @@ typedef struct X11Connection { char *peer_addr; int peer_port; SshChannel *c; /* channel structure held by SSH backend */ - Socket s; + Socket *s; const Plug_vtable *plugvt; Channel chan; @@ -288,12 +288,12 @@ struct X11Display *x11_setup_display(const char *display, Conf *conf) * display (as the standard X connection libraries do). */ if (!disp->unixdomain && sk_address_is_local(disp->addr)) { - SockAddr ux = platform_get_x11_unix_address(NULL, disp->displaynum); + SockAddr *ux = platform_get_x11_unix_address(NULL, disp->displaynum); const char *err = sk_addr_error(ux); if (!err) { /* Create trial connection to see if there is a useful Unix-domain * socket */ - Socket s = sk_new(sk_addr_dup(ux), 0, 0, 0, 0, 0, nullplug); + Socket *s = sk_new(sk_addr_dup(ux), 0, 0, 0, 0, 0, nullplug); err = sk_socket_error(s); sk_close(s); } @@ -622,7 +622,7 @@ void x11_get_auth_from_authfile(struct X11Display *disp, sfree(ourhostname); } -static void x11_log(Plug p, int type, SockAddr addr, int port, +static void x11_log(Plug *p, int type, SockAddr *addr, int port, const char *error_msg, int error_code) { /* We have no interface to the logging module here, so we drop these. */ @@ -631,7 +631,7 @@ static void x11_log(Plug p, int type, SockAddr addr, int port, static void x11_send_init_error(struct X11Connection *conn, const char *err_message); -static void x11_closing(Plug plug, const char *error_msg, int error_code, +static void x11_closing(Plug *plug, const char *error_msg, int error_code, int calling_back) { struct X11Connection *xconn = FROMFIELD( @@ -664,7 +664,7 @@ static void x11_closing(Plug plug, const char *error_msg, int error_code, } } -static void x11_receive(Plug plug, int urgent, char *data, int len) +static void x11_receive(Plug *plug, int urgent, char *data, int len) { struct X11Connection *xconn = FROMFIELD( plug, struct X11Connection, plugvt); @@ -673,7 +673,7 @@ static void x11_receive(Plug plug, int urgent, char *data, int len) sshfwd_write(xconn->c, data, len); } -static void x11_sent(Plug plug, int bufsize) +static void x11_sent(Plug *plug, int bufsize) { struct X11Connection *xconn = FROMFIELD( plug, struct X11Connection, plugvt); From e0130a48ca94773f80b7b0bd3327e5c0239ca468 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Fri, 5 Oct 2018 07:02:19 +0100 Subject: [PATCH 485/607] Switch the unifont system over to using FROMFIELD. Now that I'm doing that in so many of the new classes as a more type-safe alternative to ordinary C casts, I should make sure all the old code is also reaping the benefits. This commit converts the system of unifont vtables in the GTK front end, and also the 'unifontsel' structure that exposes only a few of its fields outside gtkfont.c. --- unix/gtkfont.c | 59 +++++++++++++++++++++++++------------------------- 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/unix/gtkfont.c b/unix/gtkfont.c index 086669e2..863183e8 100644 --- a/unix/gtkfont.c +++ b/unix/gtkfont.c @@ -52,10 +52,8 @@ * polymorphic. * * Any instance of `unifont' used in the vtable functions will - * actually be the first element of a larger structure containing - * data specific to the subtype. This is permitted by the ISO C - * provision that one may safely cast between a pointer to a - * structure and a pointer to its first element. + * actually be an element of a larger structure containing data + * specific to the subtype. */ #define FONTFLAG_CLIENTSIDE 0x0001 @@ -177,7 +175,6 @@ typedef struct x11font_individual { } x11font_individual; struct x11font { - struct unifont u; /* * Copy of the X display handle, so we don't have to keep * extracting it from GDK. @@ -212,6 +209,8 @@ struct x11font { * Data passed in to unifont_create(). */ int wide, bold, shadowoffset, shadowalways; + + unifont u; }; static const struct unifont_vtable x11font_vtable = { @@ -537,12 +536,12 @@ static unifont *x11font_create(GtkWidget *widget, const char *name, xfont->fonts[0].xfs = xfs; xfont->fonts[0].allocated = TRUE; - return (unifont *)xfont; + return &xfont->u; } static void x11font_destroy(unifont *font) { - struct x11font *xfont = (struct x11font *)font; + struct x11font *xfont = FROMFIELD(font, struct x11font, u); Display *disp = xfont->disp; int i; @@ -564,7 +563,7 @@ static void x11font_destroy(unifont *font) } #endif } - sfree(font); + sfree(xfont); } static void x11_alloc_subfont(struct x11font *xfont, int sfid) @@ -580,7 +579,7 @@ static void x11_alloc_subfont(struct x11font *xfont, int sfid) static int x11font_has_glyph(unifont *font, wchar_t glyph) { - struct x11font *xfont = (struct x11font *)font; + struct x11font *xfont = FROMFIELD(font, struct x11font, u); if (xfont->sixteen_bit) { /* @@ -894,7 +893,7 @@ static void x11font_draw_text(unifont_drawctx *ctx, unifont *font, int x, int y, const wchar_t *string, int len, int wide, int bold, int cellwidth) { - struct x11font *xfont = (struct x11font *)font; + struct x11font *xfont = FROMFIELD(font, struct x11font, u); int sfid; int shadowoffset = 0; int mult = (wide ? 2 : 1); @@ -1201,7 +1200,7 @@ static char *x11font_scale_fontname(GtkWidget *widget, const char *name, static char *x11font_size_increment(unifont *font, int increment) { - struct x11font *xfont = (struct x11font *)font; + struct x11font *xfont = FROMFIELD(font, struct x11font, u); Display *disp = xfont->disp; Atom fontprop = XInternAtom(disp, "FONT", False); char *returned_name = NULL; @@ -1324,7 +1323,6 @@ static char *pangofont_scale_fontname(GtkWidget *widget, const char *name, static char *pangofont_size_increment(unifont *font, int increment); struct pangofont { - struct unifont u; /* * Pango objects. */ @@ -1345,6 +1343,8 @@ struct pangofont { */ int *widthcache; unsigned nwidthcache; + + struct unifont u; }; static const struct unifont_vtable pangofont_vtable = { @@ -1475,7 +1475,7 @@ static unifont *pangofont_create_internal(GtkWidget *widget, pango_font_metrics_unref(metrics); - return (unifont *)pfont; + return &pfont->u; } static unifont *pangofont_create(GtkWidget *widget, const char *name, @@ -1523,11 +1523,11 @@ static unifont *pangofont_create_fallback(GtkWidget *widget, int height, static void pangofont_destroy(unifont *font) { - struct pangofont *pfont = (struct pangofont *)font; + struct pangofont *pfont = FROMFIELD(font, struct pangofont, u); pango_font_description_free(pfont->desc); sfree(pfont->widthcache); g_object_unref(pfont->fset); - sfree(font); + sfree(pfont); } static int pangofont_char_width(PangoLayout *layout, struct pangofont *pfont, @@ -1587,7 +1587,7 @@ static void pangofont_draw_internal(unifont_drawctx *ctx, unifont *font, int len, int wide, int bold, int cellwidth, int combining) { - struct pangofont *pfont = (struct pangofont *)font; + struct pangofont *pfont = FROMFIELD(font, struct pangofont, u); PangoLayout *layout; PangoRectangle rect; char *utfstring, *utfptr; @@ -2018,7 +2018,7 @@ static char *pangofont_scale_fontname(GtkWidget *widget, const char *name, static char *pangofont_size_increment(unifont *font, int increment) { - struct pangofont *pfont = (struct pangofont *)font; + struct pangofont *pfont = FROMFIELD(font, struct pangofont, u); PangoFontDescription *desc; int size; char *newname, *retname; @@ -2177,9 +2177,10 @@ static void multifont_destroy(unifont *font); static char *multifont_size_increment(unifont *font, int increment); struct multifont { - struct unifont u; unifont *main; unifont *fallback; + + struct unifont u; }; static const struct unifont_vtable multifont_vtable = { @@ -2238,16 +2239,16 @@ unifont *multifont_create(GtkWidget *widget, const char *name, mfont->main = font; mfont->fallback = fallback; - return (unifont *)mfont; + return &mfont->u; } static void multifont_destroy(unifont *font) { - struct multifont *mfont = (struct multifont *)font; + struct multifont *mfont = FROMFIELD(font, struct multifont, u); unifont_destroy(mfont->main); if (mfont->fallback) unifont_destroy(mfont->fallback); - sfree(font); + sfree(mfont); } typedef void (*unifont_draw_func_t)(unifont_drawctx *ctx, unifont *font, @@ -2260,7 +2261,7 @@ static void multifont_draw_main(unifont_drawctx *ctx, unifont *font, int x, int wide, int bold, int cellwidth, int cellinc, unifont_draw_func_t draw) { - struct multifont *mfont = (struct multifont *)font; + struct multifont *mfont = FROMFIELD(font, struct multifont, u); unifont *f; int ok, i; @@ -2306,7 +2307,7 @@ static void multifont_draw_combining(unifont_drawctx *ctx, unifont *font, static char *multifont_size_increment(unifont *font, int increment) { - struct multifont *mfont = (struct multifont *)font; + struct multifont *mfont = FROMFIELD(font, struct multifont, u); return unifont_size_increment(mfont->main, increment); } @@ -2320,8 +2321,6 @@ static char *multifont_size_increment(unifont *font, int increment) typedef struct fontinfo fontinfo; typedef struct unifontsel_internal { - /* This must be the structure's first element, for cross-casting */ - unifontsel u; GtkListStore *family_model, *style_model, *size_model; GtkWidget *family_list, *style_list, *size_entry, *size_list; GtkWidget *filter_buttons[4]; @@ -2337,6 +2336,8 @@ typedef struct unifontsel_internal { fontinfo *selected; int selsize, intendedsize; int inhibit_response; /* inhibit callbacks when we change GUI controls */ + + unifontsel u; } unifontsel_internal; /* @@ -3674,12 +3675,12 @@ unifontsel *unifontsel_new(const char *wintitle) fs->selsize = fs->intendedsize = 13; /* random default */ gtk_widget_set_sensitive(fs->u.ok_button, FALSE); - return (unifontsel *)fs; + return &fs->u; } void unifontsel_destroy(unifontsel *fontsel) { - unifontsel_internal *fs = (unifontsel_internal *)fontsel; + unifontsel_internal *fs = FROMFIELD(fontsel, unifontsel_internal, u); fontinfo *info; #ifndef NO_BACKING_PIXMAPS @@ -3698,7 +3699,7 @@ void unifontsel_destroy(unifontsel *fontsel) void unifontsel_set_name(unifontsel *fontsel, const char *fontname) { - unifontsel_internal *fs = (unifontsel_internal *)fontsel; + unifontsel_internal *fs = FROMFIELD(fontsel, unifontsel_internal, u); int i, start, end, size, flags; const char *fontname2 = NULL; fontinfo *info; @@ -3758,7 +3759,7 @@ void unifontsel_set_name(unifontsel *fontsel, const char *fontname) char *unifontsel_get_name(unifontsel *fontsel) { - unifontsel_internal *fs = (unifontsel_internal *)fontsel; + unifontsel_internal *fs = FROMFIELD(fontsel, unifontsel_internal, u); char *name; if (!fs->selected) From b7982308448deb2cc025c219e971053aa417ff6b Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Fri, 5 Oct 2018 07:03:46 +0100 Subject: [PATCH 486/607] Name vtable structure types more consistently. Now they're all called FooVtable, instead of a mixture of that and Foo_vtable. --- be_all.c | 2 +- be_all_s.c | 2 +- be_none.c | 2 +- be_nos_s.c | 2 +- be_nossh.c | 2 +- be_ssh.c | 2 +- cmdline.c | 2 +- config.c | 4 ++-- defs.h | 10 +++++----- errsock.c | 4 ++-- network.h | 4 ++-- nullplug.c | 4 ++-- pageant.c | 8 ++++---- portfwd.c | 8 ++++---- proxy.c | 4 ++-- proxy.h | 4 ++-- putty.h | 22 +++++++++++----------- raw.c | 6 +++--- rlogin.c | 6 +++--- settings.c | 12 ++++++------ ssh.c | 6 +++--- sshshare.c | 8 ++++---- telnet.c | 6 +++--- testback.c | 4 ++-- unix/gtkfont.c | 16 ++++++++-------- unix/gtkfont.h | 4 ++-- unix/gtkwin.c | 2 +- unix/unix.h | 6 +++--- unix/uxnet.c | 4 ++-- unix/uxpgnt.c | 4 ++-- unix/uxplink.c | 4 ++-- unix/uxproxy.c | 4 ++-- unix/uxpterm.c | 2 +- unix/uxpty.c | 2 +- unix/uxputty.c | 6 +++--- unix/uxser.c | 2 +- windows/window.c | 4 ++-- windows/winhsock.c | 4 ++-- windows/winnet.c | 4 ++-- windows/winnps.c | 4 ++-- windows/winplink.c | 4 ++-- windows/winser.c | 2 +- windows/winstuff.h | 2 +- x11fwd.c | 4 ++-- 44 files changed, 109 insertions(+), 109 deletions(-) diff --git a/be_all.c b/be_all.c index 6a09f748..9673c798 100644 --- a/be_all.c +++ b/be_all.c @@ -22,7 +22,7 @@ const int be_default_protocol = PROT_TELNET; const int be_default_protocol = PROT_SSH; #endif -const struct Backend_vtable *const backends[] = { +const struct BackendVtable *const backends[] = { &ssh_backend, &telnet_backend, &rlogin_backend, diff --git a/be_all_s.c b/be_all_s.c index d40d7639..2f140ec0 100644 --- a/be_all_s.c +++ b/be_all_s.c @@ -22,7 +22,7 @@ const int be_default_protocol = PROT_TELNET; const int be_default_protocol = PROT_SSH; #endif -const struct Backend_vtable *const backends[] = { +const struct BackendVtable *const backends[] = { &ssh_backend, &telnet_backend, &rlogin_backend, diff --git a/be_none.c b/be_none.c index 7cf52fa1..abc05517 100644 --- a/be_none.c +++ b/be_none.c @@ -6,6 +6,6 @@ #include #include "putty.h" -const struct Backend_vtable *const backends[] = { +const struct BackendVtable *const backends[] = { NULL }; diff --git a/be_nos_s.c b/be_nos_s.c index a12125ab..b3c61e7c 100644 --- a/be_nos_s.c +++ b/be_nos_s.c @@ -10,7 +10,7 @@ const int be_default_protocol = PROT_TELNET; const char *const appname = "PuTTYtel"; -const struct Backend_vtable *const backends[] = { +const struct BackendVtable *const backends[] = { &telnet_backend, &rlogin_backend, &raw_backend, diff --git a/be_nossh.c b/be_nossh.c index 463497a2..daf15998 100644 --- a/be_nossh.c +++ b/be_nossh.c @@ -10,7 +10,7 @@ const int be_default_protocol = PROT_TELNET; const char *const appname = "PuTTYtel"; -const struct Backend_vtable *const backends[] = { +const struct BackendVtable *const backends[] = { &telnet_backend, &rlogin_backend, &raw_backend, diff --git a/be_ssh.c b/be_ssh.c index ec1da386..40737e52 100644 --- a/be_ssh.c +++ b/be_ssh.c @@ -10,7 +10,7 @@ const int be_default_protocol = PROT_SSH; -const struct Backend_vtable *const backends[] = { +const struct BackendVtable *const backends[] = { &ssh_backend, NULL }; diff --git a/cmdline.c b/cmdline.c index 0ce3f8a1..85586176 100644 --- a/cmdline.c +++ b/cmdline.c @@ -275,7 +275,7 @@ int cmdline_process_param(const char *p, char *value, const char *comma = strchr(p, ','); if (comma) { char *prefix = dupprintf("%.*s", (int)(comma - p), p); - const struct Backend_vtable *vt = + const struct BackendVtable *vt = backend_vt_from_name(prefix); if (vt) { diff --git a/config.c b/config.c index caab152c..18c41f8f 100644 --- a/config.c +++ b/config.c @@ -267,8 +267,8 @@ void config_protocolbuttons_handler(union control *ctrl, dlgparam *dlg, conf_set_int(conf, CONF_protocol, newproto); if (oldproto != newproto) { - const struct Backend_vtable *ovt = backend_vt_from_proto(oldproto); - const struct Backend_vtable *nvt = backend_vt_from_proto(newproto); + const struct BackendVtable *ovt = backend_vt_from_proto(oldproto); + const struct BackendVtable *nvt = backend_vt_from_proto(newproto); assert(ovt); assert(nvt); /* Iff the user hasn't changed the port from the old protocol's diff --git a/defs.h b/defs.h index 6dc07e7d..f1119d10 100644 --- a/defs.h +++ b/defs.h @@ -42,11 +42,11 @@ typedef struct IdempotentCallback IdempotentCallback; typedef struct SockAddr SockAddr; -typedef struct Socket_vtable Socket_vtable; -typedef struct Plug_vtable Plug_vtable; +typedef struct SocketVtable SocketVtable; +typedef struct PlugVtable PlugVtable; typedef struct Backend Backend; -typedef struct Backend_vtable Backend_vtable; +typedef struct BackendVtable BackendVtable; typedef struct Ldisc_tag Ldisc; typedef struct LogContext_tag LogContext; @@ -74,8 +74,8 @@ typedef struct settings_e settings_e; typedef struct SessionSpecial SessionSpecial; -typedef const Socket_vtable *Socket; -typedef const Plug_vtable *Plug; +typedef const SocketVtable *Socket; +typedef const PlugVtable *Plug; /* * A small structure wrapping up a (pointer, length) pair so that it diff --git a/errsock.c b/errsock.c index 030f5739..b38497ee 100644 --- a/errsock.c +++ b/errsock.c @@ -14,7 +14,7 @@ typedef struct { char *error; Plug *plug; - const Socket_vtable *sockvt; + const SocketVtable *sockvt; } ErrorSocket; static Plug *sk_error_plug(Socket *s, Plug *p) @@ -45,7 +45,7 @@ static char *sk_error_peer_info(Socket *s) return NULL; } -static const Socket_vtable ErrorSocket_sockvt = { +static const SocketVtable ErrorSocket_sockvt = { sk_error_plug, sk_error_close, NULL /* write */, diff --git a/network.h b/network.h index 86c0f6b9..6096a745 100644 --- a/network.h +++ b/network.h @@ -15,7 +15,7 @@ #include "defs.h" -struct Socket_vtable { +struct SocketVtable { Plug *(*plug) (Socket *s, Plug *p); /* use a different plug (return the old one) */ /* if p is NULL, it doesn't change the plug */ @@ -34,7 +34,7 @@ struct Socket_vtable { typedef union { void *p; int i; } accept_ctx_t; typedef Socket *(*accept_fn_t)(accept_ctx_t ctx, Plug *plug); -struct Plug_vtable { +struct PlugVtable { void (*log)(Plug *p, int type, SockAddr *addr, int port, const char *error_msg, int error_code); /* diff --git a/nullplug.c b/nullplug.c index 4a57f33a..26c3ae8a 100644 --- a/nullplug.c +++ b/nullplug.c @@ -25,7 +25,7 @@ static void nullplug_sent(Plug *plug, int bufsize) { } -static const Plug_vtable nullplug_plugvt = { +static const PlugVtable nullplug_plugvt = { nullplug_socket_log, nullplug_closing, nullplug_receive, @@ -33,7 +33,7 @@ static const Plug_vtable nullplug_plugvt = { NULL }; -static const Plug_vtable *nullplug_plugvt_ptr = &nullplug_plugvt; +static const PlugVtable *nullplug_plugvt_ptr = &nullplug_plugvt; /* * There's a singleton instance of nullplug, because it's not diff --git a/pageant.c b/pageant.c index 270715bf..12b86638 100644 --- a/pageant.c +++ b/pageant.c @@ -707,7 +707,7 @@ struct pageant_conn_state { int real_packet; int crLine; /* for coroutine in pageant_conn_receive */ - const Plug_vtable *plugvt; + const PlugVtable *plugvt; }; static void pageant_conn_closing(Plug *plug, const char *error_msg, @@ -801,7 +801,7 @@ struct pageant_listen_state { void *logctx; pageant_logfn_t logfn; - const Plug_vtable *plugvt; + const PlugVtable *plugvt; }; static void pageant_listen_closing(Plug *plug, const char *error_msg, @@ -815,7 +815,7 @@ static void pageant_listen_closing(Plug *plug, const char *error_msg, pl->listensock = NULL; } -static const Plug_vtable pageant_connection_plugvt = { +static const PlugVtable pageant_connection_plugvt = { NULL, /* no log function, because that's for outgoing connections */ pageant_conn_closing, pageant_conn_receive, @@ -858,7 +858,7 @@ static int pageant_listen_accepting(Plug *plug, return 0; } -static const Plug_vtable pageant_listener_plugvt = { +static const PlugVtable pageant_listener_plugvt = { NULL, /* no log function, because that's for outgoing connections */ pageant_listen_closing, NULL, /* no receive function on a listening socket */ diff --git a/portfwd.c b/portfwd.c index 9c7ff137..6934bb31 100644 --- a/portfwd.c +++ b/portfwd.c @@ -56,7 +56,7 @@ typedef struct PortForwarding { strbuf *socksbuf; size_t socksbuf_consumed; - const Plug_vtable *plugvt; + const PlugVtable *plugvt; Channel chan; } PortForwarding; @@ -71,7 +71,7 @@ struct PortListener { char *hostname; int port; - const Plug_vtable *plugvt; + const PlugVtable *plugvt; }; static struct PortForwarding *new_portfwd_state(void) @@ -435,7 +435,7 @@ static void pfd_sent(Plug *plug, int bufsize) sshfwd_unthrottle(pf->c, bufsize); } -static const Plug_vtable PortForwarding_plugvt = { +static const PlugVtable PortForwarding_plugvt = { pfd_log, pfd_closing, pfd_receive, @@ -509,7 +509,7 @@ static int pfl_accepting(Plug *p, accept_fn_t constructor, accept_ctx_t ctx) return 0; } -static const Plug_vtable PortListener_plugvt = { +static const PlugVtable PortListener_plugvt = { pfl_log, pfl_closing, NULL, /* recv */ diff --git a/proxy.c b/proxy.c index 26c1eacb..213c0042 100644 --- a/proxy.c +++ b/proxy.c @@ -396,7 +396,7 @@ SockAddr *name_lookup(const char *host, int port, char **canonicalname, } } -static const struct Socket_vtable ProxySocket_sockvt = { +static const struct SocketVtable ProxySocket_sockvt = { sk_proxy_plug, sk_proxy_close, sk_proxy_write, @@ -408,7 +408,7 @@ static const struct Socket_vtable ProxySocket_sockvt = { NULL, /* peer_info */ }; -static const struct Plug_vtable ProxySocket_plugvt = { +static const struct PlugVtable ProxySocket_plugvt = { plug_proxy_log, plug_proxy_closing, plug_proxy_receive, diff --git a/proxy.h b/proxy.h index 2f39139e..0abb7d3b 100644 --- a/proxy.h +++ b/proxy.h @@ -87,8 +87,8 @@ struct ProxySocket { int chap_current_attribute; int chap_current_datalen; - const Socket_vtable *sockvt; - const Plug_vtable *plugvt; + const SocketVtable *sockvt; + const PlugVtable *plugvt; }; extern void proxy_activate (ProxySocket *); diff --git a/putty.h b/putty.h index 778dac35..aa82890f 100644 --- a/putty.h +++ b/putty.h @@ -476,9 +476,9 @@ enum { }; struct Backend { - const Backend_vtable *vt; + const BackendVtable *vt; }; -struct Backend_vtable { +struct BackendVtable { const char *(*init) (Frontend *frontend, Backend **backend_out, Conf *conf, const char *host, int port, char **realhost, int nodelay, int keepalive); @@ -535,7 +535,7 @@ struct Backend_vtable { #define backend_unthrottle(be, bufsize) ((be)->vt->unthrottle(be, bufsize)) #define backend_cfg_info(be) ((be)->vt->cfg_info(be)) -extern const struct Backend_vtable *const backends[]; +extern const struct BackendVtable *const backends[]; /* * Suggested default protocol provided by the backend link module. @@ -1099,8 +1099,8 @@ void random_destroy_seed(void); /* * Exports from settings.c. */ -const struct Backend_vtable *backend_vt_from_name(const char *name); -const struct Backend_vtable *backend_vt_from_proto(int proto); +const struct BackendVtable *backend_vt_from_name(const char *name); +const struct BackendVtable *backend_vt_from_proto(int proto); char *get_remote_username(Conf *conf); /* dynamically allocated */ char *save_settings(const char *section, Conf *conf); void save_open_settings(settings_w *sesskey, Conf *conf); @@ -1195,31 +1195,31 @@ void log_packet(LogContext *logctx, int direction, int type, * Exports from testback.c */ -extern const struct Backend_vtable null_backend; -extern const struct Backend_vtable loop_backend; +extern const struct BackendVtable null_backend; +extern const struct BackendVtable loop_backend; /* * Exports from raw.c. */ -extern const struct Backend_vtable raw_backend; +extern const struct BackendVtable raw_backend; /* * Exports from rlogin.c. */ -extern const struct Backend_vtable rlogin_backend; +extern const struct BackendVtable rlogin_backend; /* * Exports from telnet.c. */ -extern const struct Backend_vtable telnet_backend; +extern const struct BackendVtable telnet_backend; /* * Exports from ssh.c. */ -extern const struct Backend_vtable ssh_backend; +extern const struct BackendVtable ssh_backend; /* * Exports from ldisc.c. diff --git a/raw.c b/raw.c index aed3f708..dc6a40c5 100644 --- a/raw.c +++ b/raw.c @@ -20,7 +20,7 @@ struct Raw { Conf *conf; - const Plug_vtable *plugvt; + const PlugVtable *plugvt; Backend backend; }; @@ -103,7 +103,7 @@ static void raw_sent(Plug *plug, int bufsize) raw->bufsize = bufsize; } -static const Plug_vtable Raw_plugvt = { +static const PlugVtable Raw_plugvt = { raw_log, raw_closing, raw_receive, @@ -307,7 +307,7 @@ static int raw_cfg_info(Backend *be) return 0; } -const struct Backend_vtable raw_backend = { +const struct BackendVtable raw_backend = { raw_init, raw_free, raw_reconfig, diff --git a/rlogin.c b/rlogin.c index 8faf37b0..600e9f1c 100644 --- a/rlogin.c +++ b/rlogin.c @@ -26,7 +26,7 @@ struct Rlogin { /* In case we need to read a username from the terminal before starting */ prompts_t *prompt; - const Plug_vtable *plugvt; + const PlugVtable *plugvt; Backend backend; }; @@ -134,7 +134,7 @@ static void rlogin_startup(Rlogin *rlogin, const char *ruser) rlogin->prompt = NULL; } -static const Plug_vtable Rlogin_plugvt = { +static const PlugVtable Rlogin_plugvt = { rlogin_log, rlogin_closing, rlogin_receive, @@ -398,7 +398,7 @@ static int rlogin_cfg_info(Backend *be) return 0; } -const struct Backend_vtable rlogin_backend = { +const struct BackendVtable rlogin_backend = { rlogin_init, rlogin_free, rlogin_reconfig, diff --git a/settings.c b/settings.c index 5b613b66..92c8b270 100644 --- a/settings.c +++ b/settings.c @@ -74,18 +74,18 @@ const char *const ttymodes[] = { * (which is only present in tools that manage settings). */ -const struct Backend_vtable *backend_vt_from_name(const char *name) +const struct BackendVtable *backend_vt_from_name(const char *name) { - const struct Backend_vtable *const *p; + const struct BackendVtable *const *p; for (p = backends; *p != NULL; p++) if (!strcmp((*p)->name, name)) return *p; return NULL; } -const struct Backend_vtable *backend_vt_from_proto(int proto) +const struct BackendVtable *backend_vt_from_proto(int proto) { - const struct Backend_vtable *const *p; + const struct BackendVtable *const *p; for (p = backends; *p != NULL; p++) if ((*p)->protocol == proto) return *p; @@ -529,7 +529,7 @@ void save_open_settings(settings_w *sesskey, Conf *conf) write_setting_i(sesskey, "SSHLogOmitData", conf_get_int(conf, CONF_logomitdata)); p = "raw"; { - const struct Backend_vtable *vt = + const struct BackendVtable *vt = backend_vt_from_proto(conf_get_int(conf, CONF_protocol)); if (vt) p = vt->name; @@ -794,7 +794,7 @@ void load_open_settings(settings_r *sesskey, Conf *conf) conf_set_int(conf, CONF_protocol, default_protocol); conf_set_int(conf, CONF_port, default_port); { - const struct Backend_vtable *vt = backend_vt_from_name(prot); + const struct BackendVtable *vt = backend_vt_from_name(prot); if (vt) { conf_set_int(conf, CONF_protocol, vt->protocol); gppi(sesskey, "PortNumber", default_port, conf, CONF_port); diff --git a/ssh.c b/ssh.c index d6afb259..7a361319 100644 --- a/ssh.c +++ b/ssh.c @@ -37,7 +37,7 @@ struct Ssh { struct ssh_version_receiver version_receiver; int remote_bugs; - const Plug_vtable *plugvt; + const PlugVtable *plugvt; Backend backend; Ldisc *ldisc; @@ -599,7 +599,7 @@ static int ssh_test_for_upstream(const char *host, int port, Conf *conf) return ret; } -static const Plug_vtable Ssh_plugvt = { +static const PlugVtable Ssh_plugvt = { ssh_socket_log, ssh_closing, ssh_receive, @@ -1087,7 +1087,7 @@ void ssh_got_fallback_cmd(Ssh *ssh) ssh->fallback_cmd = TRUE; } -const struct Backend_vtable ssh_backend = { +const struct BackendVtable ssh_backend = { ssh_init, ssh_free, ssh_reconfig, diff --git a/sshshare.c b/sshshare.c index 3de2caa8..3b9bef50 100644 --- a/sshshare.c +++ b/sshshare.c @@ -147,7 +147,7 @@ struct ssh_sharing_state { ConnectionLayer *cl; /* instance of the ssh connection layer */ char *server_verstring; /* server version string after "SSH-" */ - const Plug_vtable *plugvt; + const PlugVtable *plugvt; }; struct share_globreq; @@ -200,7 +200,7 @@ struct ssh_sharing_connstate { /* Global requests we've sent on to the server, pending replies. */ struct share_globreq *globreq_head, *globreq_tail; - const Plug_vtable *plugvt; + const PlugVtable *plugvt; }; struct share_halfchannel { @@ -1910,7 +1910,7 @@ void share_activate(ssh_sharing_state *sharestate, } } -static const Plug_vtable ssh_sharing_conn_plugvt = { +static const PlugVtable ssh_sharing_conn_plugvt = { NULL, /* no log function, because that's for outgoing connections */ share_closing, share_receive, @@ -2054,7 +2054,7 @@ int ssh_share_test_for_upstream(const char *host, int port, Conf *conf) } } -static const Plug_vtable ssh_sharing_listen_plugvt = { +static const PlugVtable ssh_sharing_listen_plugvt = { NULL, /* no log function, because that's for outgoing connections */ share_listen_closing, NULL, /* no receive function on a listening socket */ diff --git a/telnet.c b/telnet.c index 805cb13b..9e386fb8 100644 --- a/telnet.c +++ b/telnet.c @@ -197,7 +197,7 @@ struct Telnet { Pinger *pinger; - const Plug_vtable *plugvt; + const PlugVtable *plugvt; Backend backend; }; @@ -691,7 +691,7 @@ static void telnet_sent(Plug *plug, int bufsize) telnet->bufsize = bufsize; } -static const Plug_vtable Telnet_plugvt = { +static const PlugVtable Telnet_plugvt = { telnet_log, telnet_closing, telnet_receive, @@ -1079,7 +1079,7 @@ static int telnet_cfg_info(Backend *be) return 0; } -const struct Backend_vtable telnet_backend = { +const struct BackendVtable telnet_backend = { telnet_init, telnet_free, telnet_reconfig, diff --git a/testback.c b/testback.c index dfddf93f..9e70819f 100644 --- a/testback.c +++ b/testback.c @@ -54,14 +54,14 @@ static void null_provide_logctx(Backend *, LogContext *); static void null_unthrottle(Backend *, int); static int null_cfg_info(Backend *); -const struct Backend_vtable null_backend = { +const struct BackendVtable null_backend = { null_init, null_free, null_reconfig, null_send, null_sendbuffer, null_size, null_special, null_get_specials, null_connected, null_exitcode, null_sendok, null_ldisc, null_provide_ldisc, null_provide_logctx, null_unthrottle, null_cfg_info, NULL /* test_for_upstream */, "null", -1, 0 }; -const struct Backend_vtable loop_backend = { +const struct BackendVtable loop_backend = { loop_init, loop_free, null_reconfig, loop_send, null_sendbuffer, null_size, null_special, null_get_specials, null_connected, null_exitcode, null_sendok, null_ldisc, null_provide_ldisc, null_provide_logctx, null_unthrottle, diff --git a/unix/gtkfont.c b/unix/gtkfont.c index 863183e8..d957476b 100644 --- a/unix/gtkfont.c +++ b/unix/gtkfont.c @@ -67,9 +67,9 @@ typedef void (*fontsel_add_entry)(void *ctx, const char *realfontname, const char *family, const char *charset, const char *style, const char *stylekey, int size, int flags, - const struct unifont_vtable *fontclass); + const struct UnifontVtable *fontclass); -struct unifont_vtable { +struct UnifontVtable { /* * `Methods' of the `class'. */ @@ -213,7 +213,7 @@ struct x11font { unifont u; }; -static const struct unifont_vtable x11font_vtable = { +static const struct UnifontVtable x11font_vtable = { x11font_create, NULL, /* no fallback fonts in X11 */ x11font_destroy, @@ -1347,7 +1347,7 @@ struct pangofont { struct unifont u; }; -static const struct unifont_vtable pangofont_vtable = { +static const struct UnifontVtable pangofont_vtable = { pangofont_create, pangofont_create_fallback, pangofont_destroy, @@ -2057,7 +2057,7 @@ static char *pangofont_size_increment(unifont *font, int increment) * * The 'multifont' subclass is omitted here, as discussed above. */ -static const struct unifont_vtable *unifont_types[] = { +static const struct UnifontVtable *unifont_types[] = { #if GTK_CHECK_VERSION(2,0,0) &pangofont_vtable, #endif @@ -2183,7 +2183,7 @@ struct multifont { struct unifont u; }; -static const struct unifont_vtable multifont_vtable = { +static const struct UnifontVtable multifont_vtable = { NULL, /* creation is done specially */ NULL, multifont_destroy, @@ -2363,7 +2363,7 @@ struct fontinfo { /* * The class of font. */ - const struct unifont_vtable *fontclass; + const struct UnifontVtable *fontclass; }; struct fontinfo_realname_find { @@ -2966,7 +2966,7 @@ static void unifontsel_add_entry(void *ctx, const char *realfontname, const char *family, const char *charset, const char *style, const char *stylekey, int size, int flags, - const struct unifont_vtable *fontclass) + const struct UnifontVtable *fontclass) { unifontsel_internal *fs = (unifontsel_internal *)ctx; fontinfo *info; diff --git a/unix/gtkfont.h b/unix/gtkfont.h index 35ce62e1..249828b4 100644 --- a/unix/gtkfont.h +++ b/unix/gtkfont.h @@ -49,9 +49,9 @@ /* * Exports from gtkfont.c. */ -struct unifont_vtable; /* contents internal to gtkfont.c */ +struct UnifontVtable; /* contents internal to gtkfont.c */ typedef struct unifont { - const struct unifont_vtable *vt; + const struct UnifontVtable *vt; /* * `Non-static data members' of the `class', accessible to * external code. diff --git a/unix/gtkwin.c b/unix/gtkwin.c index ee492d02..ec53b6c8 100644 --- a/unix/gtkwin.c +++ b/unix/gtkwin.c @@ -5001,7 +5001,7 @@ void update_specials_menu(Frontend *inst) static void start_backend(Frontend *inst) { - const struct Backend_vtable *vt; + const struct BackendVtable *vt; char *realhost; const char *error; char *s; diff --git a/unix/unix.h b/unix/unix.h index 75093668..932d666e 100644 --- a/unix/unix.h +++ b/unix/unix.h @@ -67,7 +67,7 @@ struct FontSpec *fontspec_new(const char *name); typedef struct draw_ctx *Context; -extern const struct Backend_vtable pty_backend; +extern const struct BackendVtable pty_backend; #define BROKEN_PIPE_ERROR_CODE EPIPE /* used in sshshare.c */ @@ -178,7 +178,7 @@ void window_setup_error(const char *errmsg); GtkWidget *make_gtk_toplevel_window(Frontend *frontend); #endif -const struct Backend_vtable *select_backend(Conf *conf); +const struct BackendVtable *select_backend(Conf *conf); /* Defined in gtkcomm.c */ void gtkcomm_setup(void); @@ -328,7 +328,7 @@ void *sk_getxdmdata(Socket *sock, int *lenp); /* * Exports from uxser.c. */ -extern const struct Backend_vtable serial_backend; +extern const struct BackendVtable serial_backend; /* * uxpeer.c, wrapping getsockopt(SO_PEERCRED). diff --git a/unix/uxnet.c b/unix/uxnet.c index e924f449..3c0f3c1f 100644 --- a/unix/uxnet.c +++ b/unix/uxnet.c @@ -89,7 +89,7 @@ struct NetSocket { */ NetSocket *parent, *child; - const Socket_vtable *sockvt; + const SocketVtable *sockvt; }; struct SockAddr { @@ -507,7 +507,7 @@ static void sk_net_set_frozen(Socket *s, int is_frozen); static char *sk_net_peer_info(Socket *s); static const char *sk_net_socket_error(Socket *s); -static struct Socket_vtable NetSocket_sockvt = { +static struct SocketVtable NetSocket_sockvt = { sk_net_plug, sk_net_close, sk_net_write, diff --git a/unix/uxpgnt.c b/unix/uxpgnt.c index 0a0a14ea..13f44c7b 100644 --- a/unix/uxpgnt.c +++ b/unix/uxpgnt.c @@ -176,7 +176,7 @@ static void x11_closing(Plug *plug, const char *error_msg, int error_code, time_to_die = TRUE; } struct X11Connection { - const Plug_vtable *plugvt; + const PlugVtable *plugvt; }; char *socketname; @@ -728,7 +728,7 @@ void run_client(void) exit(1); } -static const Plug_vtable X11Connection_plugvt = { +static const PlugVtable X11Connection_plugvt = { x11_log, x11_closing, x11_receive, diff --git a/unix/uxplink.c b/unix/uxplink.c index c211309b..b1a2ef5d 100644 --- a/unix/uxplink.c +++ b/unix/uxplink.c @@ -595,7 +595,7 @@ int main(int argc, char **argv) int just_test_share_exists = FALSE; unsigned long now; struct winsize size; - const struct Backend_vtable *backvt; + const struct BackendVtable *backvt; fdlist = NULL; fdcount = fdsize = 0; @@ -633,7 +633,7 @@ int main(int argc, char **argv) */ char *p = getenv("PLINK_PROTOCOL"); if (p) { - const struct Backend_vtable *vt = backend_vt_from_name(p); + const struct BackendVtable *vt = backend_vt_from_name(p); if (vt) { default_protocol = vt->protocol; default_port = vt->default_port; diff --git a/unix/uxproxy.c b/unix/uxproxy.c index 8e121f15..2dce0418 100644 --- a/unix/uxproxy.c +++ b/unix/uxproxy.c @@ -29,7 +29,7 @@ typedef struct LocalProxySocket { int pending_error; - const Socket_vtable *sockvt; + const SocketVtable *sockvt; } LocalProxySocket; static void localproxy_select_result(int fd, int event); @@ -303,7 +303,7 @@ static void localproxy_select_result(int fd, int event) } } -static const Socket_vtable LocalProxySocket_sockvt = { +static const SocketVtable LocalProxySocket_sockvt = { sk_localproxy_plug, sk_localproxy_close, sk_localproxy_write, diff --git a/unix/uxpterm.c b/unix/uxpterm.c index 4df8b164..c7325722 100644 --- a/unix/uxpterm.c +++ b/unix/uxpterm.c @@ -13,7 +13,7 @@ const int new_session = 0, saved_sessions = 0; /* or these */ const int dup_check_launchable = 0; /* no need to check host name in conf */ const int use_pty_argv = TRUE; -const struct Backend_vtable *select_backend(Conf *conf) +const struct BackendVtable *select_backend(Conf *conf) { return &pty_backend; } diff --git a/unix/uxpty.c b/unix/uxpty.c index 3389074c..aebfb5c2 100644 --- a/unix/uxpty.c +++ b/unix/uxpty.c @@ -1240,7 +1240,7 @@ static int pty_cfg_info(Backend *be) return 0; } -const struct Backend_vtable pty_backend = { +const struct BackendVtable pty_backend = { pty_init, pty_free, pty_reconfig, diff --git a/unix/uxputty.c b/unix/uxputty.c index 52e4cef1..fdfa6c21 100644 --- a/unix/uxputty.c +++ b/unix/uxputty.c @@ -37,9 +37,9 @@ void cleanup_exit(int code) exit(code); } -const struct Backend_vtable *select_backend(Conf *conf) +const struct BackendVtable *select_backend(Conf *conf) { - const struct Backend_vtable *vt = + const struct BackendVtable *vt = backend_vt_from_proto(conf_get_int(conf, CONF_protocol)); assert(vt != NULL); return vt; @@ -84,7 +84,7 @@ void setup(int single) default_protocol = be_default_protocol; /* Find the appropriate default port. */ { - const struct Backend_vtable *vt = + const struct BackendVtable *vt = backend_vt_from_proto(default_protocol); default_port = 0; /* illegal */ if (vt) diff --git a/unix/uxser.c b/unix/uxser.c index 2db560b9..dc96f643 100644 --- a/unix/uxser.c +++ b/unix/uxser.c @@ -575,7 +575,7 @@ static int serial_cfg_info(Backend *be) return 0; } -const struct Backend_vtable serial_backend = { +const struct BackendVtable serial_backend = { serial_init, serial_free, serial_reconfig, diff --git a/windows/window.c b/windows/window.c index 40836435..7bef7ee6 100644 --- a/windows/window.c +++ b/windows/window.c @@ -247,7 +247,7 @@ char *get_ttymode(Frontend *frontend, const char *mode) static void start_backend(void) { - const struct Backend_vtable *vt; + const struct BackendVtable *vt; const char *error; char msg[1024], *title; char *realhost; @@ -412,7 +412,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) default_protocol = be_default_protocol; /* Find the appropriate default port. */ { - const struct Backend_vtable *vt = + const struct BackendVtable *vt = backend_vt_from_proto(default_protocol); default_port = 0; /* illegal */ if (vt) diff --git a/windows/winhsock.c b/windows/winhsock.c index f8349831..4fefe31f 100644 --- a/windows/winhsock.c +++ b/windows/winhsock.c @@ -43,7 +43,7 @@ typedef struct HandleSocket { Plug *plug; - const Socket_vtable *sockvt; + const SocketVtable *sockvt; } HandleSocket; static int handle_gotdata(struct handle *h, void *data, int len) @@ -306,7 +306,7 @@ static char *sk_handle_peer_info(Socket *s) return NULL; } -static const Socket_vtable HandleSocket_sockvt = { +static const SocketVtable HandleSocket_sockvt = { sk_handle_plug, sk_handle_close, sk_handle_write, diff --git a/windows/winnet.c b/windows/winnet.c index 454e649a..2427b688 100644 --- a/windows/winnet.c +++ b/windows/winnet.c @@ -76,7 +76,7 @@ struct NetSocket { */ NetSocket *parent, *child; - const Socket_vtable *sockvt; + const SocketVtable *sockvt; }; struct SockAddr { @@ -935,7 +935,7 @@ static char *sk_net_peer_info(Socket *s); extern char *do_select(SOCKET skt, int startup); -static const Socket_vtable NetSocket_sockvt = { +static const SocketVtable NetSocket_sockvt = { sk_net_plug, sk_net_close, sk_net_write, diff --git a/windows/winnps.c b/windows/winnps.c index e827c0a7..c6a9f6a6 100644 --- a/windows/winnps.c +++ b/windows/winnps.c @@ -34,7 +34,7 @@ typedef struct NamedPipeServerSocket { Plug *plug; char *error; - const Socket_vtable *sockvt; + const SocketVtable *sockvt; } NamedPipeServerSocket; static Plug *sk_namedpipeserver_plug(Socket *s, Plug *p) @@ -204,7 +204,7 @@ static void named_pipe_connect_callback(void *vps) * This socket type is only used for listening, so it should never * be asked to write or flush or set_frozen. */ -static const Socket_vtable NamedPipeServerSocket_sockvt = { +static const SocketVtable NamedPipeServerSocket_sockvt = { sk_namedpipeserver_plug, sk_namedpipeserver_close, NULL /* write */, diff --git a/windows/winplink.c b/windows/winplink.c index c215ec19..255fb2fd 100644 --- a/windows/winplink.c +++ b/windows/winplink.c @@ -289,7 +289,7 @@ int main(int argc, char **argv) int use_subsystem = 0; int just_test_share_exists = FALSE; unsigned long now, next, then; - const struct Backend_vtable *vt; + const struct BackendVtable *vt; dll_hijacking_protection(); @@ -324,7 +324,7 @@ int main(int argc, char **argv) */ char *p = getenv("PLINK_PROTOCOL"); if (p) { - const struct Backend_vtable *vt = backend_vt_from_name(p); + const struct BackendVtable *vt = backend_vt_from_name(p); if (vt) { default_protocol = vt->protocol; default_port = vt->default_port; diff --git a/windows/winser.c b/windows/winser.c index 5367c4a6..30c605f7 100644 --- a/windows/winser.c +++ b/windows/winser.c @@ -440,7 +440,7 @@ static int serial_cfg_info(Backend *be) return 0; } -const struct Backend_vtable serial_backend = { +const struct BackendVtable serial_backend = { serial_init, serial_free, serial_reconfig, diff --git a/windows/winstuff.h b/windows/winstuff.h index e57bf0da..bb64ac07 100644 --- a/windows/winstuff.h +++ b/windows/winstuff.h @@ -596,7 +596,7 @@ void agent_schedule_callback(void (*callback)(void *, void *, int), /* * Exports from winser.c. */ -extern const struct Backend_vtable serial_backend; +extern const struct BackendVtable serial_backend; /* * Exports from winjump.c. diff --git a/x11fwd.c b/x11fwd.c index 658008d9..34c5cb96 100644 --- a/x11fwd.c +++ b/x11fwd.c @@ -42,7 +42,7 @@ typedef struct X11Connection { SshChannel *c; /* channel structure held by SSH backend */ Socket *s; - const Plug_vtable *plugvt; + const PlugVtable *plugvt; Channel chan; } X11Connection; @@ -699,7 +699,7 @@ int x11_get_screen_number(char *display) return atoi(display + n + 1); } -static const Plug_vtable X11Connection_plugvt = { +static const PlugVtable X11Connection_plugvt = { x11_log, x11_closing, x11_receive, From 884a7df94b9bf83ba2915d64f2658e0c55e6491d Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Fri, 5 Oct 2018 07:24:16 +0100 Subject: [PATCH 487/607] Make Socket and Plug into structs. I think that means that _every_ one of my traitoids is now a struct containing a vtable pointer as one of its fields (albeit sometimes the only field), and never just a bare pointer. --- defs.h | 7 ++---- errsock.c | 12 ++++----- network.h | 46 +++++++++++++++++++++++----------- nullplug.c | 4 +-- pageant.c | 22 ++++++++-------- portfwd.c | 24 +++++++++--------- proxy.c | 42 +++++++++++++++---------------- proxy.h | 4 +-- raw.c | 14 +++++------ rlogin.c | 14 +++++------ ssh.c | 16 ++++++------ sshshare.c | 22 ++++++++-------- telnet.c | 14 +++++------ unix/uxnet.c | 62 +++++++++++++++++++++++----------------------- unix/uxpgnt.c | 6 ++--- unix/uxproxy.c | 28 ++++++++++----------- windows/winhsock.c | 24 +++++++++--------- windows/winnet.c | 46 +++++++++++++++++----------------- windows/winnps.c | 12 ++++----- x11fwd.c | 12 ++++----- 20 files changed, 222 insertions(+), 209 deletions(-) diff --git a/defs.h b/defs.h index f1119d10..776ab888 100644 --- a/defs.h +++ b/defs.h @@ -42,8 +42,8 @@ typedef struct IdempotentCallback IdempotentCallback; typedef struct SockAddr SockAddr; -typedef struct SocketVtable SocketVtable; -typedef struct PlugVtable PlugVtable; +typedef struct Socket Socket; +typedef struct Plug Plug; typedef struct Backend Backend; typedef struct BackendVtable BackendVtable; @@ -74,9 +74,6 @@ typedef struct settings_e settings_e; typedef struct SessionSpecial SessionSpecial; -typedef const SocketVtable *Socket; -typedef const PlugVtable *Plug; - /* * A small structure wrapping up a (pointer, length) pair so that it * can be conveniently passed to or from a function. diff --git a/errsock.c b/errsock.c index b38497ee..a15f75cf 100644 --- a/errsock.c +++ b/errsock.c @@ -14,12 +14,12 @@ typedef struct { char *error; Plug *plug; - const SocketVtable *sockvt; + Socket sock; } ErrorSocket; static Plug *sk_error_plug(Socket *s, Plug *p) { - ErrorSocket *es = FROMFIELD(s, ErrorSocket, sockvt); + ErrorSocket *es = FROMFIELD(s, ErrorSocket, sock); Plug *ret = es->plug; if (p) es->plug = p; @@ -28,7 +28,7 @@ static Plug *sk_error_plug(Socket *s, Plug *p) static void sk_error_close(Socket *s) { - ErrorSocket *es = FROMFIELD(s, ErrorSocket, sockvt); + ErrorSocket *es = FROMFIELD(s, ErrorSocket, sock); sfree(es->error); sfree(es); @@ -36,7 +36,7 @@ static void sk_error_close(Socket *s) static const char *sk_error_socket_error(Socket *s) { - ErrorSocket *es = FROMFIELD(s, ErrorSocket, sockvt); + ErrorSocket *es = FROMFIELD(s, ErrorSocket, sock); return es->error; } @@ -60,8 +60,8 @@ static const SocketVtable ErrorSocket_sockvt = { Socket *new_error_socket(const char *errmsg, Plug *plug) { ErrorSocket *es = snew(ErrorSocket); - es->sockvt = &ErrorSocket_sockvt; + es->sock.vt = &ErrorSocket_sockvt; es->plug = plug; es->error = dupstr(errmsg); - return &es->sockvt; + return &es->sock; } diff --git a/network.h b/network.h index 6096a745..10492665 100644 --- a/network.h +++ b/network.h @@ -15,6 +15,13 @@ #include "defs.h" +typedef struct SocketVtable SocketVtable; +typedef struct PlugVtable PlugVtable; + +struct Socket { + const struct SocketVtable *vt; +}; + struct SocketVtable { Plug *(*plug) (Socket *s, Plug *p); /* use a different plug (return the old one) */ @@ -34,6 +41,10 @@ struct SocketVtable { typedef union { void *p; int i; } accept_ctx_t; typedef Socket *(*accept_fn_t)(accept_ctx_t ctx, Plug *plug); +struct Plug { + const struct PlugVtable *vt; +}; + struct PlugVtable { void (*log)(Plug *p, int type, SockAddr *addr, int port, const char *error_msg, int error_code); @@ -138,19 +149,24 @@ Socket *sk_new(SockAddr *addr, int port, int privport, int oobinline, Socket *sk_newlistener(const char *srcaddr, int port, Plug *plug, int local_host_only, int address_family); -#define sk_plug(s,p) (((*s)->plug) (s, p)) -#define sk_close(s) (((*s)->close) (s)) -#define sk_write(s,buf,len) (((*s)->write) (s, buf, len)) -#define sk_write_oob(s,buf,len) (((*s)->write_oob) (s, buf, len)) -#define sk_write_eof(s) (((*s)->write_eof) (s)) -#define sk_flush(s) (((*s)->flush) (s)) +#define sk_plug(s,p) (((s)->vt->plug) (s, p)) +#define sk_close(s) (((s)->vt->close) (s)) +#define sk_write(s,buf,len) (((s)->vt->write) (s, buf, len)) +#define sk_write_oob(s,buf,len) (((s)->vt->write_oob) (s, buf, len)) +#define sk_write_eof(s) (((s)->vt->write_eof) (s)) +#define sk_flush(s) (((s)->vt->flush) (s)) #ifdef DEFINE_PLUG_METHOD_MACROS -#define plug_log(p,type,addr,port,msg,code) (((*p)->log) (p, type, addr, port, msg, code)) -#define plug_closing(p,msg,code,callback) (((*p)->closing) (p, msg, code, callback)) -#define plug_receive(p,urgent,buf,len) (((*p)->receive) (p, urgent, buf, len)) -#define plug_sent(p,bufsize) (((*p)->sent) (p, bufsize)) -#define plug_accepting(p, constructor, ctx) (((*p)->accepting)(p, constructor, ctx)) +#define plug_log(p,type,addr,port,msg,code) \ + (((p)->vt->log) (p, type, addr, port, msg, code)) +#define plug_closing(p,msg,code,callback) \ + (((p)->vt->closing) (p, msg, code, callback)) +#define plug_receive(p,urgent,buf,len) \ + (((p)->vt->receive) (p, urgent, buf, len)) +#define plug_sent(p,bufsize) \ + (((p)->vt->sent) (p, bufsize)) +#define plug_accepting(p, constructor, ctx) \ + (((p)->vt->accepting)(p, constructor, ctx)) #endif /* @@ -159,7 +175,7 @@ Socket *sk_newlistener(const char *srcaddr, int port, Plug *plug, * or return NULL if there's no problem. */ const char *sk_addr_error(SockAddr *addr); -#define sk_socket_error(s) (((*s)->socket_error) (s)) +#define sk_socket_error(s) (((s)->vt->socket_error) (s)) /* * Set the `frozen' flag on a socket. A frozen socket is one in @@ -178,14 +194,14 @@ const char *sk_addr_error(SockAddr *addr); * associated local socket in order to avoid unbounded buffer * growth. */ -#define sk_set_frozen(s, is_frozen) (((*s)->set_frozen) (s, is_frozen)) +#define sk_set_frozen(s, is_frozen) (((s)->vt->set_frozen) (s, is_frozen)) /* * Return a (dynamically allocated) string giving some information * about the other end of the socket, suitable for putting in log * files. May be NULL if nothing is available at all. */ -#define sk_peer_info(s) (((*s)->peer_info) (s)) +#define sk_peer_info(s) (((s)->vt->peer_info) (s)) /* * Simple wrapper on getservbyname(), needed by ssh.c. Returns the @@ -211,7 +227,7 @@ Socket *new_error_socket(const char *errmsg, Plug *plug); /* * Trivial plug that does absolutely nothing. Found in nullplug.c. */ -extern Plug *nullplug; +extern Plug *const nullplug; /* ---------------------------------------------------------------------- * Functions defined outside the network code, which have to be diff --git a/nullplug.c b/nullplug.c index 26c3ae8a..4fc16841 100644 --- a/nullplug.c +++ b/nullplug.c @@ -33,10 +33,10 @@ static const PlugVtable nullplug_plugvt = { NULL }; -static const PlugVtable *nullplug_plugvt_ptr = &nullplug_plugvt; +static Plug nullplug_plug = { &nullplug_plugvt }; /* * There's a singleton instance of nullplug, because it's not * interesting enough to worry about making more than one of them. */ -Plug *nullplug = &nullplug_plugvt_ptr; +Plug *const nullplug = &nullplug_plug; diff --git a/pageant.c b/pageant.c index 12b86638..438fbe58 100644 --- a/pageant.c +++ b/pageant.c @@ -707,14 +707,14 @@ struct pageant_conn_state { int real_packet; int crLine; /* for coroutine in pageant_conn_receive */ - const PlugVtable *plugvt; + Plug plug; }; static void pageant_conn_closing(Plug *plug, const char *error_msg, int error_code, int calling_back) { struct pageant_conn_state *pc = FROMFIELD( - plug, struct pageant_conn_state, plugvt); + plug, struct pageant_conn_state, plug); if (error_msg) plog(pc->logctx, pc->logfn, "%p: error: %s", pc, error_msg); else @@ -726,7 +726,7 @@ static void pageant_conn_closing(Plug *plug, const char *error_msg, static void pageant_conn_sent(Plug *plug, int bufsize) { /* struct pageant_conn_state *pc = FROMFIELD( - plug, struct pageant_conn_state, plugvt); */ + plug, struct pageant_conn_state, plug); */ /* * We do nothing here, because we expect that there won't be a @@ -748,7 +748,7 @@ static void pageant_conn_log(void *logctx, const char *fmt, va_list ap) static void pageant_conn_receive(Plug *plug, int urgent, char *data, int len) { struct pageant_conn_state *pc = FROMFIELD( - plug, struct pageant_conn_state, plugvt); + plug, struct pageant_conn_state, plug); char c; crBegin(pc->crLine); @@ -801,14 +801,14 @@ struct pageant_listen_state { void *logctx; pageant_logfn_t logfn; - const PlugVtable *plugvt; + Plug plug; }; static void pageant_listen_closing(Plug *plug, const char *error_msg, int error_code, int calling_back) { struct pageant_listen_state *pl = FROMFIELD( - plug, struct pageant_listen_state, plugvt); + plug, struct pageant_listen_state, plug); if (error_msg) plog(pl->logctx, pl->logfn, "listening socket: error: %s", error_msg); sk_close(pl->listensock); @@ -827,18 +827,18 @@ static int pageant_listen_accepting(Plug *plug, accept_fn_t constructor, accept_ctx_t ctx) { struct pageant_listen_state *pl = FROMFIELD( - plug, struct pageant_listen_state, plugvt); + plug, struct pageant_listen_state, plug); struct pageant_conn_state *pc; const char *err; char *peerinfo; pc = snew(struct pageant_conn_state); - pc->plugvt = &pageant_connection_plugvt; + pc->plug.vt = &pageant_connection_plugvt; pc->logfn = pl->logfn; pc->logctx = pl->logctx; pc->crLine = 0; - pc->connsock = constructor(ctx, &pc->plugvt); + pc->connsock = constructor(ctx, &pc->plug); if ((err = sk_socket_error(pc->connsock)) != NULL) { sk_close(pc->connsock); sfree(pc); @@ -869,11 +869,11 @@ static const PlugVtable pageant_listener_plugvt = { struct pageant_listen_state *pageant_listener_new(Plug **plug) { struct pageant_listen_state *pl = snew(struct pageant_listen_state); - pl->plugvt = &pageant_listener_plugvt; + pl->plug.vt = &pageant_listener_plugvt; pl->logctx = NULL; pl->logfn = NULL; pl->listensock = NULL; - *plug = &pl->plugvt; + *plug = &pl->plug; return pl; } diff --git a/portfwd.c b/portfwd.c index 6934bb31..40c09c7b 100644 --- a/portfwd.c +++ b/portfwd.c @@ -56,7 +56,7 @@ typedef struct PortForwarding { strbuf *socksbuf; size_t socksbuf_consumed; - const PlugVtable *plugvt; + Plug plug; Channel chan; } PortForwarding; @@ -71,7 +71,7 @@ struct PortListener { char *hostname; int port; - const PlugVtable *plugvt; + Plug plug; }; static struct PortForwarding *new_portfwd_state(void) @@ -124,7 +124,7 @@ static void pfd_close(struct PortForwarding *pf); static void pfd_closing(Plug *plug, const char *error_msg, int error_code, int calling_back) { - struct PortForwarding *pf = FROMFIELD(plug, struct PortForwarding, plugvt); + struct PortForwarding *pf = FROMFIELD(plug, struct PortForwarding, plug); if (error_msg) { /* @@ -205,7 +205,7 @@ static char *ipv6_to_string(ptrlen ipv6) static void pfd_receive(Plug *plug, int urgent, char *data, int len) { - struct PortForwarding *pf = FROMFIELD(plug, struct PortForwarding, plugvt); + struct PortForwarding *pf = FROMFIELD(plug, struct PortForwarding, plug); if (len == 0) return; @@ -429,7 +429,7 @@ static void pfd_receive(Plug *plug, int urgent, char *data, int len) static void pfd_sent(Plug *plug, int bufsize) { - struct PortForwarding *pf = FROMFIELD(plug, struct PortForwarding, plugvt); + struct PortForwarding *pf = FROMFIELD(plug, struct PortForwarding, plug); if (pf->c) sshfwd_unthrottle(pf->c, bufsize); @@ -473,9 +473,9 @@ static int pfl_accepting(Plug *p, accept_fn_t constructor, accept_ctx_t ctx) Socket *s; const char *err; - pl = FROMFIELD(p, struct PortListener, plugvt); + pl = FROMFIELD(p, struct PortListener, plug); pf = new_portfwd_state(); - pf->plugvt = &PortForwarding_plugvt; + pf->plug.vt = &PortForwarding_plugvt; pf->chan.initial_fixed_window_size = 0; pf->chan.vt = &PortForwarding_channelvt; pf->input_wanted = TRUE; @@ -483,7 +483,7 @@ static int pfl_accepting(Plug *p, accept_fn_t constructor, accept_ctx_t ctx) pf->c = NULL; pf->cl = pl->cl; - pf->s = s = constructor(ctx, &pf->plugvt); + pf->s = s = constructor(ctx, &pf->plug); if ((err = sk_socket_error(s)) != NULL) { free_portfwd_state(pf); return err != NULL; @@ -536,7 +536,7 @@ static char *pfl_listen(char *desthost, int destport, char *srcaddr, * Open socket. */ pl = *pl_ret = new_portlistener_state(); - pl->plugvt = &PortListener_plugvt; + pl->plug.vt = &PortListener_plugvt; if (desthost) { pl->hostname = dupstr(desthost); pl->port = destport; @@ -545,7 +545,7 @@ static char *pfl_listen(char *desthost, int destport, char *srcaddr, pl->is_dynamic = TRUE; pl->cl = cl; - pl->s = new_listener(srcaddr, port, &pl->plugvt, + pl->s = new_listener(srcaddr, port, &pl->plug, !conf_get_int(conf, CONF_lport_acceptall), conf, address_family); if ((err = sk_socket_error(pl->s)) != NULL) { @@ -1042,7 +1042,7 @@ char *portfwdmgr_connect(PortFwdManager *mgr, Channel **chan_ret, */ pf = new_portfwd_state(); *chan_ret = &pf->chan; - pf->plugvt = &PortForwarding_plugvt; + pf->plug.vt = &PortForwarding_plugvt; pf->chan.initial_fixed_window_size = 0; pf->chan.vt = &PortForwarding_channelvt; pf->input_wanted = TRUE; @@ -1052,7 +1052,7 @@ char *portfwdmgr_connect(PortFwdManager *mgr, Channel **chan_ret, pf->socks_state = SOCKS_NONE; pf->s = new_connection(addr, dummy_realhost, port, - 0, 1, 0, 0, &pf->plugvt, mgr->conf); + 0, 1, 0, 0, &pf->plug, mgr->conf); sfree(dummy_realhost); if ((err = sk_socket_error(pf->s)) != NULL) { char *err_ret = dupstr(err); diff --git a/proxy.c b/proxy.c index 213c0042..138d12aa 100644 --- a/proxy.c +++ b/proxy.c @@ -73,14 +73,14 @@ void proxy_activate (ProxySocket *p) * unfreezing the actual underlying socket. */ if (!p->freeze) - sk_set_frozen(&p->sockvt, 0); + sk_set_frozen(&p->sock, 0); } /* basic proxy socket functions */ static Plug *sk_proxy_plug (Socket *s, Plug *p) { - ProxySocket *ps = FROMFIELD(s, ProxySocket, sockvt); + ProxySocket *ps = FROMFIELD(s, ProxySocket, sock); Plug *ret = ps->plug; if (p) ps->plug = p; @@ -89,7 +89,7 @@ static Plug *sk_proxy_plug (Socket *s, Plug *p) static void sk_proxy_close (Socket *s) { - ProxySocket *ps = FROMFIELD(s, ProxySocket, sockvt); + ProxySocket *ps = FROMFIELD(s, ProxySocket, sock); sk_close(ps->sub_socket); sk_addr_free(ps->remote_addr); @@ -98,7 +98,7 @@ static void sk_proxy_close (Socket *s) static int sk_proxy_write (Socket *s, const void *data, int len) { - ProxySocket *ps = FROMFIELD(s, ProxySocket, sockvt); + ProxySocket *ps = FROMFIELD(s, ProxySocket, sock); if (ps->state != PROXY_STATE_ACTIVE) { bufchain_add(&ps->pending_output_data, data, len); @@ -109,7 +109,7 @@ static int sk_proxy_write (Socket *s, const void *data, int len) static int sk_proxy_write_oob (Socket *s, const void *data, int len) { - ProxySocket *ps = FROMFIELD(s, ProxySocket, sockvt); + ProxySocket *ps = FROMFIELD(s, ProxySocket, sock); if (ps->state != PROXY_STATE_ACTIVE) { bufchain_clear(&ps->pending_output_data); @@ -122,7 +122,7 @@ static int sk_proxy_write_oob (Socket *s, const void *data, int len) static void sk_proxy_write_eof (Socket *s) { - ProxySocket *ps = FROMFIELD(s, ProxySocket, sockvt); + ProxySocket *ps = FROMFIELD(s, ProxySocket, sock); if (ps->state != PROXY_STATE_ACTIVE) { ps->pending_eof = 1; @@ -133,7 +133,7 @@ static void sk_proxy_write_eof (Socket *s) static void sk_proxy_flush (Socket *s) { - ProxySocket *ps = FROMFIELD(s, ProxySocket, sockvt); + ProxySocket *ps = FROMFIELD(s, ProxySocket, sock); if (ps->state != PROXY_STATE_ACTIVE) { ps->pending_flush = 1; @@ -144,7 +144,7 @@ static void sk_proxy_flush (Socket *s) static void sk_proxy_set_frozen (Socket *s, int is_frozen) { - ProxySocket *ps = FROMFIELD(s, ProxySocket, sockvt); + ProxySocket *ps = FROMFIELD(s, ProxySocket, sock); if (ps->state != PROXY_STATE_ACTIVE) { ps->freeze = is_frozen; @@ -183,7 +183,7 @@ static void sk_proxy_set_frozen (Socket *s, int is_frozen) static const char * sk_proxy_socket_error (Socket *s) { - ProxySocket *ps = FROMFIELD(s, ProxySocket, sockvt); + ProxySocket *ps = FROMFIELD(s, ProxySocket, sock); if (ps->error != NULL || ps->sub_socket == NULL) { return ps->error; } @@ -195,7 +195,7 @@ static const char * sk_proxy_socket_error (Socket *s) static void plug_proxy_log(Plug *plug, int type, SockAddr *addr, int port, const char *error_msg, int error_code) { - ProxySocket *ps = FROMFIELD(plug, ProxySocket, plugvt); + ProxySocket *ps = FROMFIELD(plug, ProxySocket, plugimpl); plug_log(ps->plug, type, addr, port, error_msg, error_code); } @@ -203,7 +203,7 @@ static void plug_proxy_log(Plug *plug, int type, SockAddr *addr, int port, static void plug_proxy_closing (Plug *p, const char *error_msg, int error_code, int calling_back) { - ProxySocket *ps = FROMFIELD(p, ProxySocket, plugvt); + ProxySocket *ps = FROMFIELD(p, ProxySocket, plugimpl); if (ps->state != PROXY_STATE_ACTIVE) { ps->closing_error_msg = error_msg; @@ -217,7 +217,7 @@ static void plug_proxy_closing (Plug *p, const char *error_msg, static void plug_proxy_receive (Plug *p, int urgent, char *data, int len) { - ProxySocket *ps = FROMFIELD(p, ProxySocket, plugvt); + ProxySocket *ps = FROMFIELD(p, ProxySocket, plugimpl); if (ps->state != PROXY_STATE_ACTIVE) { /* we will lose the urgentness of this data, but since most, @@ -236,7 +236,7 @@ static void plug_proxy_receive (Plug *p, int urgent, char *data, int len) static void plug_proxy_sent (Plug *p, int bufsize) { - ProxySocket *ps = FROMFIELD(p, ProxySocket, plugvt); + ProxySocket *ps = FROMFIELD(p, ProxySocket, plugimpl); if (ps->state != PROXY_STATE_ACTIVE) { ps->sent_bufsize = bufsize; @@ -249,7 +249,7 @@ static void plug_proxy_sent (Plug *p, int bufsize) static int plug_proxy_accepting(Plug *p, accept_fn_t constructor, accept_ctx_t ctx) { - ProxySocket *ps = FROMFIELD(p, ProxySocket, plugvt); + ProxySocket *ps = FROMFIELD(p, ProxySocket, plugimpl); if (ps->state != PROXY_STATE_ACTIVE) { ps->accepting_constructor = constructor; @@ -438,8 +438,8 @@ Socket *new_connection(SockAddr *addr, const char *hostname, return sret; ret = snew(ProxySocket); - ret->sockvt = &ProxySocket_sockvt; - ret->plugvt = &ProxySocket_plugvt; + ret->sock.vt = &ProxySocket_sockvt; + ret->plugimpl.vt = &ProxySocket_plugvt; ret->conf = conf_copy(conf); ret->plug = plug; ret->remote_addr = addr; /* will need to be freed on close */ @@ -473,7 +473,7 @@ Socket *new_connection(SockAddr *addr, const char *hostname, proxy_type = "Telnet"; } else { ret->error = "Proxy error: Unknown proxy method"; - return &ret->sockvt; + return &ret->sock; } { @@ -501,7 +501,7 @@ Socket *new_connection(SockAddr *addr, const char *hostname, if (sk_addr_error(proxy_addr) != NULL) { ret->error = "Proxy error: Unable to resolve proxy host name"; sk_addr_free(proxy_addr); - return &ret->sockvt; + return &ret->sock; } sfree(proxy_canonical_name); @@ -521,15 +521,15 @@ Socket *new_connection(SockAddr *addr, const char *hostname, ret->sub_socket = sk_new(proxy_addr, conf_get_int(conf, CONF_proxy_port), privport, oobinline, - nodelay, keepalive, &ret->plugvt); + nodelay, keepalive, &ret->plugimpl); if (sk_socket_error(ret->sub_socket) != NULL) - return &ret->sockvt; + return &ret->sock; /* start the proxy negotiation process... */ sk_set_frozen(ret->sub_socket, 0); ret->negotiate(ret, PROXY_CHANGE_NEW); - return &ret->sockvt; + return &ret->sock; } /* no proxy, so just return the direct socket */ diff --git a/proxy.h b/proxy.h index 0abb7d3b..e37b820c 100644 --- a/proxy.h +++ b/proxy.h @@ -87,8 +87,8 @@ struct ProxySocket { int chap_current_attribute; int chap_current_datalen; - const SocketVtable *sockvt; - const PlugVtable *plugvt; + Socket sock; + Plug plugimpl; }; extern void proxy_activate (ProxySocket *); diff --git a/raw.c b/raw.c index dc6a40c5..9e451d9c 100644 --- a/raw.c +++ b/raw.c @@ -20,7 +20,7 @@ struct Raw { Conf *conf; - const PlugVtable *plugvt; + Plug plug; Backend backend; }; @@ -35,7 +35,7 @@ static void c_write(Raw *raw, const void *buf, int len) static void raw_log(Plug *plug, int type, SockAddr *addr, int port, const char *error_msg, int error_code) { - Raw *raw = FROMFIELD(plug, Raw, plugvt); + Raw *raw = FROMFIELD(plug, Raw, plug); backend_socket_log(raw->frontend, type, addr, port, error_msg, error_code, raw->conf, raw->session_started); } @@ -58,7 +58,7 @@ static void raw_check_close(Raw *raw) static void raw_closing(Plug *plug, const char *error_msg, int error_code, int calling_back) { - Raw *raw = FROMFIELD(plug, Raw, plugvt); + Raw *raw = FROMFIELD(plug, Raw, plug); if (error_msg) { /* A socket error has occurred. */ @@ -90,7 +90,7 @@ static void raw_closing(Plug *plug, const char *error_msg, int error_code, static void raw_receive(Plug *plug, int urgent, char *data, int len) { - Raw *raw = FROMFIELD(plug, Raw, plugvt); + Raw *raw = FROMFIELD(plug, Raw, plug); c_write(raw, data, len); /* We count 'session start', for proxy logging purposes, as being * when data is received from the network and printed. */ @@ -99,7 +99,7 @@ static void raw_receive(Plug *plug, int urgent, char *data, int len) static void raw_sent(Plug *plug, int bufsize) { - Raw *raw = FROMFIELD(plug, Raw, plugvt); + Raw *raw = FROMFIELD(plug, Raw, plug); raw->bufsize = bufsize; } @@ -130,7 +130,7 @@ static const char *raw_init(Frontend *frontend, Backend **backend_handle, char *loghost; raw = snew(Raw); - raw->plugvt = &Raw_plugvt; + raw->plug.vt = &Raw_plugvt; raw->backend.vt = &raw_backend; raw->s = NULL; raw->closed_on_socket_error = FALSE; @@ -160,7 +160,7 @@ static const char *raw_init(Frontend *frontend, Backend **backend_handle, * Open socket. */ raw->s = new_connection(addr, *realhost, port, 0, 1, nodelay, keepalive, - &raw->plugvt, conf); + &raw->plug, conf); if ((err = sk_socket_error(raw->s)) != NULL) return err; diff --git a/rlogin.c b/rlogin.c index 600e9f1c..01f79fc3 100644 --- a/rlogin.c +++ b/rlogin.c @@ -26,7 +26,7 @@ struct Rlogin { /* In case we need to read a username from the terminal before starting */ prompts_t *prompt; - const PlugVtable *plugvt; + Plug plug; Backend backend; }; @@ -39,7 +39,7 @@ static void c_write(Rlogin *rlogin, const void *buf, int len) static void rlogin_log(Plug *plug, int type, SockAddr *addr, int port, const char *error_msg, int error_code) { - Rlogin *rlogin = FROMFIELD(plug, Rlogin, plugvt); + Rlogin *rlogin = FROMFIELD(plug, Rlogin, plug); backend_socket_log(rlogin->frontend, type, addr, port, error_msg, error_code, rlogin->conf, !rlogin->firstbyte); @@ -48,7 +48,7 @@ static void rlogin_log(Plug *plug, int type, SockAddr *addr, int port, static void rlogin_closing(Plug *plug, const char *error_msg, int error_code, int calling_back) { - Rlogin *rlogin = FROMFIELD(plug, Rlogin, plugvt); + Rlogin *rlogin = FROMFIELD(plug, Rlogin, plug); /* * We don't implement independent EOF in each direction for Telnet @@ -72,7 +72,7 @@ static void rlogin_closing(Plug *plug, const char *error_msg, int error_code, static void rlogin_receive(Plug *plug, int urgent, char *data, int len) { - Rlogin *rlogin = FROMFIELD(plug, Rlogin, plugvt); + Rlogin *rlogin = FROMFIELD(plug, Rlogin, plug); if (urgent == 2) { char c; @@ -109,7 +109,7 @@ static void rlogin_receive(Plug *plug, int urgent, char *data, int len) static void rlogin_sent(Plug *plug, int bufsize) { - Rlogin *rlogin = FROMFIELD(plug, Rlogin, plugvt); + Rlogin *rlogin = FROMFIELD(plug, Rlogin, plug); rlogin->bufsize = bufsize; } @@ -162,7 +162,7 @@ static const char *rlogin_init(Frontend *frontend, Backend **backend_handle, char *loghost; rlogin = snew(Rlogin); - rlogin->plugvt = &Rlogin_plugvt; + rlogin->plug.vt = &Rlogin_plugvt; rlogin->backend.vt = &rlogin_backend; rlogin->s = NULL; rlogin->closed_on_socket_error = FALSE; @@ -193,7 +193,7 @@ static const char *rlogin_init(Frontend *frontend, Backend **backend_handle, * Open socket. */ rlogin->s = new_connection(addr, *realhost, port, 1, 0, - nodelay, keepalive, &rlogin->plugvt, conf); + nodelay, keepalive, &rlogin->plug, conf); if ((err = sk_socket_error(rlogin->s)) != NULL) return err; diff --git a/ssh.c b/ssh.c index 7a361319..c94554dd 100644 --- a/ssh.c +++ b/ssh.c @@ -37,7 +37,7 @@ struct Ssh { struct ssh_version_receiver version_receiver; int remote_bugs; - const PlugVtable *plugvt; + Plug plug; Backend backend; Ldisc *ldisc; @@ -489,7 +489,7 @@ void ssh_user_close(Ssh *ssh, const char *fmt, ...) static void ssh_socket_log(Plug *plug, int type, SockAddr *addr, int port, const char *error_msg, int error_code) { - Ssh *ssh = FROMFIELD(plug, Ssh, plugvt); + Ssh *ssh = FROMFIELD(plug, Ssh, plug); /* * While we're attempting connection sharing, don't loudly log @@ -509,7 +509,7 @@ static void ssh_socket_log(Plug *plug, int type, SockAddr *addr, int port, static void ssh_closing(Plug *plug, const char *error_msg, int error_code, int calling_back) { - Ssh *ssh = FROMFIELD(plug, Ssh, plugvt); + Ssh *ssh = FROMFIELD(plug, Ssh, plug); if (error_msg) { ssh_remote_error(ssh, "Network error: %s", error_msg); } else if (ssh->bpp) { @@ -520,7 +520,7 @@ static void ssh_closing(Plug *plug, const char *error_msg, int error_code, static void ssh_receive(Plug *plug, int urgent, char *data, int len) { - Ssh *ssh = FROMFIELD(plug, Ssh, plugvt); + Ssh *ssh = FROMFIELD(plug, Ssh, plug); /* Log raw data, if we're in that mode. */ if (ssh->logctx) @@ -534,7 +534,7 @@ static void ssh_receive(Plug *plug, int urgent, char *data, int len) static void ssh_sent(Plug *plug, int bufsize) { - Ssh *ssh = FROMFIELD(plug, Ssh, plugvt); + Ssh *ssh = FROMFIELD(plug, Ssh, plug); /* * If the send backlog on the SSH socket itself clears, we should * unthrottle the whole world if it was throttled. Also trigger an @@ -624,7 +624,7 @@ static const char *connect_to_host(Ssh *ssh, const char *host, int port, ssh_hostport_setup(host, port, ssh->conf, &ssh->savedhost, &ssh->savedport, &loghost); - ssh->plugvt = &Ssh_plugvt; + ssh->plug.vt = &Ssh_plugvt; /* * Try connection-sharing, in case that means we don't open a @@ -639,7 +639,7 @@ static const char *connect_to_host(Ssh *ssh, const char *host, int port, ssh->attempting_connshare = TRUE; /* affects socket logging behaviour */ ssh->s = ssh_connection_sharing_init( ssh->savedhost, ssh->savedport, ssh->conf, ssh->frontend, - &ssh->plugvt, &ssh->connshare); + &ssh->plug, &ssh->connshare); ssh->attempting_connshare = FALSE; if (ssh->s != NULL) { /* @@ -677,7 +677,7 @@ static const char *connect_to_host(Ssh *ssh, const char *host, int port, ssh->s = new_connection(addr, *realhost, port, 0, 1, nodelay, keepalive, - &ssh->plugvt, ssh->conf); + &ssh->plug, ssh->conf); if ((err = sk_socket_error(ssh->s)) != NULL) { ssh->s = NULL; notify_remote_exit(ssh->frontend); diff --git a/sshshare.c b/sshshare.c index 3b9bef50..0f35635e 100644 --- a/sshshare.c +++ b/sshshare.c @@ -147,7 +147,7 @@ struct ssh_sharing_state { ConnectionLayer *cl; /* instance of the ssh connection layer */ char *server_verstring; /* server version string after "SSH-" */ - const PlugVtable *plugvt; + Plug plug; }; struct share_globreq; @@ -200,7 +200,7 @@ struct ssh_sharing_connstate { /* Global requests we've sent on to the server, pending replies. */ struct share_globreq *globreq_head, *globreq_tail; - const PlugVtable *plugvt; + Plug plug; }; struct share_halfchannel { @@ -951,7 +951,7 @@ static void share_closing(Plug *plug, const char *error_msg, int error_code, int calling_back) { struct ssh_sharing_connstate *cs = FROMFIELD( - plug, struct ssh_sharing_connstate, plugvt); + plug, struct ssh_sharing_connstate, plug); if (error_msg) { #ifdef BROKEN_PIPE_ERROR_CODE @@ -1767,7 +1767,7 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs, static void share_receive(Plug *plug, int urgent, char *data, int len) { ssh_sharing_connstate *cs = FROMFIELD( - plug, ssh_sharing_connstate, plugvt); + plug, ssh_sharing_connstate, plug); static const char expected_verstring_prefix[] = "SSHCONNECTION@putty.projects.tartarus.org-2.0-"; unsigned char c; @@ -1843,7 +1843,7 @@ static void share_receive(Plug *plug, int urgent, char *data, int len) static void share_sent(Plug *plug, int bufsize) { /* ssh_sharing_connstate *cs = FROMFIELD( - plug, ssh_sharing_connstate, plugvt); */ + plug, ssh_sharing_connstate, plug); */ /* * We do nothing here, because we expect that there won't be a @@ -1858,7 +1858,7 @@ static void share_sent(Plug *plug, int bufsize) static void share_listen_closing(Plug *plug, const char *error_msg, int error_code, int calling_back) { - ssh_sharing_state *sharestate = FROMFIELD(plug, ssh_sharing_state, plugvt); + ssh_sharing_state *sharestate = FROMFIELD(plug, ssh_sharing_state, plug); if (error_msg) log_general(sharestate, "listening socket: %s", error_msg); sk_close(sharestate->listensock); @@ -1922,7 +1922,7 @@ static int share_listen_accepting(Plug *plug, accept_fn_t constructor, accept_ctx_t ctx) { struct ssh_sharing_state *sharestate = FROMFIELD( - plug, struct ssh_sharing_state, plugvt); + plug, struct ssh_sharing_state, plug); struct ssh_sharing_connstate *cs; const char *err; char *peerinfo; @@ -1931,7 +1931,7 @@ static int share_listen_accepting(Plug *plug, * A new downstream has connected to us. */ cs = snew(struct ssh_sharing_connstate); - cs->plugvt = &ssh_sharing_conn_plugvt; + cs->plug.vt = &ssh_sharing_conn_plugvt; cs->parent = sharestate; if ((cs->id = share_find_unused_id(sharestate, sharestate->nextid)) == 0 && @@ -1943,7 +1943,7 @@ static int share_listen_accepting(Plug *plug, if (sharestate->nextid == 0) sharestate->nextid++; /* only happens in VERY long-running upstreams */ - cs->sock = constructor(ctx, &cs->plugvt); + cs->sock = constructor(ctx, &cs->plug); if ((err = sk_socket_error(cs->sock)) != NULL) { sfree(cs); return err != NULL; @@ -2104,7 +2104,7 @@ Socket *ssh_connection_sharing_init( * to be an upstream. */ sharestate = snew(struct ssh_sharing_state); - sharestate->plugvt = &ssh_sharing_listen_plugvt; + sharestate->plug.vt = &ssh_sharing_listen_plugvt; sharestate->listensock = NULL; sharestate->cl = NULL; @@ -2118,7 +2118,7 @@ Socket *ssh_connection_sharing_init( sock = NULL; logtext = ds_err = us_err = NULL; result = platform_ssh_share( - sockname, conf, sshplug, &sharestate->plugvt, &sock, &logtext, + sockname, conf, sshplug, &sharestate->plug, &sock, &logtext, &ds_err, &us_err, can_upstream, can_downstream); switch (result) { case SHARE_NONE: diff --git a/telnet.c b/telnet.c index 9e386fb8..dee0aab9 100644 --- a/telnet.c +++ b/telnet.c @@ -197,7 +197,7 @@ struct Telnet { Pinger *pinger; - const PlugVtable *plugvt; + Plug plug; Backend backend; }; @@ -645,7 +645,7 @@ static void do_telnet_read(Telnet *telnet, char *buf, int len) static void telnet_log(Plug *plug, int type, SockAddr *addr, int port, const char *error_msg, int error_code) { - Telnet *telnet = FROMFIELD(plug, Telnet, plugvt); + Telnet *telnet = FROMFIELD(plug, Telnet, plug); backend_socket_log(telnet->frontend, type, addr, port, error_msg, error_code, telnet->conf, telnet->session_started); @@ -654,7 +654,7 @@ static void telnet_log(Plug *plug, int type, SockAddr *addr, int port, static void telnet_closing(Plug *plug, const char *error_msg, int error_code, int calling_back) { - Telnet *telnet = FROMFIELD(plug, Telnet, plugvt); + Telnet *telnet = FROMFIELD(plug, Telnet, plug); /* * We don't implement independent EOF in each direction for Telnet @@ -678,7 +678,7 @@ static void telnet_closing(Plug *plug, const char *error_msg, int error_code, static void telnet_receive(Plug *plug, int urgent, char *data, int len) { - Telnet *telnet = FROMFIELD(plug, Telnet, plugvt); + Telnet *telnet = FROMFIELD(plug, Telnet, plug); if (urgent) telnet->in_synch = TRUE; telnet->session_started = TRUE; @@ -687,7 +687,7 @@ static void telnet_receive(Plug *plug, int urgent, char *data, int len) static void telnet_sent(Plug *plug, int bufsize) { - Telnet *telnet = FROMFIELD(plug, Telnet, plugvt); + Telnet *telnet = FROMFIELD(plug, Telnet, plug); telnet->bufsize = bufsize; } @@ -717,7 +717,7 @@ static const char *telnet_init(Frontend *frontend, Backend **backend_handle, int addressfamily; telnet = snew(Telnet); - telnet->plugvt = &Telnet_plugvt; + telnet->plug.vt = &Telnet_plugvt; telnet->backend.vt = &telnet_backend; telnet->conf = conf_copy(conf); telnet->s = NULL; @@ -754,7 +754,7 @@ static const char *telnet_init(Frontend *frontend, Backend **backend_handle, * Open socket. */ telnet->s = new_connection(addr, *realhost, port, 0, 1, nodelay, keepalive, - &telnet->plugvt, telnet->conf); + &telnet->plug, telnet->conf); if ((err = sk_socket_error(telnet->s)) != NULL) return err; diff --git a/unix/uxnet.c b/unix/uxnet.c index 3c0f3c1f..41cc0758 100644 --- a/unix/uxnet.c +++ b/unix/uxnet.c @@ -89,7 +89,7 @@ struct NetSocket { */ NetSocket *parent, *child; - const SocketVtable *sockvt; + Socket sock; }; struct SockAddr { @@ -484,7 +484,7 @@ SockAddr *sk_addr_dup(SockAddr *addr) static Plug *sk_net_plug(Socket *sock, Plug *p) { - NetSocket *s = FROMFIELD(sock, NetSocket, sockvt); + NetSocket *s = FROMFIELD(sock, NetSocket, sock); Plug *ret = s->plug; if (p) s->plug = p; @@ -528,7 +528,7 @@ static Socket *sk_net_accept(accept_ctx_t ctx, Plug *plug) * Create NetSocket structure. */ ret = snew(NetSocket); - ret->sockvt = &NetSocket_sockvt; + ret->sock.vt = &NetSocket_sockvt; ret->error = NULL; ret->plug = plug; bufchain_init(&ret->output_data); @@ -549,7 +549,7 @@ static Socket *sk_net_accept(accept_ctx_t ctx, Plug *plug) if (ret->s < 0) { ret->error = strerror(errno); - return &ret->sockvt; + return &ret->sock; } ret->oobinline = 0; @@ -557,7 +557,7 @@ static Socket *sk_net_accept(accept_ctx_t ctx, Plug *plug) uxsel_tell(ret); add234(sktree, ret); - return &ret->sockvt; + return &ret->sock; } static int try_connect(NetSocket *sock) @@ -769,7 +769,7 @@ Socket *sk_new(SockAddr *addr, int port, int privport, int oobinline, * Create NetSocket structure. */ ret = snew(NetSocket); - ret->sockvt = &NetSocket_sockvt; + ret->sock.vt = &NetSocket_sockvt; ret->error = NULL; ret->plug = plug; bufchain_init(&ret->output_data); @@ -801,7 +801,7 @@ Socket *sk_new(SockAddr *addr, int port, int privport, int oobinline, if (err) ret->error = strerror(err); - return &ret->sockvt; + return &ret->sock; } Socket *sk_newlistener(const char *srcaddr, int port, Plug *plug, @@ -824,7 +824,7 @@ Socket *sk_newlistener(const char *srcaddr, int port, Plug *plug, * Create NetSocket structure. */ ret = snew(NetSocket); - ret->sockvt = &NetSocket_sockvt; + ret->sock.vt = &NetSocket_sockvt; ret->error = NULL; ret->plug = plug; bufchain_init(&ret->output_data); @@ -875,7 +875,7 @@ Socket *sk_newlistener(const char *srcaddr, int port, Plug *plug, if (s < 0) { ret->error = strerror(errno); - return &ret->sockvt; + return &ret->sock; } cloexec(s); @@ -886,7 +886,7 @@ Socket *sk_newlistener(const char *srcaddr, int port, Plug *plug, (const char *)&on, sizeof(on)) < 0) { ret->error = strerror(errno); close(s); - return &ret->sockvt; + return &ret->sock; } retcode = -1; @@ -964,13 +964,13 @@ Socket *sk_newlistener(const char *srcaddr, int port, Plug *plug, if (retcode < 0) { close(s); ret->error = strerror(errno); - return &ret->sockvt; + return &ret->sock; } if (listen(s, SOMAXCONN) < 0) { close(s); ret->error = strerror(errno); - return &ret->sockvt; + return &ret->sock; } #ifndef NO_IPV6 @@ -984,7 +984,7 @@ Socket *sk_newlistener(const char *srcaddr, int port, Plug *plug, other = FROMFIELD( sk_newlistener(srcaddr, port, plug, local_host_only, ADDRTYPE_IPV4), - NetSocket, sockvt); + NetSocket, sock); if (other) { if (!other->error) { @@ -995,7 +995,7 @@ Socket *sk_newlistener(const char *srcaddr, int port, Plug *plug, * as IPv6, we must return an error overall. */ close(s); sfree(ret); - return &other->sockvt; + return &other->sock; } } } @@ -1006,15 +1006,15 @@ Socket *sk_newlistener(const char *srcaddr, int port, Plug *plug, uxsel_tell(ret); add234(sktree, ret); - return &ret->sockvt; + return &ret->sock; } static void sk_net_close(Socket *sock) { - NetSocket *s = FROMFIELD(sock, NetSocket, sockvt); + NetSocket *s = FROMFIELD(sock, NetSocket, sock); if (s->child) - sk_net_close(&s->child->sockvt); + sk_net_close(&s->child->sock); del234(sktree, s); if (s->s >= 0) { @@ -1038,9 +1038,9 @@ void *sk_getxdmdata(Socket *sock, int *lenp) * We must check that this socket really _is_ a NetSocket before * downcasting it. */ - if (*sock != &NetSocket_sockvt) + if (sock->vt != &NetSocket_sockvt) return NULL; /* failure */ - s = FROMFIELD(sock, NetSocket, sockvt); + s = FROMFIELD(sock, NetSocket, sock); addrlen = sizeof(u); if (getsockname(s->s, &u.sa, &addrlen) < 0) @@ -1186,7 +1186,7 @@ void try_send(NetSocket *s) static int sk_net_write(Socket *sock, const void *buf, int len) { - NetSocket *s = FROMFIELD(sock, NetSocket, sockvt); + NetSocket *s = FROMFIELD(sock, NetSocket, sock); assert(s->outgoingeof == EOF_NO); @@ -1212,7 +1212,7 @@ static int sk_net_write(Socket *sock, const void *buf, int len) static int sk_net_write_oob(Socket *sock, const void *buf, int len) { - NetSocket *s = FROMFIELD(sock, NetSocket, sockvt); + NetSocket *s = FROMFIELD(sock, NetSocket, sock); assert(s->outgoingeof == EOF_NO); @@ -1241,7 +1241,7 @@ static int sk_net_write_oob(Socket *sock, const void *buf, int len) static void sk_net_write_eof(Socket *sock) { - NetSocket *s = FROMFIELD(sock, NetSocket, sockvt); + NetSocket *s = FROMFIELD(sock, NetSocket, sock); assert(s->outgoingeof == EOF_NO); @@ -1468,13 +1468,13 @@ const char *sk_addr_error(SockAddr *addr) } static const char *sk_net_socket_error(Socket *sock) { - NetSocket *s = FROMFIELD(sock, NetSocket, sockvt); + NetSocket *s = FROMFIELD(sock, NetSocket, sock); return s->error; } static void sk_net_set_frozen(Socket *sock, int is_frozen) { - NetSocket *s = FROMFIELD(sock, NetSocket, sockvt); + NetSocket *s = FROMFIELD(sock, NetSocket, sock); if (s->frozen == is_frozen) return; s->frozen = is_frozen; @@ -1483,7 +1483,7 @@ static void sk_net_set_frozen(Socket *sock, int is_frozen) static char *sk_net_peer_info(Socket *sock) { - NetSocket *s = FROMFIELD(sock, NetSocket, sockvt); + NetSocket *s = FROMFIELD(sock, NetSocket, sock); union sockaddr_union addr; socklen_t addrlen = sizeof(addr); #ifndef NO_IPV6 @@ -1644,7 +1644,7 @@ Socket *new_unix_listener(SockAddr *listenaddr, Plug *plug) * Create NetSocket structure. */ ret = snew(NetSocket); - ret->sockvt = &NetSocket_sockvt; + ret->sock.vt = &NetSocket_sockvt; ret->error = NULL; ret->plug = plug; bufchain_init(&ret->output_data); @@ -1669,7 +1669,7 @@ Socket *new_unix_listener(SockAddr *listenaddr, Plug *plug) s = socket(AF_UNIX, SOCK_STREAM, 0); if (s < 0) { ret->error = strerror(errno); - return &ret->sockvt; + return &ret->sock; } cloexec(s); @@ -1692,20 +1692,20 @@ Socket *new_unix_listener(SockAddr *listenaddr, Plug *plug) if (unlink(u.su.sun_path) < 0 && errno != ENOENT) { close(s); ret->error = strerror(errno); - return &ret->sockvt; + return &ret->sock; } retcode = bind(s, &addr->sa, addrlen); if (retcode < 0) { close(s); ret->error = strerror(errno); - return &ret->sockvt; + return &ret->sock; } if (listen(s, SOMAXCONN) < 0) { close(s); ret->error = strerror(errno); - return &ret->sockvt; + return &ret->sock; } ret->s = s; @@ -1713,5 +1713,5 @@ Socket *new_unix_listener(SockAddr *listenaddr, Plug *plug) uxsel_tell(ret); add234(sktree, ret); - return &ret->sockvt; + return &ret->sock; } diff --git a/unix/uxpgnt.c b/unix/uxpgnt.c index 13f44c7b..8feff9df 100644 --- a/unix/uxpgnt.c +++ b/unix/uxpgnt.c @@ -176,7 +176,7 @@ static void x11_closing(Plug *plug, const char *error_msg, int error_code, time_to_die = TRUE; } struct X11Connection { - const PlugVtable *plugvt; + Plug plug; }; char *socketname; @@ -809,10 +809,10 @@ void run_agent(void) disp = x11_setup_display(display, conf); conn = snew(struct X11Connection); - conn->plugvt = &X11Connection_plugvt; + conn->plug.vt = &X11Connection_plugvt; s = new_connection(sk_addr_dup(disp->addr), disp->realhost, disp->port, - 0, 1, 0, 0, &conn->plugvt, conf); + 0, 1, 0, 0, &conn->plug, conf); if ((err = sk_socket_error(s)) != NULL) { fprintf(stderr, "pageant: unable to connect to X server: %s", err); exit(1); diff --git a/unix/uxproxy.c b/unix/uxproxy.c index 2dce0418..67757ca6 100644 --- a/unix/uxproxy.c +++ b/unix/uxproxy.c @@ -29,7 +29,7 @@ typedef struct LocalProxySocket { int pending_error; - const SocketVtable *sockvt; + Socket sock; } LocalProxySocket; static void localproxy_select_result(int fd, int event); @@ -105,7 +105,7 @@ static int localproxy_errfd_find(void *av, void *bv) static Plug *sk_localproxy_plug (Socket *s, Plug *p) { - LocalProxySocket *ps = FROMFIELD(s, LocalProxySocket, sockvt); + LocalProxySocket *ps = FROMFIELD(s, LocalProxySocket, sock); Plug *ret = ps->plug; if (p) ps->plug = p; @@ -114,7 +114,7 @@ static Plug *sk_localproxy_plug (Socket *s, Plug *p) static void sk_localproxy_close (Socket *s) { - LocalProxySocket *ps = FROMFIELD(s, LocalProxySocket, sockvt); + LocalProxySocket *ps = FROMFIELD(s, LocalProxySocket, sock); if (ps->to_cmd >= 0) { del234(localproxy_by_tofd, ps); @@ -202,7 +202,7 @@ static int localproxy_try_send(LocalProxySocket *ps) static int sk_localproxy_write (Socket *s, const void *data, int len) { - LocalProxySocket *ps = FROMFIELD(s, LocalProxySocket, sockvt); + LocalProxySocket *ps = FROMFIELD(s, LocalProxySocket, sock); assert(ps->outgoingeof == EOF_NO); @@ -224,7 +224,7 @@ static int sk_localproxy_write_oob (Socket *s, const void *data, int len) static void sk_localproxy_write_eof (Socket *s) { - LocalProxySocket *ps = FROMFIELD(s, LocalProxySocket, sockvt); + LocalProxySocket *ps = FROMFIELD(s, LocalProxySocket, sock); assert(ps->outgoingeof == EOF_NO); ps->outgoingeof = EOF_PENDING; @@ -234,13 +234,13 @@ static void sk_localproxy_write_eof (Socket *s) static void sk_localproxy_flush (Socket *s) { - /* LocalProxySocket *ps = FROMFIELD(s, LocalProxySocket, sockvt); */ + /* LocalProxySocket *ps = FROMFIELD(s, LocalProxySocket, sock); */ /* do nothing */ } static void sk_localproxy_set_frozen (Socket *s, int is_frozen) { - LocalProxySocket *ps = FROMFIELD(s, LocalProxySocket, sockvt); + LocalProxySocket *ps = FROMFIELD(s, LocalProxySocket, sock); if (ps->from_cmd < 0) return; @@ -253,7 +253,7 @@ static void sk_localproxy_set_frozen (Socket *s, int is_frozen) static const char * sk_localproxy_socket_error (Socket *s) { - LocalProxySocket *ps = FROMFIELD(s, LocalProxySocket, sockvt); + LocalProxySocket *ps = FROMFIELD(s, LocalProxySocket, sock); return ps->error; } @@ -330,7 +330,7 @@ Socket *platform_new_connection(SockAddr *addr, const char *hostname, return NULL; ret = snew(LocalProxySocket); - ret->sockvt = &LocalProxySocket_sockvt; + ret->sock.vt = &LocalProxySocket_sockvt; ret->plug = plug; ret->error = NULL; ret->outgoingeof = EOF_NO; @@ -358,7 +358,7 @@ Socket *platform_new_connection(SockAddr *addr, const char *hostname, pipe(cmd_err_pipe) < 0) { ret->error = dupprintf("pipe: %s", strerror(errno)); sfree(cmd); - return &ret->sockvt; + return &ret->sock; } cloexec(to_cmd_pipe[1]); cloexec(from_cmd_pipe[0]); @@ -369,7 +369,7 @@ Socket *platform_new_connection(SockAddr *addr, const char *hostname, if (pid < 0) { ret->error = dupprintf("fork: %s", strerror(errno)); sfree(cmd); - return &ret->sockvt; + return &ret->sock; } else if (pid == 0) { close(0); close(1); @@ -399,13 +399,13 @@ Socket *platform_new_connection(SockAddr *addr, const char *hostname, if (ret->to_cmd == -1) { ret->error = dupprintf("/dev/null: %s", strerror(errno)); sfree(cmd); - return &ret->sockvt; + return &ret->sock; } ret->from_cmd = open(cmd, O_RDONLY); if (ret->from_cmd == -1) { ret->error = dupprintf("%s: %s", cmd, strerror(errno)); sfree(cmd); - return &ret->sockvt; + return &ret->sock; } sfree(cmd); ret->cmd_err = -1; @@ -430,5 +430,5 @@ Socket *platform_new_connection(SockAddr *addr, const char *hostname, /* We are responsible for this and don't need it any more */ sk_addr_free(addr); - return &ret->sockvt; + return &ret->sock; } diff --git a/windows/winhsock.c b/windows/winhsock.c index 4fefe31f..b120c143 100644 --- a/windows/winhsock.c +++ b/windows/winhsock.c @@ -43,7 +43,7 @@ typedef struct HandleSocket { Plug *plug; - const SocketVtable *sockvt; + Socket sock; } HandleSocket; static int handle_gotdata(struct handle *h, void *data, int len) @@ -107,7 +107,7 @@ static void handle_sentdata(struct handle *h, int new_backlog) static Plug *sk_handle_plug(Socket *s, Plug *p) { - HandleSocket *hs = FROMFIELD(s, HandleSocket, sockvt); + HandleSocket *hs = FROMFIELD(s, HandleSocket, sock); Plug *ret = hs->plug; if (p) hs->plug = p; @@ -116,7 +116,7 @@ static Plug *sk_handle_plug(Socket *s, Plug *p) static void sk_handle_close(Socket *s) { - HandleSocket *hs = FROMFIELD(s, HandleSocket, sockvt); + HandleSocket *hs = FROMFIELD(s, HandleSocket, sock); if (hs->defer_close) { hs->deferred_close = TRUE; @@ -136,7 +136,7 @@ static void sk_handle_close(Socket *s) static int sk_handle_write(Socket *s, const void *data, int len) { - HandleSocket *hs = FROMFIELD(s, HandleSocket, sockvt); + HandleSocket *hs = FROMFIELD(s, HandleSocket, sock); return handle_write(hs->send_h, data, len); } @@ -152,14 +152,14 @@ static int sk_handle_write_oob(Socket *s, const void *data, int len) static void sk_handle_write_eof(Socket *s) { - HandleSocket *hs = FROMFIELD(s, HandleSocket, sockvt); + HandleSocket *hs = FROMFIELD(s, HandleSocket, sock); handle_write_eof(hs->send_h); } static void sk_handle_flush(Socket *s) { - /* HandleSocket *hs = FROMFIELD(s, HandleSocket, sockvt); */ + /* HandleSocket *hs = FROMFIELD(s, HandleSocket, sock); */ /* do nothing */ } @@ -191,7 +191,7 @@ static void handle_socket_unfreeze(void *hsv) bufchain_consume(&hs->inputdata, len); hs->defer_close = FALSE; if (hs->deferred_close) { - sk_handle_close(&hs->sockvt); + sk_handle_close(&hs->sock); return; } @@ -212,7 +212,7 @@ static void handle_socket_unfreeze(void *hsv) static void sk_handle_set_frozen(Socket *s, int is_frozen) { - HandleSocket *hs = FROMFIELD(s, HandleSocket, sockvt); + HandleSocket *hs = FROMFIELD(s, HandleSocket, sock); if (is_frozen) { switch (hs->frozen) { @@ -267,13 +267,13 @@ static void sk_handle_set_frozen(Socket *s, int is_frozen) static const char *sk_handle_socket_error(Socket *s) { - HandleSocket *hs = FROMFIELD(s, HandleSocket, sockvt); + HandleSocket *hs = FROMFIELD(s, HandleSocket, sock); return hs->error; } static char *sk_handle_peer_info(Socket *s) { - HandleSocket *hs = FROMFIELD(s, HandleSocket, sockvt); + HandleSocket *hs = FROMFIELD(s, HandleSocket, sock); ULONG pid; static HMODULE kernel32_module; DECL_WINDOWS_FUNCTION(static, BOOL, GetNamedPipeClientProcessId, @@ -325,7 +325,7 @@ Socket *make_handle_socket(HANDLE send_H, HANDLE recv_H, HANDLE stderr_H, int flags = (overlapped ? HANDLE_FLAG_OVERLAPPED : 0); hs = snew(HandleSocket); - hs->sockvt = &HandleSocket_sockvt; + hs->sock.vt = &HandleSocket_sockvt; hs->plug = plug; hs->error = NULL; hs->frozen = UNFROZEN; @@ -343,5 +343,5 @@ Socket *make_handle_socket(HANDLE send_H, HANDLE recv_H, HANDLE stderr_H, hs->defer_close = hs->deferred_close = FALSE; - return &hs->sockvt; + return &hs->sock; } diff --git a/windows/winnet.c b/windows/winnet.c index 2427b688..8d0c4ac6 100644 --- a/windows/winnet.c +++ b/windows/winnet.c @@ -76,7 +76,7 @@ struct NetSocket { */ NetSocket *parent, *child; - const SocketVtable *sockvt; + Socket sock; }; struct SockAddr { @@ -910,7 +910,7 @@ SockAddr *sk_addr_dup(SockAddr *addr) static Plug *sk_net_plug(Socket *sock, Plug *p) { - NetSocket *s = FROMFIELD(sock, NetSocket, sockvt); + NetSocket *s = FROMFIELD(sock, NetSocket, sock); Plug *ret = s->plug; if (p) s->plug = p; @@ -957,7 +957,7 @@ static Socket *sk_net_accept(accept_ctx_t ctx, Plug *plug) * Create NetSocket structure. */ ret = snew(NetSocket); - ret->sockvt = &NetSocket_sockvt; + ret->sock.vt = &NetSocket_sockvt; ret->error = NULL; ret->plug = plug; bufchain_init(&ret->output_data); @@ -976,7 +976,7 @@ static Socket *sk_net_accept(accept_ctx_t ctx, Plug *plug) if (ret->s == INVALID_SOCKET) { err = p_WSAGetLastError(); ret->error = winsock_error_string(err); - return &ret->sockvt; + return &ret->sock; } ret->oobinline = 0; @@ -986,12 +986,12 @@ static Socket *sk_net_accept(accept_ctx_t ctx, Plug *plug) errstr = do_select(ret->s, 1); if (errstr) { ret->error = errstr; - return &ret->sockvt; + return &ret->sock; } add234(sktree, ret); - return &ret->sockvt; + return &ret->sock; } static DWORD try_connect(NetSocket *sock) @@ -1202,7 +1202,7 @@ Socket *sk_new(SockAddr *addr, int port, int privport, int oobinline, * Create NetSocket structure. */ ret = snew(NetSocket); - ret->sockvt = &NetSocket_sockvt; + ret->sock.vt = &NetSocket_sockvt; ret->error = NULL; ret->plug = plug; bufchain_init(&ret->output_data); @@ -1229,7 +1229,7 @@ Socket *sk_new(SockAddr *addr, int port, int privport, int oobinline, err = try_connect(ret); } while (err && sk_nextaddr(ret->addr, &ret->step)); - return &ret->sockvt; + return &ret->sock; } Socket *sk_newlistener(const char *srcaddr, int port, Plug *plug, @@ -1253,7 +1253,7 @@ Socket *sk_newlistener(const char *srcaddr, int port, Plug *plug, * Create NetSocket structure. */ ret = snew(NetSocket); - ret->sockvt = &NetSocket_sockvt; + ret->sock.vt = &NetSocket_sockvt; ret->error = NULL; ret->plug = plug; bufchain_init(&ret->output_data); @@ -1295,7 +1295,7 @@ Socket *sk_newlistener(const char *srcaddr, int port, Plug *plug, if (s == INVALID_SOCKET) { err = p_WSAGetLastError(); ret->error = winsock_error_string(err); - return &ret->sockvt; + return &ret->sock; } SetHandleInformation((HANDLE)s, HANDLE_FLAG_INHERIT, 0); @@ -1381,14 +1381,14 @@ Socket *sk_newlistener(const char *srcaddr, int port, Plug *plug, if (err) { p_closesocket(s); ret->error = winsock_error_string(err); - return &ret->sockvt; + return &ret->sock; } if (p_listen(s, SOMAXCONN) == SOCKET_ERROR) { p_closesocket(s); ret->error = winsock_error_string(p_WSAGetLastError()); - return &ret->sockvt; + return &ret->sock; } /* Set up a select mechanism. This could be an AsyncSelect on a @@ -1397,7 +1397,7 @@ Socket *sk_newlistener(const char *srcaddr, int port, Plug *plug, if (errstr) { p_closesocket(s); ret->error = errstr; - return &ret->sockvt; + return &ret->sock; } add234(sktree, ret); @@ -1412,7 +1412,7 @@ Socket *sk_newlistener(const char *srcaddr, int port, Plug *plug, local_host_only, ADDRTYPE_IPV6); if (other) { - NetSocket *ns = FROMFIELD(other, NetSocket, sockvt); + NetSocket *ns = FROMFIELD(other, NetSocket, sock); if (!ns->error) { ns->parent = ret; ret->child = ns; @@ -1423,16 +1423,16 @@ Socket *sk_newlistener(const char *srcaddr, int port, Plug *plug, } #endif - return &ret->sockvt; + return &ret->sock; } static void sk_net_close(Socket *sock) { extern char *do_select(SOCKET skt, int startup); - NetSocket *s = FROMFIELD(sock, NetSocket, sockvt); + NetSocket *s = FROMFIELD(sock, NetSocket, sock); if (s->child) - sk_net_close(&s->child->sockvt); + sk_net_close(&s->child->sock); del234(sktree, s); do_select(s->s, 0); @@ -1540,7 +1540,7 @@ void try_send(NetSocket *s) static int sk_net_write(Socket *sock, const void *buf, int len) { - NetSocket *s = FROMFIELD(sock, NetSocket, sockvt); + NetSocket *s = FROMFIELD(sock, NetSocket, sock); assert(s->outgoingeof == EOF_NO); @@ -1560,7 +1560,7 @@ static int sk_net_write(Socket *sock, const void *buf, int len) static int sk_net_write_oob(Socket *sock, const void *buf, int len) { - NetSocket *s = FROMFIELD(sock, NetSocket, sockvt); + NetSocket *s = FROMFIELD(sock, NetSocket, sock); assert(s->outgoingeof == EOF_NO); @@ -1583,7 +1583,7 @@ static int sk_net_write_oob(Socket *sock, const void *buf, int len) static void sk_net_write_eof(Socket *sock) { - NetSocket *s = FROMFIELD(sock, NetSocket, sockvt); + NetSocket *s = FROMFIELD(sock, NetSocket, sock); assert(s->outgoingeof == EOF_NO); @@ -1786,13 +1786,13 @@ const char *sk_addr_error(SockAddr *addr) } static const char *sk_net_socket_error(Socket *sock) { - NetSocket *s = FROMFIELD(sock, NetSocket, sockvt); + NetSocket *s = FROMFIELD(sock, NetSocket, sock); return s->error; } static char *sk_net_peer_info(Socket *sock) { - NetSocket *s = FROMFIELD(sock, NetSocket, sockvt); + NetSocket *s = FROMFIELD(sock, NetSocket, sock); #ifdef NO_IPV6 struct sockaddr_in addr; #else @@ -1824,7 +1824,7 @@ static char *sk_net_peer_info(Socket *sock) static void sk_net_set_frozen(Socket *sock, int is_frozen) { - NetSocket *s = FROMFIELD(sock, NetSocket, sockvt); + NetSocket *s = FROMFIELD(sock, NetSocket, sock); if (s->frozen == is_frozen) return; s->frozen = is_frozen; diff --git a/windows/winnps.c b/windows/winnps.c index c6a9f6a6..908b0435 100644 --- a/windows/winnps.c +++ b/windows/winnps.c @@ -34,12 +34,12 @@ typedef struct NamedPipeServerSocket { Plug *plug; char *error; - const SocketVtable *sockvt; + Socket sock; } NamedPipeServerSocket; static Plug *sk_namedpipeserver_plug(Socket *s, Plug *p) { - NamedPipeServerSocket *ps = FROMFIELD(s, NamedPipeServerSocket, sockvt); + NamedPipeServerSocket *ps = FROMFIELD(s, NamedPipeServerSocket, sock); Plug *ret = ps->plug; if (p) ps->plug = p; @@ -48,7 +48,7 @@ static Plug *sk_namedpipeserver_plug(Socket *s, Plug *p) static void sk_namedpipeserver_close(Socket *s) { - NamedPipeServerSocket *ps = FROMFIELD(s, NamedPipeServerSocket, sockvt); + NamedPipeServerSocket *ps = FROMFIELD(s, NamedPipeServerSocket, sock); if (ps->callback_handle) handle_free(ps->callback_handle); @@ -65,7 +65,7 @@ static void sk_namedpipeserver_close(Socket *s) static const char *sk_namedpipeserver_socket_error(Socket *s) { - NamedPipeServerSocket *ps = FROMFIELD(s, NamedPipeServerSocket, sockvt); + NamedPipeServerSocket *ps = FROMFIELD(s, NamedPipeServerSocket, sock); return ps->error; } @@ -219,7 +219,7 @@ static const SocketVtable NamedPipeServerSocket_sockvt = { Socket *new_named_pipe_listener(const char *pipename, Plug *plug) { NamedPipeServerSocket *ret = snew(NamedPipeServerSocket); - ret->sockvt = &NamedPipeServerSocket_sockvt; + ret->sock.vt = &NamedPipeServerSocket_sockvt; ret->plug = plug; ret->error = NULL; ret->psd = NULL; @@ -249,7 +249,7 @@ Socket *new_named_pipe_listener(const char *pipename, Plug *plug) named_pipe_accept_loop(ret, FALSE); cleanup: - return &ret->sockvt; + return &ret->sock; } #endif /* !defined NO_SECURITY */ diff --git a/x11fwd.c b/x11fwd.c index 34c5cb96..b975bd19 100644 --- a/x11fwd.c +++ b/x11fwd.c @@ -42,7 +42,7 @@ typedef struct X11Connection { SshChannel *c; /* channel structure held by SSH backend */ Socket *s; - const PlugVtable *plugvt; + Plug plug; Channel chan; } X11Connection; @@ -635,7 +635,7 @@ static void x11_closing(Plug *plug, const char *error_msg, int error_code, int calling_back) { struct X11Connection *xconn = FROMFIELD( - plug, struct X11Connection, plugvt); + plug, struct X11Connection, plug); if (error_msg) { /* @@ -667,7 +667,7 @@ static void x11_closing(Plug *plug, const char *error_msg, int error_code, static void x11_receive(Plug *plug, int urgent, char *data, int len) { struct X11Connection *xconn = FROMFIELD( - plug, struct X11Connection, plugvt); + plug, struct X11Connection, plug); xconn->no_data_sent_to_x_client = FALSE; sshfwd_write(xconn->c, data, len); @@ -676,7 +676,7 @@ static void x11_receive(Plug *plug, int urgent, char *data, int len) static void x11_sent(Plug *plug, int bufsize) { struct X11Connection *xconn = FROMFIELD( - plug, struct X11Connection, plugvt); + plug, struct X11Connection, plug); sshfwd_unthrottle(xconn->c, bufsize); } @@ -738,7 +738,7 @@ Channel *x11_new_channel(tree234 *authtree, SshChannel *c, * Open socket. */ xconn = snew(struct X11Connection); - xconn->plugvt = &X11Connection_plugvt; + xconn->plug.vt = &X11Connection_plugvt; xconn->chan.vt = &X11Connection_channelvt; xconn->chan.initial_fixed_window_size = (connection_sharing_possible ? 128 : 0); @@ -945,7 +945,7 @@ static int x11_send(Channel *chan, int is_stderr, const void *vdata, int len) xconn->disp = auth_matched->disp; xconn->s = new_connection(sk_addr_dup(xconn->disp->addr), xconn->disp->realhost, xconn->disp->port, - 0, 1, 0, 0, &xconn->plugvt, + 0, 1, 0, 0, &xconn->plug, sshfwd_get_conf(xconn->c)); if ((err = sk_socket_error(xconn->s)) != NULL) { char *err_message = dupprintf("unable to connect to" From ed652a70e80ae505a2b0e3302b0d2640df6a0e05 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Fri, 5 Oct 2018 19:42:32 +0100 Subject: [PATCH 488/607] Get rid of #ifdef DEFINE_PLUG_METHOD_MACROS. I don't actually know why this was ever here; it appeared in the very first commit that invented Plug in the first place (7b0e08270) without explanation. Perhaps Dave's original idea was that sometimes you'd need those macros _not_ to be defined so that the same names could be reused as the methods for a particular Plug instance? But I don't think that ever actually happened, and the code base builds just fine with those macros defined unconditionally just like all the other sets of method macros we now have, so let's get rid of this piece of cruft that was apparently unnecessary all along. --- be_misc.c | 1 - cproxy.c | 1 - errsock.c | 1 - network.h | 2 -- nocproxy.c | 1 - proxy.c | 1 - unix/uxnet.c | 1 - unix/uxproxy.c | 1 - unix/uxshare.c | 1 - windows/winhsock.c | 1 - windows/winnet.c | 1 - windows/winnpc.c | 1 - windows/winnps.c | 1 - windows/winproxy.c | 1 - windows/winshare.c | 1 - 15 files changed, 16 deletions(-) diff --git a/be_misc.c b/be_misc.c index 42da1302..86a7e739 100644 --- a/be_misc.c +++ b/be_misc.c @@ -5,7 +5,6 @@ #include #include -#define DEFINE_PLUG_METHOD_MACROS #include "putty.h" #include "network.h" diff --git a/cproxy.c b/cproxy.c index 5d5439fa..0fd4a8ec 100644 --- a/cproxy.c +++ b/cproxy.c @@ -9,7 +9,6 @@ #include #include -#define DEFINE_PLUG_METHOD_MACROS #include "putty.h" #include "ssh.h" /* For MD5 support */ #include "network.h" diff --git a/errsock.c b/errsock.c index a15f75cf..89c40a1d 100644 --- a/errsock.c +++ b/errsock.c @@ -5,7 +5,6 @@ #include #include -#define DEFINE_PLUG_METHOD_MACROS #include "tree234.h" #include "putty.h" #include "network.h" diff --git a/network.h b/network.h index 10492665..62361d11 100644 --- a/network.h +++ b/network.h @@ -156,7 +156,6 @@ Socket *sk_newlistener(const char *srcaddr, int port, Plug *plug, #define sk_write_eof(s) (((s)->vt->write_eof) (s)) #define sk_flush(s) (((s)->vt->flush) (s)) -#ifdef DEFINE_PLUG_METHOD_MACROS #define plug_log(p,type,addr,port,msg,code) \ (((p)->vt->log) (p, type, addr, port, msg, code)) #define plug_closing(p,msg,code,callback) \ @@ -167,7 +166,6 @@ Socket *sk_newlistener(const char *srcaddr, int port, Plug *plug, (((p)->vt->sent) (p, bufsize)) #define plug_accepting(p, constructor, ctx) \ (((p)->vt->accepting)(p, constructor, ctx)) -#endif /* * Special error values are returned from sk_namelookup and sk_new diff --git a/nocproxy.c b/nocproxy.c index 26d75a7e..45e36a35 100644 --- a/nocproxy.c +++ b/nocproxy.c @@ -8,7 +8,6 @@ #include #include -#define DEFINE_PLUG_METHOD_MACROS #include "putty.h" #include "network.h" #include "proxy.h" diff --git a/proxy.c b/proxy.c index 138d12aa..f255824b 100644 --- a/proxy.c +++ b/proxy.c @@ -9,7 +9,6 @@ #include #include -#define DEFINE_PLUG_METHOD_MACROS #include "putty.h" #include "network.h" #include "proxy.h" diff --git a/unix/uxnet.c b/unix/uxnet.c index 41cc0758..dbd1231b 100644 --- a/unix/uxnet.c +++ b/unix/uxnet.c @@ -19,7 +19,6 @@ #include #include -#define DEFINE_PLUG_METHOD_MACROS #include "putty.h" #include "network.h" #include "tree234.h" diff --git a/unix/uxproxy.c b/unix/uxproxy.c index 67757ca6..cd5f4e7a 100644 --- a/unix/uxproxy.c +++ b/unix/uxproxy.c @@ -9,7 +9,6 @@ #include #include -#define DEFINE_PLUG_METHOD_MACROS #include "tree234.h" #include "putty.h" #include "network.h" diff --git a/unix/uxshare.c b/unix/uxshare.c index 633ed502..2b96f7d8 100644 --- a/unix/uxshare.c +++ b/unix/uxshare.c @@ -13,7 +13,6 @@ #include #include -#define DEFINE_PLUG_METHOD_MACROS #include "tree234.h" #include "putty.h" #include "network.h" diff --git a/windows/winhsock.c b/windows/winhsock.c index b120c143..b0387ffc 100644 --- a/windows/winhsock.c +++ b/windows/winhsock.c @@ -7,7 +7,6 @@ #include #include -#define DEFINE_PLUG_METHOD_MACROS #include "tree234.h" #include "putty.h" #include "network.h" diff --git a/windows/winnet.c b/windows/winnet.c index 8d0c4ac6..94396d14 100644 --- a/windows/winnet.c +++ b/windows/winnet.c @@ -11,7 +11,6 @@ #include #include -#define DEFINE_PLUG_METHOD_MACROS #define NEED_DECLARATION_OF_SELECT /* in order to initialise it */ #include "putty.h" diff --git a/windows/winnpc.c b/windows/winnpc.c index 7797ba40..b61ddada 100644 --- a/windows/winnpc.c +++ b/windows/winnpc.c @@ -5,7 +5,6 @@ #include #include -#define DEFINE_PLUG_METHOD_MACROS #include "tree234.h" #include "putty.h" #include "network.h" diff --git a/windows/winnps.c b/windows/winnps.c index 908b0435..8422d493 100644 --- a/windows/winnps.c +++ b/windows/winnps.c @@ -5,7 +5,6 @@ #include #include -#define DEFINE_PLUG_METHOD_MACROS #include "tree234.h" #include "putty.h" #include "network.h" diff --git a/windows/winproxy.c b/windows/winproxy.c index 6868325c..2059d964 100644 --- a/windows/winproxy.c +++ b/windows/winproxy.c @@ -7,7 +7,6 @@ #include #include -#define DEFINE_PLUG_METHOD_MACROS #include "tree234.h" #include "putty.h" #include "network.h" diff --git a/windows/winshare.c b/windows/winshare.c index 5b7f93ad..af4bc974 100644 --- a/windows/winshare.c +++ b/windows/winshare.c @@ -7,7 +7,6 @@ #if !defined NO_SECURITY -#define DEFINE_PLUG_METHOD_MACROS #include "tree234.h" #include "putty.h" #include "network.h" From 9396fcc9f7fbece620fcf602f734b35ee921740b Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Fri, 5 Oct 2018 23:49:08 +0100 Subject: [PATCH 489/607] Rename FROMFIELD to 'container_of'. Ian Jackson points out that the Linux kernel has a macro of this name with the same purpose, and suggests that it's a good idea to use the same name as they do, so that at least some people reading one code base might recognise it from the other. I never really thought very hard about what order FROMFIELD's parameters should go in, and therefore I'm pleasantly surprised to find that my order agrees with the kernel's, so I don't have to permute every call site as part of making this change :-) --- agentf.c | 8 ++--- defs.h | 2 +- errsock.c | 6 ++-- import.c | 2 +- misc.c | 10 +++---- pageant.c | 10 +++---- portfwd.c | 23 +++++++------- proxy.c | 26 ++++++++-------- raw.c | 22 +++++++------- rlogin.c | 26 ++++++++-------- ssh.c | 42 +++++++++++++------------- ssh1bpp.c | 8 ++--- ssh1connection.c | 38 ++++++++++++------------ ssh1login.c | 14 +++++---- ssh2bpp-bare.c | 6 ++-- ssh2bpp.c | 10 +++---- ssh2connection.c | 74 +++++++++++++++++++++++----------------------- ssh2transport.c | 18 +++++------ ssh2userauth.c | 12 ++++---- sshaes.c | 12 ++++---- ssharcf.c | 6 ++-- sshblowf.c | 20 ++++++------- sshccp.c | 21 ++++++------- sshcommon.c | 6 ++-- sshdes.c | 38 ++++++++++++------------ sshdss.c | 18 +++++------ sshecc.c | 20 ++++++------- sshmd5.c | 12 +++++--- sshrsa.c | 20 ++++++------- sshsh256.c | 16 +++++----- sshsh512.c | 10 +++---- sshsha.c | 16 +++++----- sshshare.c | 11 +++---- sshverstring.c | 10 +++---- sshzlib.c | 8 ++--- telnet.c | 32 ++++++++++---------- testback.c | 4 +-- unix/gtkfont.c | 26 ++++++++-------- unix/uxnet.c | 20 ++++++------- unix/uxproxy.c | 14 ++++----- unix/uxpty.c | 30 +++++++++---------- unix/uxser.c | 14 ++++----- windows/winhsock.c | 16 +++++----- windows/winnet.c | 18 +++++------ windows/winnps.c | 6 ++-- windows/winser.c | 14 ++++----- x11fwd.c | 14 ++++----- 47 files changed, 410 insertions(+), 399 deletions(-) diff --git a/agentf.c b/agentf.c index 2c869fe5..3b3407fa 100644 --- a/agentf.c +++ b/agentf.c @@ -174,7 +174,7 @@ Channel *agentf_new(SshChannel *c) static void agentf_free(Channel *chan) { assert(chan->vt == &agentf_channelvt); - agentf *af = FROMFIELD(chan, agentf, chan); + agentf *af = container_of(chan, agentf, chan); if (af->pending) agent_cancel_query(af->pending); @@ -186,7 +186,7 @@ static int agentf_send(Channel *chan, int is_stderr, const void *data, int length) { assert(chan->vt == &agentf_channelvt); - agentf *af = FROMFIELD(chan, agentf, chan); + agentf *af = container_of(chan, agentf, chan); bufchain_add(&af->inbuffer, data, length); agentf_try_forward(af); @@ -204,7 +204,7 @@ static int agentf_send(Channel *chan, int is_stderr, static void agentf_send_eof(Channel *chan) { assert(chan->vt == &agentf_channelvt); - agentf *af = FROMFIELD(chan, agentf, chan); + agentf *af = container_of(chan, agentf, chan); af->rcvd_eof = TRUE; @@ -222,7 +222,7 @@ static char *agentf_log_close_msg(Channel *chan) static void agentf_set_input_wanted(Channel *chan, int wanted) { assert(chan->vt == &agentf_channelvt); - agentf *af = FROMFIELD(chan, agentf, chan); + agentf *af = container_of(chan, agentf, chan); af->input_wanted = wanted; diff --git a/defs.h b/defs.h index 776ab888..0d98b70c 100644 --- a/defs.h +++ b/defs.h @@ -97,7 +97,7 @@ typedef struct PacketProtocolLayer PacketProtocolLayer; /* Return a pointer to the object of structure type 'type' whose field * with name 'field' is pointed at by 'object'. */ -#define FROMFIELD(object, type, field) \ +#define container_of(object, type, field) \ TYPECHECK(object == &((type *)0)->field, \ ((type *)(((char *)(object)) - offsetof(type, field)))) diff --git a/errsock.c b/errsock.c index 89c40a1d..d4878a9a 100644 --- a/errsock.c +++ b/errsock.c @@ -18,7 +18,7 @@ typedef struct { static Plug *sk_error_plug(Socket *s, Plug *p) { - ErrorSocket *es = FROMFIELD(s, ErrorSocket, sock); + ErrorSocket *es = container_of(s, ErrorSocket, sock); Plug *ret = es->plug; if (p) es->plug = p; @@ -27,7 +27,7 @@ static Plug *sk_error_plug(Socket *s, Plug *p) static void sk_error_close(Socket *s) { - ErrorSocket *es = FROMFIELD(s, ErrorSocket, sock); + ErrorSocket *es = container_of(s, ErrorSocket, sock); sfree(es->error); sfree(es); @@ -35,7 +35,7 @@ static void sk_error_close(Socket *s) static const char *sk_error_socket_error(Socket *s) { - ErrorSocket *es = FROMFIELD(s, ErrorSocket, sock); + ErrorSocket *es = container_of(s, ErrorSocket, sock); return es->error; } diff --git a/import.c b/import.c index 98cf8010..66be77cb 100644 --- a/import.c +++ b/import.c @@ -916,7 +916,7 @@ int openssh_pem_write(const Filename *filename, struct ssh2_userkey *key, ssh_key_alg(key->key) == &ssh_ecdsa_nistp384 || ssh_key_alg(key->key) == &ssh_ecdsa_nistp521) { const unsigned char *oid; - struct ec_key *ec = FROMFIELD(key->key, struct ec_key, sshk); + struct ec_key *ec = container_of(key->key, struct ec_key, sshk); int oidlen; int pointlen; strbuf *seq, *sub; diff --git a/misc.c b/misc.c index efb83579..f24a6e36 100644 --- a/misc.c +++ b/misc.c @@ -493,7 +493,7 @@ struct strbuf_impl { void *strbuf_append(strbuf *buf_o, size_t len) { - struct strbuf_impl *buf = FROMFIELD(buf_o, struct strbuf_impl, visible); + struct strbuf_impl *buf = container_of(buf_o, struct strbuf_impl, visible); char *toret; if (buf->size < buf->visible.len + len + 1) { buf->size = (buf->visible.len + len + 1) * 5 / 4 + 512; @@ -524,7 +524,7 @@ strbuf *strbuf_new(void) } void strbuf_free(strbuf *buf_o) { - struct strbuf_impl *buf = FROMFIELD(buf_o, struct strbuf_impl, visible); + struct strbuf_impl *buf = container_of(buf_o, struct strbuf_impl, visible); if (buf->visible.s) { smemclr(buf->visible.s, buf->size); sfree(buf->visible.s); @@ -533,14 +533,14 @@ void strbuf_free(strbuf *buf_o) } char *strbuf_to_str(strbuf *buf_o) { - struct strbuf_impl *buf = FROMFIELD(buf_o, struct strbuf_impl, visible); + struct strbuf_impl *buf = container_of(buf_o, struct strbuf_impl, visible); char *ret = buf->visible.s; sfree(buf); return ret; } void strbuf_catfv(strbuf *buf_o, const char *fmt, va_list ap) { - struct strbuf_impl *buf = FROMFIELD(buf_o, struct strbuf_impl, visible); + struct strbuf_impl *buf = container_of(buf_o, struct strbuf_impl, visible); STRBUF_SET_PTR(buf, dupvprintf_inner(buf->visible.s, buf->visible.len, &buf->size, fmt, ap)); buf->visible.len += strlen(buf->visible.s + buf->visible.len); @@ -561,7 +561,7 @@ strbuf *strbuf_new_for_agent_query(void) } void strbuf_finalise_agent_query(strbuf *buf_o) { - struct strbuf_impl *buf = FROMFIELD(buf_o, struct strbuf_impl, visible); + struct strbuf_impl *buf = container_of(buf_o, struct strbuf_impl, visible); assert(buf->visible.len >= 5); PUT_32BIT_MSB_FIRST(buf->visible.u, buf->visible.len - 4); } diff --git a/pageant.c b/pageant.c index 438fbe58..5f22127e 100644 --- a/pageant.c +++ b/pageant.c @@ -713,7 +713,7 @@ struct pageant_conn_state { static void pageant_conn_closing(Plug *plug, const char *error_msg, int error_code, int calling_back) { - struct pageant_conn_state *pc = FROMFIELD( + struct pageant_conn_state *pc = container_of( plug, struct pageant_conn_state, plug); if (error_msg) plog(pc->logctx, pc->logfn, "%p: error: %s", pc, error_msg); @@ -725,7 +725,7 @@ static void pageant_conn_closing(Plug *plug, const char *error_msg, static void pageant_conn_sent(Plug *plug, int bufsize) { - /* struct pageant_conn_state *pc = FROMFIELD( + /* struct pageant_conn_state *pc = container_of( plug, struct pageant_conn_state, plug); */ /* @@ -747,7 +747,7 @@ static void pageant_conn_log(void *logctx, const char *fmt, va_list ap) static void pageant_conn_receive(Plug *plug, int urgent, char *data, int len) { - struct pageant_conn_state *pc = FROMFIELD( + struct pageant_conn_state *pc = container_of( plug, struct pageant_conn_state, plug); char c; @@ -807,7 +807,7 @@ struct pageant_listen_state { static void pageant_listen_closing(Plug *plug, const char *error_msg, int error_code, int calling_back) { - struct pageant_listen_state *pl = FROMFIELD( + struct pageant_listen_state *pl = container_of( plug, struct pageant_listen_state, plug); if (error_msg) plog(pl->logctx, pl->logfn, "listening socket: error: %s", error_msg); @@ -826,7 +826,7 @@ static const PlugVtable pageant_connection_plugvt = { static int pageant_listen_accepting(Plug *plug, accept_fn_t constructor, accept_ctx_t ctx) { - struct pageant_listen_state *pl = FROMFIELD( + struct pageant_listen_state *pl = container_of( plug, struct pageant_listen_state, plug); struct pageant_conn_state *pc; const char *err; diff --git a/portfwd.c b/portfwd.c index 40c09c7b..8ae9e80c 100644 --- a/portfwd.c +++ b/portfwd.c @@ -124,7 +124,8 @@ static void pfd_close(struct PortForwarding *pf); static void pfd_closing(Plug *plug, const char *error_msg, int error_code, int calling_back) { - struct PortForwarding *pf = FROMFIELD(plug, struct PortForwarding, plug); + struct PortForwarding *pf = + container_of(plug, struct PortForwarding, plug); if (error_msg) { /* @@ -205,7 +206,8 @@ static char *ipv6_to_string(ptrlen ipv6) static void pfd_receive(Plug *plug, int urgent, char *data, int len) { - struct PortForwarding *pf = FROMFIELD(plug, struct PortForwarding, plug); + struct PortForwarding *pf = + container_of(plug, struct PortForwarding, plug); if (len == 0) return; @@ -429,7 +431,8 @@ static void pfd_receive(Plug *plug, int urgent, char *data, int len) static void pfd_sent(Plug *plug, int bufsize) { - struct PortForwarding *pf = FROMFIELD(plug, struct PortForwarding, plug); + struct PortForwarding *pf = + container_of(plug, struct PortForwarding, plug); if (pf->c) sshfwd_unthrottle(pf->c, bufsize); @@ -473,7 +476,7 @@ static int pfl_accepting(Plug *p, accept_fn_t constructor, accept_ctx_t ctx) Socket *s; const char *err; - pl = FROMFIELD(p, struct PortListener, plug); + pl = container_of(p, struct PortListener, plug); pf = new_portfwd_state(); pf->plug.vt = &PortForwarding_plugvt; pf->chan.initial_fixed_window_size = 0; @@ -588,7 +591,7 @@ static void pfl_terminate(struct PortListener *pl) static void pfd_set_input_wanted(Channel *chan, int wanted) { assert(chan->vt == &PortForwarding_channelvt); - PortForwarding *pf = FROMFIELD(chan, PortForwarding, chan); + PortForwarding *pf = container_of(chan, PortForwarding, chan); pf->input_wanted = wanted; sk_set_frozen(pf->s, !pf->input_wanted); } @@ -596,7 +599,7 @@ static void pfd_set_input_wanted(Channel *chan, int wanted) static void pfd_chan_free(Channel *chan) { assert(chan->vt == &PortForwarding_channelvt); - PortForwarding *pf = FROMFIELD(chan, PortForwarding, chan); + PortForwarding *pf = container_of(chan, PortForwarding, chan); pfd_close(pf); } @@ -606,21 +609,21 @@ static void pfd_chan_free(Channel *chan) static int pfd_send(Channel *chan, int is_stderr, const void *data, int len) { assert(chan->vt == &PortForwarding_channelvt); - PortForwarding *pf = FROMFIELD(chan, PortForwarding, chan); + PortForwarding *pf = container_of(chan, PortForwarding, chan); return sk_write(pf->s, data, len); } static void pfd_send_eof(Channel *chan) { assert(chan->vt == &PortForwarding_channelvt); - PortForwarding *pf = FROMFIELD(chan, PortForwarding, chan); + PortForwarding *pf = container_of(chan, PortForwarding, chan); sk_write_eof(pf->s); } static void pfd_open_confirmation(Channel *chan) { assert(chan->vt == &PortForwarding_channelvt); - PortForwarding *pf = FROMFIELD(chan, PortForwarding, chan); + PortForwarding *pf = container_of(chan, PortForwarding, chan); pf->ready = 1; sk_set_frozen(pf->s, 0); @@ -636,7 +639,7 @@ static void pfd_open_confirmation(Channel *chan) static void pfd_open_failure(Channel *chan, const char *errtext) { assert(chan->vt == &PortForwarding_channelvt); - PortForwarding *pf = FROMFIELD(chan, PortForwarding, chan); + PortForwarding *pf = container_of(chan, PortForwarding, chan); logeventf(pf->cl->frontend, "Forwarded connection refused by server%s%s", diff --git a/proxy.c b/proxy.c index f255824b..ee97472c 100644 --- a/proxy.c +++ b/proxy.c @@ -79,7 +79,7 @@ void proxy_activate (ProxySocket *p) static Plug *sk_proxy_plug (Socket *s, Plug *p) { - ProxySocket *ps = FROMFIELD(s, ProxySocket, sock); + ProxySocket *ps = container_of(s, ProxySocket, sock); Plug *ret = ps->plug; if (p) ps->plug = p; @@ -88,7 +88,7 @@ static Plug *sk_proxy_plug (Socket *s, Plug *p) static void sk_proxy_close (Socket *s) { - ProxySocket *ps = FROMFIELD(s, ProxySocket, sock); + ProxySocket *ps = container_of(s, ProxySocket, sock); sk_close(ps->sub_socket); sk_addr_free(ps->remote_addr); @@ -97,7 +97,7 @@ static void sk_proxy_close (Socket *s) static int sk_proxy_write (Socket *s, const void *data, int len) { - ProxySocket *ps = FROMFIELD(s, ProxySocket, sock); + ProxySocket *ps = container_of(s, ProxySocket, sock); if (ps->state != PROXY_STATE_ACTIVE) { bufchain_add(&ps->pending_output_data, data, len); @@ -108,7 +108,7 @@ static int sk_proxy_write (Socket *s, const void *data, int len) static int sk_proxy_write_oob (Socket *s, const void *data, int len) { - ProxySocket *ps = FROMFIELD(s, ProxySocket, sock); + ProxySocket *ps = container_of(s, ProxySocket, sock); if (ps->state != PROXY_STATE_ACTIVE) { bufchain_clear(&ps->pending_output_data); @@ -121,7 +121,7 @@ static int sk_proxy_write_oob (Socket *s, const void *data, int len) static void sk_proxy_write_eof (Socket *s) { - ProxySocket *ps = FROMFIELD(s, ProxySocket, sock); + ProxySocket *ps = container_of(s, ProxySocket, sock); if (ps->state != PROXY_STATE_ACTIVE) { ps->pending_eof = 1; @@ -132,7 +132,7 @@ static void sk_proxy_write_eof (Socket *s) static void sk_proxy_flush (Socket *s) { - ProxySocket *ps = FROMFIELD(s, ProxySocket, sock); + ProxySocket *ps = container_of(s, ProxySocket, sock); if (ps->state != PROXY_STATE_ACTIVE) { ps->pending_flush = 1; @@ -143,7 +143,7 @@ static void sk_proxy_flush (Socket *s) static void sk_proxy_set_frozen (Socket *s, int is_frozen) { - ProxySocket *ps = FROMFIELD(s, ProxySocket, sock); + ProxySocket *ps = container_of(s, ProxySocket, sock); if (ps->state != PROXY_STATE_ACTIVE) { ps->freeze = is_frozen; @@ -182,7 +182,7 @@ static void sk_proxy_set_frozen (Socket *s, int is_frozen) static const char * sk_proxy_socket_error (Socket *s) { - ProxySocket *ps = FROMFIELD(s, ProxySocket, sock); + ProxySocket *ps = container_of(s, ProxySocket, sock); if (ps->error != NULL || ps->sub_socket == NULL) { return ps->error; } @@ -194,7 +194,7 @@ static const char * sk_proxy_socket_error (Socket *s) static void plug_proxy_log(Plug *plug, int type, SockAddr *addr, int port, const char *error_msg, int error_code) { - ProxySocket *ps = FROMFIELD(plug, ProxySocket, plugimpl); + ProxySocket *ps = container_of(plug, ProxySocket, plugimpl); plug_log(ps->plug, type, addr, port, error_msg, error_code); } @@ -202,7 +202,7 @@ static void plug_proxy_log(Plug *plug, int type, SockAddr *addr, int port, static void plug_proxy_closing (Plug *p, const char *error_msg, int error_code, int calling_back) { - ProxySocket *ps = FROMFIELD(p, ProxySocket, plugimpl); + ProxySocket *ps = container_of(p, ProxySocket, plugimpl); if (ps->state != PROXY_STATE_ACTIVE) { ps->closing_error_msg = error_msg; @@ -216,7 +216,7 @@ static void plug_proxy_closing (Plug *p, const char *error_msg, static void plug_proxy_receive (Plug *p, int urgent, char *data, int len) { - ProxySocket *ps = FROMFIELD(p, ProxySocket, plugimpl); + ProxySocket *ps = container_of(p, ProxySocket, plugimpl); if (ps->state != PROXY_STATE_ACTIVE) { /* we will lose the urgentness of this data, but since most, @@ -235,7 +235,7 @@ static void plug_proxy_receive (Plug *p, int urgent, char *data, int len) static void plug_proxy_sent (Plug *p, int bufsize) { - ProxySocket *ps = FROMFIELD(p, ProxySocket, plugimpl); + ProxySocket *ps = container_of(p, ProxySocket, plugimpl); if (ps->state != PROXY_STATE_ACTIVE) { ps->sent_bufsize = bufsize; @@ -248,7 +248,7 @@ static void plug_proxy_sent (Plug *p, int bufsize) static int plug_proxy_accepting(Plug *p, accept_fn_t constructor, accept_ctx_t ctx) { - ProxySocket *ps = FROMFIELD(p, ProxySocket, plugimpl); + ProxySocket *ps = container_of(p, ProxySocket, plugimpl); if (ps->state != PROXY_STATE_ACTIVE) { ps->accepting_constructor = constructor; diff --git a/raw.c b/raw.c index 9e451d9c..e5db12f9 100644 --- a/raw.c +++ b/raw.c @@ -35,7 +35,7 @@ static void c_write(Raw *raw, const void *buf, int len) static void raw_log(Plug *plug, int type, SockAddr *addr, int port, const char *error_msg, int error_code) { - Raw *raw = FROMFIELD(plug, Raw, plug); + Raw *raw = container_of(plug, Raw, plug); backend_socket_log(raw->frontend, type, addr, port, error_msg, error_code, raw->conf, raw->session_started); } @@ -58,7 +58,7 @@ static void raw_check_close(Raw *raw) static void raw_closing(Plug *plug, const char *error_msg, int error_code, int calling_back) { - Raw *raw = FROMFIELD(plug, Raw, plug); + Raw *raw = container_of(plug, Raw, plug); if (error_msg) { /* A socket error has occurred. */ @@ -90,7 +90,7 @@ static void raw_closing(Plug *plug, const char *error_msg, int error_code, static void raw_receive(Plug *plug, int urgent, char *data, int len) { - Raw *raw = FROMFIELD(plug, Raw, plug); + Raw *raw = container_of(plug, Raw, plug); c_write(raw, data, len); /* We count 'session start', for proxy logging purposes, as being * when data is received from the network and printed. */ @@ -99,7 +99,7 @@ static void raw_receive(Plug *plug, int urgent, char *data, int len) static void raw_sent(Plug *plug, int bufsize) { - Raw *raw = FROMFIELD(plug, Raw, plug); + Raw *raw = container_of(plug, Raw, plug); raw->bufsize = bufsize; } @@ -181,7 +181,7 @@ static const char *raw_init(Frontend *frontend, Backend **backend_handle, static void raw_free(Backend *be) { - Raw *raw = FROMFIELD(be, Raw, backend); + Raw *raw = container_of(be, Raw, backend); if (raw->s) sk_close(raw->s); @@ -201,7 +201,7 @@ static void raw_reconfig(Backend *be, Conf *conf) */ static int raw_send(Backend *be, const char *buf, int len) { - Raw *raw = FROMFIELD(be, Raw, backend); + Raw *raw = container_of(be, Raw, backend); if (raw->s == NULL) return 0; @@ -216,7 +216,7 @@ static int raw_send(Backend *be, const char *buf, int len) */ static int raw_sendbuffer(Backend *be) { - Raw *raw = FROMFIELD(be, Raw, backend); + Raw *raw = container_of(be, Raw, backend); return raw->bufsize; } @@ -234,7 +234,7 @@ static void raw_size(Backend *be, int width, int height) */ static void raw_special(Backend *be, SessionSpecialCode code, int arg) { - Raw *raw = FROMFIELD(be, Raw, backend); + Raw *raw = container_of(be, Raw, backend); if (code == SS_EOF && raw->s) { sk_write_eof(raw->s); raw->sent_socket_eof= TRUE; @@ -255,7 +255,7 @@ static const SessionSpecial *raw_get_specials(Backend *be) static int raw_connected(Backend *be) { - Raw *raw = FROMFIELD(be, Raw, backend); + Raw *raw = container_of(be, Raw, backend); return raw->s != NULL; } @@ -266,7 +266,7 @@ static int raw_sendok(Backend *be) static void raw_unthrottle(Backend *be, int backlog) { - Raw *raw = FROMFIELD(be, Raw, backend); + Raw *raw = container_of(be, Raw, backend); sk_set_frozen(raw->s, backlog > RAW_MAX_BACKLOG); } @@ -289,7 +289,7 @@ static void raw_provide_logctx(Backend *be, LogContext *logctx) static int raw_exitcode(Backend *be) { - Raw *raw = FROMFIELD(be, Raw, backend); + Raw *raw = container_of(be, Raw, backend); if (raw->s != NULL) return -1; /* still connected */ else if (raw->closed_on_socket_error) diff --git a/rlogin.c b/rlogin.c index 01f79fc3..e982552b 100644 --- a/rlogin.c +++ b/rlogin.c @@ -39,7 +39,7 @@ static void c_write(Rlogin *rlogin, const void *buf, int len) static void rlogin_log(Plug *plug, int type, SockAddr *addr, int port, const char *error_msg, int error_code) { - Rlogin *rlogin = FROMFIELD(plug, Rlogin, plug); + Rlogin *rlogin = container_of(plug, Rlogin, plug); backend_socket_log(rlogin->frontend, type, addr, port, error_msg, error_code, rlogin->conf, !rlogin->firstbyte); @@ -48,7 +48,7 @@ static void rlogin_log(Plug *plug, int type, SockAddr *addr, int port, static void rlogin_closing(Plug *plug, const char *error_msg, int error_code, int calling_back) { - Rlogin *rlogin = FROMFIELD(plug, Rlogin, plug); + Rlogin *rlogin = container_of(plug, Rlogin, plug); /* * We don't implement independent EOF in each direction for Telnet @@ -72,7 +72,7 @@ static void rlogin_closing(Plug *plug, const char *error_msg, int error_code, static void rlogin_receive(Plug *plug, int urgent, char *data, int len) { - Rlogin *rlogin = FROMFIELD(plug, Rlogin, plug); + Rlogin *rlogin = container_of(plug, Rlogin, plug); if (urgent == 2) { char c; @@ -109,7 +109,7 @@ static void rlogin_receive(Plug *plug, int urgent, char *data, int len) static void rlogin_sent(Plug *plug, int bufsize) { - Rlogin *rlogin = FROMFIELD(plug, Rlogin, plug); + Rlogin *rlogin = container_of(plug, Rlogin, plug); rlogin->bufsize = bufsize; } @@ -236,7 +236,7 @@ static const char *rlogin_init(Frontend *frontend, Backend **backend_handle, static void rlogin_free(Backend *be) { - Rlogin *rlogin = FROMFIELD(be, Rlogin, backend); + Rlogin *rlogin = container_of(be, Rlogin, backend); if (rlogin->prompt) free_prompts(rlogin->prompt); @@ -258,7 +258,7 @@ static void rlogin_reconfig(Backend *be, Conf *conf) */ static int rlogin_send(Backend *be, const char *buf, int len) { - Rlogin *rlogin = FROMFIELD(be, Rlogin, backend); + Rlogin *rlogin = container_of(be, Rlogin, backend); bufchain bc; if (rlogin->s == NULL) @@ -300,7 +300,7 @@ static int rlogin_send(Backend *be, const char *buf, int len) */ static int rlogin_sendbuffer(Backend *be) { - Rlogin *rlogin = FROMFIELD(be, Rlogin, backend); + Rlogin *rlogin = container_of(be, Rlogin, backend); return rlogin->bufsize; } @@ -309,7 +309,7 @@ static int rlogin_sendbuffer(Backend *be) */ static void rlogin_size(Backend *be, int width, int height) { - Rlogin *rlogin = FROMFIELD(be, Rlogin, backend); + Rlogin *rlogin = container_of(be, Rlogin, backend); char b[12] = { '\xFF', '\xFF', 0x73, 0x73, 0, 0, 0, 0, 0, 0, 0, 0 }; rlogin->term_width = width; @@ -346,25 +346,25 @@ static const SessionSpecial *rlogin_get_specials(Backend *be) static int rlogin_connected(Backend *be) { - Rlogin *rlogin = FROMFIELD(be, Rlogin, backend); + Rlogin *rlogin = container_of(be, Rlogin, backend); return rlogin->s != NULL; } static int rlogin_sendok(Backend *be) { - /* Rlogin *rlogin = FROMFIELD(be, Rlogin, backend); */ + /* Rlogin *rlogin = container_of(be, Rlogin, backend); */ return 1; } static void rlogin_unthrottle(Backend *be, int backlog) { - Rlogin *rlogin = FROMFIELD(be, Rlogin, backend); + Rlogin *rlogin = container_of(be, Rlogin, backend); sk_set_frozen(rlogin->s, backlog > RLOGIN_MAX_BACKLOG); } static int rlogin_ldisc(Backend *be, int option) { - /* Rlogin *rlogin = FROMFIELD(be, Rlogin, backend); */ + /* Rlogin *rlogin = container_of(be, Rlogin, backend); */ return 0; } @@ -380,7 +380,7 @@ static void rlogin_provide_logctx(Backend *be, LogContext *logctx) static int rlogin_exitcode(Backend *be) { - Rlogin *rlogin = FROMFIELD(be, Rlogin, backend); + Rlogin *rlogin = container_of(be, Rlogin, backend); if (rlogin->s != NULL) return -1; /* still connected */ else if (rlogin->closed_on_socket_error) diff --git a/ssh.c b/ssh.c index c94554dd..5227b4de 100644 --- a/ssh.c +++ b/ssh.c @@ -141,7 +141,7 @@ static void ssh_connect_ppl(Ssh *ssh, PacketProtocolLayer *ppl) static void ssh_got_ssh_version(struct ssh_version_receiver *rcv, int major_version) { - Ssh *ssh = FROMFIELD(rcv, Ssh, version_receiver); + Ssh *ssh = container_of(rcv, Ssh, version_receiver); BinaryPacketProtocol *old_bpp; PacketProtocolLayer *connection_layer; @@ -489,7 +489,7 @@ void ssh_user_close(Ssh *ssh, const char *fmt, ...) static void ssh_socket_log(Plug *plug, int type, SockAddr *addr, int port, const char *error_msg, int error_code) { - Ssh *ssh = FROMFIELD(plug, Ssh, plug); + Ssh *ssh = container_of(plug, Ssh, plug); /* * While we're attempting connection sharing, don't loudly log @@ -509,7 +509,7 @@ static void ssh_socket_log(Plug *plug, int type, SockAddr *addr, int port, static void ssh_closing(Plug *plug, const char *error_msg, int error_code, int calling_back) { - Ssh *ssh = FROMFIELD(plug, Ssh, plug); + Ssh *ssh = container_of(plug, Ssh, plug); if (error_msg) { ssh_remote_error(ssh, "Network error: %s", error_msg); } else if (ssh->bpp) { @@ -520,7 +520,7 @@ static void ssh_closing(Plug *plug, const char *error_msg, int error_code, static void ssh_receive(Plug *plug, int urgent, char *data, int len) { - Ssh *ssh = FROMFIELD(plug, Ssh, plug); + Ssh *ssh = container_of(plug, Ssh, plug); /* Log raw data, if we're in that mode. */ if (ssh->logctx) @@ -534,7 +534,7 @@ static void ssh_receive(Plug *plug, int urgent, char *data, int len) static void ssh_sent(Plug *plug, int bufsize) { - Ssh *ssh = FROMFIELD(plug, Ssh, plug); + Ssh *ssh = container_of(plug, Ssh, plug); /* * If the send backlog on the SSH socket itself clears, we should * unthrottle the whole world if it was throttled. Also trigger an @@ -825,7 +825,7 @@ static const char *ssh_init(Frontend *frontend, Backend **backend_handle, static void ssh_free(Backend *be) { - Ssh *ssh = FROMFIELD(be, Ssh, backend); + Ssh *ssh = container_of(be, Ssh, backend); int need_random_unref; ssh_shutdown(ssh); @@ -860,7 +860,7 @@ static void ssh_free(Backend *be) */ static void ssh_reconfig(Backend *be, Conf *conf) { - Ssh *ssh = FROMFIELD(be, Ssh, backend); + Ssh *ssh = container_of(be, Ssh, backend); if (ssh->pinger) pinger_reconfig(ssh->pinger, ssh->conf, conf); @@ -877,7 +877,7 @@ static void ssh_reconfig(Backend *be, Conf *conf) */ static int ssh_send(Backend *be, const char *buf, int len) { - Ssh *ssh = FROMFIELD(be, Ssh, backend); + Ssh *ssh = container_of(be, Ssh, backend); if (ssh == NULL || ssh->s == NULL) return 0; @@ -894,7 +894,7 @@ static int ssh_send(Backend *be, const char *buf, int len) */ static int ssh_sendbuffer(Backend *be) { - Ssh *ssh = FROMFIELD(be, Ssh, backend); + Ssh *ssh = container_of(be, Ssh, backend); int backlog; if (!ssh || !ssh->s || !ssh->cl) @@ -919,7 +919,7 @@ static int ssh_sendbuffer(Backend *be) */ static void ssh_size(Backend *be, int width, int height) { - Ssh *ssh = FROMFIELD(be, Ssh, backend); + Ssh *ssh = container_of(be, Ssh, backend); ssh->term_width = width; ssh->term_height = height; @@ -956,7 +956,7 @@ static void ssh_add_special(void *vctx, const char *text, */ static const SessionSpecial *ssh_get_specials(Backend *be) { - Ssh *ssh = FROMFIELD(be, Ssh, backend); + Ssh *ssh = container_of(be, Ssh, backend); /* * Ask all our active protocol layers what specials they've got, @@ -986,7 +986,7 @@ static const SessionSpecial *ssh_get_specials(Backend *be) */ static void ssh_special(Backend *be, SessionSpecialCode code, int arg) { - Ssh *ssh = FROMFIELD(be, Ssh, backend); + Ssh *ssh = container_of(be, Ssh, backend); if (ssh->base_layer) ssh_ppl_special_cmd(ssh->base_layer, code, arg); @@ -998,20 +998,20 @@ static void ssh_special(Backend *be, SessionSpecialCode code, int arg) */ static void ssh_unthrottle(Backend *be, int bufsize) { - Ssh *ssh = FROMFIELD(be, Ssh, backend); + Ssh *ssh = container_of(be, Ssh, backend); ssh_stdout_unthrottle(ssh->cl, bufsize); } static int ssh_connected(Backend *be) { - Ssh *ssh = FROMFIELD(be, Ssh, backend); + Ssh *ssh = container_of(be, Ssh, backend); return ssh->s != NULL; } static int ssh_sendok(Backend *be) { - Ssh *ssh = FROMFIELD(be, Ssh, backend); + Ssh *ssh = container_of(be, Ssh, backend); return ssh->base_layer && ssh_ppl_want_user_input(ssh->base_layer); } @@ -1025,19 +1025,19 @@ void ssh_ldisc_update(Ssh *ssh) static int ssh_ldisc(Backend *be, int option) { - Ssh *ssh = FROMFIELD(be, Ssh, backend); + Ssh *ssh = container_of(be, Ssh, backend); return ssh->cl ? ssh_ldisc_option(ssh->cl, option) : FALSE; } static void ssh_provide_ldisc(Backend *be, Ldisc *ldisc) { - Ssh *ssh = FROMFIELD(be, Ssh, backend); + Ssh *ssh = container_of(be, Ssh, backend); ssh->ldisc = ldisc; } static void ssh_provide_logctx(Backend *be, LogContext *logctx) { - Ssh *ssh = FROMFIELD(be, Ssh, backend); + Ssh *ssh = container_of(be, Ssh, backend); ssh->logctx = logctx; } @@ -1048,7 +1048,7 @@ void ssh_got_exitcode(Ssh *ssh, int exitcode) static int ssh_return_exitcode(Backend *be) { - Ssh *ssh = FROMFIELD(be, Ssh, backend); + Ssh *ssh = container_of(be, Ssh, backend); if (ssh->s && (!ssh->session_started || ssh->base_layer)) return -1; else @@ -1062,7 +1062,7 @@ static int ssh_return_exitcode(Backend *be) */ static int ssh_cfg_info(Backend *be) { - Ssh *ssh = FROMFIELD(be, Ssh, backend); + Ssh *ssh = container_of(be, Ssh, backend); if (ssh->version == 0) return 0; /* don't know yet */ else if (ssh->bare_connection) @@ -1078,7 +1078,7 @@ static int ssh_cfg_info(Backend *be) */ extern int ssh_fallback_cmd(Backend *be) { - Ssh *ssh = FROMFIELD(be, Ssh, backend); + Ssh *ssh = container_of(be, Ssh, backend); return ssh->fallback_cmd; } diff --git a/ssh1bpp.c b/ssh1bpp.c index 98763e03..36afcd24 100644 --- a/ssh1bpp.c +++ b/ssh1bpp.c @@ -54,7 +54,7 @@ BinaryPacketProtocol *ssh1_bpp_new(void) static void ssh1_bpp_free(BinaryPacketProtocol *bpp) { - struct ssh1_bpp_state *s = FROMFIELD(bpp, struct ssh1_bpp_state, bpp); + struct ssh1_bpp_state *s = container_of(bpp, struct ssh1_bpp_state, bpp); if (s->cipher) ssh1_cipher_free(s->cipher); if (s->compctx) @@ -73,7 +73,7 @@ void ssh1_bpp_new_cipher(BinaryPacketProtocol *bpp, { struct ssh1_bpp_state *s; assert(bpp->vt == &ssh1_bpp_vtable); - s = FROMFIELD(bpp, struct ssh1_bpp_state, bpp); + s = container_of(bpp, struct ssh1_bpp_state, bpp); assert(!s->cipher); @@ -97,7 +97,7 @@ void ssh1_bpp_new_cipher(BinaryPacketProtocol *bpp, static void ssh1_bpp_handle_input(BinaryPacketProtocol *bpp) { - struct ssh1_bpp_state *s = FROMFIELD(bpp, struct ssh1_bpp_state, bpp); + struct ssh1_bpp_state *s = container_of(bpp, struct ssh1_bpp_state, bpp); crBegin(s->crState); @@ -314,7 +314,7 @@ static void ssh1_bpp_format_packet(struct ssh1_bpp_state *s, PktOut *pkt) static void ssh1_bpp_handle_output(BinaryPacketProtocol *bpp) { - struct ssh1_bpp_state *s = FROMFIELD(bpp, struct ssh1_bpp_state, bpp); + struct ssh1_bpp_state *s = container_of(bpp, struct ssh1_bpp_state, bpp); PktOut *pkt; if (s->pending_compression_request) { diff --git a/ssh1connection.c b/ssh1connection.c index 6a02676f..3cf75967 100644 --- a/ssh1connection.c +++ b/ssh1connection.c @@ -276,7 +276,7 @@ PacketProtocolLayer *ssh1_connection_new( static void ssh1_connection_free(PacketProtocolLayer *ppl) { struct ssh1_connection_state *s = - FROMFIELD(ppl, struct ssh1_connection_state, ppl); + container_of(ppl, struct ssh1_connection_state, ppl); struct X11FakeAuth *auth; struct ssh1_channel *c; struct ssh_rportfwd *rpf; @@ -305,7 +305,7 @@ void ssh1_connection_set_local_protoflags(PacketProtocolLayer *ppl, int flags) { assert(ppl->vt == &ssh1_connection_vtable); struct ssh1_connection_state *s = - FROMFIELD(ppl, struct ssh1_connection_state, ppl); + container_of(ppl, struct ssh1_connection_state, ppl); s->local_protoflags = flags; } @@ -619,7 +619,7 @@ static PktIn *ssh1_connection_pop(struct ssh1_connection_state *s) static void ssh1_connection_process_queue(PacketProtocolLayer *ppl) { struct ssh1_connection_state *s = - FROMFIELD(ppl, struct ssh1_connection_state, ppl); + container_of(ppl, struct ssh1_connection_state, ppl); PktIn *pktin; PktOut *pktout; @@ -942,14 +942,14 @@ static void ssh1_channel_init(struct ssh1_channel *c) static Conf *ssh1channel_get_conf(SshChannel *sc) { - struct ssh1_channel *c = FROMFIELD(sc, struct ssh1_channel, sc); + struct ssh1_channel *c = container_of(sc, struct ssh1_channel, sc); struct ssh1_connection_state *s = c->connlayer; return s->conf; } static void ssh1channel_write_eof(SshChannel *sc) { - struct ssh1_channel *c = FROMFIELD(sc, struct ssh1_channel, sc); + struct ssh1_channel *c = container_of(sc, struct ssh1_channel, sc); if (c->closes & CLOSES_SENT_CLOSE) return; @@ -960,7 +960,7 @@ static void ssh1channel_write_eof(SshChannel *sc) static void ssh1channel_unclean_close(SshChannel *sc, const char *err) { - struct ssh1_channel *c = FROMFIELD(sc, struct ssh1_channel, sc); + struct ssh1_channel *c = container_of(sc, struct ssh1_channel, sc); char *reason; reason = dupprintf("due to local error: %s", err); @@ -973,7 +973,7 @@ static void ssh1channel_unclean_close(SshChannel *sc, const char *err) static void ssh1channel_unthrottle(SshChannel *sc, int bufsize) { - struct ssh1_channel *c = FROMFIELD(sc, struct ssh1_channel, sc); + struct ssh1_channel *c = container_of(sc, struct ssh1_channel, sc); struct ssh1_connection_state *s = c->connlayer; if (c->throttling_conn && bufsize <= SSH1_BUFFER_LIMIT) { @@ -984,7 +984,7 @@ static void ssh1channel_unthrottle(SshChannel *sc, int bufsize) static int ssh1channel_write(SshChannel *sc, const void *buf, int len) { - struct ssh1_channel *c = FROMFIELD(sc, struct ssh1_channel, sc); + struct ssh1_channel *c = container_of(sc, struct ssh1_channel, sc); struct ssh1_connection_state *s = c->connlayer; assert(!(c->closes & CLOSES_SENT_CLOSE)); @@ -1009,7 +1009,7 @@ static SshChannel *ssh1_lportfwd_open( const char *org, Channel *chan) { struct ssh1_connection_state *s = - FROMFIELD(cl, struct ssh1_connection_state, cl); + container_of(cl, struct ssh1_connection_state, cl); PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */ struct ssh1_channel *c = snew(struct ssh1_channel); PktOut *pktout; @@ -1059,7 +1059,7 @@ static struct ssh_rportfwd *ssh1_rportfwd_alloc( ssh_sharing_connstate *share_ctx) { struct ssh1_connection_state *s = - FROMFIELD(cl, struct ssh1_connection_state, cl); + container_of(cl, struct ssh1_connection_state, cl); struct ssh_rportfwd *rpf = snew(struct ssh_rportfwd); rpf->shost = dupstr(shost); @@ -1098,7 +1098,7 @@ static void ssh1_rportfwd_remove(ConnectionLayer *cl, struct ssh_rportfwd *rpf) static int ssh1_agent_forwarding_permitted(ConnectionLayer *cl) { struct ssh1_connection_state *s = - FROMFIELD(cl, struct ssh1_connection_state, cl); + container_of(cl, struct ssh1_connection_state, cl); return conf_get_int(s->conf, CONF_agentfwd) && agent_exists(); } @@ -1106,7 +1106,7 @@ static void ssh1_connection_special_cmd(PacketProtocolLayer *ppl, SessionSpecialCode code, int arg) { struct ssh1_connection_state *s = - FROMFIELD(ppl, struct ssh1_connection_state, ppl); + container_of(ppl, struct ssh1_connection_state, ppl); PktOut *pktout; if (code == SS_PING || code == SS_NOP) { @@ -1134,7 +1134,7 @@ static void ssh1_connection_special_cmd(PacketProtocolLayer *ppl, static void ssh1_terminal_size(ConnectionLayer *cl, int width, int height) { struct ssh1_connection_state *s = - FROMFIELD(cl, struct ssh1_connection_state, cl); + container_of(cl, struct ssh1_connection_state, cl); s->term_width = width; s->term_height = height; @@ -1152,7 +1152,7 @@ static void ssh1_terminal_size(ConnectionLayer *cl, int width, int height) static void ssh1_stdout_unthrottle(ConnectionLayer *cl, int bufsize) { struct ssh1_connection_state *s = - FROMFIELD(cl, struct ssh1_connection_state, cl); + container_of(cl, struct ssh1_connection_state, cl); if (s->stdout_throttling && bufsize < SSH1_BUFFER_LIMIT) { s->stdout_throttling = 0; @@ -1168,7 +1168,7 @@ static int ssh1_stdin_backlog(ConnectionLayer *cl) static void ssh1_throttle_all_channels(ConnectionLayer *cl, int throttled) { struct ssh1_connection_state *s = - FROMFIELD(cl, struct ssh1_connection_state, cl); + container_of(cl, struct ssh1_connection_state, cl); struct ssh1_channel *c; int i; @@ -1179,7 +1179,7 @@ static void ssh1_throttle_all_channels(ConnectionLayer *cl, int throttled) static int ssh1_ldisc_option(ConnectionLayer *cl, int option) { struct ssh1_connection_state *s = - FROMFIELD(cl, struct ssh1_connection_state, cl); + container_of(cl, struct ssh1_connection_state, cl); /* We always return the same value for LD_ECHO and LD_EDIT */ return s->echoedit; @@ -1188,14 +1188,14 @@ static int ssh1_ldisc_option(ConnectionLayer *cl, int option) static int ssh1_connection_want_user_input(PacketProtocolLayer *ppl) { struct ssh1_connection_state *s = - FROMFIELD(ppl, struct ssh1_connection_state, ppl); + container_of(ppl, struct ssh1_connection_state, ppl); return s->session_ready && !s->session_eof_sent; } static void ssh1_connection_got_user_input(PacketProtocolLayer *ppl) { struct ssh1_connection_state *s = - FROMFIELD(ppl, struct ssh1_connection_state, ppl); + container_of(ppl, struct ssh1_connection_state, ppl); if (s->session_ready && !s->session_eof_sent) queue_idempotent_callback(&s->ppl.ic_process_queue); } @@ -1203,7 +1203,7 @@ static void ssh1_connection_got_user_input(PacketProtocolLayer *ppl) static void ssh1_connection_reconfigure(PacketProtocolLayer *ppl, Conf *conf) { struct ssh1_connection_state *s = - FROMFIELD(ppl, struct ssh1_connection_state, ppl); + container_of(ppl, struct ssh1_connection_state, ppl); conf_free(s->conf); s->conf = conf_copy(conf); diff --git a/ssh1login.c b/ssh1login.c index d2404fc5..e64bc834 100644 --- a/ssh1login.c +++ b/ssh1login.c @@ -99,7 +99,8 @@ PacketProtocolLayer *ssh1_login_new( static void ssh1_login_free(PacketProtocolLayer *ppl) { - struct ssh1_login_state *s = FROMFIELD(ppl, struct ssh1_login_state, ppl); + struct ssh1_login_state *s = + container_of(ppl, struct ssh1_login_state, ppl); if (s->successor_layer) ssh_ppl_free(s->successor_layer); @@ -166,7 +167,8 @@ static PktIn *ssh1_login_pop(struct ssh1_login_state *s) static void ssh1_login_process_queue(PacketProtocolLayer *ppl) { - struct ssh1_login_state *s = FROMFIELD(ppl, struct ssh1_login_state, ppl); + struct ssh1_login_state *s = + container_of(ppl, struct ssh1_login_state, ppl); PktIn *pktin; PktOut *pkt; int i; @@ -1172,7 +1174,7 @@ static void ssh1_login_special_cmd(PacketProtocolLayer *ppl, SessionSpecialCode code, int arg) { struct ssh1_login_state *s = - FROMFIELD(ppl, struct ssh1_login_state, ppl); + container_of(ppl, struct ssh1_login_state, ppl); PktOut *pktout; if (code == SS_PING || code == SS_NOP) { @@ -1187,14 +1189,14 @@ static void ssh1_login_special_cmd(PacketProtocolLayer *ppl, static int ssh1_login_want_user_input(PacketProtocolLayer *ppl) { struct ssh1_login_state *s = - FROMFIELD(ppl, struct ssh1_login_state, ppl); + container_of(ppl, struct ssh1_login_state, ppl); return s->want_user_input; } static void ssh1_login_got_user_input(PacketProtocolLayer *ppl) { struct ssh1_login_state *s = - FROMFIELD(ppl, struct ssh1_login_state, ppl); + container_of(ppl, struct ssh1_login_state, ppl); if (s->want_user_input) queue_idempotent_callback(&s->ppl.ic_process_queue); } @@ -1202,6 +1204,6 @@ static void ssh1_login_got_user_input(PacketProtocolLayer *ppl) static void ssh1_login_reconfigure(PacketProtocolLayer *ppl, Conf *conf) { struct ssh1_login_state *s = - FROMFIELD(ppl, struct ssh1_login_state, ppl); + container_of(ppl, struct ssh1_login_state, ppl); ssh_ppl_reconfigure(s->successor_layer, conf); } diff --git a/ssh2bpp-bare.c b/ssh2bpp-bare.c index ba40e7ab..213acf0c 100644 --- a/ssh2bpp-bare.c +++ b/ssh2bpp-bare.c @@ -45,7 +45,7 @@ BinaryPacketProtocol *ssh2_bare_bpp_new(void) static void ssh2_bare_bpp_free(BinaryPacketProtocol *bpp) { struct ssh2_bare_bpp_state *s = - FROMFIELD(bpp, struct ssh2_bare_bpp_state, bpp); + container_of(bpp, struct ssh2_bare_bpp_state, bpp); sfree(s->pktin); sfree(s); } @@ -62,7 +62,7 @@ static void ssh2_bare_bpp_free(BinaryPacketProtocol *bpp) static void ssh2_bare_bpp_handle_input(BinaryPacketProtocol *bpp) { struct ssh2_bare_bpp_state *s = - FROMFIELD(bpp, struct ssh2_bare_bpp_state, bpp); + container_of(bpp, struct ssh2_bare_bpp_state, bpp); crBegin(s->crState); @@ -175,7 +175,7 @@ static void ssh2_bare_bpp_format_packet(struct ssh2_bare_bpp_state *s, static void ssh2_bare_bpp_handle_output(BinaryPacketProtocol *bpp) { struct ssh2_bare_bpp_state *s = - FROMFIELD(bpp, struct ssh2_bare_bpp_state, bpp); + container_of(bpp, struct ssh2_bare_bpp_state, bpp); PktOut *pkt; while ((pkt = pq_pop(&s->bpp.out_pq)) != NULL) { diff --git a/ssh2bpp.c b/ssh2bpp.c index 6bda41d0..f0b6fd22 100644 --- a/ssh2bpp.c +++ b/ssh2bpp.c @@ -63,7 +63,7 @@ BinaryPacketProtocol *ssh2_bpp_new(struct DataTransferStats *stats) static void ssh2_bpp_free(BinaryPacketProtocol *bpp) { - struct ssh2_bpp_state *s = FROMFIELD(bpp, struct ssh2_bpp_state, bpp); + struct ssh2_bpp_state *s = container_of(bpp, struct ssh2_bpp_state, bpp); sfree(s->buf); if (s->out.cipher) ssh2_cipher_free(s->out.cipher); @@ -89,7 +89,7 @@ void ssh2_bpp_new_outgoing_crypto( { struct ssh2_bpp_state *s; assert(bpp->vt == &ssh2_bpp_vtable); - s = FROMFIELD(bpp, struct ssh2_bpp_state, bpp); + s = container_of(bpp, struct ssh2_bpp_state, bpp); if (s->out.cipher) ssh2_cipher_free(s->out.cipher); @@ -132,7 +132,7 @@ void ssh2_bpp_new_incoming_crypto( { struct ssh2_bpp_state *s; assert(bpp->vt == &ssh2_bpp_vtable); - s = FROMFIELD(bpp, struct ssh2_bpp_state, bpp); + s = container_of(bpp, struct ssh2_bpp_state, bpp); if (s->in.cipher) ssh2_cipher_free(s->in.cipher); @@ -177,7 +177,7 @@ void ssh2_bpp_new_incoming_crypto( static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp) { - struct ssh2_bpp_state *s = FROMFIELD(bpp, struct ssh2_bpp_state, bpp); + struct ssh2_bpp_state *s = container_of(bpp, struct ssh2_bpp_state, bpp); crBegin(s->crState); @@ -700,7 +700,7 @@ static void ssh2_bpp_format_packet(struct ssh2_bpp_state *s, PktOut *pkt) static void ssh2_bpp_handle_output(BinaryPacketProtocol *bpp) { - struct ssh2_bpp_state *s = FROMFIELD(bpp, struct ssh2_bpp_state, bpp); + struct ssh2_bpp_state *s = container_of(bpp, struct ssh2_bpp_state, bpp); PktOut *pkt; if (s->cbc_ignore_workaround) { diff --git a/ssh2connection.c b/ssh2connection.c index 9aa45dc9..6da82951 100644 --- a/ssh2connection.c +++ b/ssh2connection.c @@ -407,7 +407,7 @@ PacketProtocolLayer *ssh2_connection_new( static void ssh2_connection_free(PacketProtocolLayer *ppl) { struct ssh2_connection_state *s = - FROMFIELD(ppl, struct ssh2_connection_state, ppl); + container_of(ppl, struct ssh2_connection_state, ppl); struct X11FakeAuth *auth; struct ssh2_channel *c; struct ssh_rportfwd *rpf; @@ -1153,7 +1153,7 @@ static PktIn *ssh2_connection_pop(struct ssh2_connection_state *s) static void ssh2_connection_process_queue(PacketProtocolLayer *ppl) { struct ssh2_connection_state *s = - FROMFIELD(ppl, struct ssh2_connection_state, ppl); + container_of(ppl, struct ssh2_connection_state, ppl); PktIn *pktin; PktOut *pktout; @@ -1198,7 +1198,7 @@ static void ssh2_connection_process_queue(PacketProtocolLayer *ppl) &s->cl, conf_get_str(s->conf, CONF_ssh_nc_host), conf_get_int(s->conf, CONF_ssh_nc_port), "main channel", &mc->chan); - s->mainchan = FROMFIELD(mc->sc, struct ssh2_channel, sc); + s->mainchan = container_of(mc->sc, struct ssh2_channel, sc); break; } @@ -1865,14 +1865,14 @@ static PktOut *ssh2_chanreq_init(struct ssh2_channel *c, const char *type, static Conf *ssh2channel_get_conf(SshChannel *sc) { - struct ssh2_channel *c = FROMFIELD(sc, struct ssh2_channel, sc); + struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc); struct ssh2_connection_state *s = c->connlayer; return s->conf; } static void ssh2channel_write_eof(SshChannel *sc) { - struct ssh2_channel *c = FROMFIELD(sc, struct ssh2_channel, sc); + struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc); if (c->closes & CLOSES_SENT_EOF) return; @@ -1883,7 +1883,7 @@ static void ssh2channel_write_eof(SshChannel *sc) static void ssh2channel_unclean_close(SshChannel *sc, const char *err) { - struct ssh2_channel *c = FROMFIELD(sc, struct ssh2_channel, sc); + struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc); char *reason; reason = dupprintf("due to local error: %s", err); @@ -1896,7 +1896,7 @@ static void ssh2channel_unclean_close(SshChannel *sc, const char *err) static void ssh2channel_unthrottle(SshChannel *sc, int bufsize) { - struct ssh2_channel *c = FROMFIELD(sc, struct ssh2_channel, sc); + struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc); struct ssh2_connection_state *s = c->connlayer; int buflimit; @@ -1912,7 +1912,7 @@ static void ssh2channel_unthrottle(SshChannel *sc, int bufsize) static int ssh2channel_write(SshChannel *sc, const void *buf, int len) { - struct ssh2_channel *c = FROMFIELD(sc, struct ssh2_channel, sc); + struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc); assert(!(c->closes & CLOSES_SENT_EOF)); bufchain_add(&c->outbuffer, buf, len); return ssh2_try_send(c); @@ -1923,7 +1923,7 @@ static void ssh2channel_x11_sharing_handover( const char *peer_addr, int peer_port, int endian, int protomajor, int protominor, const void *initial_data, int initial_len) { - struct ssh2_channel *c = FROMFIELD(sc, struct ssh2_channel, sc); + struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc); /* * This function is called when we've just discovered that an X * forwarding channel on which we'd been handling the initial auth @@ -1945,7 +1945,7 @@ static void ssh2channel_x11_sharing_handover( static void ssh2channel_window_override_removed(SshChannel *sc) { - struct ssh2_channel *c = FROMFIELD(sc, struct ssh2_channel, sc); + struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc); struct ssh2_connection_state *s = c->connlayer; /* @@ -1961,7 +1961,7 @@ static SshChannel *ssh2_lportfwd_open( const char *org, Channel *chan) { struct ssh2_connection_state *s = - FROMFIELD(cl, struct ssh2_connection_state, cl); + container_of(cl, struct ssh2_connection_state, cl); PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */ struct ssh2_channel *c = snew(struct ssh2_channel); PktOut *pktout; @@ -2022,7 +2022,7 @@ static struct ssh_rportfwd *ssh2_rportfwd_alloc( ssh_sharing_connstate *share_ctx) { struct ssh2_connection_state *s = - FROMFIELD(cl, struct ssh2_connection_state, cl); + container_of(cl, struct ssh2_connection_state, cl); struct ssh_rportfwd *rpf = snew(struct ssh_rportfwd); rpf->shost = dupstr(shost); @@ -2058,7 +2058,7 @@ static struct ssh_rportfwd *ssh2_rportfwd_alloc( static void ssh2_rportfwd_remove(ConnectionLayer *cl, struct ssh_rportfwd *rpf) { struct ssh2_connection_state *s = - FROMFIELD(cl, struct ssh2_connection_state, cl); + container_of(cl, struct ssh2_connection_state, cl); if (rpf->share_ctx) { /* @@ -2095,14 +2095,14 @@ static void ssh2_sharing_queue_global_request( ConnectionLayer *cl, ssh_sharing_connstate *cs) { struct ssh2_connection_state *s = - FROMFIELD(cl, struct ssh2_connection_state, cl); + container_of(cl, struct ssh2_connection_state, cl); ssh2_queue_global_request_handler(s, ssh2_sharing_globreq_response, cs); } static void ssh2_sharing_no_more_downstreams(ConnectionLayer *cl) { struct ssh2_connection_state *s = - FROMFIELD(cl, struct ssh2_connection_state, cl); + container_of(cl, struct ssh2_connection_state, cl); queue_toplevel_callback(ssh2_check_termination_callback, s); } @@ -2111,7 +2111,7 @@ static struct X11FakeAuth *ssh2_add_sharing_x11_display( share_channel *share_chan) { struct ssh2_connection_state *s = - FROMFIELD(cl, struct ssh2_connection_state, cl); + container_of(cl, struct ssh2_connection_state, cl); struct X11FakeAuth *auth; /* @@ -2130,7 +2130,7 @@ static void ssh2_remove_sharing_x11_display( ConnectionLayer *cl, struct X11FakeAuth *auth) { struct ssh2_connection_state *s = - FROMFIELD(cl, struct ssh2_connection_state, cl); + container_of(cl, struct ssh2_connection_state, cl); del234(s->x11authtree, auth); x11_free_fake_auth(auth); } @@ -2139,7 +2139,7 @@ static unsigned ssh2_alloc_sharing_channel( ConnectionLayer *cl, ssh_sharing_connstate *connstate) { struct ssh2_connection_state *s = - FROMFIELD(cl, struct ssh2_connection_state, cl); + container_of(cl, struct ssh2_connection_state, cl); struct ssh2_channel *c = snew(struct ssh2_channel); c->connlayer = s; @@ -2152,7 +2152,7 @@ static unsigned ssh2_alloc_sharing_channel( static void ssh2_delete_sharing_channel(ConnectionLayer *cl, unsigned localid) { struct ssh2_connection_state *s = - FROMFIELD(cl, struct ssh2_connection_state, cl); + container_of(cl, struct ssh2_connection_state, cl); struct ssh2_channel *c = find234(s->channels, &localid, ssh2_channelfind); if (c) ssh2_channel_destroy(c); @@ -2163,7 +2163,7 @@ static void ssh2_send_packet_from_downstream( const void *data, int datalen, const char *additional_log_text) { struct ssh2_connection_state *s = - FROMFIELD(cl, struct ssh2_connection_state, cl); + container_of(cl, struct ssh2_connection_state, cl); PktOut *pkt = ssh_bpp_new_pktout(s->ppl.bpp, type); pkt->downstream_id = id; pkt->additional_log_text = additional_log_text; @@ -2174,7 +2174,7 @@ static void ssh2_send_packet_from_downstream( static int ssh2_agent_forwarding_permitted(ConnectionLayer *cl) { struct ssh2_connection_state *s = - FROMFIELD(cl, struct ssh2_connection_state, cl); + container_of(cl, struct ssh2_connection_state, cl); return conf_get_int(s->conf, CONF_agentfwd) && agent_exists(); } @@ -2210,7 +2210,7 @@ static mainchan *mainchan_new(struct ssh2_connection_state *s) static void mainchan_free(Channel *chan) { assert(chan->vt == &mainchan_channelvt); - mainchan *mc = FROMFIELD(chan, mainchan, chan); + mainchan *mc = container_of(chan, mainchan, chan); struct ssh2_connection_state *s = mc->connlayer; s->mainchan = NULL; sfree(mc); @@ -2218,7 +2218,7 @@ static void mainchan_free(Channel *chan) static void mainchan_open_confirmation(Channel *chan) { - mainchan *mc = FROMFIELD(chan, mainchan, chan); + mainchan *mc = container_of(chan, mainchan, chan); struct ssh2_connection_state *s = mc->connlayer; PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */ @@ -2229,7 +2229,7 @@ static void mainchan_open_confirmation(Channel *chan) static void mainchan_open_failure(Channel *chan, const char *errtext) { assert(chan->vt == &mainchan_channelvt); - mainchan *mc = FROMFIELD(chan, mainchan, chan); + mainchan *mc = container_of(chan, mainchan, chan); struct ssh2_connection_state *s = mc->connlayer; /* @@ -2244,7 +2244,7 @@ static int mainchan_send(Channel *chan, int is_stderr, const void *data, int length) { assert(chan->vt == &mainchan_channelvt); - mainchan *mc = FROMFIELD(chan, mainchan, chan); + mainchan *mc = container_of(chan, mainchan, chan); struct ssh2_connection_state *s = mc->connlayer; return from_backend(s->ppl.frontend, is_stderr, data, length); } @@ -2252,7 +2252,7 @@ static int mainchan_send(Channel *chan, int is_stderr, static void mainchan_send_eof(Channel *chan) { assert(chan->vt == &mainchan_channelvt); - mainchan *mc = FROMFIELD(chan, mainchan, chan); + mainchan *mc = container_of(chan, mainchan, chan); struct ssh2_connection_state *s = mc->connlayer; PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */ @@ -2275,7 +2275,7 @@ static void mainchan_send_eof(Channel *chan) static void mainchan_set_input_wanted(Channel *chan, int wanted) { assert(chan->vt == &mainchan_channelvt); - mainchan *mc = FROMFIELD(chan, mainchan, chan); + mainchan *mc = container_of(chan, mainchan, chan); struct ssh2_connection_state *s = mc->connlayer; /* @@ -2321,7 +2321,7 @@ static int ssh2_connection_get_specials( PacketProtocolLayer *ppl, add_special_fn_t add_special, void *ctx) { struct ssh2_connection_state *s = - FROMFIELD(ppl, struct ssh2_connection_state, ppl); + container_of(ppl, struct ssh2_connection_state, ppl); int toret = FALSE; if (s->mainchan) { @@ -2381,7 +2381,7 @@ static void ssh2_connection_special_cmd(PacketProtocolLayer *ppl, SessionSpecialCode code, int arg) { struct ssh2_connection_state *s = - FROMFIELD(ppl, struct ssh2_connection_state, ppl); + container_of(ppl, struct ssh2_connection_state, ppl); PktOut *pktout; const char *signame; @@ -2421,7 +2421,7 @@ static void ssh2_connection_special_cmd(PacketProtocolLayer *ppl, static void ssh2_terminal_size(ConnectionLayer *cl, int width, int height) { struct ssh2_connection_state *s = - FROMFIELD(cl, struct ssh2_connection_state, cl); + container_of(cl, struct ssh2_connection_state, cl); s->term_width = width; s->term_height = height; @@ -2440,7 +2440,7 @@ static void ssh2_terminal_size(ConnectionLayer *cl, int width, int height) static void ssh2_stdout_unthrottle(ConnectionLayer *cl, int bufsize) { struct ssh2_connection_state *s = - FROMFIELD(cl, struct ssh2_connection_state, cl); + container_of(cl, struct ssh2_connection_state, cl); if (s->mainchan) ssh2channel_unthrottle(&s->mainchan->sc, bufsize); @@ -2449,7 +2449,7 @@ static void ssh2_stdout_unthrottle(ConnectionLayer *cl, int bufsize) static int ssh2_stdin_backlog(ConnectionLayer *cl) { struct ssh2_connection_state *s = - FROMFIELD(cl, struct ssh2_connection_state, cl); + container_of(cl, struct ssh2_connection_state, cl); return s->mainchan ? bufchain_size(&s->mainchan->outbuffer) : 0; } @@ -2457,7 +2457,7 @@ static int ssh2_stdin_backlog(ConnectionLayer *cl) static void ssh2_throttle_all_channels(ConnectionLayer *cl, int throttled) { struct ssh2_connection_state *s = - FROMFIELD(cl, struct ssh2_connection_state, cl); + container_of(cl, struct ssh2_connection_state, cl); struct ssh2_channel *c; int i; @@ -2470,7 +2470,7 @@ static void ssh2_throttle_all_channels(ConnectionLayer *cl, int throttled) static int ssh2_ldisc_option(ConnectionLayer *cl, int option) { struct ssh2_connection_state *s = - FROMFIELD(cl, struct ssh2_connection_state, cl); + container_of(cl, struct ssh2_connection_state, cl); /* We always return the same value for LD_ECHO and LD_EDIT */ return s->echoedit; @@ -2479,14 +2479,14 @@ static int ssh2_ldisc_option(ConnectionLayer *cl, int option) static int ssh2_connection_want_user_input(PacketProtocolLayer *ppl) { struct ssh2_connection_state *s = - FROMFIELD(ppl, struct ssh2_connection_state, ppl); + container_of(ppl, struct ssh2_connection_state, ppl); return s->mainchan_ready && s->want_user_input; } static void ssh2_connection_got_user_input(PacketProtocolLayer *ppl) { struct ssh2_connection_state *s = - FROMFIELD(ppl, struct ssh2_connection_state, ppl); + container_of(ppl, struct ssh2_connection_state, ppl); while (s->mainchan && bufchain_size(s->ppl.user_input) > 0) { /* @@ -2503,7 +2503,7 @@ static void ssh2_connection_got_user_input(PacketProtocolLayer *ppl) static void ssh2_connection_reconfigure(PacketProtocolLayer *ppl, Conf *conf) { struct ssh2_connection_state *s = - FROMFIELD(ppl, struct ssh2_connection_state, ppl); + container_of(ppl, struct ssh2_connection_state, ppl); conf_free(s->conf); s->conf = conf_copy(conf); diff --git a/ssh2transport.c b/ssh2transport.c index 9a5a970d..bec55dac 100644 --- a/ssh2transport.c +++ b/ssh2transport.c @@ -357,7 +357,7 @@ PacketProtocolLayer *ssh2_transport_new( static void ssh2_transport_free(PacketProtocolLayer *ppl) { struct ssh2_transport_state *s = - FROMFIELD(ppl, struct ssh2_transport_state, ppl); + container_of(ppl, struct ssh2_transport_state, ppl); /* * As our last act before being freed, move any outgoing packets @@ -596,7 +596,7 @@ static PktIn *ssh2_transport_pop(struct ssh2_transport_state *s) static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) { struct ssh2_transport_state *s = - FROMFIELD(ppl, struct ssh2_transport_state, ppl); + container_of(ppl, struct ssh2_transport_state, ppl); PktIn *pktin; PktOut *pktout; @@ -2767,7 +2767,7 @@ ptrlen ssh2_transport_get_session_id(PacketProtocolLayer *ppl) struct ssh2_transport_state *s; assert(ppl->vt == &ssh2_transport_vtable); - s = FROMFIELD(ppl, struct ssh2_transport_state, ppl); + s = container_of(ppl, struct ssh2_transport_state, ppl); assert(s->got_session_id); return make_ptrlen(s->session_id, s->session_id_len); @@ -2778,7 +2778,7 @@ void ssh2_transport_notify_auth_done(PacketProtocolLayer *ppl) struct ssh2_transport_state *s; assert(ppl->vt == &ssh2_transport_vtable); - s = FROMFIELD(ppl, struct ssh2_transport_state, ppl); + s = container_of(ppl, struct ssh2_transport_state, ppl); s->rekey_reason = NULL; /* will be filled in later */ s->rekey_class = RK_POST_USERAUTH; @@ -2791,7 +2791,7 @@ static int ssh2_transport_get_specials( PacketProtocolLayer *ppl, add_special_fn_t add_special, void *ctx) { struct ssh2_transport_state *s = - FROMFIELD(ppl, struct ssh2_transport_state, ppl); + container_of(ppl, struct ssh2_transport_state, ppl); int need_separator = FALSE; int toret; @@ -2836,7 +2836,7 @@ static void ssh2_transport_special_cmd(PacketProtocolLayer *ppl, SessionSpecialCode code, int arg) { struct ssh2_transport_state *s = - FROMFIELD(ppl, struct ssh2_transport_state, ppl); + container_of(ppl, struct ssh2_transport_state, ppl); if (code == SS_REKEY) { if (!s->kex_in_progress) { @@ -2884,7 +2884,7 @@ static void ssh2_transport_reconfigure(PacketProtocolLayer *ppl, Conf *conf) int i; assert(ppl->vt == &ssh2_transport_vtable); - s = FROMFIELD(ppl, struct ssh2_transport_state, ppl); + s = container_of(ppl, struct ssh2_transport_state, ppl); rekey_time = sanitise_rekey_time( conf_get_int(conf, CONF_ssh_rekey_time), 60); @@ -2951,7 +2951,7 @@ static void ssh2_transport_reconfigure(PacketProtocolLayer *ppl, Conf *conf) static int ssh2_transport_want_user_input(PacketProtocolLayer *ppl) { struct ssh2_transport_state *s = - FROMFIELD(ppl, struct ssh2_transport_state, ppl); + container_of(ppl, struct ssh2_transport_state, ppl); /* Just delegate this to the higher layer */ return ssh_ppl_want_user_input(s->higher_layer); @@ -2960,7 +2960,7 @@ static int ssh2_transport_want_user_input(PacketProtocolLayer *ppl) static void ssh2_transport_got_user_input(PacketProtocolLayer *ppl) { struct ssh2_transport_state *s = - FROMFIELD(ppl, struct ssh2_transport_state, ppl); + container_of(ppl, struct ssh2_transport_state, ppl); /* Just delegate this to the higher layer */ ssh_ppl_got_user_input(s->higher_layer); diff --git a/ssh2userauth.c b/ssh2userauth.c index 1e5a1207..5dbb7394 100644 --- a/ssh2userauth.c +++ b/ssh2userauth.c @@ -145,14 +145,14 @@ void ssh2_userauth_set_transport_layer(PacketProtocolLayer *userauth, PacketProtocolLayer *transport) { struct ssh2_userauth_state *s = - FROMFIELD(userauth, struct ssh2_userauth_state, ppl); + container_of(userauth, struct ssh2_userauth_state, ppl); s->transport_layer = transport; } static void ssh2_userauth_free(PacketProtocolLayer *ppl) { struct ssh2_userauth_state *s = - FROMFIELD(ppl, struct ssh2_userauth_state, ppl); + container_of(ppl, struct ssh2_userauth_state, ppl); bufchain_clear(&s->banner); if (s->successor_layer) @@ -198,7 +198,7 @@ static PktIn *ssh2_userauth_pop(struct ssh2_userauth_state *s) static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) { struct ssh2_userauth_state *s = - FROMFIELD(ppl, struct ssh2_userauth_state, ppl); + container_of(ppl, struct ssh2_userauth_state, ppl); PktIn *pktin; ssh2_userauth_filter_queue(s); /* no matter why we were called */ @@ -1653,14 +1653,14 @@ static void ssh2_userauth_special_cmd(PacketProtocolLayer *ppl, static int ssh2_userauth_want_user_input(PacketProtocolLayer *ppl) { struct ssh2_userauth_state *s = - FROMFIELD(ppl, struct ssh2_userauth_state, ppl); + container_of(ppl, struct ssh2_userauth_state, ppl); return s->want_user_input; } static void ssh2_userauth_got_user_input(PacketProtocolLayer *ppl) { struct ssh2_userauth_state *s = - FROMFIELD(ppl, struct ssh2_userauth_state, ppl); + container_of(ppl, struct ssh2_userauth_state, ppl); if (s->want_user_input) queue_idempotent_callback(&s->ppl.ic_process_queue); } @@ -1668,6 +1668,6 @@ static void ssh2_userauth_got_user_input(PacketProtocolLayer *ppl) static void ssh2_userauth_reconfigure(PacketProtocolLayer *ppl, Conf *conf) { struct ssh2_userauth_state *s = - FROMFIELD(ppl, struct ssh2_userauth_state, ppl); + container_of(ppl, struct ssh2_userauth_state, ppl); ssh_ppl_reconfigure(s->successor_layer, conf); } diff --git a/sshaes.c b/sshaes.c index 06e82f54..0790fc61 100644 --- a/sshaes.c +++ b/sshaes.c @@ -1054,38 +1054,38 @@ ssh2_cipher *aes_ssh2_new(const struct ssh2_cipheralg *alg) static void aes_ssh2_free(ssh2_cipher *cipher) { - struct aes_ssh2_ctx *ctx = FROMFIELD(cipher, struct aes_ssh2_ctx, vt); + struct aes_ssh2_ctx *ctx = container_of(cipher, struct aes_ssh2_ctx, vt); smemclr(ctx, sizeof(*ctx)); sfree(ctx); } static void aes_ssh2_setiv(ssh2_cipher *cipher, const void *iv) { - struct aes_ssh2_ctx *ctx = FROMFIELD(cipher, struct aes_ssh2_ctx, vt); + struct aes_ssh2_ctx *ctx = container_of(cipher, struct aes_ssh2_ctx, vt); aes_iv(&ctx->context, iv); } static void aes_ssh2_setkey(ssh2_cipher *cipher, const void *key) { - struct aes_ssh2_ctx *ctx = FROMFIELD(cipher, struct aes_ssh2_ctx, vt); + struct aes_ssh2_ctx *ctx = container_of(cipher, struct aes_ssh2_ctx, vt); aes_setup(&ctx->context, key, ctx->vt->padded_keybytes); } static void aes_ssh2_encrypt(ssh2_cipher *cipher, void *blk, int len) { - struct aes_ssh2_ctx *ctx = FROMFIELD(cipher, struct aes_ssh2_ctx, vt); + struct aes_ssh2_ctx *ctx = container_of(cipher, struct aes_ssh2_ctx, vt); aes_encrypt_cbc(blk, len, &ctx->context); } static void aes_ssh2_decrypt(ssh2_cipher *cipher, void *blk, int len) { - struct aes_ssh2_ctx *ctx = FROMFIELD(cipher, struct aes_ssh2_ctx, vt); + struct aes_ssh2_ctx *ctx = container_of(cipher, struct aes_ssh2_ctx, vt); aes_decrypt_cbc(blk, len, &ctx->context); } static void aes_ssh2_sdctr_method(ssh2_cipher *cipher, void *blk, int len) { - struct aes_ssh2_ctx *ctx = FROMFIELD(cipher, struct aes_ssh2_ctx, vt); + struct aes_ssh2_ctx *ctx = container_of(cipher, struct aes_ssh2_ctx, vt); aes_sdctr(blk, len, &ctx->context); } diff --git a/ssharcf.c b/ssharcf.c index 3434459c..fe1282fa 100644 --- a/ssharcf.c +++ b/ssharcf.c @@ -71,7 +71,7 @@ static ssh2_cipher *arcfour_new(const struct ssh2_cipheralg *alg) static void arcfour_free(ssh2_cipher *cipher) { - ArcfourContext *ctx = FROMFIELD(cipher, ArcfourContext, vt); + ArcfourContext *ctx = container_of(cipher, ArcfourContext, vt); smemclr(ctx, sizeof(*ctx)); sfree(ctx); } @@ -92,14 +92,14 @@ static void arcfour_ssh2_setiv(ssh2_cipher *cipher, const void *key) static void arcfour_ssh2_setkey(ssh2_cipher *cipher, const void *key) { - ArcfourContext *ctx = FROMFIELD(cipher, ArcfourContext, vt); + ArcfourContext *ctx = container_of(cipher, ArcfourContext, vt); arcfour_setkey(ctx, key, ctx->vt->padded_keybytes); arcfour_stir(ctx); } static void arcfour_ssh2_block(ssh2_cipher *cipher, void *blk, int len) { - ArcfourContext *ctx = FROMFIELD(cipher, ArcfourContext, vt); + ArcfourContext *ctx = container_of(cipher, ArcfourContext, vt); arcfour_block(ctx, blk, len); } diff --git a/sshblowf.c b/sshblowf.c index f5460518..d1d53c11 100644 --- a/sshblowf.c +++ b/sshblowf.c @@ -589,7 +589,7 @@ static ssh1_cipher *blowfish_ssh1_new(void) static void blowfish_ssh1_free(ssh1_cipher *cipher) { struct blowfish_ssh1_ctx *ctx = - FROMFIELD(cipher, struct blowfish_ssh1_ctx, vt); + container_of(cipher, struct blowfish_ssh1_ctx, vt); smemclr(ctx, sizeof(*ctx)); sfree(ctx); } @@ -597,7 +597,7 @@ static void blowfish_ssh1_free(ssh1_cipher *cipher) static void blowfish_ssh1_sesskey(ssh1_cipher *cipher, const void *key) { struct blowfish_ssh1_ctx *ctx = - FROMFIELD(cipher, struct blowfish_ssh1_ctx, vt); + container_of(cipher, struct blowfish_ssh1_ctx, vt); blowfish_setkey(&ctx->contexts[0], key, SSH1_SESSION_KEY_LENGTH); ctx->contexts[0].iv0 = ctx->contexts[0].iv1 = 0; ctx->contexts[1] = ctx->contexts[0]; /* structure copy */ @@ -606,14 +606,14 @@ static void blowfish_ssh1_sesskey(ssh1_cipher *cipher, const void *key) static void blowfish_ssh1_encrypt_blk(ssh1_cipher *cipher, void *blk, int len) { struct blowfish_ssh1_ctx *ctx = - FROMFIELD(cipher, struct blowfish_ssh1_ctx, vt); + container_of(cipher, struct blowfish_ssh1_ctx, vt); blowfish_lsb_encrypt_cbc(blk, len, ctx->contexts); } static void blowfish_ssh1_decrypt_blk(ssh1_cipher *cipher, void *blk, int len) { struct blowfish_ssh1_ctx *ctx = - FROMFIELD(cipher, struct blowfish_ssh1_ctx, vt); + container_of(cipher, struct blowfish_ssh1_ctx, vt); blowfish_lsb_decrypt_cbc(blk, len, ctx->contexts+1); } @@ -632,7 +632,7 @@ static ssh2_cipher *blowfish_ssh2_new(const struct ssh2_cipheralg *alg) static void blowfish_ssh2_free(ssh2_cipher *cipher) { struct blowfish_ssh2_ctx *ctx = - FROMFIELD(cipher, struct blowfish_ssh2_ctx, vt); + container_of(cipher, struct blowfish_ssh2_ctx, vt); smemclr(ctx, sizeof(*ctx)); sfree(ctx); } @@ -640,35 +640,35 @@ static void blowfish_ssh2_free(ssh2_cipher *cipher) static void blowfish_ssh2_setiv(ssh2_cipher *cipher, const void *iv) { struct blowfish_ssh2_ctx *ctx = - FROMFIELD(cipher, struct blowfish_ssh2_ctx, vt); + container_of(cipher, struct blowfish_ssh2_ctx, vt); blowfish_iv(&ctx->context, iv); } static void blowfish_ssh2_setkey(ssh2_cipher *cipher, const void *key) { struct blowfish_ssh2_ctx *ctx = - FROMFIELD(cipher, struct blowfish_ssh2_ctx, vt); + container_of(cipher, struct blowfish_ssh2_ctx, vt); blowfish_setkey(&ctx->context, key, ctx->vt->padded_keybytes); } static void blowfish_ssh2_encrypt_blk(ssh2_cipher *cipher, void *blk, int len) { struct blowfish_ssh2_ctx *ctx = - FROMFIELD(cipher, struct blowfish_ssh2_ctx, vt); + container_of(cipher, struct blowfish_ssh2_ctx, vt); blowfish_msb_encrypt_cbc(blk, len, &ctx->context); } static void blowfish_ssh2_decrypt_blk(ssh2_cipher *cipher, void *blk, int len) { struct blowfish_ssh2_ctx *ctx = - FROMFIELD(cipher, struct blowfish_ssh2_ctx, vt); + container_of(cipher, struct blowfish_ssh2_ctx, vt); blowfish_msb_decrypt_cbc(blk, len, &ctx->context); } static void blowfish_ssh2_sdctr(ssh2_cipher *cipher, void *blk, int len) { struct blowfish_ssh2_ctx *ctx = - FROMFIELD(cipher, struct blowfish_ssh2_ctx, vt); + container_of(cipher, struct blowfish_ssh2_ctx, vt); blowfish_msb_sdctr(blk, len, &ctx->context); } diff --git a/sshccp.c b/sshccp.c index dfcb02c8..4b26a438 100644 --- a/sshccp.c +++ b/sshccp.c @@ -873,7 +873,7 @@ struct ccp_context { static ssh2_mac *poly_ssh2_new( const struct ssh2_macalg *alg, ssh2_cipher *cipher) { - struct ccp_context *ctx = FROMFIELD(cipher, struct ccp_context, cvt); + struct ccp_context *ctx = container_of(cipher, struct ccp_context, cvt); ctx->mac_if.vt = alg; BinarySink_DELEGATE_INIT(&ctx->mac_if, ctx); return &ctx->mac_if; @@ -891,7 +891,7 @@ static void poly_setkey(ssh2_mac *mac, const void *key) static void poly_start(ssh2_mac *mac) { - struct ccp_context *ctx = FROMFIELD(mac, struct ccp_context, mac_if); + struct ccp_context *ctx = container_of(mac, struct ccp_context, mac_if); ctx->mac_initialised = 0; memset(ctx->mac_iv, 0, 8); @@ -933,7 +933,7 @@ static void poly_BinarySink_write(BinarySink *bs, const void *blkv, size_t len) static void poly_genresult(ssh2_mac *mac, unsigned char *blk) { - struct ccp_context *ctx = FROMFIELD(mac, struct ccp_context, mac_if); + struct ccp_context *ctx = container_of(mac, struct ccp_context, mac_if); poly1305_finalise(&ctx->mac, blk); } @@ -956,7 +956,7 @@ static ssh2_cipher *ccp_new(const struct ssh2_cipheralg *alg) static void ccp_free(ssh2_cipher *cipher) { - struct ccp_context *ctx = FROMFIELD(cipher, struct ccp_context, cvt); + struct ccp_context *ctx = container_of(cipher, struct ccp_context, cvt); smemclr(&ctx->a_cipher, sizeof(ctx->a_cipher)); smemclr(&ctx->b_cipher, sizeof(ctx->b_cipher)); smemclr(&ctx->mac, sizeof(ctx->mac)); @@ -965,14 +965,15 @@ static void ccp_free(ssh2_cipher *cipher) static void ccp_iv(ssh2_cipher *cipher, const void *iv) { - /* struct ccp_context *ctx = FROMFIELD(cipher, struct ccp_context, cvt); */ + /* struct ccp_context *ctx = + container_of(cipher, struct ccp_context, cvt); */ /* IV is set based on the sequence number */ } static void ccp_key(ssh2_cipher *cipher, const void *vkey) { const unsigned char *key = (const unsigned char *)vkey; - struct ccp_context *ctx = FROMFIELD(cipher, struct ccp_context, cvt); + struct ccp_context *ctx = container_of(cipher, struct ccp_context, cvt); /* Initialise the a_cipher (for decrypting lengths) with the first 256 bits */ chacha20_key(&ctx->a_cipher, key + 32); /* Initialise the b_cipher (for content and MAC) with the second 256 bits */ @@ -981,13 +982,13 @@ static void ccp_key(ssh2_cipher *cipher, const void *vkey) static void ccp_encrypt(ssh2_cipher *cipher, void *blk, int len) { - struct ccp_context *ctx = FROMFIELD(cipher, struct ccp_context, cvt); + struct ccp_context *ctx = container_of(cipher, struct ccp_context, cvt); chacha20_encrypt(&ctx->b_cipher, blk, len); } static void ccp_decrypt(ssh2_cipher *cipher, void *blk, int len) { - struct ccp_context *ctx = FROMFIELD(cipher, struct ccp_context, cvt); + struct ccp_context *ctx = container_of(cipher, struct ccp_context, cvt); chacha20_decrypt(&ctx->b_cipher, blk, len); } @@ -1011,7 +1012,7 @@ static void ccp_length_op(struct ccp_context *ctx, void *blk, int len, static void ccp_encrypt_length(ssh2_cipher *cipher, void *blk, int len, unsigned long seq) { - struct ccp_context *ctx = FROMFIELD(cipher, struct ccp_context, cvt); + struct ccp_context *ctx = container_of(cipher, struct ccp_context, cvt); ccp_length_op(ctx, blk, len, seq); chacha20_encrypt(&ctx->a_cipher, blk, len); } @@ -1019,7 +1020,7 @@ static void ccp_encrypt_length(ssh2_cipher *cipher, void *blk, int len, static void ccp_decrypt_length(ssh2_cipher *cipher, void *blk, int len, unsigned long seq) { - struct ccp_context *ctx = FROMFIELD(cipher, struct ccp_context, cvt); + struct ccp_context *ctx = container_of(cipher, struct ccp_context, cvt); ccp_length_op(ctx, blk, len, seq); chacha20_decrypt(&ctx->a_cipher, blk, len); } diff --git a/sshcommon.c b/sshcommon.c index ac4a6715..f7007ea9 100644 --- a/sshcommon.c +++ b/sshcommon.c @@ -59,7 +59,7 @@ static void pktin_free_queue_callback(void *vctx) { while (pktin_freeq_head.next != &pktin_freeq_head) { PacketQueueNode *node = pktin_freeq_head.next; - PktIn *pktin = FROMFIELD(node, PktIn, qnode); + PktIn *pktin = container_of(node, PktIn, qnode); pktin_freeq_head.next = node->next; sfree(pktin); } @@ -89,7 +89,7 @@ static PktIn *pq_in_get(PacketQueueBase *pqb, int pop) queue_idempotent_callback(&ic_pktin_free); } - return FROMFIELD(node, PktIn, qnode); + return container_of(node, PktIn, qnode); } static PktOut *pq_out_get(PacketQueueBase *pqb, int pop) @@ -104,7 +104,7 @@ static PktOut *pq_out_get(PacketQueueBase *pqb, int pop) node->prev = node->next = NULL; } - return FROMFIELD(node, PktOut, qnode); + return container_of(node, PktOut, qnode); } void pq_in_init(PktInQueue *pq) diff --git a/sshdes.c b/sshdes.c index d35c894e..b69e9bc0 100644 --- a/sshdes.c +++ b/sshdes.c @@ -800,53 +800,53 @@ static ssh1_cipher *des_ssh1_new(void) static void des3_ssh1_free(ssh1_cipher *cipher) { - struct des3_ssh1_ctx *ctx = FROMFIELD(cipher, struct des3_ssh1_ctx, vt); + struct des3_ssh1_ctx *ctx = container_of(cipher, struct des3_ssh1_ctx, vt); smemclr(ctx, sizeof(*ctx)); sfree(ctx); } static void des_ssh1_free(ssh1_cipher *cipher) { - struct des_ssh1_ctx *ctx = FROMFIELD(cipher, struct des_ssh1_ctx, vt); + struct des_ssh1_ctx *ctx = container_of(cipher, struct des_ssh1_ctx, vt); smemclr(ctx, sizeof(*ctx)); sfree(ctx); } static void des3_ssh1_sesskey(ssh1_cipher *cipher, const void *key) { - struct des3_ssh1_ctx *ctx = FROMFIELD(cipher, struct des3_ssh1_ctx, vt); + struct des3_ssh1_ctx *ctx = container_of(cipher, struct des3_ssh1_ctx, vt); des3_key(ctx->contexts, key); des3_key(ctx->contexts+3, key); } static void des3_ssh1_encrypt_blk(ssh1_cipher *cipher, void *blk, int len) { - struct des3_ssh1_ctx *ctx = FROMFIELD(cipher, struct des3_ssh1_ctx, vt); + struct des3_ssh1_ctx *ctx = container_of(cipher, struct des3_ssh1_ctx, vt); des_3cbc_encrypt(blk, len, ctx->contexts); } static void des3_ssh1_decrypt_blk(ssh1_cipher *cipher, void *blk, int len) { - struct des3_ssh1_ctx *ctx = FROMFIELD(cipher, struct des3_ssh1_ctx, vt); + struct des3_ssh1_ctx *ctx = container_of(cipher, struct des3_ssh1_ctx, vt); des_3cbc_decrypt(blk, len, ctx->contexts+3); } static void des_ssh1_sesskey(ssh1_cipher *cipher, const void *key) { - struct des_ssh1_ctx *ctx = FROMFIELD(cipher, struct des_ssh1_ctx, vt); + struct des_ssh1_ctx *ctx = container_of(cipher, struct des_ssh1_ctx, vt); des_key(ctx->contexts, key); des_key(ctx->contexts+1, key); } static void des_ssh1_encrypt_blk(ssh1_cipher *cipher, void *blk, int len) { - struct des_ssh1_ctx *ctx = FROMFIELD(cipher, struct des_ssh1_ctx, vt); + struct des_ssh1_ctx *ctx = container_of(cipher, struct des_ssh1_ctx, vt); des_cbc_encrypt(blk, len, ctx->contexts); } static void des_ssh1_decrypt_blk(ssh1_cipher *cipher, void *blk, int len) { - struct des_ssh1_ctx *ctx = FROMFIELD(cipher, struct des_ssh1_ctx, vt); + struct des_ssh1_ctx *ctx = container_of(cipher, struct des_ssh1_ctx, vt); des_cbc_decrypt(blk, len, ctx->contexts+1); } @@ -876,21 +876,21 @@ static ssh2_cipher *des_ssh2_new(const struct ssh2_cipheralg *alg) static void des3_ssh2_free(ssh2_cipher *cipher) { - struct des3_ssh2_ctx *ctx = FROMFIELD(cipher, struct des3_ssh2_ctx, vt); + struct des3_ssh2_ctx *ctx = container_of(cipher, struct des3_ssh2_ctx, vt); smemclr(ctx, sizeof(*ctx)); sfree(ctx); } static void des_ssh2_free(ssh2_cipher *cipher) { - struct des_ssh2_ctx *ctx = FROMFIELD(cipher, struct des_ssh2_ctx, vt); + struct des_ssh2_ctx *ctx = container_of(cipher, struct des_ssh2_ctx, vt); smemclr(ctx, sizeof(*ctx)); sfree(ctx); } static void des3_ssh2_setiv(ssh2_cipher *cipher, const void *iv) { - struct des3_ssh2_ctx *ctx = FROMFIELD(cipher, struct des3_ssh2_ctx, vt); + struct des3_ssh2_ctx *ctx = container_of(cipher, struct des3_ssh2_ctx, vt); des_iv(&ctx->contexts[0], iv); /* SSH-2 treats triple-DES as a single block cipher to wrap in * CBC, so there's only one IV required, not three */ @@ -898,49 +898,49 @@ static void des3_ssh2_setiv(ssh2_cipher *cipher, const void *iv) static void des3_ssh2_setkey(ssh2_cipher *cipher, const void *key) { - struct des3_ssh2_ctx *ctx = FROMFIELD(cipher, struct des3_ssh2_ctx, vt); + struct des3_ssh2_ctx *ctx = container_of(cipher, struct des3_ssh2_ctx, vt); des3_key(ctx->contexts, key); } static void des_ssh2_setiv(ssh2_cipher *cipher, const void *iv) { - struct des_ssh2_ctx *ctx = FROMFIELD(cipher, struct des_ssh2_ctx, vt); + struct des_ssh2_ctx *ctx = container_of(cipher, struct des_ssh2_ctx, vt); des_iv(&ctx->context, iv); } static void des_ssh2_setkey(ssh2_cipher *cipher, const void *key) { - struct des_ssh2_ctx *ctx = FROMFIELD(cipher, struct des_ssh2_ctx, vt); + struct des_ssh2_ctx *ctx = container_of(cipher, struct des_ssh2_ctx, vt); des_key(&ctx->context, key); } static void des3_ssh2_encrypt_blk(ssh2_cipher *cipher, void *blk, int len) { - struct des3_ssh2_ctx *ctx = FROMFIELD(cipher, struct des3_ssh2_ctx, vt); + struct des3_ssh2_ctx *ctx = container_of(cipher, struct des3_ssh2_ctx, vt); des_cbc3_encrypt(blk, len, ctx->contexts); } static void des3_ssh2_decrypt_blk(ssh2_cipher *cipher, void *blk, int len) { - struct des3_ssh2_ctx *ctx = FROMFIELD(cipher, struct des3_ssh2_ctx, vt); + struct des3_ssh2_ctx *ctx = container_of(cipher, struct des3_ssh2_ctx, vt); des_cbc3_decrypt(blk, len, ctx->contexts); } static void des3_ssh2_sdctr(ssh2_cipher *cipher, void *blk, int len) { - struct des3_ssh2_ctx *ctx = FROMFIELD(cipher, struct des3_ssh2_ctx, vt); + struct des3_ssh2_ctx *ctx = container_of(cipher, struct des3_ssh2_ctx, vt); des_sdctr3(blk, len, ctx->contexts); } static void des_ssh2_encrypt_blk(ssh2_cipher *cipher, void *blk, int len) { - struct des_ssh2_ctx *ctx = FROMFIELD(cipher, struct des_ssh2_ctx, vt); + struct des_ssh2_ctx *ctx = container_of(cipher, struct des_ssh2_ctx, vt); des_cbc_encrypt(blk, len, &ctx->context); } static void des_ssh2_decrypt_blk(ssh2_cipher *cipher, void *blk, int len) { - struct des_ssh2_ctx *ctx = FROMFIELD(cipher, struct des_ssh2_ctx, vt); + struct des_ssh2_ctx *ctx = container_of(cipher, struct des_ssh2_ctx, vt); des_cbc_decrypt(blk, len, &ctx->context); } diff --git a/sshdss.c b/sshdss.c index c4686645..3aa462b8 100644 --- a/sshdss.c +++ b/sshdss.c @@ -40,7 +40,7 @@ static ssh_key *dss_new_pub(const ssh_keyalg *self, ptrlen data) static void dss_freekey(ssh_key *key) { - struct dss_key *dss = FROMFIELD(key, struct dss_key, sshk); + struct dss_key *dss = container_of(key, struct dss_key, sshk); if (dss->p) freebn(dss->p); if (dss->q) @@ -56,7 +56,7 @@ static void dss_freekey(ssh_key *key) static char *dss_cache_str(ssh_key *key) { - struct dss_key *dss = FROMFIELD(key, struct dss_key, sshk); + struct dss_key *dss = container_of(key, struct dss_key, sshk); char *p; int len, i, pos, nibbles; static const char hex[] = "0123456789abcdef"; @@ -106,7 +106,7 @@ static char *dss_cache_str(ssh_key *key) static int dss_verify(ssh_key *key, ptrlen sig, ptrlen data) { - struct dss_key *dss = FROMFIELD(key, struct dss_key, sshk); + struct dss_key *dss = container_of(key, struct dss_key, sshk); BinarySource src[1]; unsigned char hash[20]; Bignum r, s, w, gu1p, yu2p, gu1yu2p, u1, u2, sha, v; @@ -206,7 +206,7 @@ static int dss_verify(ssh_key *key, ptrlen sig, ptrlen data) static void dss_public_blob(ssh_key *key, BinarySink *bs) { - struct dss_key *dss = FROMFIELD(key, struct dss_key, sshk); + struct dss_key *dss = container_of(key, struct dss_key, sshk); put_stringz(bs, "ssh-dss"); put_mp_ssh2(bs, dss->p); @@ -217,7 +217,7 @@ static void dss_public_blob(ssh_key *key, BinarySink *bs) static void dss_private_blob(ssh_key *key, BinarySink *bs) { - struct dss_key *dss = FROMFIELD(key, struct dss_key, sshk); + struct dss_key *dss = container_of(key, struct dss_key, sshk); put_mp_ssh2(bs, dss->x); } @@ -236,7 +236,7 @@ static ssh_key *dss_new_priv(const ssh_keyalg *self, ptrlen pub, ptrlen priv) if (!sshk) return NULL; - dss = FROMFIELD(sshk, struct dss_key, sshk); + dss = container_of(sshk, struct dss_key, sshk); BinarySource_BARE_INIT(src, priv.ptr, priv.len); dss->x = get_mp_ssh2(src); if (get_err(src)) { @@ -300,7 +300,7 @@ static ssh_key *dss_new_priv_openssh(const ssh_keyalg *self, static void dss_openssh_blob(ssh_key *key, BinarySink *bs) { - struct dss_key *dss = FROMFIELD(key, struct dss_key, sshk); + struct dss_key *dss = container_of(key, struct dss_key, sshk); put_mp_ssh2(bs, dss->p); put_mp_ssh2(bs, dss->q); @@ -319,7 +319,7 @@ static int dss_pubkey_bits(const ssh_keyalg *self, ptrlen pub) if (!sshk) return -1; - dss = FROMFIELD(sshk, struct dss_key, sshk); + dss = container_of(sshk, struct dss_key, sshk); ret = bignum_bitcount(dss->p); dss_freekey(&dss->sshk); @@ -449,7 +449,7 @@ Bignum *dss_gen_k(const char *id_string, Bignum modulus, Bignum private_key, static void dss_sign(ssh_key *key, const void *data, int datalen, BinarySink *bs) { - struct dss_key *dss = FROMFIELD(key, struct dss_key, sshk); + struct dss_key *dss = container_of(key, struct dss_key, sshk); Bignum k, gkp, hash, kinv, hxr, r, s; unsigned char digest[20]; int i; diff --git a/sshecc.c b/sshecc.c index 34d0e948..2806ea51 100644 --- a/sshecc.c +++ b/sshecc.c @@ -1700,7 +1700,7 @@ static void ecdsa_freekey(ssh_key *key) struct ec_key *ec; if (!key) return; - ec = FROMFIELD(key, struct ec_key, sshk); + ec = container_of(key, struct ec_key, sshk); if (ec->publicKey.x) freebn(ec->publicKey.x); @@ -1760,7 +1760,7 @@ static ssh_key *ecdsa_new_pub(const ssh_keyalg *self, ptrlen data) static char *ecdsa_cache_str(ssh_key *key) { - struct ec_key *ec = FROMFIELD(key, struct ec_key, sshk); + struct ec_key *ec = container_of(key, struct ec_key, sshk); char *p; int len, i, pos, nibbles; static const char hex[] = "0123456789abcdef"; @@ -1799,7 +1799,7 @@ static char *ecdsa_cache_str(ssh_key *key) static void ecdsa_public_blob(ssh_key *key, BinarySink *bs) { - struct ec_key *ec = FROMFIELD(key, struct ec_key, sshk); + struct ec_key *ec = container_of(key, struct ec_key, sshk); int pointlen; int i; @@ -1839,7 +1839,7 @@ static void ecdsa_public_blob(ssh_key *key, BinarySink *bs) static void ecdsa_private_blob(ssh_key *key, BinarySink *bs) { - struct ec_key *ec = FROMFIELD(key, struct ec_key, sshk); + struct ec_key *ec = container_of(key, struct ec_key, sshk); int keylen; int i; @@ -1875,7 +1875,7 @@ static ssh_key *ecdsa_new_priv(const ssh_keyalg *self, ptrlen pub, ptrlen priv) if (!sshk) return NULL; - ec = FROMFIELD(sshk, struct ec_key, sshk); + ec = container_of(sshk, struct ec_key, sshk); BinarySource_BARE_INIT(src, priv.ptr, priv.len); if (ec->publicKey.curve->type != EC_WEIERSTRASS @@ -1967,7 +1967,7 @@ static ssh_key *ed25519_new_priv_openssh(const ssh_keyalg *self, static void ed25519_openssh_blob(ssh_key *key, BinarySink *bs) { - struct ec_key *ec = FROMFIELD(key, struct ec_key, sshk); + struct ec_key *ec = container_of(key, struct ec_key, sshk); strbuf *pub; int pointlen; @@ -2068,7 +2068,7 @@ static ssh_key *ecdsa_new_priv_openssh(const ssh_keyalg *self, static void ecdsa_openssh_blob(ssh_key *key, BinarySink *bs) { - struct ec_key *ec = FROMFIELD(key, struct ec_key, sshk); + struct ec_key *ec = container_of(key, struct ec_key, sshk); int pointlen; int i; @@ -2099,7 +2099,7 @@ static int ecdsa_pubkey_bits(const ssh_keyalg *self, ptrlen blob) if (!sshk) return -1; - ec = FROMFIELD(sshk, struct ec_key, sshk); + ec = container_of(sshk, struct ec_key, sshk); ret = ec->publicKey.curve->fieldBits; ecdsa_freekey(&ec->sshk); @@ -2108,7 +2108,7 @@ static int ecdsa_pubkey_bits(const ssh_keyalg *self, ptrlen blob) static int ecdsa_verify(ssh_key *key, ptrlen sig, ptrlen data) { - struct ec_key *ec = FROMFIELD(key, struct ec_key, sshk); + struct ec_key *ec = container_of(key, struct ec_key, sshk); const struct ecsign_extra *extra = (const struct ecsign_extra *)ec->sshk->extra; BinarySource src[1]; @@ -2258,7 +2258,7 @@ static int ecdsa_verify(ssh_key *key, ptrlen sig, ptrlen data) static void ecdsa_sign(ssh_key *key, const void *data, int datalen, BinarySink *bs) { - struct ec_key *ec = FROMFIELD(key, struct ec_key, sshk); + struct ec_key *ec = container_of(key, struct ec_key, sshk); const struct ecsign_extra *extra = (const struct ecsign_extra *)ec->sshk->extra; unsigned char digest[512 / 8]; diff --git a/sshmd5.c b/sshmd5.c index 35a21df4..743df03f 100644 --- a/sshmd5.c +++ b/sshmd5.c @@ -256,7 +256,8 @@ void hmacmd5_free_context(struct hmacmd5_context *ctx) static void hmacmd5_ssh2_free(ssh2_mac *mac) { - struct hmacmd5_context *ctx = FROMFIELD(mac, struct hmacmd5_context, mac); + struct hmacmd5_context *ctx = + container_of(mac, struct hmacmd5_context, mac); hmacmd5_free_context(ctx); } @@ -283,13 +284,15 @@ void hmacmd5_key(struct hmacmd5_context *ctx, void const *keyv, int len) static void hmacmd5_ssh2_setkey(ssh2_mac *mac, const void *key) { - struct hmacmd5_context *ctx = FROMFIELD(mac, struct hmacmd5_context, mac); + struct hmacmd5_context *ctx = + container_of(mac, struct hmacmd5_context, mac); hmacmd5_key(ctx, key, ctx->mac.vt->keylen); } static void hmacmd5_start(ssh2_mac *mac) { - struct hmacmd5_context *ctx = FROMFIELD(mac, struct hmacmd5_context, mac); + struct hmacmd5_context *ctx = + container_of(mac, struct hmacmd5_context, mac); ctx->md5[2] = ctx->md5[0]; /* structure copy */ BinarySink_COPIED(&ctx->md5[2]); @@ -297,7 +300,8 @@ static void hmacmd5_start(ssh2_mac *mac) static void hmacmd5_genresult(ssh2_mac *mac, unsigned char *hmac) { - struct hmacmd5_context *ctx = FROMFIELD(mac, struct hmacmd5_context, mac); + struct hmacmd5_context *ctx = + container_of(mac, struct hmacmd5_context, mac); struct MD5Context s; unsigned char intermediate[16]; diff --git a/sshrsa.c b/sshrsa.c index c2bc4bfb..4d4ea5b1 100644 --- a/sshrsa.c +++ b/sshrsa.c @@ -501,14 +501,14 @@ static ssh_key *rsa2_new_pub(const ssh_keyalg *self, ptrlen data) static void rsa2_freekey(ssh_key *key) { - struct RSAKey *rsa = FROMFIELD(key, struct RSAKey, sshk); + struct RSAKey *rsa = container_of(key, struct RSAKey, sshk); freersakey(rsa); sfree(rsa); } static char *rsa2_cache_str(ssh_key *key) { - struct RSAKey *rsa = FROMFIELD(key, struct RSAKey, sshk); + struct RSAKey *rsa = container_of(key, struct RSAKey, sshk); char *p; int len; @@ -520,7 +520,7 @@ static char *rsa2_cache_str(ssh_key *key) static void rsa2_public_blob(ssh_key *key, BinarySink *bs) { - struct RSAKey *rsa = FROMFIELD(key, struct RSAKey, sshk); + struct RSAKey *rsa = container_of(key, struct RSAKey, sshk); put_stringz(bs, "ssh-rsa"); put_mp_ssh2(bs, rsa->exponent); @@ -529,7 +529,7 @@ static void rsa2_public_blob(ssh_key *key, BinarySink *bs) static void rsa2_private_blob(ssh_key *key, BinarySink *bs) { - struct RSAKey *rsa = FROMFIELD(key, struct RSAKey, sshk); + struct RSAKey *rsa = container_of(key, struct RSAKey, sshk); put_mp_ssh2(bs, rsa->private_exponent); put_mp_ssh2(bs, rsa->p); @@ -548,7 +548,7 @@ static ssh_key *rsa2_new_priv(const ssh_keyalg *self, if (!sshk) return NULL; - rsa = FROMFIELD(sshk, struct RSAKey, sshk); + rsa = container_of(sshk, struct RSAKey, sshk); BinarySource_BARE_INIT(src, priv.ptr, priv.len); rsa->private_exponent = get_mp_ssh2(src); rsa->p = get_mp_ssh2(src); @@ -589,7 +589,7 @@ static ssh_key *rsa2_new_priv_openssh(const ssh_keyalg *self, static void rsa2_openssh_blob(ssh_key *key, BinarySink *bs) { - struct RSAKey *rsa = FROMFIELD(key, struct RSAKey, sshk); + struct RSAKey *rsa = container_of(key, struct RSAKey, sshk); put_mp_ssh2(bs, rsa->modulus); put_mp_ssh2(bs, rsa->exponent); @@ -609,7 +609,7 @@ static int rsa2_pubkey_bits(const ssh_keyalg *self, ptrlen pub) if (!sshk) return -1; - rsa = FROMFIELD(sshk, struct RSAKey, sshk); + rsa = container_of(sshk, struct RSAKey, sshk); ret = bignum_bitcount(rsa->modulus); rsa2_freekey(&rsa->sshk); @@ -649,7 +649,7 @@ static const unsigned char asn1_weird_stuff[] = { static int rsa2_verify(ssh_key *key, ptrlen sig, ptrlen data) { - struct RSAKey *rsa = FROMFIELD(key, struct RSAKey, sshk); + struct RSAKey *rsa = container_of(key, struct RSAKey, sshk); BinarySource src[1]; ptrlen type, in_pl; Bignum in, out; @@ -709,7 +709,7 @@ static int rsa2_verify(ssh_key *key, ptrlen sig, ptrlen data) static void rsa2_sign(ssh_key *key, const void *data, int datalen, BinarySink *bs) { - struct RSAKey *rsa = FROMFIELD(key, struct RSAKey, sshk); + struct RSAKey *rsa = container_of(key, struct RSAKey, sshk); unsigned char *bytes; int nbytes; unsigned char hash[20]; @@ -770,7 +770,7 @@ struct RSAKey *ssh_rsakex_newkey(const void *data, int len) ssh_key *sshk = rsa2_new_pub(&ssh_rsa, make_ptrlen(data, len)); if (!sshk) return NULL; - return FROMFIELD(sshk, struct RSAKey, sshk); + return container_of(sshk, struct RSAKey, sshk); } void ssh_rsakex_freekey(struct RSAKey *key) diff --git a/sshsh256.c b/sshsh256.c index 75a04495..dbdfbcf0 100644 --- a/sshsh256.c +++ b/sshsh256.c @@ -223,8 +223,8 @@ static ssh_hash *sha256_copy(ssh_hash *hashold) struct sha256_hash *hold, *hnew; ssh_hash *hashnew = sha256_new(hashold->vt); - hold = FROMFIELD(hashold, struct sha256_hash, hash); - hnew = FROMFIELD(hashnew, struct sha256_hash, hash); + hold = container_of(hashold, struct sha256_hash, hash); + hnew = container_of(hashnew, struct sha256_hash, hash); hnew->state = hold->state; BinarySink_COPIED(&hnew->state); @@ -234,7 +234,7 @@ static ssh_hash *sha256_copy(ssh_hash *hashold) static void sha256_free(ssh_hash *hash) { - struct sha256_hash *h = FROMFIELD(hash, struct sha256_hash, hash); + struct sha256_hash *h = container_of(hash, struct sha256_hash, hash); smemclr(h, sizeof(*h)); sfree(h); @@ -242,7 +242,7 @@ static void sha256_free(ssh_hash *hash) static void sha256_final(ssh_hash *hash, unsigned char *output) { - struct sha256_hash *h = FROMFIELD(hash, struct sha256_hash, hash); + struct sha256_hash *h = container_of(hash, struct sha256_hash, hash); SHA256_Final(&h->state, output); sha256_free(hash); } @@ -272,7 +272,7 @@ static ssh2_mac *hmacsha256_new( static void hmacsha256_free(ssh2_mac *mac) { - struct hmacsha256 *ctx = FROMFIELD(mac, struct hmacsha256, mac); + struct hmacsha256 *ctx = container_of(mac, struct hmacsha256, mac); smemclr(ctx, sizeof(*ctx)); sfree(ctx); } @@ -300,13 +300,13 @@ static void sha256_key_internal(struct hmacsha256 *ctx, static void hmacsha256_key(ssh2_mac *mac, const void *key) { - struct hmacsha256 *ctx = FROMFIELD(mac, struct hmacsha256, mac); + struct hmacsha256 *ctx = container_of(mac, struct hmacsha256, mac); sha256_key_internal(ctx, key, ctx->mac.vt->keylen); } static void hmacsha256_start(ssh2_mac *mac) { - struct hmacsha256 *ctx = FROMFIELD(mac, struct hmacsha256, mac); + struct hmacsha256 *ctx = container_of(mac, struct hmacsha256, mac); ctx->sha[2] = ctx->sha[0]; /* structure copy */ BinarySink_COPIED(&ctx->sha[2]); @@ -314,7 +314,7 @@ static void hmacsha256_start(ssh2_mac *mac) static void hmacsha256_genresult(ssh2_mac *mac, unsigned char *hmac) { - struct hmacsha256 *ctx = FROMFIELD(mac, struct hmacsha256, mac); + struct hmacsha256 *ctx = container_of(mac, struct hmacsha256, mac); SHA256_State s; unsigned char intermediate[32]; diff --git a/sshsh512.c b/sshsh512.c index 85df1f29..b518f6a5 100644 --- a/sshsh512.c +++ b/sshsh512.c @@ -346,8 +346,8 @@ static ssh_hash *sha512_copy(ssh_hash *hashold) struct sha512_hash *hold, *hnew; ssh_hash *hashnew = sha512_new(hashold->vt); - hold = FROMFIELD(hashold, struct sha512_hash, hash); - hnew = FROMFIELD(hashnew, struct sha512_hash, hash); + hold = container_of(hashold, struct sha512_hash, hash); + hnew = container_of(hashnew, struct sha512_hash, hash); hnew->state = hold->state; BinarySink_COPIED(&hnew->state); @@ -357,7 +357,7 @@ static ssh_hash *sha512_copy(ssh_hash *hashold) static void sha512_free(ssh_hash *hash) { - struct sha512_hash *h = FROMFIELD(hash, struct sha512_hash, hash); + struct sha512_hash *h = container_of(hash, struct sha512_hash, hash); smemclr(h, sizeof(*h)); sfree(h); @@ -365,7 +365,7 @@ static void sha512_free(ssh_hash *hash) static void sha512_final(ssh_hash *hash, unsigned char *output) { - struct sha512_hash *h = FROMFIELD(hash, struct sha512_hash, hash); + struct sha512_hash *h = container_of(hash, struct sha512_hash, hash); SHA512_Final(&h->state, output); sha512_free(hash); } @@ -385,7 +385,7 @@ static ssh_hash *sha384_new(const struct ssh_hashalg *alg) static void sha384_final(ssh_hash *hash, unsigned char *output) { - struct sha512_hash *h = FROMFIELD(hash, struct sha512_hash, hash); + struct sha512_hash *h = container_of(hash, struct sha512_hash, hash); SHA384_Final(&h->state, output); sha512_free(hash); } diff --git a/sshsha.c b/sshsha.c index 282e98a3..a7f02791 100644 --- a/sshsha.c +++ b/sshsha.c @@ -251,8 +251,8 @@ static ssh_hash *sha1_copy(ssh_hash *hashold) struct sha1_hash *hold, *hnew; ssh_hash *hashnew = sha1_new(hashold->vt); - hold = FROMFIELD(hashold, struct sha1_hash, hash); - hnew = FROMFIELD(hashnew, struct sha1_hash, hash); + hold = container_of(hashold, struct sha1_hash, hash); + hnew = container_of(hashnew, struct sha1_hash, hash); hnew->state = hold->state; BinarySink_COPIED(&hnew->state); @@ -262,7 +262,7 @@ static ssh_hash *sha1_copy(ssh_hash *hashold) static void sha1_free(ssh_hash *hash) { - struct sha1_hash *h = FROMFIELD(hash, struct sha1_hash, hash); + struct sha1_hash *h = container_of(hash, struct sha1_hash, hash); smemclr(h, sizeof(*h)); sfree(h); @@ -270,7 +270,7 @@ static void sha1_free(ssh_hash *hash) static void sha1_final(ssh_hash *hash, unsigned char *output) { - struct sha1_hash *h = FROMFIELD(hash, struct sha1_hash, hash); + struct sha1_hash *h = container_of(hash, struct sha1_hash, hash); SHA_Final(&h->state, output); sha1_free(hash); } @@ -300,7 +300,7 @@ static ssh2_mac *hmacsha1_new( static void hmacsha1_free(ssh2_mac *mac) { - struct hmacsha1 *ctx = FROMFIELD(mac, struct hmacsha1, mac); + struct hmacsha1 *ctx = container_of(mac, struct hmacsha1, mac); smemclr(ctx, sizeof(*ctx)); sfree(ctx); } @@ -328,7 +328,7 @@ static void sha1_key_internal(SHA_State *keys, static void hmacsha1_key(ssh2_mac *mac, const void *key) { - struct hmacsha1 *ctx = FROMFIELD(mac, struct hmacsha1, mac); + struct hmacsha1 *ctx = container_of(mac, struct hmacsha1, mac); /* Reading the key length out of the ssh2_macalg structure means * this same method can be used for the _buggy variants which use * a shorter key */ @@ -337,7 +337,7 @@ static void hmacsha1_key(ssh2_mac *mac, const void *key) static void hmacsha1_start(ssh2_mac *mac) { - struct hmacsha1 *ctx = FROMFIELD(mac, struct hmacsha1, mac); + struct hmacsha1 *ctx = container_of(mac, struct hmacsha1, mac); ctx->sha[2] = ctx->sha[0]; /* structure copy */ BinarySink_COPIED(&ctx->sha[2]); @@ -345,7 +345,7 @@ static void hmacsha1_start(ssh2_mac *mac) static void hmacsha1_genresult(ssh2_mac *mac, unsigned char *hmac) { - struct hmacsha1 *ctx = FROMFIELD(mac, struct hmacsha1, mac); + struct hmacsha1 *ctx = container_of(mac, struct hmacsha1, mac); SHA_State s; unsigned char intermediate[20]; diff --git a/sshshare.c b/sshshare.c index 0f35635e..688f73b2 100644 --- a/sshshare.c +++ b/sshshare.c @@ -950,7 +950,7 @@ static void share_disconnect(struct ssh_sharing_connstate *cs, static void share_closing(Plug *plug, const char *error_msg, int error_code, int calling_back) { - struct ssh_sharing_connstate *cs = FROMFIELD( + struct ssh_sharing_connstate *cs = container_of( plug, struct ssh_sharing_connstate, plug); if (error_msg) { @@ -1766,7 +1766,7 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs, static void share_receive(Plug *plug, int urgent, char *data, int len) { - ssh_sharing_connstate *cs = FROMFIELD( + ssh_sharing_connstate *cs = container_of( plug, ssh_sharing_connstate, plug); static const char expected_verstring_prefix[] = "SSHCONNECTION@putty.projects.tartarus.org-2.0-"; @@ -1842,7 +1842,7 @@ static void share_receive(Plug *plug, int urgent, char *data, int len) static void share_sent(Plug *plug, int bufsize) { - /* ssh_sharing_connstate *cs = FROMFIELD( + /* ssh_sharing_connstate *cs = container_of( plug, ssh_sharing_connstate, plug); */ /* @@ -1858,7 +1858,8 @@ static void share_sent(Plug *plug, int bufsize) static void share_listen_closing(Plug *plug, const char *error_msg, int error_code, int calling_back) { - ssh_sharing_state *sharestate = FROMFIELD(plug, ssh_sharing_state, plug); + ssh_sharing_state *sharestate = + container_of(plug, ssh_sharing_state, plug); if (error_msg) log_general(sharestate, "listening socket: %s", error_msg); sk_close(sharestate->listensock); @@ -1921,7 +1922,7 @@ static const PlugVtable ssh_sharing_conn_plugvt = { static int share_listen_accepting(Plug *plug, accept_fn_t constructor, accept_ctx_t ctx) { - struct ssh_sharing_state *sharestate = FROMFIELD( + struct ssh_sharing_state *sharestate = container_of( plug, struct ssh_sharing_state, plug); struct ssh_sharing_connstate *cs; const char *err; diff --git a/sshverstring.c b/sshverstring.c index d9bc8077..060587f4 100644 --- a/sshverstring.c +++ b/sshverstring.c @@ -107,7 +107,7 @@ BinaryPacketProtocol *ssh_verstring_new( void ssh_verstring_free(BinaryPacketProtocol *bpp) { struct ssh_verstring_state *s = - FROMFIELD(bpp, struct ssh_verstring_state, bpp); + container_of(bpp, struct ssh_verstring_state, bpp); conf_free(s->conf); sfree(s->vstring); sfree(s->protoversion); @@ -213,7 +213,7 @@ static void ssh_verstring_send(struct ssh_verstring_state *s) void ssh_verstring_handle_input(BinaryPacketProtocol *bpp) { struct ssh_verstring_state *s = - FROMFIELD(bpp, struct ssh_verstring_state, bpp); + container_of(bpp, struct ssh_verstring_state, bpp); crBegin(s->crState); @@ -604,21 +604,21 @@ static void ssh_detect_bugs(struct ssh_verstring_state *s) const char *ssh_verstring_get_remote(BinaryPacketProtocol *bpp) { struct ssh_verstring_state *s = - FROMFIELD(bpp, struct ssh_verstring_state, bpp); + container_of(bpp, struct ssh_verstring_state, bpp); return s->vstring; } const char *ssh_verstring_get_local(BinaryPacketProtocol *bpp) { struct ssh_verstring_state *s = - FROMFIELD(bpp, struct ssh_verstring_state, bpp); + container_of(bpp, struct ssh_verstring_state, bpp); return s->our_vstring; } int ssh_verstring_get_bugs(BinaryPacketProtocol *bpp) { struct ssh_verstring_state *s = - FROMFIELD(bpp, struct ssh_verstring_state, bpp); + container_of(bpp, struct ssh_verstring_state, bpp); return s->remote_bugs; } diff --git a/sshzlib.c b/sshzlib.c index ec8708b5..d0cbef8f 100644 --- a/sshzlib.c +++ b/sshzlib.c @@ -630,7 +630,7 @@ ssh_compressor *zlib_compress_init(void) void zlib_compress_cleanup(ssh_compressor *sc) { struct ssh_zlib_compressor *comp = - FROMFIELD(sc, struct ssh_zlib_compressor, sc); + container_of(sc, struct ssh_zlib_compressor, sc); sfree(comp->ectx.userdata); sfree(comp->ectx.ictx); sfree(comp); @@ -641,7 +641,7 @@ void zlib_compress_block(ssh_compressor *sc, unsigned char *block, int len, int minlen) { struct ssh_zlib_compressor *comp = - FROMFIELD(sc, struct ssh_zlib_compressor, sc); + container_of(sc, struct ssh_zlib_compressor, sc); struct Outbuf *out = (struct Outbuf *) comp->ectx.userdata; int in_block; @@ -916,7 +916,7 @@ ssh_decompressor *zlib_decompress_init(void) void zlib_decompress_cleanup(ssh_decompressor *dc) { struct zlib_decompress_ctx *dctx = - FROMFIELD(dc, struct zlib_decompress_ctx, dc); + container_of(dc, struct zlib_decompress_ctx, dc); if (dctx->currlentable && dctx->currlentable != dctx->staticlentable) zlib_freetable(&dctx->currlentable); @@ -978,7 +978,7 @@ int zlib_decompress_block(ssh_decompressor *dc, unsigned char *block, int len, unsigned char **outblock, int *outlen) { struct zlib_decompress_ctx *dctx = - FROMFIELD(dc, struct zlib_decompress_ctx, dc); + container_of(dc, struct zlib_decompress_ctx, dc); const coderecord *rec; int code, blktype, rep, dist, nlen, header; static const unsigned char lenlenmap[] = { diff --git a/telnet.c b/telnet.c index dee0aab9..fcaab876 100644 --- a/telnet.c +++ b/telnet.c @@ -645,7 +645,7 @@ static void do_telnet_read(Telnet *telnet, char *buf, int len) static void telnet_log(Plug *plug, int type, SockAddr *addr, int port, const char *error_msg, int error_code) { - Telnet *telnet = FROMFIELD(plug, Telnet, plug); + Telnet *telnet = container_of(plug, Telnet, plug); backend_socket_log(telnet->frontend, type, addr, port, error_msg, error_code, telnet->conf, telnet->session_started); @@ -654,7 +654,7 @@ static void telnet_log(Plug *plug, int type, SockAddr *addr, int port, static void telnet_closing(Plug *plug, const char *error_msg, int error_code, int calling_back) { - Telnet *telnet = FROMFIELD(plug, Telnet, plug); + Telnet *telnet = container_of(plug, Telnet, plug); /* * We don't implement independent EOF in each direction for Telnet @@ -678,7 +678,7 @@ static void telnet_closing(Plug *plug, const char *error_msg, int error_code, static void telnet_receive(Plug *plug, int urgent, char *data, int len) { - Telnet *telnet = FROMFIELD(plug, Telnet, plug); + Telnet *telnet = container_of(plug, Telnet, plug); if (urgent) telnet->in_synch = TRUE; telnet->session_started = TRUE; @@ -687,7 +687,7 @@ static void telnet_receive(Plug *plug, int urgent, char *data, int len) static void telnet_sent(Plug *plug, int bufsize) { - Telnet *telnet = FROMFIELD(plug, Telnet, plug); + Telnet *telnet = container_of(plug, Telnet, plug); telnet->bufsize = bufsize; } @@ -809,7 +809,7 @@ static const char *telnet_init(Frontend *frontend, Backend **backend_handle, static void telnet_free(Backend *be) { - Telnet *telnet = FROMFIELD(be, Telnet, backend); + Telnet *telnet = container_of(be, Telnet, backend); sfree(telnet->sb_buf); if (telnet->s) @@ -826,7 +826,7 @@ static void telnet_free(Backend *be) */ static void telnet_reconfig(Backend *be, Conf *conf) { - Telnet *telnet = FROMFIELD(be, Telnet, backend); + Telnet *telnet = container_of(be, Telnet, backend); pinger_reconfig(telnet->pinger, telnet->conf, conf); conf_free(telnet->conf); telnet->conf = conf_copy(conf); @@ -837,7 +837,7 @@ static void telnet_reconfig(Backend *be, Conf *conf) */ static int telnet_send(Backend *be, const char *buf, int len) { - Telnet *telnet = FROMFIELD(be, Telnet, backend); + Telnet *telnet = container_of(be, Telnet, backend); unsigned char *p, *end; static const unsigned char iac[2] = { IAC, IAC }; static const unsigned char cr[2] = { CR, NUL }; @@ -872,7 +872,7 @@ static int telnet_send(Backend *be, const char *buf, int len) */ static int telnet_sendbuffer(Backend *be) { - Telnet *telnet = FROMFIELD(be, Telnet, backend); + Telnet *telnet = container_of(be, Telnet, backend); return telnet->bufsize; } @@ -881,7 +881,7 @@ static int telnet_sendbuffer(Backend *be) */ static void telnet_size(Backend *be, int width, int height) { - Telnet *telnet = FROMFIELD(be, Telnet, backend); + Telnet *telnet = container_of(be, Telnet, backend); unsigned char b[24]; int n; char *logbuf; @@ -917,7 +917,7 @@ static void telnet_size(Backend *be, int width, int height) */ static void telnet_special(Backend *be, SessionSpecialCode code, int arg) { - Telnet *telnet = FROMFIELD(be, Telnet, backend); + Telnet *telnet = container_of(be, Telnet, backend); unsigned char b[2]; if (telnet->s == NULL) @@ -1022,25 +1022,25 @@ static const SessionSpecial *telnet_get_specials(Backend *be) static int telnet_connected(Backend *be) { - Telnet *telnet = FROMFIELD(be, Telnet, backend); + Telnet *telnet = container_of(be, Telnet, backend); return telnet->s != NULL; } static int telnet_sendok(Backend *be) { - /* Telnet *telnet = FROMFIELD(be, Telnet, backend); */ + /* Telnet *telnet = container_of(be, Telnet, backend); */ return 1; } static void telnet_unthrottle(Backend *be, int backlog) { - Telnet *telnet = FROMFIELD(be, Telnet, backend); + Telnet *telnet = container_of(be, Telnet, backend); sk_set_frozen(telnet->s, backlog > TELNET_MAX_BACKLOG); } static int telnet_ldisc(Backend *be, int option) { - Telnet *telnet = FROMFIELD(be, Telnet, backend); + Telnet *telnet = container_of(be, Telnet, backend); if (option == LD_ECHO) return telnet->echoing; if (option == LD_EDIT) @@ -1050,7 +1050,7 @@ static int telnet_ldisc(Backend *be, int option) static void telnet_provide_ldisc(Backend *be, Ldisc *ldisc) { - Telnet *telnet = FROMFIELD(be, Telnet, backend); + Telnet *telnet = container_of(be, Telnet, backend); telnet->ldisc = ldisc; } @@ -1061,7 +1061,7 @@ static void telnet_provide_logctx(Backend *be, LogContext *logctx) static int telnet_exitcode(Backend *be) { - Telnet *telnet = FROMFIELD(be, Telnet, backend); + Telnet *telnet = container_of(be, Telnet, backend); if (telnet->s != NULL) return -1; /* still connected */ else if (telnet->closed_on_socket_error) diff --git a/testback.c b/testback.c index 9e70819f..16f6476e 100644 --- a/testback.c +++ b/testback.c @@ -97,7 +97,7 @@ static void null_free(Backend *be) static void loop_free(Backend *be) { - struct loop_state *st = FROMFIELD(be, struct loop_state, backend); + struct loop_state *st = container_of(be, struct loop_state, backend); sfree(st); } @@ -112,7 +112,7 @@ static int null_send(Backend *be, const char *buf, int len) { } static int loop_send(Backend *be, const char *buf, int len) { - struct loop_state *st = FROMFIELD(be, struct loop_state, backend); + struct loop_state *st = container_of(be, struct loop_state, backend); return from_backend(st->frontend, 0, buf, len); } diff --git a/unix/gtkfont.c b/unix/gtkfont.c index d957476b..d0ecaa96 100644 --- a/unix/gtkfont.c +++ b/unix/gtkfont.c @@ -541,7 +541,7 @@ static unifont *x11font_create(GtkWidget *widget, const char *name, static void x11font_destroy(unifont *font) { - struct x11font *xfont = FROMFIELD(font, struct x11font, u); + struct x11font *xfont = container_of(font, struct x11font, u); Display *disp = xfont->disp; int i; @@ -579,7 +579,7 @@ static void x11_alloc_subfont(struct x11font *xfont, int sfid) static int x11font_has_glyph(unifont *font, wchar_t glyph) { - struct x11font *xfont = FROMFIELD(font, struct x11font, u); + struct x11font *xfont = container_of(font, struct x11font, u); if (xfont->sixteen_bit) { /* @@ -893,7 +893,7 @@ static void x11font_draw_text(unifont_drawctx *ctx, unifont *font, int x, int y, const wchar_t *string, int len, int wide, int bold, int cellwidth) { - struct x11font *xfont = FROMFIELD(font, struct x11font, u); + struct x11font *xfont = container_of(font, struct x11font, u); int sfid; int shadowoffset = 0; int mult = (wide ? 2 : 1); @@ -1200,7 +1200,7 @@ static char *x11font_scale_fontname(GtkWidget *widget, const char *name, static char *x11font_size_increment(unifont *font, int increment) { - struct x11font *xfont = FROMFIELD(font, struct x11font, u); + struct x11font *xfont = container_of(font, struct x11font, u); Display *disp = xfont->disp; Atom fontprop = XInternAtom(disp, "FONT", False); char *returned_name = NULL; @@ -1523,7 +1523,7 @@ static unifont *pangofont_create_fallback(GtkWidget *widget, int height, static void pangofont_destroy(unifont *font) { - struct pangofont *pfont = FROMFIELD(font, struct pangofont, u); + struct pangofont *pfont = container_of(font, struct pangofont, u); pango_font_description_free(pfont->desc); sfree(pfont->widthcache); g_object_unref(pfont->fset); @@ -1587,7 +1587,7 @@ static void pangofont_draw_internal(unifont_drawctx *ctx, unifont *font, int len, int wide, int bold, int cellwidth, int combining) { - struct pangofont *pfont = FROMFIELD(font, struct pangofont, u); + struct pangofont *pfont = container_of(font, struct pangofont, u); PangoLayout *layout; PangoRectangle rect; char *utfstring, *utfptr; @@ -2018,7 +2018,7 @@ static char *pangofont_scale_fontname(GtkWidget *widget, const char *name, static char *pangofont_size_increment(unifont *font, int increment) { - struct pangofont *pfont = FROMFIELD(font, struct pangofont, u); + struct pangofont *pfont = container_of(font, struct pangofont, u); PangoFontDescription *desc; int size; char *newname, *retname; @@ -2244,7 +2244,7 @@ unifont *multifont_create(GtkWidget *widget, const char *name, static void multifont_destroy(unifont *font) { - struct multifont *mfont = FROMFIELD(font, struct multifont, u); + struct multifont *mfont = container_of(font, struct multifont, u); unifont_destroy(mfont->main); if (mfont->fallback) unifont_destroy(mfont->fallback); @@ -2261,7 +2261,7 @@ static void multifont_draw_main(unifont_drawctx *ctx, unifont *font, int x, int wide, int bold, int cellwidth, int cellinc, unifont_draw_func_t draw) { - struct multifont *mfont = FROMFIELD(font, struct multifont, u); + struct multifont *mfont = container_of(font, struct multifont, u); unifont *f; int ok, i; @@ -2307,7 +2307,7 @@ static void multifont_draw_combining(unifont_drawctx *ctx, unifont *font, static char *multifont_size_increment(unifont *font, int increment) { - struct multifont *mfont = FROMFIELD(font, struct multifont, u); + struct multifont *mfont = container_of(font, struct multifont, u); return unifont_size_increment(mfont->main, increment); } @@ -3680,7 +3680,7 @@ unifontsel *unifontsel_new(const char *wintitle) void unifontsel_destroy(unifontsel *fontsel) { - unifontsel_internal *fs = FROMFIELD(fontsel, unifontsel_internal, u); + unifontsel_internal *fs = container_of(fontsel, unifontsel_internal, u); fontinfo *info; #ifndef NO_BACKING_PIXMAPS @@ -3699,7 +3699,7 @@ void unifontsel_destroy(unifontsel *fontsel) void unifontsel_set_name(unifontsel *fontsel, const char *fontname) { - unifontsel_internal *fs = FROMFIELD(fontsel, unifontsel_internal, u); + unifontsel_internal *fs = container_of(fontsel, unifontsel_internal, u); int i, start, end, size, flags; const char *fontname2 = NULL; fontinfo *info; @@ -3759,7 +3759,7 @@ void unifontsel_set_name(unifontsel *fontsel, const char *fontname) char *unifontsel_get_name(unifontsel *fontsel) { - unifontsel_internal *fs = FROMFIELD(fontsel, unifontsel_internal, u); + unifontsel_internal *fs = container_of(fontsel, unifontsel_internal, u); char *name; if (!fs->selected) diff --git a/unix/uxnet.c b/unix/uxnet.c index dbd1231b..dddaee9a 100644 --- a/unix/uxnet.c +++ b/unix/uxnet.c @@ -483,7 +483,7 @@ SockAddr *sk_addr_dup(SockAddr *addr) static Plug *sk_net_plug(Socket *sock, Plug *p) { - NetSocket *s = FROMFIELD(sock, NetSocket, sock); + NetSocket *s = container_of(sock, NetSocket, sock); Plug *ret = s->plug; if (p) s->plug = p; @@ -980,7 +980,7 @@ Socket *sk_newlistener(const char *srcaddr, int port, Plug *plug, if (address_family == AF_INET6 && orig_address_family == ADDRTYPE_UNSPEC) { NetSocket *other; - other = FROMFIELD( + other = container_of( sk_newlistener(srcaddr, port, plug, local_host_only, ADDRTYPE_IPV4), NetSocket, sock); @@ -1010,7 +1010,7 @@ Socket *sk_newlistener(const char *srcaddr, int port, Plug *plug, static void sk_net_close(Socket *sock) { - NetSocket *s = FROMFIELD(sock, NetSocket, sock); + NetSocket *s = container_of(sock, NetSocket, sock); if (s->child) sk_net_close(&s->child->sock); @@ -1039,7 +1039,7 @@ void *sk_getxdmdata(Socket *sock, int *lenp) */ if (sock->vt != &NetSocket_sockvt) return NULL; /* failure */ - s = FROMFIELD(sock, NetSocket, sock); + s = container_of(sock, NetSocket, sock); addrlen = sizeof(u); if (getsockname(s->s, &u.sa, &addrlen) < 0) @@ -1185,7 +1185,7 @@ void try_send(NetSocket *s) static int sk_net_write(Socket *sock, const void *buf, int len) { - NetSocket *s = FROMFIELD(sock, NetSocket, sock); + NetSocket *s = container_of(sock, NetSocket, sock); assert(s->outgoingeof == EOF_NO); @@ -1211,7 +1211,7 @@ static int sk_net_write(Socket *sock, const void *buf, int len) static int sk_net_write_oob(Socket *sock, const void *buf, int len) { - NetSocket *s = FROMFIELD(sock, NetSocket, sock); + NetSocket *s = container_of(sock, NetSocket, sock); assert(s->outgoingeof == EOF_NO); @@ -1240,7 +1240,7 @@ static int sk_net_write_oob(Socket *sock, const void *buf, int len) static void sk_net_write_eof(Socket *sock) { - NetSocket *s = FROMFIELD(sock, NetSocket, sock); + NetSocket *s = container_of(sock, NetSocket, sock); assert(s->outgoingeof == EOF_NO); @@ -1467,13 +1467,13 @@ const char *sk_addr_error(SockAddr *addr) } static const char *sk_net_socket_error(Socket *sock) { - NetSocket *s = FROMFIELD(sock, NetSocket, sock); + NetSocket *s = container_of(sock, NetSocket, sock); return s->error; } static void sk_net_set_frozen(Socket *sock, int is_frozen) { - NetSocket *s = FROMFIELD(sock, NetSocket, sock); + NetSocket *s = container_of(sock, NetSocket, sock); if (s->frozen == is_frozen) return; s->frozen = is_frozen; @@ -1482,7 +1482,7 @@ static void sk_net_set_frozen(Socket *sock, int is_frozen) static char *sk_net_peer_info(Socket *sock) { - NetSocket *s = FROMFIELD(sock, NetSocket, sock); + NetSocket *s = container_of(sock, NetSocket, sock); union sockaddr_union addr; socklen_t addrlen = sizeof(addr); #ifndef NO_IPV6 diff --git a/unix/uxproxy.c b/unix/uxproxy.c index cd5f4e7a..9e727ef8 100644 --- a/unix/uxproxy.c +++ b/unix/uxproxy.c @@ -104,7 +104,7 @@ static int localproxy_errfd_find(void *av, void *bv) static Plug *sk_localproxy_plug (Socket *s, Plug *p) { - LocalProxySocket *ps = FROMFIELD(s, LocalProxySocket, sock); + LocalProxySocket *ps = container_of(s, LocalProxySocket, sock); Plug *ret = ps->plug; if (p) ps->plug = p; @@ -113,7 +113,7 @@ static Plug *sk_localproxy_plug (Socket *s, Plug *p) static void sk_localproxy_close (Socket *s) { - LocalProxySocket *ps = FROMFIELD(s, LocalProxySocket, sock); + LocalProxySocket *ps = container_of(s, LocalProxySocket, sock); if (ps->to_cmd >= 0) { del234(localproxy_by_tofd, ps); @@ -201,7 +201,7 @@ static int localproxy_try_send(LocalProxySocket *ps) static int sk_localproxy_write (Socket *s, const void *data, int len) { - LocalProxySocket *ps = FROMFIELD(s, LocalProxySocket, sock); + LocalProxySocket *ps = container_of(s, LocalProxySocket, sock); assert(ps->outgoingeof == EOF_NO); @@ -223,7 +223,7 @@ static int sk_localproxy_write_oob (Socket *s, const void *data, int len) static void sk_localproxy_write_eof (Socket *s) { - LocalProxySocket *ps = FROMFIELD(s, LocalProxySocket, sock); + LocalProxySocket *ps = container_of(s, LocalProxySocket, sock); assert(ps->outgoingeof == EOF_NO); ps->outgoingeof = EOF_PENDING; @@ -233,13 +233,13 @@ static void sk_localproxy_write_eof (Socket *s) static void sk_localproxy_flush (Socket *s) { - /* LocalProxySocket *ps = FROMFIELD(s, LocalProxySocket, sock); */ + /* LocalProxySocket *ps = container_of(s, LocalProxySocket, sock); */ /* do nothing */ } static void sk_localproxy_set_frozen (Socket *s, int is_frozen) { - LocalProxySocket *ps = FROMFIELD(s, LocalProxySocket, sock); + LocalProxySocket *ps = container_of(s, LocalProxySocket, sock); if (ps->from_cmd < 0) return; @@ -252,7 +252,7 @@ static void sk_localproxy_set_frozen (Socket *s, int is_frozen) static const char * sk_localproxy_socket_error (Socket *s) { - LocalProxySocket *ps = FROMFIELD(s, LocalProxySocket, sock); + LocalProxySocket *ps = container_of(s, LocalProxySocket, sock); return ps->error; } diff --git a/unix/uxpty.c b/unix/uxpty.c index aebfb5c2..e0951808 100644 --- a/unix/uxpty.c +++ b/unix/uxpty.c @@ -1041,7 +1041,7 @@ static const char *pty_init(Frontend *frontend, Backend **backend_handle, static void pty_reconfig(Backend *be, Conf *conf) { - Pty *pty = FROMFIELD(be, Pty, backend); + Pty *pty = container_of(be, Pty, backend); /* * We don't have much need to reconfigure this backend, but * unfortunately we do need to pick up the setting of Close On @@ -1055,7 +1055,7 @@ static void pty_reconfig(Backend *be, Conf *conf) */ static void pty_free(Backend *be) { - Pty *pty = FROMFIELD(be, Pty, backend); + Pty *pty = container_of(be, Pty, backend); /* Either of these may fail `not found'. That's fine with us. */ del234(ptys_by_pid, pty); @@ -1108,7 +1108,7 @@ static void pty_try_write(Pty *pty) */ static int pty_send(Backend *be, const char *buf, int len) { - Pty *pty = FROMFIELD(be, Pty, backend); + Pty *pty = container_of(be, Pty, backend); if (pty->master_fd < 0) return 0; /* ignore all writes if fd closed */ @@ -1138,7 +1138,7 @@ static void pty_close(Pty *pty) */ static int pty_sendbuffer(Backend *be) { - /* Pty *pty = FROMFIELD(be, Pty, backend); */ + /* Pty *pty = container_of(be, Pty, backend); */ return 0; } @@ -1147,7 +1147,7 @@ static int pty_sendbuffer(Backend *be) */ static void pty_size(Backend *be, int width, int height) { - Pty *pty = FROMFIELD(be, Pty, backend); + Pty *pty = container_of(be, Pty, backend); struct winsize size; pty->term_width = width; @@ -1168,7 +1168,7 @@ static void pty_size(Backend *be, int width, int height) */ static void pty_special(Backend *be, SessionSpecialCode code, int arg) { - /* Pty *pty = FROMFIELD(be, Pty, backend); */ + /* Pty *pty = container_of(be, Pty, backend); */ /* Do nothing! */ return; } @@ -1179,7 +1179,7 @@ static void pty_special(Backend *be, SessionSpecialCode code, int arg) */ static const SessionSpecial *pty_get_specials(Backend *be) { - /* Pty *pty = FROMFIELD(be, Pty, backend); */ + /* Pty *pty = container_of(be, Pty, backend); */ /* * Hmm. When I get round to having this actually usable, it * might be quite nice to have the ability to deliver a few @@ -1191,43 +1191,43 @@ static const SessionSpecial *pty_get_specials(Backend *be) static int pty_connected(Backend *be) { - /* Pty *pty = FROMFIELD(be, Pty, backend); */ + /* Pty *pty = container_of(be, Pty, backend); */ return TRUE; } static int pty_sendok(Backend *be) { - /* Pty *pty = FROMFIELD(be, Pty, backend); */ + /* Pty *pty = container_of(be, Pty, backend); */ return 1; } static void pty_unthrottle(Backend *be, int backlog) { - /* Pty *pty = FROMFIELD(be, Pty, backend); */ + /* Pty *pty = container_of(be, Pty, backend); */ /* do nothing */ } static int pty_ldisc(Backend *be, int option) { - /* Pty *pty = FROMFIELD(be, Pty, backend); */ + /* Pty *pty = container_of(be, Pty, backend); */ return 0; /* neither editing nor echoing */ } static void pty_provide_ldisc(Backend *be, Ldisc *ldisc) { - /* Pty *pty = FROMFIELD(be, Pty, backend); */ + /* Pty *pty = container_of(be, Pty, backend); */ /* This is a stub. */ } static void pty_provide_logctx(Backend *be, LogContext *logctx) { - /* Pty *pty = FROMFIELD(be, Pty, backend); */ + /* Pty *pty = container_of(be, Pty, backend); */ /* This is a stub. */ } static int pty_exitcode(Backend *be) { - Pty *pty = FROMFIELD(be, Pty, backend); + Pty *pty = container_of(be, Pty, backend); if (!pty->finished) return -1; /* not dead yet */ else @@ -1236,7 +1236,7 @@ static int pty_exitcode(Backend *be) static int pty_cfg_info(Backend *be) { - /* Pty *pty = FROMFIELD(be, Pty, backend); */ + /* Pty *pty = container_of(be, Pty, backend); */ return 0; } diff --git a/unix/uxser.c b/unix/uxser.c index dc96f643..0b53d859 100644 --- a/unix/uxser.c +++ b/unix/uxser.c @@ -350,7 +350,7 @@ static void serial_close(Serial *serial) static void serial_free(Backend *be) { - Serial *serial = FROMFIELD(be, Serial, backend); + Serial *serial = container_of(be, Serial, backend); serial_close(serial); @@ -361,7 +361,7 @@ static void serial_free(Backend *be) static void serial_reconfig(Backend *be, Conf *conf) { - Serial *serial = FROMFIELD(be, Serial, backend); + Serial *serial = container_of(be, Serial, backend); /* * FIXME: what should we do if this returns an error? @@ -465,7 +465,7 @@ static void serial_try_write(Serial *serial) */ static int serial_send(Backend *be, const char *buf, int len) { - Serial *serial = FROMFIELD(be, Serial, backend); + Serial *serial = container_of(be, Serial, backend); if (serial->fd < 0) return 0; @@ -481,7 +481,7 @@ static int serial_send(Backend *be, const char *buf, int len) */ static int serial_sendbuffer(Backend *be) { - Serial *serial = FROMFIELD(be, Serial, backend); + Serial *serial = container_of(be, Serial, backend); return bufchain_size(&serial->output_data); } @@ -499,7 +499,7 @@ static void serial_size(Backend *be, int width, int height) */ static void serial_special(Backend *be, SessionSpecialCode code, int arg) { - Serial *serial = FROMFIELD(be, Serial, backend); + Serial *serial = container_of(be, Serial, backend); if (serial->fd >= 0 && code == SS_BRK) { tcsendbreak(serial->fd, 0); @@ -534,7 +534,7 @@ static int serial_sendok(Backend *be) static void serial_unthrottle(Backend *be, int backlog) { - Serial *serial = FROMFIELD(be, Serial, backend); + Serial *serial = container_of(be, Serial, backend); serial->inbufsize = backlog; serial_uxsel_setup(serial); } @@ -559,7 +559,7 @@ static void serial_provide_logctx(Backend *be, LogContext *logctx) static int serial_exitcode(Backend *be) { - Serial *serial = FROMFIELD(be, Serial, backend); + Serial *serial = container_of(be, Serial, backend); if (serial->fd >= 0) return -1; /* still connected */ else diff --git a/windows/winhsock.c b/windows/winhsock.c index b0387ffc..f4d0d916 100644 --- a/windows/winhsock.c +++ b/windows/winhsock.c @@ -106,7 +106,7 @@ static void handle_sentdata(struct handle *h, int new_backlog) static Plug *sk_handle_plug(Socket *s, Plug *p) { - HandleSocket *hs = FROMFIELD(s, HandleSocket, sock); + HandleSocket *hs = container_of(s, HandleSocket, sock); Plug *ret = hs->plug; if (p) hs->plug = p; @@ -115,7 +115,7 @@ static Plug *sk_handle_plug(Socket *s, Plug *p) static void sk_handle_close(Socket *s) { - HandleSocket *hs = FROMFIELD(s, HandleSocket, sock); + HandleSocket *hs = container_of(s, HandleSocket, sock); if (hs->defer_close) { hs->deferred_close = TRUE; @@ -135,7 +135,7 @@ static void sk_handle_close(Socket *s) static int sk_handle_write(Socket *s, const void *data, int len) { - HandleSocket *hs = FROMFIELD(s, HandleSocket, sock); + HandleSocket *hs = container_of(s, HandleSocket, sock); return handle_write(hs->send_h, data, len); } @@ -151,14 +151,14 @@ static int sk_handle_write_oob(Socket *s, const void *data, int len) static void sk_handle_write_eof(Socket *s) { - HandleSocket *hs = FROMFIELD(s, HandleSocket, sock); + HandleSocket *hs = container_of(s, HandleSocket, sock); handle_write_eof(hs->send_h); } static void sk_handle_flush(Socket *s) { - /* HandleSocket *hs = FROMFIELD(s, HandleSocket, sock); */ + /* HandleSocket *hs = container_of(s, HandleSocket, sock); */ /* do nothing */ } @@ -211,7 +211,7 @@ static void handle_socket_unfreeze(void *hsv) static void sk_handle_set_frozen(Socket *s, int is_frozen) { - HandleSocket *hs = FROMFIELD(s, HandleSocket, sock); + HandleSocket *hs = container_of(s, HandleSocket, sock); if (is_frozen) { switch (hs->frozen) { @@ -266,13 +266,13 @@ static void sk_handle_set_frozen(Socket *s, int is_frozen) static const char *sk_handle_socket_error(Socket *s) { - HandleSocket *hs = FROMFIELD(s, HandleSocket, sock); + HandleSocket *hs = container_of(s, HandleSocket, sock); return hs->error; } static char *sk_handle_peer_info(Socket *s) { - HandleSocket *hs = FROMFIELD(s, HandleSocket, sock); + HandleSocket *hs = container_of(s, HandleSocket, sock); ULONG pid; static HMODULE kernel32_module; DECL_WINDOWS_FUNCTION(static, BOOL, GetNamedPipeClientProcessId, diff --git a/windows/winnet.c b/windows/winnet.c index 94396d14..458ee4ec 100644 --- a/windows/winnet.c +++ b/windows/winnet.c @@ -909,7 +909,7 @@ SockAddr *sk_addr_dup(SockAddr *addr) static Plug *sk_net_plug(Socket *sock, Plug *p) { - NetSocket *s = FROMFIELD(sock, NetSocket, sock); + NetSocket *s = container_of(sock, NetSocket, sock); Plug *ret = s->plug; if (p) s->plug = p; @@ -1411,7 +1411,7 @@ Socket *sk_newlistener(const char *srcaddr, int port, Plug *plug, local_host_only, ADDRTYPE_IPV6); if (other) { - NetSocket *ns = FROMFIELD(other, NetSocket, sock); + NetSocket *ns = container_of(other, NetSocket, sock); if (!ns->error) { ns->parent = ret; ret->child = ns; @@ -1428,7 +1428,7 @@ Socket *sk_newlistener(const char *srcaddr, int port, Plug *plug, static void sk_net_close(Socket *sock) { extern char *do_select(SOCKET skt, int startup); - NetSocket *s = FROMFIELD(sock, NetSocket, sock); + NetSocket *s = container_of(sock, NetSocket, sock); if (s->child) sk_net_close(&s->child->sock); @@ -1539,7 +1539,7 @@ void try_send(NetSocket *s) static int sk_net_write(Socket *sock, const void *buf, int len) { - NetSocket *s = FROMFIELD(sock, NetSocket, sock); + NetSocket *s = container_of(sock, NetSocket, sock); assert(s->outgoingeof == EOF_NO); @@ -1559,7 +1559,7 @@ static int sk_net_write(Socket *sock, const void *buf, int len) static int sk_net_write_oob(Socket *sock, const void *buf, int len) { - NetSocket *s = FROMFIELD(sock, NetSocket, sock); + NetSocket *s = container_of(sock, NetSocket, sock); assert(s->outgoingeof == EOF_NO); @@ -1582,7 +1582,7 @@ static int sk_net_write_oob(Socket *sock, const void *buf, int len) static void sk_net_write_eof(Socket *sock) { - NetSocket *s = FROMFIELD(sock, NetSocket, sock); + NetSocket *s = container_of(sock, NetSocket, sock); assert(s->outgoingeof == EOF_NO); @@ -1785,13 +1785,13 @@ const char *sk_addr_error(SockAddr *addr) } static const char *sk_net_socket_error(Socket *sock) { - NetSocket *s = FROMFIELD(sock, NetSocket, sock); + NetSocket *s = container_of(sock, NetSocket, sock); return s->error; } static char *sk_net_peer_info(Socket *sock) { - NetSocket *s = FROMFIELD(sock, NetSocket, sock); + NetSocket *s = container_of(sock, NetSocket, sock); #ifdef NO_IPV6 struct sockaddr_in addr; #else @@ -1823,7 +1823,7 @@ static char *sk_net_peer_info(Socket *sock) static void sk_net_set_frozen(Socket *sock, int is_frozen) { - NetSocket *s = FROMFIELD(sock, NetSocket, sock); + NetSocket *s = container_of(sock, NetSocket, sock); if (s->frozen == is_frozen) return; s->frozen = is_frozen; diff --git a/windows/winnps.c b/windows/winnps.c index 8422d493..d76d5dae 100644 --- a/windows/winnps.c +++ b/windows/winnps.c @@ -38,7 +38,7 @@ typedef struct NamedPipeServerSocket { static Plug *sk_namedpipeserver_plug(Socket *s, Plug *p) { - NamedPipeServerSocket *ps = FROMFIELD(s, NamedPipeServerSocket, sock); + NamedPipeServerSocket *ps = container_of(s, NamedPipeServerSocket, sock); Plug *ret = ps->plug; if (p) ps->plug = p; @@ -47,7 +47,7 @@ static Plug *sk_namedpipeserver_plug(Socket *s, Plug *p) static void sk_namedpipeserver_close(Socket *s) { - NamedPipeServerSocket *ps = FROMFIELD(s, NamedPipeServerSocket, sock); + NamedPipeServerSocket *ps = container_of(s, NamedPipeServerSocket, sock); if (ps->callback_handle) handle_free(ps->callback_handle); @@ -64,7 +64,7 @@ static void sk_namedpipeserver_close(Socket *s) static const char *sk_namedpipeserver_socket_error(Socket *s) { - NamedPipeServerSocket *ps = FROMFIELD(s, NamedPipeServerSocket, sock); + NamedPipeServerSocket *ps = container_of(s, NamedPipeServerSocket, sock); return ps->error; } diff --git a/windows/winser.c b/windows/winser.c index 30c605f7..db53d24e 100644 --- a/windows/winser.c +++ b/windows/winser.c @@ -284,7 +284,7 @@ static const char *serial_init(Frontend *frontend, Backend **backend_handle, static void serial_free(Backend *be) { - Serial *serial = FROMFIELD(be, Serial, backend); + Serial *serial = container_of(be, Serial, backend); serial_terminate(serial); expire_timer_context(serial); @@ -293,7 +293,7 @@ static void serial_free(Backend *be) static void serial_reconfig(Backend *be, Conf *conf) { - Serial *serial = FROMFIELD(be, Serial, backend); + Serial *serial = container_of(be, Serial, backend); serial_configure(serial, serial->port, conf); @@ -308,7 +308,7 @@ static void serial_reconfig(Backend *be, Conf *conf) */ static int serial_send(Backend *be, const char *buf, int len) { - Serial *serial = FROMFIELD(be, Serial, backend); + Serial *serial = container_of(be, Serial, backend); if (serial->out == NULL) return 0; @@ -322,7 +322,7 @@ static int serial_send(Backend *be, const char *buf, int len) */ static int serial_sendbuffer(Backend *be) { - Serial *serial = FROMFIELD(be, Serial, backend); + Serial *serial = container_of(be, Serial, backend); return serial->bufsize; } @@ -351,7 +351,7 @@ static void serbreak_timer(void *ctx, unsigned long now) */ static void serial_special(Backend *be, SessionSpecialCode code, int arg) { - Serial *serial = FROMFIELD(be, Serial, backend); + Serial *serial = container_of(be, Serial, backend); if (serial->port && code == SS_BRK) { logevent(serial->frontend, "Starting serial break at user request"); @@ -399,7 +399,7 @@ static int serial_sendok(Backend *be) static void serial_unthrottle(Backend *be, int backlog) { - Serial *serial = FROMFIELD(be, Serial, backend); + Serial *serial = container_of(be, Serial, backend); if (serial->in) handle_unthrottle(serial->in, backlog); } @@ -424,7 +424,7 @@ static void serial_provide_logctx(Backend *be, LogContext *logctx) static int serial_exitcode(Backend *be) { - Serial *serial = FROMFIELD(be, Serial, backend); + Serial *serial = container_of(be, Serial, backend); if (serial->port != INVALID_HANDLE_VALUE) return -1; /* still connected */ else diff --git a/x11fwd.c b/x11fwd.c index b975bd19..9cdefeea 100644 --- a/x11fwd.c +++ b/x11fwd.c @@ -634,7 +634,7 @@ static void x11_send_init_error(struct X11Connection *conn, static void x11_closing(Plug *plug, const char *error_msg, int error_code, int calling_back) { - struct X11Connection *xconn = FROMFIELD( + struct X11Connection *xconn = container_of( plug, struct X11Connection, plug); if (error_msg) { @@ -666,7 +666,7 @@ static void x11_closing(Plug *plug, const char *error_msg, int error_code, static void x11_receive(Plug *plug, int urgent, char *data, int len) { - struct X11Connection *xconn = FROMFIELD( + struct X11Connection *xconn = container_of( plug, struct X11Connection, plug); xconn->no_data_sent_to_x_client = FALSE; @@ -675,7 +675,7 @@ static void x11_receive(Plug *plug, int urgent, char *data, int len) static void x11_sent(Plug *plug, int bufsize) { - struct X11Connection *xconn = FROMFIELD( + struct X11Connection *xconn = container_of( plug, struct X11Connection, plug); sshfwd_unthrottle(xconn->c, bufsize); @@ -773,7 +773,7 @@ Channel *x11_new_channel(tree234 *authtree, SshChannel *c, static void x11_chan_free(Channel *chan) { assert(chan->vt == &X11Connection_channelvt); - X11Connection *xconn = FROMFIELD(chan, X11Connection, chan); + X11Connection *xconn = container_of(chan, X11Connection, chan); if (xconn->auth_protocol) { sfree(xconn->auth_protocol); @@ -790,7 +790,7 @@ static void x11_chan_free(Channel *chan) static void x11_set_input_wanted(Channel *chan, int wanted) { assert(chan->vt == &X11Connection_channelvt); - X11Connection *xconn = FROMFIELD(chan, X11Connection, chan); + X11Connection *xconn = container_of(chan, X11Connection, chan); xconn->input_wanted = wanted; if (xconn->s) @@ -845,7 +845,7 @@ static int x11_parse_ip(const char *addr_string, unsigned long *ip) static int x11_send(Channel *chan, int is_stderr, const void *vdata, int len) { assert(chan->vt == &X11Connection_channelvt); - X11Connection *xconn = FROMFIELD(chan, X11Connection, chan); + X11Connection *xconn = container_of(chan, X11Connection, chan); const char *data = (const char *)vdata; /* @@ -999,7 +999,7 @@ static int x11_send(Channel *chan, int is_stderr, const void *vdata, int len) static void x11_send_eof(Channel *chan) { assert(chan->vt == &X11Connection_channelvt); - X11Connection *xconn = FROMFIELD(chan, X11Connection, chan); + X11Connection *xconn = container_of(chan, X11Connection, chan); if (xconn->s) { sk_write_eof(xconn->s); From 461ade43d1d3107a674f79b94966de84ff577d2b Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 6 Oct 2018 10:43:04 +0100 Subject: [PATCH 490/607] Return an error message from x11_setup_display. The lack of one of those has been a long-standing FIXME for ages. --- ssh.h | 6 +++++- ssh1connection.c | 8 +++++--- ssh2connection.c | 8 +++++--- unix/uxpgnt.c | 9 ++++++++- x11fwd.c | 15 ++++++++++++--- 5 files changed, 35 insertions(+), 11 deletions(-) diff --git a/ssh.h b/ssh.h index 8706e9f1..6ef465fe 100644 --- a/ssh.h +++ b/ssh.h @@ -921,8 +921,12 @@ int x11_authcmp(void *av, void *bv); /* for putting X11FakeAuth in a tree234 */ * the supplied authtype parameter configures the preferred * authorisation protocol to use at the remote end. The local auth * details are looked up by calling platform_get_x11_auth. + * + * If the returned pointer is NULL, then *error_msg will contain a + * dynamically allocated error message string. */ -extern struct X11Display *x11_setup_display(const char *display, Conf *); +extern struct X11Display *x11_setup_display(const char *display, Conf *, + char **error_msg); void x11_free_display(struct X11Display *disp); struct X11FakeAuth *x11_invent_fake_auth(tree234 *t, int authtype); void x11_free_fake_auth(struct X11FakeAuth *auth); diff --git a/ssh1connection.c b/ssh1connection.c index 3cf75967..07105176 100644 --- a/ssh1connection.c +++ b/ssh1connection.c @@ -649,13 +649,15 @@ static void ssh1_connection_process_queue(PacketProtocolLayer *ppl) } if (conf_get_int(s->conf, CONF_x11_forward)) { + char *x11_setup_err; + s->x11disp = x11_setup_display(conf_get_str(s->conf, CONF_x11_display), - s->conf); + s->conf, &x11_setup_err); if (!s->x11disp) { - /* FIXME: return an error message from x11_setup_display */ ppl_logevent(("X11 forwarding not enabled: unable to" - " initialise X display")); + " initialise X display: %s", x11_setup_err)); + sfree(x11_setup_err); } else { s->x11auth = x11_invent_fake_auth (s->x11authtree, conf_get_int(s->conf, CONF_x11_auth)); diff --git a/ssh2connection.c b/ssh2connection.c index 6da82951..e51d221f 100644 --- a/ssh2connection.c +++ b/ssh2connection.c @@ -1249,12 +1249,14 @@ static void ssh2_connection_process_queue(PacketProtocolLayer *ppl) /* Potentially enable X11 forwarding. */ if (conf_get_int(s->conf, CONF_x11_forward)) { + char *x11_setup_err; s->x11disp = x11_setup_display( - conf_get_str(s->conf, CONF_x11_display), s->conf); + conf_get_str(s->conf, CONF_x11_display), + s->conf, &x11_setup_err); if (!s->x11disp) { - /* FIXME: return an error message from x11_setup_display */ ppl_logevent(("X11 forwarding not enabled: unable to" - " initialise X display")); + " initialise X display: %s", x11_setup_err)); + sfree(x11_setup_err); } else { s->x11auth = x11_invent_fake_auth( s->x11authtree, conf_get_int(s->conf, CONF_x11_auth)); diff --git a/unix/uxpgnt.c b/unix/uxpgnt.c index 8feff9df..90a624a8 100644 --- a/unix/uxpgnt.c +++ b/unix/uxpgnt.c @@ -801,12 +801,19 @@ void run_agent(void) int greetinglen; Socket *s; struct X11Connection *conn; + char *x11_setup_err; if (!display) { fprintf(stderr, "pageant: no DISPLAY for -X mode\n"); exit(1); } - disp = x11_setup_display(display, conf); + disp = x11_setup_display(display, conf, &x11_setup_err); + if (!disp) { + fprintf(stderr, "pageant: unable to connect to X server: %s\n", + x11_setup_err); + sfree(x11_setup_err); + exit(1); + } conn = snew(struct X11Connection); conn->plug.vt = &X11Connection_plugvt; diff --git a/x11fwd.c b/x11fwd.c index 9cdefeea..0aaa3a60 100644 --- a/x11fwd.c +++ b/x11fwd.c @@ -175,11 +175,14 @@ int x11_authcmp(void *av, void *bv) } } -struct X11Display *x11_setup_display(const char *display, Conf *conf) +struct X11Display *x11_setup_display(const char *display, Conf *conf, + char **error_msg) { struct X11Display *disp = snew(struct X11Display); char *localcopy; + *error_msg = NULL; + if (!display || !*display) { localcopy = platform_get_x_display(); if (!localcopy || !*localcopy) { @@ -217,9 +220,12 @@ struct X11Display *x11_setup_display(const char *display, Conf *conf) colon = host_strrchr(localcopy, ':'); if (!colon) { + *error_msg = dupprintf("display name '%s' has no ':number'" + " suffix", localcopy); + sfree(disp); sfree(localcopy); - return NULL; /* FIXME: report a specific error? */ + return NULL; } *colon++ = '\0'; @@ -275,11 +281,14 @@ struct X11Display *x11_setup_display(const char *display, Conf *conf) NULL, NULL); if ((err = sk_addr_error(disp->addr)) != NULL) { + *error_msg = dupprintf("unable to resolve host name '%s' in " + "display name", disp->hostname); + sk_addr_free(disp->addr); sfree(disp->hostname); sfree(disp->unixsocketpath); sfree(disp); - return NULL; /* FIXME: report an error */ + return NULL; } } From 07f99e6e82deede236e2ef3aae64537220c3c89f Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 6 Oct 2018 11:45:26 +0100 Subject: [PATCH 491/607] Remove 'defused' parameter from wc_to_mb. It's never set to anything but NULL at any call site, and there's been a FIXME comment in uxucs.c for ages saying it should be removed. I think it only existed in the first place because it was a facility supported by the underlying Windows API function and we couldn't see a reason _not_ to pass it through. But I'm cleaning up FIXMEs, so we should get rid of it. (It stood for 'default used', incidentally - as in 'did the function at any point have to make use of the parameter providing a default fallback character?'. Nothing to do with _defusing_ things :-) --- ldiscucs.c | 2 +- putty.h | 2 +- unix/gtkfont.c | 6 +++--- unix/gtkwin.c | 2 +- unix/uxucs.c | 6 +----- windows/winucs.c | 9 +++++---- 6 files changed, 12 insertions(+), 15 deletions(-) diff --git a/ldiscucs.c b/ldiscucs.c index 6c943a09..50ce2094 100644 --- a/ldiscucs.c +++ b/ldiscucs.c @@ -84,7 +84,7 @@ void luni_send(Ldisc *ldisc, const wchar_t *widebuf, int len, int interactive) } else { int rv; rv = wc_to_mb(ldisc->term->ucsdata->line_codepage, 0, widebuf, len, - linebuffer, linesize, NULL, NULL, ldisc->term->ucsdata); + linebuffer, linesize, NULL, ldisc->term->ucsdata); if (rv >= 0) p = linebuffer + rv; else diff --git a/putty.h b/putty.h index aa82890f..242bfa67 100644 --- a/putty.h +++ b/putty.h @@ -1294,7 +1294,7 @@ int is_dbcs_leadbyte(int codepage, char byte); int mb_to_wc(int codepage, int flags, const char *mbstr, int mblen, wchar_t *wcstr, int wclen); int wc_to_mb(int codepage, int flags, const wchar_t *wcstr, int wclen, - char *mbstr, int mblen, const char *defchr, int *defused, + char *mbstr, int mblen, const char *defchr, struct unicode_data *ucsdata); wchar_t xlat_uskbd2cyrllic(int ch); int check_compose(int first, int second); diff --git a/unix/gtkfont.c b/unix/gtkfont.c index d0ecaa96..c2a610f1 100644 --- a/unix/gtkfont.c +++ b/unix/gtkfont.c @@ -595,7 +595,7 @@ static int x11font_has_glyph(unifont *font, wchar_t glyph) */ char sbstring[2]; int sblen = wc_to_mb(xfont->real_charset, 0, &glyph, 1, - sbstring, 2, "", NULL, NULL); + sbstring, 2, "", NULL); if (sblen == 0 || !sbstring[0]) return FALSE; /* not even in the charset */ @@ -950,7 +950,7 @@ static void x11font_draw_text(unifont_drawctx *ctx, unifont *font, */ char *sbstring = snewn(len+1, char); int sblen = wc_to_mb(xfont->real_charset, 0, string, len, - sbstring, len+1, ".", NULL, NULL); + sbstring, len+1, ".", NULL); x11font_really_draw_text(x11font_drawfuncs + index + 0, ctx, &xfont->fonts[sfid], xfont->disp, x, y, sbstring, sblen, shadowoffset, @@ -1631,7 +1631,7 @@ static void pangofont_draw_internal(unifont_drawctx *ctx, unifont *font, */ utfstring = snewn(len*6+1, char); /* UTF-8 has max 6 bytes/char */ utflen = wc_to_mb(CS_UTF8, 0, string, len, - utfstring, len*6+1, ".", NULL, NULL); + utfstring, len*6+1, ".", NULL); utfptr = utfstring; while (utflen > 0) { diff --git a/unix/gtkwin.c b/unix/gtkwin.c index ec53b6c8..64aae476 100644 --- a/unix/gtkwin.c +++ b/unix/gtkwin.c @@ -3049,7 +3049,7 @@ void write_clip(Frontend *inst, int clipboard, state->pasteout_data_len = wc_to_mb(inst->ucsdata.line_codepage, 0, data, len, state->pasteout_data, state->pasteout_data_len, - NULL, NULL, NULL); + NULL, NULL); if (state->pasteout_data_len == 0) { sfree(state->pasteout_data); state->pasteout_data = NULL; diff --git a/unix/uxucs.c b/unix/uxucs.c index 86cc33d4..edaca92c 100644 --- a/unix/uxucs.c +++ b/unix/uxucs.c @@ -57,13 +57,9 @@ int mb_to_wc(int codepage, int flags, const char *mbstr, int mblen, } int wc_to_mb(int codepage, int flags, const wchar_t *wcstr, int wclen, - char *mbstr, int mblen, const char *defchr, int *defused, + char *mbstr, int mblen, const char *defchr, struct unicode_data *ucsdata) { - /* FIXME: we should remove the defused param completely... */ - if (defused) - *defused = 0; - if (codepage == DEFAULT_CODEPAGE) { char output[MB_LEN_MAX]; mbstate_t state; diff --git a/windows/winucs.c b/windows/winucs.c index 0ecd225e..f40444c9 100644 --- a/windows/winucs.c +++ b/windows/winucs.c @@ -1157,7 +1157,7 @@ void get_unitab(int codepage, wchar_t * unitab, int ftype) } int wc_to_mb(int codepage, int flags, const wchar_t *wcstr, int wclen, - char *mbstr, int mblen, const char *defchr, int *defused, + char *mbstr, int mblen, const char *defchr, struct unicode_data *ucsdata) { char *p; @@ -1180,7 +1180,6 @@ int wc_to_mb(int codepage, int flags, const wchar_t *wcstr, int wclen, int j; for (j = 0; defchr[j]; j++) *p++ = defchr[j]; - if (defused) *defused = 1; } #if 1 else @@ -1189,9 +1188,11 @@ int wc_to_mb(int codepage, int flags, const wchar_t *wcstr, int wclen, assert(p - mbstr < mblen); } return p - mbstr; - } else + } else { + int defused; return WideCharToMultiByte(codepage, flags, wcstr, wclen, - mbstr, mblen, defchr, defused); + mbstr, mblen, defchr, &defused); + } } int mb_to_wc(int codepage, int flags, const char *mbstr, int mblen, From e655053942b788d63513def4ba4d92dd9f396675 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 6 Oct 2018 11:46:37 +0100 Subject: [PATCH 492/607] Add a couple of missing 'static' qualifiers. --- unix/uxstore.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/unix/uxstore.c b/unix/uxstore.c index 54a20b8a..155f3647 100644 --- a/unix/uxstore.c +++ b/unix/uxstore.c @@ -299,7 +299,7 @@ struct skeyval { static tree234 *xrmtree = NULL; -int keycmp(void *av, void *bv) +static int keycmp(void *av, void *bv) { struct skeyval *a = (struct skeyval *)av; struct skeyval *b = (struct skeyval *)bv; @@ -340,7 +340,7 @@ void provide_xrm_string(char *string) } } -const char *get_setting(const char *key) +static const char *get_setting(const char *key) { struct skeyval tmp, *ret; tmp.key = key; From d9369d4a46c40c3c4cd8108fea9d64ee69fbd041 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 6 Oct 2018 11:49:09 +0100 Subject: [PATCH 493/607] Give PuTTYtel its own Windows manifest file. While grepping for FIXME comments I could get rid of easily, I came across a completely unexplained one in puttytel.rc, and after a moment of thought, realised that it was there because PuTTYtel sharing PuTTY's manifest file means the manifest has the wrong application name. Of course I could do something a bit more clever involving having one copy of the manifest file and templating it to multiple applications, but I think it would be more pain than it's worth given that the templating system would have to be compatible with all the makefiles and run on Windows systems where no sensible scripting was available. So I just do it the trivial way. --- windows/puttytel.mft | 31 +++++++++++++++++++++++++++++++ windows/puttytel.rc | 3 +-- 2 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 windows/puttytel.mft diff --git a/windows/puttytel.mft b/windows/puttytel.mft new file mode 100644 index 00000000..2fda22dc --- /dev/null +++ b/windows/puttytel.mft @@ -0,0 +1,31 @@ + + + + + A network client and terminal emulator + + + + + + + + + + true + + + diff --git a/windows/puttytel.rc b/windows/puttytel.rc index dbdfc46d..a5cba2c8 100644 --- a/windows/puttytel.rc +++ b/windows/puttytel.rc @@ -6,6 +6,5 @@ #include "win_res.rc2" #ifndef NO_MANIFESTS -/* FIXME */ -1 RT_MANIFEST "putty.mft" +1 RT_MANIFEST "puttytel.mft" #endif /* NO_MANIFESTS */ From 6c0f22bb9fe9c0e1dd8763327b02ca5d1693a59e Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 6 Oct 2018 11:52:04 +0100 Subject: [PATCH 494/607] Give fxp_mkdir_send an attrs parameter. It's not used anywhere, but this would make it one step easier to add a mode argument to PSFTP's mkdir command, if anyone needs it. Mostly the point is to get rid of the FIXME comment in fxp_mkdir_send itself. --- pscp.c | 2 +- psftp.c | 4 ++-- sftp.c | 14 +++++++------- sftp.h | 5 +++-- 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/pscp.c b/pscp.c index 4cc09a41..d1efe426 100644 --- a/pscp.c +++ b/pscp.c @@ -1015,7 +1015,7 @@ int scp_send_dirname(const char *name, int modes) * exists and is a directory we will assume we were either * successful or it didn't matter. */ - req = fxp_mkdir_send(fullname); + req = fxp_mkdir_send(fullname, NULL); pktin = sftp_wait_for_reply(req); ret = fxp_mkdir_recv(pktin, req); diff --git a/psftp.c b/psftp.c index c20bfb44..557264be 100644 --- a/psftp.c +++ b/psftp.c @@ -516,7 +516,7 @@ int sftp_put_file(char *fname, char *outfname, int recurse, int restart) if (!result || !(attrs.flags & SSH_FILEXFER_ATTR_PERMISSIONS) || !(attrs.permissions & 0040000)) { - req = fxp_mkdir_send(outfname); + req = fxp_mkdir_send(outfname, NULL); pktin = sftp_wait_for_reply(req); result = fxp_mkdir_recv(pktin, req); @@ -1422,7 +1422,7 @@ int sftp_cmd_mkdir(struct sftp_command *cmd) return 0; } - req = fxp_mkdir_send(dir); + req = fxp_mkdir_send(dir, NULL); pktin = sftp_wait_for_reply(req); result = fxp_mkdir_recv(pktin, req); diff --git a/sftp.c b/sftp.c index 7e7f1ffa..9aa4a7db 100644 --- a/sftp.c +++ b/sftp.c @@ -85,6 +85,8 @@ static void BinarySink_put_fxp_attrs(BinarySink *bs, struct fxp_attrs attrs) } } +static const struct fxp_attrs no_attrs = { 0 }; + #define put_fxp_attrs(bs, attrs) \ BinarySink_put_fxp_attrs(BinarySink_UPCAST(bs), attrs) @@ -460,7 +462,7 @@ char *fxp_realpath_recv(struct sftp_packet *pktin, struct sftp_request *req) * Open a file. */ struct sftp_request *fxp_open_send(const char *path, int type, - struct fxp_attrs *attrs) + const struct fxp_attrs *attrs) { struct sftp_request *req = sftp_alloc_request(); struct sftp_packet *pktout; @@ -469,10 +471,7 @@ struct sftp_request *fxp_open_send(const char *path, int type, put_uint32(pktout, req->id); put_stringz(pktout, path); put_uint32(pktout, type); - if (attrs) - put_fxp_attrs(pktout, *attrs); - else - put_uint32(pktout, 0); /* empty ATTRS structure */ + put_fxp_attrs(pktout, attrs ? *attrs : no_attrs); sftp_send(pktout); return req; @@ -566,7 +565,8 @@ int fxp_close_recv(struct sftp_packet *pktin, struct sftp_request *req) return fxp_errtype == SSH_FX_OK; } -struct sftp_request *fxp_mkdir_send(const char *path) +struct sftp_request *fxp_mkdir_send(const char *path, + const struct fxp_attrs *attrs) { struct sftp_request *req = sftp_alloc_request(); struct sftp_packet *pktout; @@ -574,7 +574,7 @@ struct sftp_request *fxp_mkdir_send(const char *path) pktout = sftp_pkt_init(SSH_FXP_MKDIR); put_uint32(pktout, req->id); put_stringz(pktout, path); - put_uint32(pktout, 0); /* (FIXME) empty ATTRS structure */ + put_fxp_attrs(pktout, attrs ? *attrs : no_attrs); sftp_send(pktout); return req; diff --git a/sftp.h b/sftp.h index 7e93356b..65c8a44d 100644 --- a/sftp.h +++ b/sftp.h @@ -138,7 +138,7 @@ char *fxp_realpath_recv(struct sftp_packet *pktin, struct sftp_request *req); * if it's being created. */ struct sftp_request *fxp_open_send(const char *path, int type, - struct fxp_attrs *attrs); + const struct fxp_attrs *attrs); struct fxp_handle *fxp_open_recv(struct sftp_packet *pktin, struct sftp_request *req); @@ -158,7 +158,8 @@ int fxp_close_recv(struct sftp_packet *pktin, struct sftp_request *req); /* * Make a directory. */ -struct sftp_request *fxp_mkdir_send(const char *path); +struct sftp_request *fxp_mkdir_send(const char *path, + const struct fxp_attrs *attrs); int fxp_mkdir_recv(struct sftp_packet *pktin, struct sftp_request *req); /* From 62f630d4b30c2bcea0c6c908496ed063cecd48a2 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 6 Oct 2018 11:55:56 +0100 Subject: [PATCH 495/607] cygtermd: remove all uses of 'FIXME' as program name. There was a while when I hadn't decided what the name of the program was going to be, and apparently once I did I never got round to substituting it back in everywhere. --- contrib/cygtermd/main.c | 2 +- contrib/cygtermd/pty.h | 6 +++--- contrib/cygtermd/sel.h | 6 +++--- contrib/cygtermd/telnet.h | 6 +++--- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/contrib/cygtermd/main.c b/contrib/cygtermd/main.c index e7ed5f0a..154c4315 100644 --- a/contrib/cygtermd/main.c +++ b/contrib/cygtermd/main.c @@ -36,7 +36,7 @@ void sigchld(int signum) void fatal(const char *fmt, ...) { va_list ap; - fprintf(stderr, "FIXME: "); + fprintf(stderr, "cygtermd: "); va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); diff --git a/contrib/cygtermd/pty.h b/contrib/cygtermd/pty.h index bee10e47..523331b3 100644 --- a/contrib/cygtermd/pty.h +++ b/contrib/cygtermd/pty.h @@ -2,8 +2,8 @@ * pty.h - FIXME */ -#ifndef FIXME_PTY_H -#define FIXME_PTY_H +#ifndef CYGTERMD_PTY_H +#define CYGTERMD_PTY_H #include "telnet.h" /* for struct shdata */ @@ -25,4 +25,4 @@ void pty_resize(int w, int h); int run_program_in_pty(const struct shell_data *shdata, char *directory, char **program_args); -#endif /* FIXME_PTY_H */ +#endif /* CYGTERMD_PTY_H */ diff --git a/contrib/cygtermd/sel.h b/contrib/cygtermd/sel.h index 98767e2f..42c615ff 100644 --- a/contrib/cygtermd/sel.h +++ b/contrib/cygtermd/sel.h @@ -4,8 +4,8 @@ * reads. */ -#ifndef FIXME_SEL_H -#define FIXME_SEL_H +#ifndef CYGTERMD_SEL_H +#define CYGTERMD_SEL_H typedef struct sel sel; typedef struct sel_wfd sel_wfd; @@ -158,4 +158,4 @@ void sel_wfd_setfd(sel_wfd *wfd, int fd); */ void sel_rfd_setfd(sel_rfd *rfd, int fd); -#endif /* FIXME_SEL_H */ +#endif /* CYGTERMD_SEL_H */ diff --git a/contrib/cygtermd/telnet.h b/contrib/cygtermd/telnet.h index 40a05dd9..2dc1582b 100644 --- a/contrib/cygtermd/telnet.h +++ b/contrib/cygtermd/telnet.h @@ -2,8 +2,8 @@ * Header declaring Telnet-handling functions. */ -#ifndef FIXME_TELNET_H -#define FIXME_TELNET_H +#ifndef CYGTERMD_TELNET_H +#define CYGTERMD_TELNET_H #include "sel.h" @@ -38,4 +38,4 @@ void telnet_from_net(Telnet *telnet, char *buf, int len); */ int telnet_shell_ok(Telnet *telnet, struct shell_data *shdata); -#endif /* FIXME_TELNET_H */ +#endif /* CYGTERMD_TELNET_H */ From 0bbe87f11e1fdc6d62a49405018fb2b1e76b88f6 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 6 Oct 2018 11:46:47 +0100 Subject: [PATCH 496/607] Rewrite some comments with FIXMEs in them. These are things where no fix was actually necessary in the code, but the FIXME indicated that the comment itself was either in need of a rewrite or removal. --- contrib/cygtermd/pty.h | 2 +- unix/uxstore.c | 26 ++++++++++++++++++-------- windows/version.rc2 | 9 ++++++--- windows/win_res.rc2 | 10 +++++++--- 4 files changed, 32 insertions(+), 15 deletions(-) diff --git a/contrib/cygtermd/pty.h b/contrib/cygtermd/pty.h index 523331b3..261fc41d 100644 --- a/contrib/cygtermd/pty.h +++ b/contrib/cygtermd/pty.h @@ -1,5 +1,5 @@ /* - * pty.h - FIXME + * pty.h - declare functions for pty setup */ #ifndef CYGTERMD_PTY_H diff --git a/unix/uxstore.c b/unix/uxstore.c index 155f3647..84d8d4d6 100644 --- a/unix/uxstore.c +++ b/unix/uxstore.c @@ -282,14 +282,19 @@ void close_settings_w(settings_w *handle) sfree(handle); } -/* - * Reading settings, for the moment, is done by retrieving X - * resources from the X display. When we introduce disk files, I - * think what will happen is that the X resources will override - * PuTTY's inbuilt defaults, but that the disk files will then - * override those. This isn't optimal, but it's the best I can - * immediately work out. - * FIXME: the above comment is a bit out of date. Did it happen? +/* ---------------------------------------------------------------------- + * System for treating X resources as a fallback source of defaults, + * after data read from a saved-session disk file. + * + * The read_setting_* functions will call get_setting(key) as a + * fallback if the setting isn't in the file they loaded. That in turn + * will hand on to x_get_default, which the front end application + * provides, and which actually reads resources from the X server (if + * appropriate). In between, there's a tree234 of X-resource shaped + * settings living locally in this file: the front end can call + * provide_xrm_string() to insert a setting into this tree (typically + * in response to an -xrm command line option or similar), and those + * will override the actual X resources. */ struct skeyval { @@ -352,6 +357,11 @@ static const char *get_setting(const char *key) return x_get_default(key); } +/* ---------------------------------------------------------------------- + * Main code for reading settings from a disk file, calling the above + * get_setting() as a fallback if necessary. + */ + struct settings_r { tree234 *t; }; diff --git a/windows/version.rc2 b/windows/version.rc2 index 500f9002..5cc127a4 100644 --- a/windows/version.rc2 +++ b/windows/version.rc2 @@ -1,9 +1,12 @@ /* * Standard Windows version information. * (For inclusion in other .rc files with appropriate macro definitions.) - * FIXME: This file is called '.rc2' rather than '.rc' to avoid MSVC trying - * to compile it on its own when using the project files. Nicer solutions - * welcome. + * + * This file has the more or less arbitrary extension '.rc2' to avoid + * IDEs taking it to be a top-level resource script in its own right + * (which has been known to happen if the extension was '.rc'), and + * also to avoid the resource compiler ignoring everything included + * from it (which happens if the extension is '.h'). */ #include "version.h" diff --git a/windows/win_res.rc2 b/windows/win_res.rc2 index 0c486ce5..503fa022 100644 --- a/windows/win_res.rc2 +++ b/windows/win_res.rc2 @@ -1,12 +1,16 @@ /* * Windows resources shared between PuTTY and PuTTYtel, to be #include'd * after defining appropriate macros. + * * Note that many of these strings mention PuTTY. Due to restrictions in * VC's handling of string concatenation, this can't easily be fixed. * It's fixed up at runtime. - * FIXME: This file is called '.rc2' rather than '.rc' to avoid MSVC trying - * to compile it on its own when using the project files. Nicer solutions - * welcome. + * + * This file has the more or less arbitrary extension '.rc2' to avoid + * IDEs taking it to be a top-level resource script in its own right + * (which has been known to happen if the extension was '.rc'), and + * also to avoid the resource compiler ignoring everything included + * from it (which happens if the extension is '.h'). */ #include "win_res.h" From 36caf03a5b718f5b2ec6115349bea6cbe322da48 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 6 Oct 2018 18:42:08 +0100 Subject: [PATCH 497/607] Utility routines for iterating over a packet queue. I haven't needed these until now, but I'm about to need to inspect the entire contents of a packet queue before deciding whether to process the first item on it. I've changed the single 'vtable method' in packet queues from get(), which returned the head of the queue and optionally popped it, to after() which does the same bug returns the item after a specified tree node. So if you pass the special end node to after(), then it behaves like get(), but now you can also use it to retrieve the successor of a packet. (Orthogonality says that you can also _pop_ the successor of a packet by calling after() with prev != pq.end and pop == TRUE. I don't have a use for that one yet.) --- ssh.h | 27 +++++++++++++++------------ sshcommon.c | 14 ++++++++------ 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/ssh.h b/ssh.h index 6ef465fe..62b8b6ad 100644 --- a/ssh.h +++ b/ssh.h @@ -90,12 +90,12 @@ typedef struct PacketQueueBase { typedef struct PktInQueue { PacketQueueBase pqb; - PktIn *(*get)(PacketQueueBase *, int pop); + PktIn *(*after)(PacketQueueBase *, PacketQueueNode *prev, int pop); } PktInQueue; typedef struct PktOutQueue { PacketQueueBase pqb; - PktOut *(*get)(PacketQueueBase *, int pop); + PktOut *(*after)(PacketQueueBase *, PacketQueueNode *prev, int pop); } PktOutQueue; void pq_base_push(PacketQueueBase *pqb, PacketQueueNode *node); @@ -108,21 +108,24 @@ void pq_out_init(PktOutQueue *pq); void pq_in_clear(PktInQueue *pq); void pq_out_clear(PktOutQueue *pq); -#define pq_push(pq, pkt) \ - TYPECHECK((pq)->get(&(pq)->pqb, FALSE) == pkt, \ +#define pq_push(pq, pkt) \ + TYPECHECK((pq)->after(&(pq)->pqb, NULL, FALSE) == pkt, \ pq_base_push(&(pq)->pqb, &(pkt)->qnode)) #define pq_push_front(pq, pkt) \ - TYPECHECK((pq)->get(&(pq)->pqb, FALSE) == pkt, \ + TYPECHECK((pq)->after(&(pq)->pqb, NULL, FALSE) == pkt, \ pq_base_push_front(&(pq)->pqb, &(pkt)->qnode)) -#define pq_peek(pq) ((pq)->get(&(pq)->pqb, FALSE)) -#define pq_pop(pq) ((pq)->get(&(pq)->pqb, TRUE)) -#define pq_concatenate(dst, q1, q2) \ - TYPECHECK((q1)->get(&(q1)->pqb, FALSE) == \ - (dst)->get(&(dst)->pqb, FALSE) && \ - (q2)->get(&(q2)->pqb, FALSE) == \ - (dst)->get(&(dst)->pqb, FALSE), \ +#define pq_peek(pq) ((pq)->after(&(pq)->pqb, &(pq)->pqb.end, FALSE)) +#define pq_pop(pq) ((pq)->after(&(pq)->pqb, &(pq)->pqb.end, TRUE)) +#define pq_concatenate(dst, q1, q2) \ + TYPECHECK((q1)->after(&(q1)->pqb, NULL, FALSE) == \ + (dst)->after(&(dst)->pqb, NULL, FALSE) && \ + (q2)->after(&(q2)->pqb, NULL, FALSE) == \ + (dst)->after(&(dst)->pqb, NULL, FALSE), \ pq_base_concatenate(&(dst)->pqb, &(q1)->pqb, &(q2)->pqb)) +#define pq_first(pq) pq_peek(pq) +#define pq_next(pq, pkt) ((pq)->after(&(pq)->pqb, &(pkt)->qnode, FALSE)) + /* * Packet type contexts, so that ssh2_pkt_type can correctly decode * the ambiguous type numbers back into the correct type strings. diff --git a/sshcommon.c b/sshcommon.c index f7007ea9..7679c5bd 100644 --- a/sshcommon.c +++ b/sshcommon.c @@ -71,9 +71,10 @@ static IdempotentCallback ic_pktin_free = { pktin_free_queue_callback, NULL, FALSE }; -static PktIn *pq_in_get(PacketQueueBase *pqb, int pop) +static PktIn *pq_in_after(PacketQueueBase *pqb, + PacketQueueNode *prev, int pop) { - PacketQueueNode *node = pqb->end.next; + PacketQueueNode *node = prev->next; if (node == &pqb->end) return NULL; @@ -92,9 +93,10 @@ static PktIn *pq_in_get(PacketQueueBase *pqb, int pop) return container_of(node, PktIn, qnode); } -static PktOut *pq_out_get(PacketQueueBase *pqb, int pop) +static PktOut *pq_out_after(PacketQueueBase *pqb, + PacketQueueNode *prev, int pop) { - PacketQueueNode *node = pqb->end.next; + PacketQueueNode *node = prev->next; if (node == &pqb->end) return NULL; @@ -111,14 +113,14 @@ void pq_in_init(PktInQueue *pq) { pq->pqb.ic = NULL; pq->pqb.end.next = pq->pqb.end.prev = &pq->pqb.end; - pq->get = pq_in_get; + pq->after = pq_in_after; } void pq_out_init(PktOutQueue *pq) { pq->pqb.ic = NULL; pq->pqb.end.next = pq->pqb.end.prev = &pq->pqb.end; - pq->get = pq_out_get; + pq->after = pq_out_after; } void pq_in_clear(PktInQueue *pq) From 2e7ced64801514e0f8c72849e281032418d96ef7 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 7 Oct 2018 08:16:44 +0100 Subject: [PATCH 498/607] Give BPPs a Frontend, so they can do their own logging. The sshverstring quasi-frontend is passed a Frontend pointer at setup time, so that it can generate Event Log entries containing the local and remote version strings and the results of remote bug detection. I'm promoting that field of sshverstring to a field of the public BPP structure, so now all BPPs have the right to talk directly to the frontend if they want to. This means I can move all the log messages of the form 'Initialised so-and-so cipher/MAC/compression' down into the BPPs themselves, where they can live exactly alongside the actual initialisation of those primitives. It also means BPPs will be able to log interesting things they detect at any point in the packet stream, which is about to come in useful for another purpose. --- ssh.c | 6 +++--- ssh.h | 2 ++ ssh1bpp.c | 10 +++++++++- ssh1login.c | 2 -- ssh2bpp-bare.c | 3 ++- ssh2bpp.c | 34 ++++++++++++++++++++++++++++++++- ssh2transport.c | 27 -------------------------- sshbpp.h | 8 +++++--- sshverstring.c | 51 ++++++++++++++++++++++++------------------------- 9 files changed, 79 insertions(+), 64 deletions(-) diff --git a/ssh.c b/ssh.c index 5227b4de..433a2572 100644 --- a/ssh.c +++ b/ssh.c @@ -172,7 +172,7 @@ static void ssh_got_ssh_version(struct ssh_version_receiver *rcv, int is_simple = (conf_get_int(ssh->conf, CONF_ssh_simple) && !ssh->connshare); - ssh->bpp = ssh2_bpp_new(&ssh->stats); + ssh->bpp = ssh2_bpp_new(ssh->frontend, &ssh->stats); ssh_connect_bpp(ssh); #ifndef NO_GSSAPI @@ -247,7 +247,7 @@ static void ssh_got_ssh_version(struct ssh_version_receiver *rcv, } else { - ssh->bpp = ssh1_bpp_new(); + ssh->bpp = ssh1_bpp_new(ssh->frontend); ssh_connect_bpp(ssh); connection_layer = ssh1_connection_new(ssh, ssh->conf, &ssh->cl); @@ -260,7 +260,7 @@ static void ssh_got_ssh_version(struct ssh_version_receiver *rcv, } } else { - ssh->bpp = ssh2_bare_bpp_new(); + ssh->bpp = ssh2_bare_bpp_new(ssh->frontend); ssh_connect_bpp(ssh); connection_layer = ssh2_connection_new( diff --git a/ssh.h b/ssh.h index 62b8b6ad..3e14aa4c 100644 --- a/ssh.h +++ b/ssh.h @@ -765,10 +765,12 @@ struct ssh_compression_alg { #define ssh_compressor_free(comp) ((comp)->vt->compress_free(comp)) #define ssh_compressor_compress(comp, in, inlen, out, outlen, minlen) \ ((comp)->vt->compress(comp, in, inlen, out, outlen, minlen)) +#define ssh_compressor_alg(comp) ((comp)->vt) #define ssh_decompressor_new(alg) ((alg)->decompress_new()) #define ssh_decompressor_free(comp) ((comp)->vt->decompress_free(comp)) #define ssh_decompressor_decompress(comp, in, inlen, out, outlen) \ ((comp)->vt->decompress(comp, in, inlen, out, outlen)) +#define ssh_decompressor_alg(comp) ((comp)->vt) struct ssh2_userkey { ssh_key *key; /* the key itself */ diff --git a/ssh1bpp.c b/ssh1bpp.c index 36afcd24..33482a2c 100644 --- a/ssh1bpp.c +++ b/ssh1bpp.c @@ -43,11 +43,12 @@ static const struct BinaryPacketProtocolVtable ssh1_bpp_vtable = { ssh1_bpp_queue_disconnect, }; -BinaryPacketProtocol *ssh1_bpp_new(void) +BinaryPacketProtocol *ssh1_bpp_new(Frontend *frontend) { struct ssh1_bpp_state *s = snew(struct ssh1_bpp_state); memset(s, 0, sizeof(*s)); s->bpp.vt = &ssh1_bpp_vtable; + s->bpp.frontend = frontend; ssh_bpp_common_setup(&s->bpp); return &s->bpp; } @@ -67,6 +68,9 @@ static void ssh1_bpp_free(BinaryPacketProtocol *bpp) sfree(s); } +#define bpp_logevent(printf_args) \ + logevent_and_free(s->bpp.frontend, dupprintf printf_args) + void ssh1_bpp_new_cipher(BinaryPacketProtocol *bpp, const struct ssh1_cipheralg *cipher, const void *session_key) @@ -83,6 +87,8 @@ void ssh1_bpp_new_cipher(BinaryPacketProtocol *bpp, assert(!s->crcda_ctx); s->crcda_ctx = crcda_make_context(); + + bpp_logevent(("Initialised %s encryption", cipher->text_name)); } } @@ -223,6 +229,8 @@ static void ssh1_bpp_handle_input(BinaryPacketProtocol *bpp) s->compctx = ssh_compressor_new(&ssh_zlib); s->decompctx = ssh_decompressor_new(&ssh_zlib); + + bpp_logevent(("Started zlib (RFC1950) compression")); } /* diff --git a/ssh1login.c b/ssh1login.c index e64bc834..0b8ea448 100644 --- a/ssh1login.c +++ b/ssh1login.c @@ -406,7 +406,6 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl) (s->cipher_type == SSH_CIPHER_BLOWFISH ? &ssh1_blowfish : s->cipher_type == SSH_CIPHER_DES ? &ssh1_des : &ssh1_3des); ssh1_bpp_new_cipher(s->ppl.bpp, cipher, s->session_key); - ppl_logevent(("Initialised %s encryption", cipher->text_name)); } if (s->servkey.modulus) { @@ -1114,7 +1113,6 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl) * easiest way to avoid race conditions if other packets * cross in transit.) */ - ppl_logevent(("Started zlib (RFC1950) compression")); } else if (pktin->type == SSH1_SMSG_FAILURE) { ppl_logevent(("Server refused to enable compression")); ppl_printf(("Server refused to compress\r\n")); diff --git a/ssh2bpp-bare.c b/ssh2bpp-bare.c index 213acf0c..e7c8f8ca 100644 --- a/ssh2bpp-bare.c +++ b/ssh2bpp-bare.c @@ -33,11 +33,12 @@ static const struct BinaryPacketProtocolVtable ssh2_bare_bpp_vtable = { ssh2_bpp_queue_disconnect, /* in sshcommon.c */ }; -BinaryPacketProtocol *ssh2_bare_bpp_new(void) +BinaryPacketProtocol *ssh2_bare_bpp_new(Frontend *frontend) { struct ssh2_bare_bpp_state *s = snew(struct ssh2_bare_bpp_state); memset(s, 0, sizeof(*s)); s->bpp.vt = &ssh2_bare_bpp_vtable; + s->bpp.frontend = frontend; ssh_bpp_common_setup(&s->bpp); return &s->bpp; } diff --git a/ssh2bpp.c b/ssh2bpp.c index f0b6fd22..67745278 100644 --- a/ssh2bpp.c +++ b/ssh2bpp.c @@ -51,11 +51,13 @@ static const struct BinaryPacketProtocolVtable ssh2_bpp_vtable = { ssh2_bpp_queue_disconnect, /* in sshcommon.c */ }; -BinaryPacketProtocol *ssh2_bpp_new(struct DataTransferStats *stats) +BinaryPacketProtocol *ssh2_bpp_new( + Frontend *frontend, struct DataTransferStats *stats) { struct ssh2_bpp_state *s = snew(struct ssh2_bpp_state); memset(s, 0, sizeof(*s)); s->bpp.vt = &ssh2_bpp_vtable; + s->bpp.frontend = frontend; s->stats = stats; ssh_bpp_common_setup(&s->bpp); return &s->bpp; @@ -81,6 +83,9 @@ static void ssh2_bpp_free(BinaryPacketProtocol *bpp) sfree(s); } +#define bpp_logevent(printf_args) \ + logevent_and_free(s->bpp.frontend, dupprintf printf_args) + void ssh2_bpp_new_outgoing_crypto( BinaryPacketProtocol *bpp, const struct ssh2_cipheralg *cipher, const void *ckey, const void *iv, @@ -106,6 +111,9 @@ void ssh2_bpp_new_outgoing_crypto( s->cbc_ignore_workaround = ( (ssh2_cipher_alg(s->out.cipher)->flags & SSH_CIPHER_IS_CBC) && !(s->bpp.remote_bugs & BUG_CHOKES_ON_SSH2_IGNORE)); + + bpp_logevent(("Initialised %.200s client->server encryption", + ssh2_cipher_alg(s->out.cipher)->text_name)); } else { s->out.cipher = NULL; s->cbc_ignore_workaround = FALSE; @@ -114,6 +122,14 @@ void ssh2_bpp_new_outgoing_crypto( if (mac) { s->out.mac = ssh2_mac_new(mac, s->out.cipher); mac->setkey(s->out.mac, mac_key); + + bpp_logevent(("Initialised %.200s client->server" + " MAC algorithm%s%s", + ssh2_mac_alg(s->out.mac)->text_name, + etm_mode ? " (in ETM mode)" : "", + (s->out.cipher && + ssh2_cipher_alg(s->out.cipher)->required_mac ? + " (required by cipher)" : ""))); } else { s->out.mac = NULL; } @@ -122,6 +138,9 @@ void ssh2_bpp_new_outgoing_crypto( * indicated by ssh_comp_none. But this setup call may return a * null out_comp. */ s->out_comp = ssh_compressor_new(compression); + if (s->out_comp) + bpp_logevent(("Initialised %s compression", + ssh_compressor_alg(s->out_comp)->text_name)); } void ssh2_bpp_new_incoming_crypto( @@ -145,6 +164,9 @@ void ssh2_bpp_new_incoming_crypto( s->in.cipher = ssh2_cipher_new(cipher); ssh2_cipher_setkey(s->in.cipher, ckey); ssh2_cipher_setiv(s->in.cipher, iv); + + bpp_logevent(("Initialised %.200s server->client encryption", + ssh2_cipher_alg(s->in.cipher)->text_name)); } else { s->in.cipher = NULL; } @@ -152,6 +174,13 @@ void ssh2_bpp_new_incoming_crypto( if (mac) { s->in.mac = ssh2_mac_new(mac, s->in.cipher); mac->setkey(s->in.mac, mac_key); + + bpp_logevent(("Initialised %.200s server->client MAC algorithm%s%s", + ssh2_mac_alg(s->in.mac)->text_name, + etm_mode ? " (in ETM mode)" : "", + (s->in.cipher && + ssh2_cipher_alg(s->in.cipher)->required_mac ? + " (required by cipher)" : ""))); } else { s->in.mac = NULL; } @@ -160,6 +189,9 @@ void ssh2_bpp_new_incoming_crypto( * indicated by ssh_comp_none. But this setup call may return a * null in_decomp. */ s->in_decomp = ssh_decompressor_new(compression); + if (s->in_decomp) + bpp_logevent(("Initialised %s decompression", + ssh_decompressor_alg(s->in_decomp)->text_name)); /* Clear the pending_newkeys flag, so that handle_input below will * start consuming the input data again. */ diff --git a/ssh2transport.c b/ssh2transport.c index bec55dac..60626403 100644 --- a/ssh2transport.c +++ b/ssh2transport.c @@ -2153,20 +2153,6 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) strbuf_free(mac_key); } - if (s->out.cipher) - ppl_logevent(("Initialised %.200s client->server encryption", - s->out.cipher->text_name)); - if (s->out.mac) - ppl_logevent(("Initialised %.200s client->server" - " MAC algorithm%s%s", - s->out.mac->text_name, - s->out.etm_mode ? " (in ETM mode)" : "", - (s->out.cipher->required_mac ? - " (required by cipher)" : ""))); - if (s->out.comp->text_name) - ppl_logevent(("Initialised %s compression", - s->out.comp->text_name)); - /* * Now our end of the key exchange is complete, we can send all * our queued higher-layer packets. Transfer the whole of the next @@ -2222,19 +2208,6 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) strbuf_free(mac_key); } - if (s->in.cipher) - ppl_logevent(("Initialised %.200s server->client encryption", - s->in.cipher->text_name)); - if (s->in.mac) - ppl_logevent(("Initialised %.200s server->client MAC algorithm%s%s", - s->in.mac->text_name, - s->in.etm_mode ? " (in ETM mode)" : "", - (s->in.cipher->required_mac ? - " (required by cipher)" : ""))); - if (s->in.comp->text_name) - ppl_logevent(("Initialised %s decompression", - s->in.comp->text_name)); - /* * Free shared secret. */ diff --git a/sshbpp.h b/sshbpp.h index ee5c1c12..3914eeb3 100644 --- a/sshbpp.h +++ b/sshbpp.h @@ -23,6 +23,7 @@ struct BinaryPacketProtocol { PacketLogSettings *pls; LogContext *logctx; Ssh *ssh; + Frontend *frontend; /* ic_in_raw is filled in by the BPP (probably by calling * ssh_bpp_common_setup). The BPP's owner triggers it when data is @@ -52,7 +53,7 @@ struct BinaryPacketProtocol { * does centralised parts of the freeing too. */ void ssh_bpp_free(BinaryPacketProtocol *bpp); -BinaryPacketProtocol *ssh1_bpp_new(void); +BinaryPacketProtocol *ssh1_bpp_new(Frontend *frontend); void ssh1_bpp_new_cipher(BinaryPacketProtocol *bpp, const struct ssh1_cipheralg *cipher, const void *session_key); @@ -96,7 +97,8 @@ struct DataTransferStats { ((stats)->direction.running = FALSE, TRUE) : \ ((stats)->direction.remaining -= (size), FALSE)) -BinaryPacketProtocol *ssh2_bpp_new(struct DataTransferStats *stats); +BinaryPacketProtocol *ssh2_bpp_new( + Frontend *frontend, struct DataTransferStats *stats); void ssh2_bpp_new_outgoing_crypto( BinaryPacketProtocol *bpp, const struct ssh2_cipheralg *cipher, const void *ckey, const void *iv, @@ -108,7 +110,7 @@ void ssh2_bpp_new_incoming_crypto( const struct ssh2_macalg *mac, int etm_mode, const void *mac_key, const struct ssh_compression_alg *compression); -BinaryPacketProtocol *ssh2_bare_bpp_new(void); +BinaryPacketProtocol *ssh2_bare_bpp_new(Frontend *frontend); /* * The initial code to handle the SSH version exchange is also diff --git a/sshverstring.c b/sshverstring.c index 060587f4..66db98b6 100644 --- a/sshverstring.c +++ b/sshverstring.c @@ -17,7 +17,6 @@ struct ssh_verstring_state { int crState; Conf *conf; - Frontend *frontend; ptrlen prefix_wanted; char *our_protoversion; struct ssh_version_receiver *receiver; @@ -88,7 +87,7 @@ BinaryPacketProtocol *ssh_verstring_new( assert(s->prefix_wanted.len <= PREFIX_MAXLEN); s->conf = conf_copy(conf); - s->frontend = frontend; + s->bpp.frontend = frontend; s->our_protoversion = dupstr(protoversion); s->receiver = rcv; @@ -146,8 +145,8 @@ static int ssh_version_includes_v2(const char *ver) return ssh_versioncmp(ver, "1.99") >= 0; } -#define vs_logevent(printf_args) \ - logevent_and_free(s->frontend, dupprintf printf_args) +#define bpp_logevent(printf_args) \ + logevent_and_free(s->bpp.frontend, dupprintf printf_args) static void ssh_verstring_send(struct ssh_verstring_state *s) { @@ -198,7 +197,7 @@ static void ssh_verstring_send(struct ssh_verstring_state *s) bufchain_add(s->bpp.out_raw, "\015", 1); bufchain_add(s->bpp.out_raw, "\012", 1); - vs_logevent(("We claim version: %s", s->our_vstring)); + bpp_logevent(("We claim version: %s", s->our_vstring)); } #define BPP_WAITFOR(minlen) do \ @@ -308,7 +307,7 @@ void ssh_verstring_handle_input(BinaryPacketProtocol *bpp) s->vslen--; s->vstring[s->vslen] = '\0'; - vs_logevent(("Remote version: %s", s->vstring)); + bpp_logevent(("Remote version: %s", s->vstring)); /* * Pick out the protocol version and software version. The former @@ -374,7 +373,7 @@ void ssh_verstring_handle_input(BinaryPacketProtocol *bpp) crStopV; } - vs_logevent(("Using SSH protocol version %d", s->major_protoversion)); + bpp_logevent(("Using SSH protocol version %d", s->major_protoversion)); if (!s->send_early) { /* @@ -443,7 +442,7 @@ static void ssh_detect_bugs(struct ssh_verstring_state *s) * sniffing. */ s->remote_bugs |= BUG_CHOKES_ON_SSH1_IGNORE; - vs_logevent(("We believe remote version has SSH-1 ignore bug")); + bpp_logevent(("We believe remote version has SSH-1 ignore bug")); } if (conf_get_int(s->conf, CONF_sshbug_plainpw1) == FORCE_ON || @@ -455,8 +454,8 @@ static void ssh_detect_bugs(struct ssh_verstring_state *s) * the password. */ s->remote_bugs |= BUG_NEEDS_SSH1_PLAIN_PASSWORD; - vs_logevent(("We believe remote version needs a " - "plain SSH-1 password")); + bpp_logevent(("We believe remote version needs a " + "plain SSH-1 password")); } if (conf_get_int(s->conf, CONF_sshbug_rsa1) == FORCE_ON || @@ -468,8 +467,8 @@ static void ssh_detect_bugs(struct ssh_verstring_state *s) * an AUTH_RSA message. */ s->remote_bugs |= BUG_CHOKES_ON_RSA; - vs_logevent(("We believe remote version can't handle SSH-1 " - "RSA authentication")); + bpp_logevent(("We believe remote version can't handle SSH-1 " + "RSA authentication")); } if (conf_get_int(s->conf, CONF_sshbug_hmac2) == FORCE_ON || @@ -482,7 +481,7 @@ static void ssh_detect_bugs(struct ssh_verstring_state *s) * These versions have the HMAC bug. */ s->remote_bugs |= BUG_SSH2_HMAC; - vs_logevent(("We believe remote version has SSH-2 HMAC bug")); + bpp_logevent(("We believe remote version has SSH-2 HMAC bug")); } if (conf_get_int(s->conf, CONF_sshbug_derivekey2) == FORCE_ON || @@ -495,8 +494,8 @@ static void ssh_detect_bugs(struct ssh_verstring_state *s) * generate the keys). */ s->remote_bugs |= BUG_SSH2_DERIVEKEY; - vs_logevent(("We believe remote version has SSH-2 " - "key-derivation bug")); + bpp_logevent(("We believe remote version has SSH-2 " + "key-derivation bug")); } if (conf_get_int(s->conf, CONF_sshbug_rsapad2) == FORCE_ON || @@ -509,7 +508,7 @@ static void ssh_detect_bugs(struct ssh_verstring_state *s) * These versions have the SSH-2 RSA padding bug. */ s->remote_bugs |= BUG_SSH2_RSA_PADDING; - vs_logevent(("We believe remote version has SSH-2 RSA padding bug")); + bpp_logevent(("We believe remote version has SSH-2 RSA padding bug")); } if (conf_get_int(s->conf, CONF_sshbug_pksessid2) == FORCE_ON || @@ -520,8 +519,8 @@ static void ssh_detect_bugs(struct ssh_verstring_state *s) * public-key authentication. */ s->remote_bugs |= BUG_SSH2_PK_SESSIONID; - vs_logevent(("We believe remote version has SSH-2 " - "public-key-session-ID bug")); + bpp_logevent(("We believe remote version has SSH-2 " + "public-key-session-ID bug")); } if (conf_get_int(s->conf, CONF_sshbug_rekey2) == FORCE_ON || @@ -537,7 +536,7 @@ static void ssh_detect_bugs(struct ssh_verstring_state *s) * These versions have the SSH-2 rekey bug. */ s->remote_bugs |= BUG_SSH2_REKEY; - vs_logevent(("We believe remote version has SSH-2 rekey bug")); + bpp_logevent(("We believe remote version has SSH-2 rekey bug")); } if (conf_get_int(s->conf, CONF_sshbug_maxpkt2) == FORCE_ON || @@ -548,8 +547,8 @@ static void ssh_detect_bugs(struct ssh_verstring_state *s) * This version ignores our makpkt and needs to be throttled. */ s->remote_bugs |= BUG_SSH2_MAXPKT; - vs_logevent(("We believe remote version ignores SSH-2 " - "maximum packet size")); + bpp_logevent(("We believe remote version ignores SSH-2 " + "maximum packet size")); } if (conf_get_int(s->conf, CONF_sshbug_ignore2) == FORCE_ON) { @@ -558,7 +557,7 @@ static void ssh_detect_bugs(struct ssh_verstring_state *s) * none detected automatically. */ s->remote_bugs |= BUG_CHOKES_ON_SSH2_IGNORE; - vs_logevent(("We believe remote version has SSH-2 ignore bug")); + bpp_logevent(("We believe remote version has SSH-2 ignore bug")); } if (conf_get_int(s->conf, CONF_sshbug_oldgex2) == FORCE_ON || @@ -570,7 +569,7 @@ static void ssh_detect_bugs(struct ssh_verstring_state *s) * we use the newer version. */ s->remote_bugs |= BUG_SSH2_OLDGEX; - vs_logevent(("We believe remote version has outdated SSH-2 GEX")); + bpp_logevent(("We believe remote version has outdated SSH-2 GEX")); } if (conf_get_int(s->conf, CONF_sshbug_winadj) == FORCE_ON) { @@ -579,7 +578,7 @@ static void ssh_detect_bugs(struct ssh_verstring_state *s) * reason or another. Currently, none detected automatically. */ s->remote_bugs |= BUG_CHOKES_ON_WINADJ; - vs_logevent(("We believe remote version has winadj bug")); + bpp_logevent(("We believe remote version has winadj bug")); } if (conf_get_int(s->conf, CONF_sshbug_chanreq) == FORCE_ON || @@ -596,8 +595,8 @@ static void ssh_detect_bugs(struct ssh_verstring_state *s) * https://secure.ucc.asn.au/hg/dropbear/rev/cd02449b709c */ s->remote_bugs |= BUG_SENDS_LATE_REQUEST_REPLY; - vs_logevent(("We believe remote version has SSH-2 " - "channel request bug")); + bpp_logevent(("We believe remote version has SSH-2 " + "channel request bug")); } } From 4c8c41b7a0e62c45e9a9b10c9a9fb849d65603a1 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 7 Oct 2018 09:10:14 +0100 Subject: [PATCH 499/607] Support OpenSSH delayed compression without a rekey. The problem with OpenSSH delayed compression is that the spec has a race condition. Compression is enabled when the server sends USERAUTH_SUCCESS. In the server->client direction, that's fine: the USERAUTH_SUCCESS packet is not itself compressed, and the next packet in the same direction is. But in the client->server direction, this specification relies on there being a moment of half-duplex in the connection: the client can't send any outgoing packet _after_ whatever userauth packet the USERAUTH_SUCCESS was a response to, and _before_ finding out whether the response is USERAUTH_SUCCESS or something else. If it emitted, say, an SSH_MSG_IGNORE or initiated a rekey (perhaps due to a timeout), then that might cross in the network with USERAUTH_SUCCESS and the server wouldn't be able to know whether to treat it as compressed. My previous solution was to note the presence of delayed compression options in the server KEXINIT, but not to negotiate them in the initial key exchange. Instead, we conduct the userauth exchange with compression="none", and then once userauth has concluded, we trigger an immediate rekey in which we do accept delayed compression methods - because of course by that time they're no different from the non- delayed versions. And that means compression is enabled by the bidirectional NEWKEYS exchange, which lacks that race condition. I think OpenSSH itself gets away with this because its layer structure is structure so as to never send any such asynchronous transport-layer message in the middle of userauth. Ours is not. But my cunning plan is that now that my BPP abstraction includes a queue of packets to be sent and a callback that processes that queue on to the output raw data bufchain, it's possible to make that callback terminate early, to leave any dangerous transport-layer messages unsent while we wait for a userauth response. Specifically: if we've negotiated a delayed compression method and not yet seen USERAUTH_SUCCESS, then ssh2_bpp_handle_output will emit all packets from its queue up to and including the last one in the userauth type-code range, and keep back any further ones. The idea is that _if_ that last userauth message was one that might provoke USERAUTH_SUCCESS, we don't want to send any difficult things after it; if it's not (e.g. it's in the middle of some ongoing userauth process like k-i or GSS) then the userauth layer will know that, and will emit some further userauth packet on its own initiative which will clue us in that it's OK to release everything up to and including that one. (So in particular it wasn't even necessary to forbid _all_ transport- layer packets during userauth. I could have done that by reordering the output queue - packets in that queue haven't been assigned their sequence numbers yet, so that would have been safe - but it's more elegant not to have to.) One particular case we do have to be careful about is not trying to initiate a _rekey_ during userauth, if delayed compression is in the offing. That's because when we start rekeying, ssh2transport stops sending any higher-layer packets at all, to discourage servers from trying to ignore the KEXINIT and press on regardless - you don't get your higher-layer replies until you actually respond to the lower-layer interrupt. But in this case, if ssh2transport sent a KEXINIT, which ssh2bpp kept back in the queue to avoid a delayed compression race and would only send if another userauth packet followed it, which ssh2transport would never pass on to ssh2bpp's output queue, there'd be a complete protocol deadlock. So instead I defer any attempt to start a rekey until after userauth finishes (using the existing system for starting a deferred rekey at that moment, which was previously used for the _old_ delayed-compression strategy, and still has to be here anyway for GSSAPI purposes). --- ssh2bpp.c | 176 +++++++++++++++++++++++++++++++++++++++++++----- ssh2transport.c | 93 +++++++++---------------- sshbpp.h | 15 ++++- 3 files changed, 203 insertions(+), 81 deletions(-) diff --git a/ssh2bpp.c b/ssh2bpp.c index 67745278..681c7d44 100644 --- a/ssh2bpp.c +++ b/ssh2bpp.c @@ -14,6 +14,7 @@ struct ssh2_bpp_direction { ssh2_cipher *cipher; ssh2_mac *mac; int etm_mode; + const struct ssh_compression_alg *pending_compression; }; struct ssh2_bpp_state { @@ -34,6 +35,7 @@ struct ssh2_bpp_state { ssh_compressor *out_comp; int pending_newkeys; + int pending_compression, seen_userauth_success; BinaryPacketProtocol bpp; }; @@ -90,7 +92,7 @@ void ssh2_bpp_new_outgoing_crypto( BinaryPacketProtocol *bpp, const struct ssh2_cipheralg *cipher, const void *ckey, const void *iv, const struct ssh2_macalg *mac, int etm_mode, const void *mac_key, - const struct ssh_compression_alg *compression) + const struct ssh_compression_alg *compression, int delayed_compression) { struct ssh2_bpp_state *s; assert(bpp->vt == &ssh2_bpp_vtable); @@ -134,20 +136,31 @@ void ssh2_bpp_new_outgoing_crypto( s->out.mac = NULL; } - /* 'compression' is always non-NULL, because no compression is - * indicated by ssh_comp_none. But this setup call may return a - * null out_comp. */ - s->out_comp = ssh_compressor_new(compression); - if (s->out_comp) - bpp_logevent(("Initialised %s compression", - ssh_compressor_alg(s->out_comp)->text_name)); + if (delayed_compression && !s->seen_userauth_success) { + s->out.pending_compression = compression; + s->out_comp = NULL; + + bpp_logevent(("Will enable %s compression after user authentication", + s->out.pending_compression->text_name)); + } else { + s->out.pending_compression = NULL; + + /* 'compression' is always non-NULL, because no compression is + * indicated by ssh_comp_none. But this setup call may return a + * null out_comp. */ + s->out_comp = ssh_compressor_new(compression); + + if (s->out_comp) + bpp_logevent(("Initialised %s compression", + ssh_compressor_alg(s->out_comp)->text_name)); + } } void ssh2_bpp_new_incoming_crypto( BinaryPacketProtocol *bpp, const struct ssh2_cipheralg *cipher, const void *ckey, const void *iv, const struct ssh2_macalg *mac, int etm_mode, const void *mac_key, - const struct ssh_compression_alg *compression) + const struct ssh_compression_alg *compression, int delayed_compression) { struct ssh2_bpp_state *s; assert(bpp->vt == &ssh2_bpp_vtable); @@ -185,19 +198,39 @@ void ssh2_bpp_new_incoming_crypto( s->in.mac = NULL; } - /* 'compression' is always non-NULL, because no compression is - * indicated by ssh_comp_none. But this setup call may return a - * null in_decomp. */ - s->in_decomp = ssh_decompressor_new(compression); - if (s->in_decomp) - bpp_logevent(("Initialised %s decompression", - ssh_decompressor_alg(s->in_decomp)->text_name)); + if (delayed_compression && !s->seen_userauth_success) { + s->in.pending_compression = compression; + s->in_decomp = NULL; + + bpp_logevent(("Will enable %s decompression after user authentication", + s->in.pending_compression->text_name)); + } else { + s->in.pending_compression = NULL; + + /* 'compression' is always non-NULL, because no compression is + * indicated by ssh_comp_none. But this setup call may return a + * null in_decomp. */ + s->in_decomp = ssh_decompressor_new(compression); + + if (s->in_decomp) + bpp_logevent(("Initialised %s decompression", + ssh_decompressor_alg(s->in_decomp)->text_name)); + } /* Clear the pending_newkeys flag, so that handle_input below will * start consuming the input data again. */ s->pending_newkeys = FALSE; } +int ssh2_bpp_rekey_inadvisable(BinaryPacketProtocol *bpp) +{ + struct ssh2_bpp_state *s; + assert(bpp->vt == &ssh2_bpp_vtable); + s = container_of(bpp, struct ssh2_bpp_state, bpp); + + return s->pending_compression; +} + #define BPP_READ(ptr, len) do \ { \ crMaybeWaitUntilV(s->bpp.input_eof || \ @@ -207,6 +240,8 @@ void ssh2_bpp_new_incoming_crypto( goto eof; \ } while (0) +#define userauth_range(pkttype) ((unsigned)((pkttype) - 50) < 20) + static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp) { struct ssh2_bpp_state *s = container_of(bpp, struct ssh2_bpp_state, bpp); @@ -537,6 +572,74 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp) */ s->pending_newkeys = TRUE; crWaitUntilV(!s->pending_newkeys); + continue; + } + + if (s->pending_compression && userauth_range(type)) { + /* + * Another one: if we were configured with OpenSSH's + * deferred compression which is triggered on receipt + * of USERAUTH_SUCCESS, and we're currently + * anticipating the next packet perhaps _being_ + * USERAUTH_SUCCESS, then we do some special handling. + */ + + if (type == SSH2_MSG_USERAUTH_SUCCESS) { + /* + * Success! This is the moment to turn on + * compression. + */ + s->pending_compression = FALSE; + s->in_decomp = + ssh_decompressor_new(s->in.pending_compression); + s->out_comp = + ssh_compressor_new(s->out.pending_compression); + s->in.pending_compression = NULL; + s->out.pending_compression = NULL; + + if (s->out_comp) + bpp_logevent(("Initialised delayed %s compression", + ssh_compressor_alg( + s->out_comp)->text_name)); + if (s->in_decomp) + bpp_logevent(("Initialised delayed %s decompression", + ssh_decompressor_alg( + s->in_decomp)->text_name)); + + /* + * Also, since we will have temporarily disabled + * output queue processing (for fear of having + * some asynchronous thing like an IGNORE message + * cross in transit with USERAUTH_SUCCESS coming + * the other way, leaving its compresssion status + * in doubt), we should schedule a run of the + * output queue now, to release any pending + * packets. + */ + queue_idempotent_callback(&s->bpp.ic_out_pq); + } else { + /* + * This message indicates that we're not about to + * see USERAUTH_SUCCESS (i.e. turn on compression) + * just yet, so we turn off the outgoing packet + * blockage and release any queued output packets, + * so that we can make another attempt to + * authenticate. + */ + s->pending_compression = FALSE; + queue_idempotent_callback(&s->bpp.ic_out_pq); + } + } + + if (type == SSH2_MSG_USERAUTH_SUCCESS) { + /* + * Whether or not we were doing delayed compression in + * _this_ set of crypto parameters, we should set a + * flag indicating that we're now authenticated, so + * that a delayed compression method enabled in any + * future rekey will be treated as un-delayed. + */ + s->seen_userauth_success = TRUE; } } } @@ -734,6 +837,31 @@ static void ssh2_bpp_handle_output(BinaryPacketProtocol *bpp) { struct ssh2_bpp_state *s = container_of(bpp, struct ssh2_bpp_state, bpp); PktOut *pkt; + int n_userauth; + + /* + * Count the userauth packets in the queue. + */ + n_userauth = 0; + for (pkt = pq_first(&s->bpp.out_pq); pkt != NULL; + pkt = pq_next(&s->bpp.out_pq, pkt)) + if (userauth_range(pkt->type)) + n_userauth++; + + if (s->pending_compression && !n_userauth) { + /* + * We're currently blocked from sending any outgoing packets + * until the other end tells us whether we're going to have to + * enable compression or not. + * + * If our end has pushed a userauth packet on the queue, that + * must mean it knows that a USERAUTH_SUCCESS is not + * immediately forthcoming, so we unblock ourselves and send + * up to and including that packet. But in this if statement, + * there aren't any, so we're still blocked. + */ + return; + } if (s->cbc_ignore_workaround) { /* @@ -761,7 +889,23 @@ static void ssh2_bpp_handle_output(BinaryPacketProtocol *bpp) } while ((pkt = pq_pop(&s->bpp.out_pq)) != NULL) { + if (userauth_range(pkt->type)) + n_userauth--; + ssh2_bpp_format_packet(s, pkt); ssh_free_pktout(pkt); + + if (n_userauth == 0 && + (s->out.pending_compression || s->in.pending_compression)) { + /* + * This is the last userauth packet in the queue, so + * unless our side decides to send another one in future, + * we have to assume will potentially provoke + * USERAUTH_SUCCESS. Block (non-userauth) outgoing packets + * until we see the reply. + */ + s->pending_compression = TRUE; + return; + } } } diff --git a/ssh2transport.c b/ssh2transport.c index 60626403..a058f752 100644 --- a/ssh2transport.c +++ b/ssh2transport.c @@ -49,7 +49,10 @@ struct kexinit_algorithm { const struct ssh2_macalg *mac; int etm; } mac; - const struct ssh_compression_alg *comp; + struct { + const struct ssh_compression_alg *comp; + int delayed; + } comp; } u; }; @@ -206,6 +209,7 @@ struct ssh2_transport_state { const struct ssh2_macalg *mac; int etm_mode; const struct ssh_compression_alg *comp; + int comp_delayed; } in, out; ptrlen hostkeydata, sigdata; char *keystr, *fingerprint; @@ -223,8 +227,6 @@ struct ssh2_transport_state { int n_preferred_ciphers; const struct ssh2_ciphers *preferred_ciphers[CIPHER_MAX]; const struct ssh_compression_alg *preferred_comp; - int userauth_succeeded; /* for delayed compression */ - int pending_compression; int got_session_id; int dlgret; int guessok; @@ -614,8 +616,6 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) s->in.comp = s->out.comp = NULL; s->got_session_id = FALSE; - s->userauth_succeeded = FALSE; - s->pending_compression = FALSE; s->need_gss_transient_hostkey = FALSE; s->warned_about_no_gss_transient_hostkey = FALSE; @@ -935,22 +935,23 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) assert(lenof(compressions) > 1); /* Prefer non-delayed versions */ alg = ssh2_kexinit_addalg(s->kexlists[j], s->preferred_comp->name); - alg->u.comp = s->preferred_comp; - /* We don't even list delayed versions of algorithms until - * they're allowed to be used, to avoid a race. See the end of - * this function. */ - if (s->userauth_succeeded && s->preferred_comp->delayed_name) { + alg->u.comp.comp = s->preferred_comp; + alg->u.comp.delayed = FALSE; + if (s->preferred_comp->delayed_name) { alg = ssh2_kexinit_addalg(s->kexlists[j], s->preferred_comp->delayed_name); - alg->u.comp = s->preferred_comp; + alg->u.comp.comp = s->preferred_comp; + alg->u.comp.delayed = TRUE; } for (i = 0; i < lenof(compressions); i++) { const struct ssh_compression_alg *c = compressions[i]; alg = ssh2_kexinit_addalg(s->kexlists[j], c->name); - alg->u.comp = c; - if (s->userauth_succeeded && c->delayed_name) { + alg->u.comp.comp = c; + alg->u.comp.delayed = FALSE; + if (c->delayed_name) { alg = ssh2_kexinit_addalg(s->kexlists[j], c->delayed_name); - alg->u.comp = c; + alg->u.comp.comp = c; + alg->u.comp.delayed = TRUE; } } } @@ -1006,6 +1007,7 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) s->in.cipher = s->out.cipher = NULL; s->in.mac = s->out.mac = NULL; s->in.comp = s->out.comp = NULL; + s->in.comp_delayed = s->out.comp_delayed = FALSE; s->warn_kex = s->warn_hk = FALSE; s->warn_cscipher = s->warn_sccipher = FALSE; @@ -1076,21 +1078,14 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) s->in.mac = alg->u.mac.mac; s->in.etm_mode = alg->u.mac.etm; } else if (i == KEXLIST_CSCOMP) { - s->out.comp = alg->u.comp; + s->out.comp = alg->u.comp.comp; + s->out.comp_delayed = alg->u.comp.delayed; } else if (i == KEXLIST_SCCOMP) { - s->in.comp = alg->u.comp; + s->in.comp = alg->u.comp.comp; + s->in.comp_delayed = alg->u.comp.delayed; } goto matched; } - - /* Set a flag if there's a delayed compression option - * available for a compression method that we just - * failed to select the immediate version of. */ - s->pending_compression = ( - (i == KEXLIST_CSCOMP || i == KEXLIST_SCCOMP) && - in_commasep_string(alg->u.comp->delayed_name, - str.ptr, str.len) && - !s->userauth_succeeded); } ssh_sw_abort(s->ppl.ssh, "Couldn't agree a %s (available: %.*s)", kexlist_descr[i], PTRLEN_PRINTF(str)); @@ -1127,10 +1122,6 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) } } - if (s->pending_compression) { - ppl_logevent(("Server supports delayed compression; " - "will try this later")); - } get_string(pktin); /* client->server language */ get_string(pktin); /* server->client language */ s->ignorepkt = get_bool(pktin) && !s->guessok; @@ -2146,7 +2137,7 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) s->ppl.bpp, s->out.cipher, cipher_key->u, cipher_iv->u, s->out.mac, s->out.etm_mode, mac_key->u, - s->out.comp); + s->out.comp, s->out.comp_delayed); strbuf_free(cipher_key); strbuf_free(cipher_iv); @@ -2201,7 +2192,7 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) s->ppl.bpp, s->in.cipher, cipher_key->u, cipher_iv->u, s->in.mac, s->in.etm_mode, mac_key->u, - s->in.comp); + s->in.comp, s->in.comp_delayed); strbuf_free(cipher_key); strbuf_free(cipher_iv); @@ -2288,41 +2279,17 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) if (s->rekey_class == RK_POST_USERAUTH) { /* - * userauth has seen a USERAUTH_SUCCEEDED. For a couple of - * reasons, this may be the moment to do an immediate - * rekey with different parameters. But it may not; so - * here we turn that rekey class into either RK_NONE or - * RK_NORMAL. + * userauth has seen a USERAUTH_SUCCESS. This may be the + * moment to do an immediate rekey with different + * parameters. But it may not; so here we turn that rekey + * class into either RK_NONE or RK_NORMAL. * - * One is to turn on delayed compression. We do this by a - * rekey to work around a protocol design bug: - * draft-miller-secsh-compression-delayed-00 says that you - * negotiate delayed compression in the first key - * exchange, and both sides start compressing when the - * server has sent USERAUTH_SUCCESS. This has a race - * condition -- the server can't know when the client has - * seen it, and thus which incoming packets it should - * treat as compressed. - * - * Instead, we do the initial key exchange without - * offering the delayed methods, but note if the server - * offers them; when we get here, if a delayed method was - * available that was higher on our list than what we got, - * we initiate a rekey in which we _do_ list the delayed - * methods (and hopefully get it as a result). Subsequent - * rekeys will do the same. - * - * Another reason for a rekey at this point is if we've - * done a GSS key exchange and don't have anything in our + * Currently the only reason for this is if we've done a + * GSS key exchange and don't have anything in our * transient hostkey cache, in which case we should make * an attempt to populate the cache now. */ - assert(!s->userauth_succeeded); /* should only happen once */ - s->userauth_succeeded = TRUE; - if (s->pending_compression) { - s->rekey_reason = "enabling delayed compression"; - s->rekey_class = RK_NORMAL; - } else if (s->need_gss_transient_hostkey) { + if (s->need_gss_transient_hostkey) { s->rekey_reason = "populating transient host key cache"; s->rekey_class = RK_NORMAL; } else { @@ -2908,7 +2875,7 @@ static void ssh2_transport_reconfigure(PacketProtocolLayer *ppl, Conf *conf) s->conf = conf_copy(conf); if (rekey_reason) { - if (!s->kex_in_progress) { + if (!s->kex_in_progress && !ssh2_bpp_rekey_inadvisable(s->ppl.bpp)) { s->rekey_reason = rekey_reason; s->rekey_class = RK_NORMAL; queue_idempotent_callback(&s->ppl.ic_process_queue); diff --git a/sshbpp.h b/sshbpp.h index 3914eeb3..e5de4dbc 100644 --- a/sshbpp.h +++ b/sshbpp.h @@ -103,12 +103,23 @@ void ssh2_bpp_new_outgoing_crypto( BinaryPacketProtocol *bpp, const struct ssh2_cipheralg *cipher, const void *ckey, const void *iv, const struct ssh2_macalg *mac, int etm_mode, const void *mac_key, - const struct ssh_compression_alg *compression); + const struct ssh_compression_alg *compression, int delayed_compression); void ssh2_bpp_new_incoming_crypto( BinaryPacketProtocol *bpp, const struct ssh2_cipheralg *cipher, const void *ckey, const void *iv, const struct ssh2_macalg *mac, int etm_mode, const void *mac_key, - const struct ssh_compression_alg *compression); + const struct ssh_compression_alg *compression, int delayed_compression); + +/* + * A query method specific to the interface between ssh2transport and + * ssh2bpp. If true, it indicates that we're potentially in the + * race-condition-prone part of delayed compression setup and so + * asynchronous outgoing transport-layer packets are currently not + * being sent, which means in particular that it would be a bad idea + * to start a rekey because then we'd stop responding to anything + * _other_ than transport-layer packets and deadlock the protocol. + */ +int ssh2_bpp_rekey_inadvisable(BinaryPacketProtocol *bpp); BinaryPacketProtocol *ssh2_bare_bpp_new(Frontend *frontend); From 34df99907a4ce8ad6dbd3d4c4426e77484156a12 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 7 Oct 2018 12:56:57 +0100 Subject: [PATCH 500/607] Try to decouple directions of delayed compression. I ran 'git push' too soon on the last commit; after a bit more thought I realise that I didn't get the logic quite right in the case where one direction of the connection negotiates delayed compression and the other negotiates ordinary or no compression. For a start, we only need to worry about temporarily delaying outgoing packets to avoid the race condition if delayed compression applies to _outgoing_ packets - that can be disabled in the case where delayed compression is inbound only (though that is admittedly unlikely). Secondly, that means that detecting USERAUTH_SUCCESS to enable compression has to happen even if the output blockage wasn't in place. Thirdly, if we're independently enabling delayed compression in the two directions, we should only print an Event Log entry for the one we actually did! This revised version is probably more robust, although for the moment all of this is theoretical - I haven't tested against a server implementing unidirectional delayed compression. --- ssh2bpp.c | 79 ++++++++++++++++++++++--------------------------------- 1 file changed, 31 insertions(+), 48 deletions(-) diff --git a/ssh2bpp.c b/ssh2bpp.c index 681c7d44..c837194a 100644 --- a/ssh2bpp.c +++ b/ssh2bpp.c @@ -575,63 +575,30 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp) continue; } - if (s->pending_compression && userauth_range(type)) { + if (type == SSH2_MSG_USERAUTH_SUCCESS) { /* * Another one: if we were configured with OpenSSH's * deferred compression which is triggered on receipt - * of USERAUTH_SUCCESS, and we're currently - * anticipating the next packet perhaps _being_ - * USERAUTH_SUCCESS, then we do some special handling. + * of USERAUTH_SUCCESS, then this is the moment to + * turn on compression. */ - - if (type == SSH2_MSG_USERAUTH_SUCCESS) { - /* - * Success! This is the moment to turn on - * compression. - */ - s->pending_compression = FALSE; + if (s->in.pending_compression) { s->in_decomp = ssh_decompressor_new(s->in.pending_compression); + bpp_logevent(("Initialised delayed %s decompression", + ssh_decompressor_alg( + s->in_decomp)->text_name)); + s->in.pending_compression = NULL; + } + if (s->out.pending_compression) { s->out_comp = ssh_compressor_new(s->out.pending_compression); - s->in.pending_compression = NULL; + bpp_logevent(("Initialised delayed %s compression", + ssh_compressor_alg( + s->out_comp)->text_name)); s->out.pending_compression = NULL; - - if (s->out_comp) - bpp_logevent(("Initialised delayed %s compression", - ssh_compressor_alg( - s->out_comp)->text_name)); - if (s->in_decomp) - bpp_logevent(("Initialised delayed %s decompression", - ssh_decompressor_alg( - s->in_decomp)->text_name)); - - /* - * Also, since we will have temporarily disabled - * output queue processing (for fear of having - * some asynchronous thing like an IGNORE message - * cross in transit with USERAUTH_SUCCESS coming - * the other way, leaving its compresssion status - * in doubt), we should schedule a run of the - * output queue now, to release any pending - * packets. - */ - queue_idempotent_callback(&s->bpp.ic_out_pq); - } else { - /* - * This message indicates that we're not about to - * see USERAUTH_SUCCESS (i.e. turn on compression) - * just yet, so we turn off the outgoing packet - * blockage and release any queued output packets, - * so that we can make another attempt to - * authenticate. - */ - s->pending_compression = FALSE; - queue_idempotent_callback(&s->bpp.ic_out_pq); } - } - if (type == SSH2_MSG_USERAUTH_SUCCESS) { /* * Whether or not we were doing delayed compression in * _this_ set of crypto parameters, we should set a @@ -641,6 +608,23 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp) */ s->seen_userauth_success = TRUE; } + + if (s->pending_compression && userauth_range(type)) { + /* + * Receiving any userauth message at all indicates + * that we're not about to turn on delayed compression + * - either because we just _have_ done, or because + * this message is a USERAUTH_FAILURE or some kind of + * intermediate 'please send more data' continuation + * message. Either way, we turn off the outgoing + * packet blockage for now, and release any queued + * output packets, so that we can make another attempt + * to authenticate. The next userauth packet we send + * will re-block the output direction. + */ + s->pending_compression = FALSE; + queue_idempotent_callback(&s->bpp.ic_out_pq); + } } } @@ -895,8 +879,7 @@ static void ssh2_bpp_handle_output(BinaryPacketProtocol *bpp) ssh2_bpp_format_packet(s, pkt); ssh_free_pktout(pkt); - if (n_userauth == 0 && - (s->out.pending_compression || s->in.pending_compression)) { + if (n_userauth == 0 && s->out.pending_compression) { /* * This is the last userauth packet in the queue, so * unless our side decides to send another one in future, From 9072bab11b70abd9e33dc8c029d25cd796542bf4 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 7 Oct 2018 14:04:26 +0100 Subject: [PATCH 501/607] Unix: fix segfault if ~/.putty/sessions doesn't exist. Looks as if I introduced this in commit 733fcca2c, where the pointer returned from enum_settings_start() stopped being the same thing as the underlying 'DIR *' - I needed to retain a check for the outer containing structure not being NULL but the DIR * being NULL inside it. --- unix/uxstore.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/unix/uxstore.c b/unix/uxstore.c index 84d8d4d6..de1680f4 100644 --- a/unix/uxstore.c +++ b/unix/uxstore.c @@ -562,6 +562,9 @@ char *enum_settings_next(settings_e *handle, char *buffer, int buflen) int maxlen, thislen, len; char *unmunged; + if (!handle->dp) + return NULL; + fullpath = make_filename(INDEX_SESSIONDIR, NULL); maxlen = len = strlen(fullpath); @@ -592,7 +595,8 @@ char *enum_settings_next(settings_e *handle, char *buffer, int buflen) void enum_settings_finish(settings_e *handle) { - closedir(handle->dp); + if (handle->dp) + closedir(handle->dp); sfree(handle); } From 55860cace76f47b11fc9889261bd3d4e5950a787 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 7 Oct 2018 14:46:21 +0100 Subject: [PATCH 502/607] log_proxy_stderr: cope with CRLF on proxy stderr lines. The CR was getting as far as GTK, where it caused a formatting oddity in the Event Log list box. It should be stripped along with the LF. --- be_misc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/be_misc.c b/be_misc.c index 86a7e739..55853411 100644 --- a/be_misc.c +++ b/be_misc.c @@ -91,6 +91,8 @@ void log_proxy_stderr(Plug *plug, bufchain *buf, const void *vdata, int len) msg = snewn(msglen+1, char); bufchain_fetch(buf, msg, msglen); bufchain_consume(buf, msglen); + while (msglen > 0 && (msg[msglen-1] == '\n' || msg[msglen-1] == '\r')) + msglen--; msg[msglen] = '\0'; fullmsg = dupprintf("proxy: %s", msg); plug_log(plug, 2, NULL, 0, fullmsg, 0); From cea1329b9ea15f7856125bf170486cda6a85145d Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 7 Oct 2018 14:47:16 +0100 Subject: [PATCH 503/607] Make new_error_socket() into a printf-style function. Almost all the call sites were doing a cumbersome dupprintf-use-free cycle to get a formatted message into an ErrorSocket anyway, so it seems more sensible to give them an easier way of doing so. The few call sites that were passing a constant string literal _shouldn't_ have been - they'll be all the better for adding a strerror suffix to the message they were previously giving! --- Recipe | 2 +- errsock.c | 16 ++++++++++++++-- network.h | 2 +- windows/winnpc.c | 37 +++++++++++++------------------------ windows/winproxy.c | 18 +++++++++--------- 5 files changed, 38 insertions(+), 37 deletions(-) diff --git a/Recipe b/Recipe index 10366fe0..eabdf3fa 100644 --- a/Recipe +++ b/Recipe @@ -270,7 +270,7 @@ MISC = misc marshal MISCNET = timing callback MISC version settings tree234 proxy CONF be_misc WINMISC = MISCNET winstore winnet winhandl cmdline windefs winmisc winproxy + wintime winhsock errsock winsecur winucs miscucs -UXMISC = MISCNET uxstore uxsel uxnet uxpeer uxmisc uxproxy time +UXMISC = MISCNET uxstore uxsel uxnet uxpeer uxmisc uxproxy errsock time # import.c and dependencies, for PuTTYgen-like utilities that have to # load foreign key files. diff --git a/errsock.c b/errsock.c index d4878a9a..7e5f97be 100644 --- a/errsock.c +++ b/errsock.c @@ -56,11 +56,23 @@ static const SocketVtable ErrorSocket_sockvt = { sk_error_peer_info, }; -Socket *new_error_socket(const char *errmsg, Plug *plug) +static Socket *new_error_socket_internal(char *errmsg, Plug *plug) { ErrorSocket *es = snew(ErrorSocket); es->sock.vt = &ErrorSocket_sockvt; es->plug = plug; - es->error = dupstr(errmsg); + es->error = errmsg; return &es->sock; } + +Socket *new_error_socket_fmt(Plug *plug, const char *fmt, ...) +{ + va_list ap; + char *msg; + + va_start(ap, fmt); + msg = dupvprintf(fmt, ap); + va_end(ap); + + return new_error_socket_internal(msg, plug); +} diff --git a/network.h b/network.h index 62361d11..f7152054 100644 --- a/network.h +++ b/network.h @@ -220,7 +220,7 @@ char *get_hostname(void); * Trivial socket implementation which just stores an error. Found in * errsock.c. */ -Socket *new_error_socket(const char *errmsg, Plug *plug); +Socket *new_error_socket_fmt(Plug *plug, const char *fmt, ...); /* * Trivial plug that does absolutely nothing. Found in nullplug.c. diff --git a/windows/winnpc.c b/windows/winnpc.c index b61ddada..63387230 100644 --- a/windows/winnpc.c +++ b/windows/winnpc.c @@ -23,7 +23,6 @@ Socket *new_named_pipe_client(const char *pipename, Plug *plug) HANDLE pipehandle; PSID usersid, pipeowner; PSECURITY_DESCRIPTOR psd; - char *err; Socket *ret; assert(strncmp(pipename, "\\\\.\\pipe\\", 9) == 0); @@ -38,11 +37,9 @@ Socket *new_named_pipe_client(const char *pipename, Plug *plug) break; if (GetLastError() != ERROR_PIPE_BUSY) { - err = dupprintf("Unable to open named pipe '%s': %s", - pipename, win_strerror(GetLastError())); - ret = new_error_socket(err, plug); - sfree(err); - return ret; + return new_error_socket_fmt( + plug, "Unable to open named pipe '%s': %s", + pipename, win_strerror(GetLastError())); } /* @@ -53,41 +50,33 @@ Socket *new_named_pipe_client(const char *pipename, Plug *plug) * take excessively long.) */ if (!WaitNamedPipe(pipename, NMPWAIT_USE_DEFAULT_WAIT)) { - err = dupprintf("Error waiting for named pipe '%s': %s", - pipename, win_strerror(GetLastError())); - ret = new_error_socket(err, plug); - sfree(err); - return ret; + return new_error_socket_fmt( + plug, "Error waiting for named pipe '%s': %s", + pipename, win_strerror(GetLastError())); } } if ((usersid = get_user_sid()) == NULL) { CloseHandle(pipehandle); - err = dupprintf("Unable to get user SID"); - ret = new_error_socket(err, plug); - sfree(err); - return ret; + return new_error_socket_fmt( + plug, "Unable to get user SID: %s", win_strerror(GetLastError())); } if (p_GetSecurityInfo(pipehandle, SE_KERNEL_OBJECT, OWNER_SECURITY_INFORMATION, &pipeowner, NULL, NULL, NULL, &psd) != ERROR_SUCCESS) { - err = dupprintf("Unable to get named pipe security information: %s", - win_strerror(GetLastError())); - ret = new_error_socket(err, plug); - sfree(err); CloseHandle(pipehandle); - return ret; + return new_error_socket_fmt( + plug, "Unable to get named pipe security information: %s", + win_strerror(GetLastError())); } if (!EqualSid(pipeowner, usersid)) { - err = dupprintf("Owner of named pipe '%s' is not us", pipename); - ret = new_error_socket(err, plug); - sfree(err); CloseHandle(pipehandle); LocalFree(psd); - return ret; + return new_error_socket_fmt( + plug, "Owner of named pipe '%s' is not us", pipename); } LocalFree(psd); diff --git a/windows/winproxy.c b/windows/winproxy.c index 2059d964..d0a8884b 100644 --- a/windows/winproxy.c +++ b/windows/winproxy.c @@ -50,30 +50,30 @@ Socket *platform_new_connection(SockAddr *addr, const char *hostname, sa.lpSecurityDescriptor = NULL; /* default */ sa.bInheritHandle = TRUE; if (!CreatePipe(&us_from_cmd, &cmd_to_us, &sa, 0)) { - Socket *ret = - new_error_socket("Unable to create pipes for proxy command", plug); sfree(cmd); - return ret; + return new_error_socket_fmt( + plug, "Unable to create pipes for proxy command: %s", + win_strerror(GetLastError())); } if (!CreatePipe(&cmd_from_us, &us_to_cmd, &sa, 0)) { - Socket *ret = - new_error_socket("Unable to create pipes for proxy command", plug); sfree(cmd); CloseHandle(us_from_cmd); CloseHandle(cmd_to_us); - return ret; + return new_error_socket_fmt( + plug, "Unable to create pipes for proxy command: %s", + win_strerror(GetLastError())); } if (!CreatePipe(&us_from_cmd_err, &cmd_err_to_us, &sa, 0)) { - Socket *ret = new_error_socket - ("Unable to create pipes for proxy command", plug); sfree(cmd); CloseHandle(us_from_cmd); CloseHandle(cmd_to_us); CloseHandle(us_to_cmd); CloseHandle(cmd_from_us); - return ret; + return new_error_socket_fmt( + plug, "Unable to create pipes for proxy command: %s", + win_strerror(GetLastError())); } SetHandleInformation(us_to_cmd, HANDLE_FLAG_INHERIT, 0); From 2ea356c46c713566b077e659ee4f9a079997142c Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 7 Oct 2018 21:22:05 +0100 Subject: [PATCH 504/607] Fix crash on early connection of a sharing downstream. If you start up two sharing-enabled PuTTYs to the same host simultaneously, the one that ends up being the downstream can connect to the upstream before the upstream has provided a ConnectionLayer to the sharestate, which means that log_downstream() will dereference cs->parent->cl->frontend to find its Frontend and fail because cl is NULL. Fixed by providing a dummy initial ConnectionLayer containing nothing but a frontend pointer, which is then replaced by the real one later. --- ssh.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/ssh.c b/ssh.c index 433a2572..0119d236 100644 --- a/ssh.c +++ b/ssh.c @@ -91,6 +91,12 @@ struct Ssh { */ ConnectionLayer *cl; + /* + * A dummy ConnectionLayer that can be used for logging sharing + * downstreams that connect before the real one is ready. + */ + ConnectionLayer cl_dummy; + /* * session_started is FALSE until we initialise the main protocol * layers. So it distinguishes between base_layer==NULL meaning @@ -106,6 +112,7 @@ struct Ssh { int need_random_unref; }; + #define ssh_logevent(params) ( \ logevent_and_free((ssh)->frontend, dupprintf params)) @@ -640,6 +647,8 @@ static const char *connect_to_host(Ssh *ssh, const char *host, int port, ssh->s = ssh_connection_sharing_init( ssh->savedhost, ssh->savedport, ssh->conf, ssh->frontend, &ssh->plug, &ssh->connshare); + if (ssh->connshare) + ssh_connshare_provide_connlayer(ssh->connshare, &ssh->cl_dummy); ssh->attempting_connshare = FALSE; if (ssh->s != NULL) { /* @@ -805,6 +814,7 @@ static const char *ssh_init(Frontend *frontend, Backend **backend_handle, *backend_handle = &ssh->backend; ssh->frontend = frontend; + ssh->cl_dummy.frontend = frontend; random_ref(); /* do this now - may be needed by sharing setup code */ ssh->need_random_unref = TRUE; From e3e434537da5e0a42fed71b9c684f1f5176cb726 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 7 Oct 2018 20:37:30 +0100 Subject: [PATCH 505/607] Fix crash when disconnecting in verstring phase. If we disconnect because the two ends' SSH protocol versions don't match, ssh_initiate_connection_close triggers a call to the BPP's handle_output method, and sshverstring's one of those unconditionally fails an assertion on the basis that nobody should be trying to send SSH packets at that stage of the connection. In fact this call to handle_output is only precautionary, and it's unproblematic because there aren't any packets on the output queue. So the assertion is now conditional on there actually being an erroneous packet. --- sshverstring.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sshverstring.c b/sshverstring.c index 66db98b6..68cee61c 100644 --- a/sshverstring.c +++ b/sshverstring.c @@ -409,8 +409,10 @@ static PktOut *ssh_verstring_new_pktout(int type) static void ssh_verstring_handle_output(BinaryPacketProtocol *bpp) { - assert(0 && "Should never try to send packets during SSH version " - "string exchange"); + if (pq_peek(&bpp->out_pq)) { + assert(0 && "Should never try to send packets during SSH version " + "string exchange"); + } } /* From d624ae2ab5090c1c14db2b329df1cd4eb71db621 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Mon, 8 Oct 2018 19:25:57 +0100 Subject: [PATCH 506/607] Fix double-free bug in (non-EC) Diffie-Hellman. The variable s->e in ssh2_transport_state should never be freed by ssh2transport itself, because it's owned by the dh_ctx, so it will be freed by dh_cleanup. --- ssh2transport.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/ssh2transport.c b/ssh2transport.c index a058f752..0b1f6506 100644 --- a/ssh2transport.c +++ b/ssh2transport.c @@ -395,7 +395,6 @@ static void ssh2_transport_free(PacketProtocolLayer *ppl) ssh_key_free(s->hkey); s->hkey = NULL; } - if (s->e) freebn(s->e); if (s->f) freebn(s->f); if (s->p) freebn(s->p); if (s->g) freebn(s->g); @@ -1368,7 +1367,6 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) dh_cleanup(s->dh_ctx); s->dh_ctx = NULL; freebn(s->f); s->f = NULL; - freebn(s->e); s->e = NULL; if (dh_is_gex(s->kex_alg)) { freebn(s->g); s->g = NULL; freebn(s->p); s->p = NULL; @@ -1690,7 +1688,6 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) dh_cleanup(s->dh_ctx); s->dh_ctx = NULL; freebn(s->f); s->f = NULL; - freebn(s->e); s->e = NULL; if (dh_is_gex(s->kex_alg)) { freebn(s->g); s->g = NULL; freebn(s->p); s->p = NULL; From a3a8b285287772b6d7c2f0870dfd3694d5d879d4 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Mon, 8 Oct 2018 19:30:01 +0100 Subject: [PATCH 507/607] Tidy up 'eventlog_stuff' structure and fix leak. This is the structure that stores the truncated version of the Event Log data to be displayed by the GTK Event Log dialog. It persists for the lifetime of the parent SSH window, so it was deliberate that it wasn't freed on destruction of the dialog itself, but I also forgot to free it on destruction of the SSH window. (This will be more important in multi-connection process architectures like the OS X port, of course.) While I'm at it, I'll follow my recent practice by exposing the structure tag outside gtkdlg.c so that callers can more easily not confuse it with some other kind of void *. --- unix/gtkdlg.c | 37 ++++++++++++++++++++++++++----------- unix/gtkwin.c | 4 +++- unix/unix.h | 8 +++++--- 3 files changed, 34 insertions(+), 15 deletions(-) diff --git a/unix/gtkdlg.c b/unix/gtkdlg.c index 6ffb5b5c..ccabe1e3 100644 --- a/unix/gtkdlg.c +++ b/unix/gtkdlg.c @@ -3772,7 +3772,7 @@ struct eventlog_stuff { static void eventlog_destroy(GtkWidget *widget, gpointer data) { - struct eventlog_stuff *es = (struct eventlog_stuff *)data; + eventlog_stuff *es = (eventlog_stuff *)data; es->window = NULL; sfree(es->seldata); @@ -3789,7 +3789,7 @@ static void eventlog_ok_handler(union control *ctrl, dlgparam *dp, static void eventlog_list_handler(union control *ctrl, dlgparam *dp, void *data, int event) { - struct eventlog_stuff *es = (struct eventlog_stuff *)data; + eventlog_stuff *es = (eventlog_stuff *)data; if (event == EVENT_REFRESH) { int i; @@ -3868,7 +3868,7 @@ static void eventlog_list_handler(union control *ctrl, dlgparam *dp, void eventlog_selection_get(GtkWidget *widget, GtkSelectionData *seldata, guint info, guint time_stamp, gpointer data) { - struct eventlog_stuff *es = (struct eventlog_stuff *)data; + eventlog_stuff *es = (eventlog_stuff *)data; gtk_selection_data_set(seldata, gtk_selection_data_get_target(seldata), 8, (unsigned char *)es->seldata, es->sellen); @@ -3877,7 +3877,7 @@ void eventlog_selection_get(GtkWidget *widget, GtkSelectionData *seldata, gint eventlog_selection_clear(GtkWidget *widget, GdkEventSelection *seldata, gpointer data) { - struct eventlog_stuff *es = (struct eventlog_stuff *)data; + eventlog_stuff *es = (eventlog_stuff *)data; struct uctrl *uc; /* @@ -3901,9 +3901,8 @@ gint eventlog_selection_clear(GtkWidget *widget, GdkEventSelection *seldata, return TRUE; } -void showeventlog(void *estuff, void *parentwin) +void showeventlog(eventlog_stuff *es, void *parentwin) { - struct eventlog_stuff *es = (struct eventlog_stuff *)estuff; GtkWidget *window, *w0, *w1; GtkWidget *parent = GTK_WIDGET(parentwin); struct controlset *s0, *s1; @@ -3984,17 +3983,33 @@ void showeventlog(void *estuff, void *parentwin) G_CALLBACK(eventlog_selection_clear), es); } -void *eventlogstuff_new(void) +eventlog_stuff *eventlogstuff_new(void) { - struct eventlog_stuff *es; - es = snew(struct eventlog_stuff); + eventlog_stuff *es = snew(eventlog_stuff); memset(es, 0, sizeof(*es)); return es; } -void logevent_dlg(void *estuff, const char *string) +void eventlogstuff_free(eventlog_stuff *es) +{ + int i; + + if (es->events_initial) { + for (i = 0; i < LOGEVENT_INITIAL_MAX; i++) + sfree(es->events_initial[i]); + sfree(es->events_initial); + } + if (es->events_circular) { + for (i = 0; i < LOGEVENT_CIRCULAR_MAX; i++) + sfree(es->events_circular[i]); + sfree(es->events_circular); + } + + sfree(es); +} + +void logevent_dlg(eventlog_stuff *es, const char *string) { - struct eventlog_stuff *es = (struct eventlog_stuff *)estuff; char timebuf[40]; struct tm tm; char **location; diff --git a/unix/gtkwin.c b/unix/gtkwin.c index 64aae476..6ec5d639 100644 --- a/unix/gtkwin.c +++ b/unix/gtkwin.c @@ -165,7 +165,7 @@ struct Frontend { int exited; struct unicode_data ucsdata; Conf *conf; - void *eventlogstuff; + eventlog_stuff *eventlogstuff; guint32 input_event_time; /* Timestamp of the most recent input event. */ GtkWidget *dialogs[DIALOG_SLOT_LIMIT]; #if GTK_CHECK_VERSION(3,4,0) @@ -2470,6 +2470,8 @@ static void delete_inst(Frontend *inst) */ delete_callbacks_for_context(inst); + eventlogstuff_free(inst->eventlogstuff); + sfree(inst); } diff --git a/unix/unix.h b/unix/unix.h index 932d666e..c85c8470 100644 --- a/unix/unix.h +++ b/unix/unix.h @@ -219,9 +219,11 @@ GtkWidget *create_config_box(const char *title, Conf *conf, #endif void nonfatal_message_box(void *window, const char *msg); void about_box(void *window); -void *eventlogstuff_new(void); -void showeventlog(void *estuff, void *parentwin); -void logevent_dlg(void *estuff, const char *string); +typedef struct eventlog_stuff eventlog_stuff; +eventlog_stuff *eventlogstuff_new(void); +void eventlogstuff_free(eventlog_stuff *); +void showeventlog(eventlog_stuff *estuff, void *parentwin); +void logevent_dlg(eventlog_stuff *estuff, const char *string); #ifdef MAY_REFER_TO_GTK_IN_HEADERS struct message_box_button { const char *title; From 78d0022c707b3dffa2514fe842be04224213da73 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Mon, 8 Oct 2018 19:35:58 +0100 Subject: [PATCH 508/607] settings.c: replace some 'void *' with proper types. Commit 733fcca2c introduced named types settings_r and settings_w and made the per-platform storage abstraction use those in place of 'void *'. But a lot of the intermediate helper functions in the centralised settings.c, like gpps() and wmap(), were still taking 'void *'. It still worked, because of C's implicit casting, but it was avoiding the type-checking advantages from making that change in the first place. --- settings.c | 55 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/settings.c b/settings.c index 92c8b270..6ba04720 100644 --- a/settings.c +++ b/settings.c @@ -105,9 +105,9 @@ char *get_remote_username(Conf *conf) } } -static char *gpps_raw(void *handle, const char *name, const char *def) +static char *gpps_raw(settings_r *sesskey, const char *name, const char *def) { - char *ret = read_setting_s(handle, name); + char *ret = read_setting_s(sesskey, name); if (!ret) ret = platform_default_s(name); if (!ret) @@ -115,10 +115,10 @@ static char *gpps_raw(void *handle, const char *name, const char *def) return ret; } -static void gpps(void *handle, const char *name, const char *def, +static void gpps(settings_r *sesskey, const char *name, const char *def, Conf *conf, int primary) { - char *val = gpps_raw(handle, name, def); + char *val = gpps_raw(sesskey, name, def); conf_set_str(conf, primary, val); sfree(val); } @@ -128,33 +128,35 @@ static void gpps(void *handle, const char *name, const char *def, * format of a Filename or FontSpec is platform-dependent. So the * platform-dependent functions MUST return some sort of value. */ -static void gppfont(void *handle, const char *name, Conf *conf, int primary) +static void gppfont(settings_r *sesskey, char *name, + Conf *conf, int primary) { - FontSpec *result = read_setting_fontspec(handle, name); + FontSpec *result = read_setting_fontspec(sesskey, name); if (!result) result = platform_default_fontspec(name); conf_set_fontspec(conf, primary, result); fontspec_free(result); } -static void gppfile(void *handle, const char *name, Conf *conf, int primary) +static void gppfile(settings_r *sesskey, const char *name, + Conf *conf, int primary) { - Filename *result = read_setting_filename(handle, name); + Filename *result = read_setting_filename(sesskey, name); if (!result) result = platform_default_filename(name); conf_set_filename(conf, primary, result); filename_free(result); } -static int gppi_raw(void *handle, const char *name, int def) +static int gppi_raw(settings_r *sesskey, const char *name, int def) { def = platform_default_i(name, def); - return read_setting_i(handle, name, def); + return read_setting_i(sesskey, name, def); } -static void gppi(void *handle, const char *name, int def, +static void gppi(settings_r *sesskey, const char *name, int def, Conf *conf, int primary) { - conf_set_int(conf, primary, gppi_raw(handle, name, def)); + conf_set_int(conf, primary, gppi_raw(sesskey, name, def)); } /* @@ -164,7 +166,8 @@ static void gppi(void *handle, const char *name, int def, * If there's no "=VALUE" (e.g. just NAME,NAME,NAME) then those keys * are mapped to the empty string. */ -static int gppmap(void *handle, const char *name, Conf *conf, int primary) +static int gppmap(settings_r *sesskey, const char *name, + Conf *conf, int primary) { char *buf, *p, *q, *key, *val; @@ -178,7 +181,7 @@ static int gppmap(void *handle, const char *name, Conf *conf, int primary) * Now read a serialised list from the settings and unmarshal it * into its components. */ - buf = gpps_raw(handle, name, NULL); + buf = gpps_raw(sesskey, name, NULL); if (!buf) return FALSE; @@ -231,8 +234,8 @@ static int gppmap(void *handle, const char *name, Conf *conf, int primary) * Write a set of name/value pairs in the above format, or just the * names if include_values is FALSE. */ -static void wmap(void *handle, char const *outkey, Conf *conf, int primary, - int include_values) +static void wmap(settings_w *sesskey, char const *outkey, Conf *conf, + int primary, int include_values) { char *buf, *p, *key, *realkey; const char *val, *q; @@ -293,7 +296,7 @@ static void wmap(void *handle, char const *outkey, Conf *conf, int primary, } } *p = '\0'; - write_setting_s(handle, outkey, buf); + write_setting_s(sesskey, outkey, buf); sfree(buf); } @@ -403,7 +406,7 @@ static void gprefs_from_str(const char *str, /* * Read a preference list. */ -static void gprefs(void *sesskey, const char *name, const char *def, +static void gprefs(settings_r *sesskey, const char *name, const char *def, const struct keyvalwhere *mapping, int nvals, Conf *conf, int primary) { @@ -418,7 +421,7 @@ static void gprefs(void *sesskey, const char *name, const char *def, /* * Write out a preference list. */ -static void wprefs(void *sesskey, const char *name, +static void wprefs(settings_w *sesskey, const char *name, const struct keyvalwhere *mapping, int nvals, Conf *conf, int primary) { @@ -452,36 +455,36 @@ static void wprefs(void *sesskey, const char *name, sfree(buf); } -static void write_clip_setting(void *handle, const char *savekey, +static void write_clip_setting(settings_w *sesskey, const char *savekey, Conf *conf, int confkey, int strconfkey) { int val = conf_get_int(conf, confkey); switch (val) { case CLIPUI_NONE: default: - write_setting_s(handle, savekey, "none"); + write_setting_s(sesskey, savekey, "none"); break; case CLIPUI_IMPLICIT: - write_setting_s(handle, savekey, "implicit"); + write_setting_s(sesskey, savekey, "implicit"); break; case CLIPUI_EXPLICIT: - write_setting_s(handle, savekey, "explicit"); + write_setting_s(sesskey, savekey, "explicit"); break; case CLIPUI_CUSTOM: { char *sval = dupcat("custom:", conf_get_str(conf, strconfkey), (const char *)NULL); - write_setting_s(handle, savekey, sval); + write_setting_s(sesskey, savekey, sval); sfree(sval); } break; } } -static void read_clip_setting(void *handle, const char *savekey, +static void read_clip_setting(settings_r *sesskey, char *savekey, int def, Conf *conf, int confkey, int strconfkey) { - char *setting = read_setting_s(handle, savekey); + char *setting = read_setting_s(sesskey, savekey); int val; conf_set_str(conf, strconfkey, ""); From 3f0f6d2013dd19afa2033d7f33961ff1ed90000f Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Tue, 9 Oct 2018 18:07:52 +0100 Subject: [PATCH 509/607] Missing error message when loading a private key file. If the file is empty, or otherwise fails to start with a recognised 'PuTTY-User-Key-File' header line, we forgot to fill in the error message before returning failure, leading to a null pointer dereference. --- sshpubk.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sshpubk.c b/sshpubk.c index 2144bc2c..510eb585 100644 --- a/sshpubk.c +++ b/sshpubk.c @@ -612,8 +612,10 @@ struct ssh2_userkey *ssh2_load_userkey(const Filename *filename, } /* Read the first header line which contains the key type. */ - if (!read_header(fp, header)) + if (!read_header(fp, header)) { + error = "no header line found in key file"; goto error; + } if (0 == strcmp(header, "PuTTY-User-Key-File-2")) { old_fmt = 0; } else if (0 == strcmp(header, "PuTTY-User-Key-File-1")) { From 5ea3a24b0ff1d8312a189b953d9c1c2d236957bd Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Tue, 9 Oct 2018 18:10:06 +0100 Subject: [PATCH 510/607] ssh2userauth: remove an unused variable. s->done_service_req was set but never read; it's not needed at all in the current code structure, where the service request has already happened in an entirely different source file and userauth never has to track it at all. --- ssh2userauth.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/ssh2userauth.c b/ssh2userauth.c index 5dbb7394..ea602726 100644 --- a/ssh2userauth.c +++ b/ssh2userauth.c @@ -38,7 +38,6 @@ struct ssh2_userauth_state { AUTH_TYPE_KEYBOARD_INTERACTIVE, AUTH_TYPE_KEYBOARD_INTERACTIVE_QUIET } type; - int done_service_req; int need_pw, can_pubkey, can_passwd, can_keyb_inter; int userpass_ret; int tried_pubkey_config, done_agent; @@ -205,7 +204,6 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) crBegin(s->crState); - s->done_service_req = FALSE; #ifndef NO_GSSAPI s->tried_gssapi = FALSE; s->tried_gssapi_keyex_auth = FALSE; From 1b67ec2963a7c98448b61852d992a3fcb043cfc3 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Tue, 9 Oct 2018 18:11:17 +0100 Subject: [PATCH 511/607] ssh2userauth: stop hardcoding the successor layer name. Not that we ever actually _support_ trying to authenticate for any SSH subprotocol other than "ssh-connection", or any plans to add such support. But it's inelegant to hardcode it at all when we have it right there in the successor layer's vtable. --- ssh2userauth.c | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/ssh2userauth.c b/ssh2userauth.c index ea602726..1be98be2 100644 --- a/ssh2userauth.c +++ b/ssh2userauth.c @@ -406,7 +406,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) s->pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH2_MSG_USERAUTH_REQUEST); put_stringz(s->pktout, s->username); - put_stringz(s->pktout, "ssh-connection");/* service requested */ + put_stringz(s->pktout, s->successor_layer->vt->name); put_stringz(s->pktout, "none"); /* method */ pq_push(s->ppl.out_pq, s->pktout); s->type = AUTH_TYPE_NONE; @@ -627,8 +627,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) s->pktout = ssh_bpp_new_pktout( s->ppl.bpp, SSH2_MSG_USERAUTH_REQUEST); put_stringz(s->pktout, s->username); - put_stringz(s->pktout, "ssh-connection"); - /* service requested */ + put_stringz(s->pktout, s->successor_layer->vt->name); put_stringz(s->pktout, "publickey"); /* method */ put_bool(s->pktout, FALSE); /* no signature included */ @@ -659,8 +658,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) s->pktout = ssh_bpp_new_pktout( s->ppl.bpp, SSH2_MSG_USERAUTH_REQUEST); put_stringz(s->pktout, s->username); - put_stringz(s->pktout, "ssh-connection"); - /* service requested */ + put_stringz(s->pktout, s->successor_layer->vt->name); put_stringz(s->pktout, "publickey"); /* method */ put_bool(s->pktout, TRUE); /* signature included */ @@ -734,8 +732,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) s->pktout = ssh_bpp_new_pktout( s->ppl.bpp, SSH2_MSG_USERAUTH_REQUEST); put_stringz(s->pktout, s->username); - put_stringz(s->pktout, "ssh-connection"); - /* service requested */ + put_stringz(s->pktout, s->successor_layer->vt->name); put_stringz(s->pktout, "publickey"); /* method */ put_bool(s->pktout, FALSE); /* no signature included */ @@ -843,8 +840,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) s->pktout = ssh_bpp_new_pktout( s->ppl.bpp, SSH2_MSG_USERAUTH_REQUEST); put_stringz(s->pktout, s->username); - put_stringz(s->pktout, "ssh-connection"); - /* service requested */ + put_stringz(s->pktout, s->successor_layer->vt->name); put_stringz(s->pktout, "publickey"); /* method */ put_bool(s->pktout, TRUE); /* signature follows */ put_stringz(s->pktout, ssh_key_ssh_id(key->key)); @@ -901,7 +897,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) s->pktout = ssh_bpp_new_pktout( s->ppl.bpp, SSH2_MSG_USERAUTH_REQUEST); put_stringz(s->pktout, s->username); - put_stringz(s->pktout, "ssh-connection"); + put_stringz(s->pktout, s->successor_layer->vt->name); put_stringz(s->pktout, "gssapi-with-mic"); ppl_logevent(("Attempting GSSAPI authentication")); @@ -1057,8 +1053,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) s->pktout = ssh_bpp_new_pktout( s->ppl.bpp, SSH2_MSG_USERAUTH_REQUEST); put_stringz(s->pktout, s->username); - put_stringz(s->pktout, "ssh-connection"); - /* service requested */ + put_stringz(s->pktout, s->successor_layer->vt->name); put_stringz(s->pktout, "keyboard-interactive"); /* method */ put_stringz(s->pktout, ""); /* lang */ @@ -1272,8 +1267,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) s->pktout = ssh_bpp_new_pktout( s->ppl.bpp, SSH2_MSG_USERAUTH_REQUEST); put_stringz(s->pktout, s->username); - put_stringz(s->pktout, "ssh-connection"); - /* service requested */ + put_stringz(s->pktout, s->successor_layer->vt->name); put_stringz(s->pktout, "password"); put_bool(s->pktout, FALSE); put_stringz(s->pktout, s->password); @@ -1407,8 +1401,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) s->pktout = ssh_bpp_new_pktout( s->ppl.bpp, SSH2_MSG_USERAUTH_REQUEST); put_stringz(s->pktout, s->username); - put_stringz(s->pktout, "ssh-connection"); - /* service requested */ + put_stringz(s->pktout, s->successor_layer->vt->name); put_stringz(s->pktout, "password"); put_bool(s->pktout, TRUE); put_stringz(s->pktout, s->password); @@ -1611,7 +1604,7 @@ static PktOut *ssh2_userauth_gss_packet( put_stringpl(sb, s->session_id); put_byte(sb, SSH2_MSG_USERAUTH_REQUEST); put_stringz(sb, s->username); - put_stringz(sb, "ssh-connection"); + put_stringz(sb, s->successor_layer->vt->name); put_stringz(sb, authtype); /* Compute the mic */ @@ -1626,7 +1619,7 @@ static PktOut *ssh2_userauth_gss_packet( } else { p = ssh_bpp_new_pktout(s->ppl.bpp, SSH2_MSG_USERAUTH_REQUEST); put_stringz(p, s->username); - put_stringz(p, "ssh-connection"); + put_stringz(p, s->successor_layer->vt->name); put_stringz(p, authtype); } put_string(p, mic.value, mic.length); From ad0c502cefcbc0ab039c936034c2603f5793a161 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Wed, 10 Oct 2018 19:26:18 +0100 Subject: [PATCH 512/607] Refactor the LogContext type. LogContext is now the owner of the logevent() function that back ends and so forth are constantly calling. Previously, logevent was owned by the Frontend, which would store the message into its list for the GUI Event Log dialog (or print it to standard error, or whatever) and then pass it _back_ to LogContext to write to the currently open log file. Now it's the other way round: LogContext gets the message from the back end first, writes it to its log file if it feels so inclined, and communicates it back to the front end. This means that lots of parts of the back end system no longer need to have a pointer to a full-on Frontend; the only thing they needed it for was logging, so now they just have a LogContext (which many of them had to have anyway, e.g. for logging SSH packets or session traffic). LogContext itself also doesn't get a full Frontend pointer any more: it now talks back to the front end via a little vtable of its own called LogPolicy, which contains the method that passes Event Log entries through, the old askappend() function that decides whether to truncate a pre-existing log file, and an emergency function for printing an especially prominent message if the log file can't be created. One minor nice effect of this is that console and GUI apps can implement that last function subtly differently, so that Unix console apps can write it with a plain \n instead of the \r\n (harmless but inelegant) that the old centralised implementation generated. One other consequence of this is that the LogContext has to be provided to backend_init() so that it's available to backends from the instant of creation, rather than being provided via a separate API call a couple of function calls later, because backends have typically started doing things that need logging (like making network connections) before the call to backend_provide_logctx. Fortunately, there's no case in the whole code base where we don't already have logctx by the time we make a backend (so I don't actually remember why I ever delayed providing one). So that shortens the backend API by one function, which is always nice. While I'm tidying up, I've also moved the printf-style logeventf() and the handy logevent_and_free() into logging.c, instead of having copies of them scattered around other places. This has also let me remove some stub functions from a couple of outlying applications like Pageant. Finally, I've removed the pointless "_tag" at the end of LogContext's official struct name. --- Recipe | 2 +- be_misc.c | 5 +-- cmdgen.c | 3 -- defs.h | 4 ++- fuzzterm.c | 5 --- logging.c | 64 ++++++++++++++++++++---------------- misc.c | 6 ---- misc.h | 7 ---- network.h | 6 ++-- portfwd.c | 28 +++++----------- proxy.c | 20 ++++------- pscp.c | 7 ++-- psftp.c | 7 ++-- putty.h | 80 +++++++++++++++++++++++++++++++++----------- raw.c | 16 ++++----- rlogin.c | 16 ++++----- ssh.c | 41 ++++++++++------------- ssh.h | 8 ++--- ssh1bpp.c | 7 ++-- ssh1connection.c | 4 +-- ssh2bpp-bare.c | 4 +-- ssh2bpp.c | 7 ++-- ssh2connection.c | 4 +-- sshbpp.h | 16 ++++++--- sshcommon.c | 6 ---- sshppl.h | 5 +-- sshshare.c | 29 +++++----------- sshverstring.c | 9 +++-- telnet.c | 82 ++++++++++++++++------------------------------ testback.c | 5 ++- testbn.c | 1 - unix/gtkdlg.c | 4 +-- unix/gtkwin.c | 43 +++++++++++++++++++----- unix/uxcons.c | 40 +++++++++++++--------- unix/uxpgnt.c | 1 - unix/uxplink.c | 6 ++-- unix/uxpty.c | 10 ++---- unix/uxser.c | 43 +++++++----------------- windows/wincons.c | 32 +++++++++++------- windows/windlg.c | 24 +++++++++++--- windows/window.c | 10 +++--- windows/winnet.c | 28 +--------------- windows/winpgen.c | 1 - windows/winpgnt.c | 1 - windows/winplink.c | 8 ++--- windows/winser.c | 46 ++++++++------------------ windows/winsftp.c | 2 +- 47 files changed, 363 insertions(+), 440 deletions(-) diff --git a/Recipe b/Recipe index eabdf3fa..581d030c 100644 --- a/Recipe +++ b/Recipe @@ -347,7 +347,7 @@ psftp : [U] psftp uxsftp uxcons UXSSH BE_SSH SFTP wildcard UXMISC uxnogtk pageant : [X] uxpgnt uxagentc aqsync pageant sshrsa sshpubk sshdes sshbn + sshmd5 version tree234 misc sshaes sshsha sshdss sshsh256 sshsh512 + sshecc CONF uxsignal nocproxy nogss be_none x11fwd ux_x11 uxcons - + gtkask gtkmisc nullplug UXMISC + + gtkask gtkmisc nullplug logging UXMISC ptermapp : [XT] GTKTERM uxmisc misc ldisc settings uxpty uxsel BE_NONE uxstore + uxsignal CHARSET uxpterm version time xpmpterm xpmptcfg diff --git a/be_misc.c b/be_misc.c index 55853411..1e8026ea 100644 --- a/be_misc.c +++ b/be_misc.c @@ -8,7 +8,8 @@ #include "putty.h" #include "network.h" -void backend_socket_log(Frontend *frontend, int type, SockAddr *addr, int port, +void backend_socket_log(Frontend *frontend, LogContext *logctx, + int type, SockAddr *addr, int port, const char *error_msg, int error_code, Conf *conf, int session_started) { @@ -53,7 +54,7 @@ void backend_socket_log(Frontend *frontend, int type, SockAddr *addr, int port, } if (msg) { - logevent(frontend, msg); + logevent(logctx, msg); sfree(msg); } } diff --git a/cmdgen.c b/cmdgen.c index fe083a0c..7e98ef24 100644 --- a/cmdgen.c +++ b/cmdgen.c @@ -116,9 +116,6 @@ void nonfatal(const char *p, ...) /* * Stubs to let everything else link sensibly. */ -void log_eventlog(LogContext *logctx, const char *event) -{ -} char *x_get_default(const char *key) { return NULL; diff --git a/defs.h b/defs.h index 0d98b70c..f524378e 100644 --- a/defs.h +++ b/defs.h @@ -49,7 +49,9 @@ typedef struct Backend Backend; typedef struct BackendVtable BackendVtable; typedef struct Ldisc_tag Ldisc; -typedef struct LogContext_tag LogContext; +typedef struct LogContext LogContext; +typedef struct LogPolicy LogPolicy; +typedef struct LogPolicyVtable LogPolicyVtable; typedef struct Frontend Frontend; diff --git a/fuzzterm.c b/fuzzterm.c index fb68482c..d6152661 100644 --- a/fuzzterm.c +++ b/fuzzterm.c @@ -137,11 +137,6 @@ int dlg_coloursel_results(union control *ctrl, void *dlg, int *r, int *g, int *b) { return 0; } void dlg_refresh(union control *ctrl, void *dlg) { } -/* miscellany */ -void logevent(Frontend *frontend, const char *msg) { } -int askappend(Frontend *frontend, Filename *filename, - void (*callback)(void *ctx, int result), void *ctx) { return 0; } - const char *const appname = "FuZZterm"; const int ngsslibs = 0; const char *const gsslibnames[0] = { }; diff --git a/logging.c b/logging.c index f07982ac..eb1aeec2 100644 --- a/logging.c +++ b/logging.c @@ -12,12 +12,12 @@ #include "putty.h" /* log session to file stuff ... */ -struct LogContext_tag { +struct LogContext { FILE *lgfp; enum { L_CLOSED, L_OPENING, L_OPEN, L_ERROR } state; bufchain queue; Filename *currlogfilename; - Frontend *frontend; + LogPolicy *lp; Conf *conf; int logtype; /* cached out of conf */ }; @@ -48,9 +48,8 @@ static void logwrite(LogContext *ctx, void *data, int len) if (fwrite(data, 1, len, ctx->lgfp) < (size_t)len) { logfclose(ctx); ctx->state = L_ERROR; - /* Log state is L_ERROR so this won't cause a loop */ - logevent(ctx->frontend, - "Disabled writing session log due to error while writing"); + lp_eventlog(ctx->lp, "Disabled writing session log " + "due to error while writing"); } } /* else L_ERROR, so ignore the write */ } @@ -121,23 +120,14 @@ static void logfopen_callback(void *vctx, int mode) ctx->logtype == LGTYP_SSHRAW ? "SSH raw data" : "unknown"), filename_to_str(ctx->currlogfilename)); - logevent(ctx->frontend, event); + lp_eventlog(ctx->lp, event); if (shout) { /* * If we failed to open the log file due to filesystem error * (as opposed to user action such as clicking Cancel in the - * askappend box), we should log it more prominently. We do - * this by sending it to the same place that stderr output - * from the main session goes (so, either a console tool's - * actual stderr, or a terminal window). - * - * Of course this is one case in which that policy won't cause - * it to turn up embarrassingly in a log file of real server - * output, because the whole point is that we haven't managed - * to open any such log file :-) + * askappend box), we should log it more prominently. */ - from_backend(ctx->frontend, 1, event, strlen(event)); - from_backend(ctx->frontend, 1, "\r\n", 2); + lp_logging_error(ctx->lp, event); } sfree(event); @@ -188,8 +178,8 @@ void logfopen(LogContext *ctx) if (logxfovr != LGXF_ASK) { mode = ((logxfovr == LGXF_OVR) ? 2 : 1); } else - mode = askappend(ctx->frontend, ctx->currlogfilename, - logfopen_callback, ctx); + mode = lp_askappend(ctx->lp, ctx->currlogfilename, + logfopen_callback, ctx); } else mode = 2; /* create == overwrite */ @@ -223,16 +213,32 @@ void logtraffic(LogContext *ctx, unsigned char c, int logmode) * Log an Event Log entry. Used in SSH packet logging mode, to copy * the Event Log entries into the same log file as the packet data. */ -void log_eventlog(LogContext *ctx, const char *event) +void logevent(LogContext *ctx, const char *event) { - /* If we don't have a context yet (eg winnet.c init) then skip entirely */ if (!ctx) - return; - if (ctx->logtype != LGTYP_PACKETS && - ctx->logtype != LGTYP_SSHRAW) - return; - logprintf(ctx, "Event Log: %s\r\n", event); - logflush(ctx); + return; + if (ctx->logtype == LGTYP_PACKETS || ctx->logtype == LGTYP_SSHRAW) { + logprintf(ctx, "Event Log: %s\r\n", event); + logflush(ctx); + } + lp_eventlog(ctx->lp, event); +} + +void logevent_and_free(LogContext *ctx, char *event) +{ + logevent(ctx, event); + sfree(event); +} + +void logeventf(LogContext *ctx, const char *fmt, ...) +{ + va_list ap; + char *buf; + + va_start(ap, fmt); + buf = dupvprintf(fmt, ap); + va_end(ap); + logevent_and_free(ctx, buf); } /* @@ -359,12 +365,12 @@ void log_packet(LogContext *ctx, int direction, int type, logflush(ctx); } -LogContext *log_init(Frontend *frontend, Conf *conf) +LogContext *log_init(LogPolicy *lp, Conf *conf) { LogContext *ctx = snew(LogContext); ctx->lgfp = NULL; ctx->state = L_CLOSED; - ctx->frontend = frontend; + ctx->lp = lp; ctx->conf = conf_copy(conf); ctx->logtype = conf_get_int(ctx->conf, CONF_logtype); ctx->currlogfilename = NULL; diff --git a/misc.c b/misc.c index f24a6e36..0b9e6c25 100644 --- a/misc.c +++ b/misc.c @@ -337,12 +337,6 @@ void burnstr(char *string) /* sfree(str), only clear it first */ } } -void logevent_and_free(Frontend *frontend, char *s) -{ - logevent(frontend, s); - sfree(s); -} - int toint(unsigned u) { /* diff --git a/misc.h b/misc.h index 0977050b..968c3d5d 100644 --- a/misc.h +++ b/misc.h @@ -31,13 +31,6 @@ char *dupprintf(const char *fmt, ...) char *dupvprintf(const char *fmt, va_list ap); void burnstr(char *string); -/* - * Pass a dynamically allocated string to logevent and immediately - * free it. Intended for use by wrapper macros which pass the return - * value of dupprintf straight to this. - */ -void logevent_and_free(Frontend *frontend, char *msg); - struct strbuf { char *s; unsigned char *u; diff --git a/network.h b/network.h index f7152054..9a1b2383 100644 --- a/network.h +++ b/network.h @@ -106,8 +106,7 @@ Socket *new_connection(SockAddr *addr, const char *hostname, Socket *new_listener(const char *srcaddr, int port, Plug *plug, int local_host_only, Conf *conf, int addressfamily); SockAddr *name_lookup(const char *host, int port, char **canonicalname, - Conf *conf, int addressfamily, - Frontend *frontend_for_logging, + Conf *conf, int addressfamily, LogContext *logctx, const char *lookup_reason_for_logging); int proxy_for_destination (SockAddr *addr, const char *hostname, int port, Conf *conf); @@ -236,7 +235,8 @@ extern Plug *const nullplug; /* * Exports from be_misc.c. */ -void backend_socket_log(Frontend *frontend, int type, SockAddr *addr, int port, +void backend_socket_log(Frontend *frontend, LogContext *logctx, + int type, SockAddr *addr, int port, const char *error_msg, int error_code, Conf *conf, int session_started); void log_proxy_stderr(Plug *plug, bufchain *buf, const void *vdata, int len); diff --git a/portfwd.c b/portfwd.c index 8ae9e80c..5d8250ca 100644 --- a/portfwd.c +++ b/portfwd.c @@ -10,18 +10,6 @@ #include "ssh.h" #include "sshchan.h" -static void logeventf(Frontend *frontend, const char *fmt, ...) -{ - va_list ap; - char *buf; - - va_start(ap, fmt); - buf = dupvprintf(fmt, ap); - va_end(ap); - logevent(frontend, buf); - sfree(buf); -} - /* * Enumeration of values that live in the 'socks_state' field of * struct PortForwarding. @@ -641,7 +629,7 @@ static void pfd_open_failure(Channel *chan, const char *errtext) assert(chan->vt == &PortForwarding_channelvt); PortForwarding *pf = container_of(chan, PortForwarding, chan); - logeventf(pf->cl->frontend, + logeventf(pf->cl->logctx, "Forwarded connection refused by server%s%s", errtext ? ": " : "", errtext ? errtext : ""); } @@ -803,7 +791,7 @@ void portfwdmgr_config(PortFwdManager *mgr, Conf *conf) sserv = 1; sport = net_service_lookup(sports); if (!sport) { - logeventf(mgr->cl->frontend, "Service lookup failed for source" + logeventf(mgr->cl->logctx, "Service lookup failed for source" " port \"%s\"", sports); } } @@ -829,7 +817,7 @@ void portfwdmgr_config(PortFwdManager *mgr, Conf *conf) dserv = 1; dport = net_service_lookup(dports); if (!dport) { - logeventf(mgr->cl->frontend, + logeventf(mgr->cl->logctx, "Service lookup failed for destination" " port \"%s\"", dports); } @@ -899,7 +887,7 @@ void portfwdmgr_config(PortFwdManager *mgr, Conf *conf) message = msg2; } - logeventf(mgr->cl->frontend, "Cancelling %s", message); + logeventf(mgr->cl->logctx, "Cancelling %s", message); sfree(message); /* pfr->remote or pfr->local may be NULL if setting up a @@ -959,7 +947,7 @@ void portfwdmgr_config(PortFwdManager *mgr, Conf *conf) mgr->cl, conf, &pfr->local, pfr->addressfamily); - logeventf(mgr->cl->frontend, + logeventf(mgr->cl->logctx, "Local %sport %s forwarding to %s%s%s", pfr->addressfamily == ADDRTYPE_IPV4 ? "IPv4 " : pfr->addressfamily == ADDRTYPE_IPV6 ? "IPv6 " : "", @@ -972,7 +960,7 @@ void portfwdmgr_config(PortFwdManager *mgr, Conf *conf) mgr->cl, conf, &pfr->local, pfr->addressfamily); - logeventf(mgr->cl->frontend, + logeventf(mgr->cl->logctx, "Local %sport %s SOCKS dynamic forwarding%s%s", pfr->addressfamily == ADDRTYPE_IPV4 ? "IPv4 " : pfr->addressfamily == ADDRTYPE_IPV6 ? "IPv6 " : "", @@ -997,12 +985,12 @@ void portfwdmgr_config(PortFwdManager *mgr, Conf *conf) pfr->addressfamily, sportdesc, pfr, NULL); if (!pfr->remote) { - logeventf(mgr->cl->frontend, + logeventf(mgr->cl->logctx, "Duplicate remote port forwarding to %s:%d", pfr->daddr, pfr->dport); pfr_free(pfr); } else { - logeventf(mgr->cl->frontend, "Requesting remote port %s" + logeventf(mgr->cl->logctx, "Requesting remote port %s" " forward to %s", sportdesc, dportdesc); } } diff --git a/proxy.c b/proxy.c index ee97472c..14f72e2b 100644 --- a/proxy.c +++ b/proxy.c @@ -367,29 +367,23 @@ static char *dns_log_msg(const char *host, int addressfamily, } SockAddr *name_lookup(const char *host, int port, char **canonicalname, - Conf *conf, int addressfamily, Frontend *frontend, + Conf *conf, int addressfamily, LogContext *logctx, const char *reason) { - char *logmsg; if (conf_get_int(conf, CONF_proxy_type) != PROXY_NONE && do_proxy_dns(conf) && proxy_for_destination(NULL, host, port, conf)) { - if (frontend) { - logmsg = dupprintf("Leaving host lookup to proxy of \"%s\"" - " (for %s)", host, reason); - logevent(frontend, logmsg); - sfree(logmsg); - } + if (logctx) + logeventf(logctx, "Leaving host lookup to proxy of \"%s\"" + " (for %s)", host, reason); *canonicalname = dupstr(host); return sk_nonamelookup(host); } else { - if (frontend) { - logmsg = dns_log_msg(host, addressfamily, reason); - logevent(frontend, logmsg); - sfree(logmsg); - } + if (logctx) + logevent_and_free( + logctx, dns_log_msg(host, addressfamily, reason)); return sk_namelookup(host, canonicalname, addressfamily); } diff --git a/pscp.c b/pscp.c index d1efe426..1b9e7c34 100644 --- a/pscp.c +++ b/pscp.c @@ -509,19 +509,17 @@ static void do_cmd(char *host, char *user, char *cmd) } conf_set_int(conf, CONF_nopty, TRUE); - logctx = log_init(NULL, conf); - console_provide_logctx(logctx); + logctx = log_init(default_logpolicy, conf); platform_psftp_pre_conn_setup(); - err = backend_init(&ssh_backend, NULL, &backend, conf, + err = backend_init(&ssh_backend, NULL, &backend, logctx, conf, conf_get_str(conf, CONF_host), conf_get_int(conf, CONF_port), &realhost, 0, conf_get_int(conf, CONF_tcp_keepalives)); if (err != NULL) bump("ssh_init: %s", err); - backend_provide_logctx(backend, logctx); ssh_scp_init(); if (verbose && realhost != NULL && errs == 0) tell_user(stderr, "Connected to %s", realhost); @@ -2382,7 +2380,6 @@ int psftp_main(int argc, char *argv[]) random_save_seed(); cmdline_cleanup(); - console_provide_logctx(NULL); backend_free(backend); backend = NULL; sk_cleanup(); diff --git a/psftp.c b/psftp.c index 557264be..4caabe76 100644 --- a/psftp.c +++ b/psftp.c @@ -2816,12 +2816,11 @@ static int psftp_connect(char *userhost, char *user, int portnumber) "exec sftp-server"); conf_set_int(conf, CONF_ssh_subsys2, FALSE); - logctx = log_init(NULL, conf); - console_provide_logctx(logctx); + logctx = log_init(default_logpolicy, conf); platform_psftp_pre_conn_setup(); - err = backend_init(&ssh_backend, NULL, &backend, conf, + err = backend_init(&ssh_backend, NULL, &backend, logctx, conf, conf_get_str(conf, CONF_host), conf_get_int(conf, CONF_port), &realhost, 0, @@ -2830,7 +2829,6 @@ static int psftp_connect(char *userhost, char *user, int portnumber) fprintf(stderr, "ssh_init: %s\n", err); return 1; } - backend_provide_logctx(backend, logctx); while (!backend_sendok(backend)) { if (backend_exitcode(backend) >= 0) return 1; @@ -2972,7 +2970,6 @@ int psftp_main(int argc, char *argv[]) do_sftp_cleanup(); random_save_seed(); cmdline_cleanup(); - console_provide_logctx(NULL); sk_cleanup(); return ret; diff --git a/putty.h b/putty.h index 242bfa67..f1d78473 100644 --- a/putty.h +++ b/putty.h @@ -480,7 +480,8 @@ struct Backend { }; struct BackendVtable { const char *(*init) (Frontend *frontend, Backend **backend_out, - Conf *conf, const char *host, int port, + LogContext *logctx, Conf *conf, + const char *host, int port, char **realhost, int nodelay, int keepalive); void (*free) (Backend *be); @@ -501,7 +502,6 @@ struct BackendVtable { int (*sendok) (Backend *be); int (*ldisc_option_state) (Backend *be, int); void (*provide_ldisc) (Backend *be, Ldisc *ldisc); - void (*provide_logctx) (Backend *be, LogContext *logctx); /* Tells the back end that the front end buffer is clearing. */ void (*unthrottle) (Backend *be, int bufsize); int (*cfg_info) (Backend *be); @@ -515,8 +515,8 @@ struct BackendVtable { int default_port; }; -#define backend_init(vt, fe, out, conf, host, port, rhost, nd, ka) \ - ((vt)->init(fe, out, conf, host, port, rhost, nd, ka)) +#define backend_init(vt, fe, out, logctx, conf, host, port, rhost, nd, ka) \ + ((vt)->init(fe, out, logctx, conf, host, port, rhost, nd, ka)) #define backend_free(be) ((be)->vt->free(be)) #define backend_reconfig(be, conf) ((be)->vt->reconfig(be, conf)) #define backend_send(be, buf, len) ((be)->vt->send(be, buf, len)) @@ -530,8 +530,6 @@ struct BackendVtable { #define backend_ldisc_option_state(be, opt) \ ((be)->vt->ldisc_option_state(be, opt)) #define backend_provide_ldisc(be, ldisc) ((be)->vt->provide_ldisc(be, ldisc)) -#define backend_provide_logctx(be, logctx) \ - ((be)->vt->provide_logctx(be, logctx)) #define backend_unthrottle(be, bufsize) ((be)->vt->unthrottle(be, bufsize)) #define backend_cfg_info(be) ((be)->vt->cfg_info(be)) @@ -1170,14 +1168,64 @@ int format_arrow_key(char *buf, Terminal *term, int xkey, int ctrl); /* * Exports from logging.c. */ -LogContext *log_init(Frontend *frontend, Conf *conf); +struct LogPolicyVtable { + /* + * Pass Event Log entries on from LogContext to the front end, + * which might write them to standard error or save them for a GUI + * list box or other things. + */ + void (*eventlog)(LogPolicy *lp, const char *event); + + /* + * Ask what to do about the specified output log file already + * existing. Can return four values: + * + * - 2 means overwrite the log file + * - 1 means append to the log file + * - 0 means cancel logging for this session + * - -1 means please wait, and callback() will be called with one + * of those options. + */ + int (*askappend)(LogPolicy *lp, Filename *filename, + void (*callback)(void *ctx, int result), void *ctx); + + /* + * Emergency logging when the log file itself can't be opened, + * which typically means we want to shout about it more loudly + * than a mere Event Log entry. + * + * One reasonable option is to send it to the same place that + * stderr output from the main session goes (so, either a console + * tool's actual stderr, or a terminal window). In many cases this + * is unlikely to cause this error message to turn up + * embarrassingly in a log file of real server output, because the + * whole point is that we haven't managed to open any such log + * file :-) + */ + void (*logging_error)(LogPolicy *lp, const char *event); +}; +struct LogPolicy { + const LogPolicyVtable *vt; +}; +#define lp_eventlog(lp, event) ((lp)->vt->eventlog(lp, event)) +#define lp_askappend(lp, fn, cb, ctx) ((lp)->vt->askappend(lp, fn, cb, ctx)) +#define lp_logging_error(lp, event) ((lp)->vt->logging_error(lp, event)) + +LogContext *log_init(LogPolicy *lp, Conf *conf); void log_free(LogContext *logctx); void log_reconfig(LogContext *logctx, Conf *conf); void logfopen(LogContext *logctx); void logfclose(LogContext *logctx); void logtraffic(LogContext *logctx, unsigned char c, int logmode); void logflush(LogContext *logctx); -void log_eventlog(LogContext *logctx, const char *string); +void logevent(LogContext *logctx, const char *event); +void logeventf(LogContext *logctx, const char *fmt, ...); +/* + * Pass a dynamically allocated string to logevent and immediately + * free it. Intended for use by wrapper macros which pass the return + * value of dupprintf straight to this. + */ +void logevent_and_free(LogContext *logctx, char *event); enum { PKT_INCOMING, PKT_OUTGOING }; enum { PKTLOG_EMIT, PKTLOG_BLANK, PKTLOG_OMIT }; struct logblank_t { @@ -1191,6 +1239,10 @@ void log_packet(LogContext *logctx, int direction, int type, const unsigned long *sequence, unsigned downstream_id, const char *additional_log_text); +/* This is defined by applications that have an obvious logging + * destination like standard error or the GUI. */ +extern LogPolicy default_logpolicy[1]; + /* * Exports from testback.c */ @@ -1352,7 +1404,6 @@ int wc_unescape(char *output, const char *wildcard); /* * Exports from frontend (windlg.c etc) */ -void logevent(Frontend *frontend, const char *); void pgp_fingerprints(void); /* * verify_ssh_host_key() can return one of three values: @@ -1386,16 +1437,6 @@ int askalg(Frontend *frontend, const char *algtype, const char *algname, void (*callback)(void *ctx, int result), void *ctx); int askhk(Frontend *frontend, const char *algname, const char *betteralgs, void (*callback)(void *ctx, int result), void *ctx); -/* - * askappend can return four values: - * - * - 2 means overwrite the log file - * - 1 means append to the log file - * - 0 means cancel logging for this session - * - -1 means please wait. - */ -int askappend(Frontend *frontend, Filename *filename, - void (*callback)(void *ctx, int result), void *ctx); /* * Exports from console frontends (wincons.c, uxcons.c) @@ -1403,7 +1444,6 @@ int askappend(Frontend *frontend, Filename *filename, */ extern int console_batch_mode; int console_get_userpass_input(prompts_t *p); -void console_provide_logctx(LogContext *logctx); int is_interactive(void); /* diff --git a/raw.c b/raw.c index e5db12f9..09cdb1d3 100644 --- a/raw.c +++ b/raw.c @@ -16,6 +16,7 @@ struct Raw { int closed_on_socket_error; int bufsize; Frontend *frontend; + LogContext *logctx; int sent_console_eof, sent_socket_eof, session_started; Conf *conf; @@ -36,7 +37,7 @@ static void raw_log(Plug *plug, int type, SockAddr *addr, int port, const char *error_msg, int error_code) { Raw *raw = container_of(plug, Raw, plug); - backend_socket_log(raw->frontend, type, addr, port, + backend_socket_log(raw->frontend, raw->logctx, type, addr, port, error_msg, error_code, raw->conf, raw->session_started); } @@ -68,7 +69,7 @@ static void raw_closing(Plug *plug, const char *error_msg, int error_code, raw->closed_on_socket_error = TRUE; notify_remote_exit(raw->frontend); } - logevent(raw->frontend, error_msg); + logevent(raw->logctx, error_msg); connection_fatal(raw->frontend, "%s", error_msg); } else { /* Otherwise, the remote side closed the connection normally. */ @@ -119,7 +120,7 @@ static const PlugVtable Raw_plugvt = { * freed by the caller. */ static const char *raw_init(Frontend *frontend, Backend **backend_handle, - Conf *conf, + LogContext *logctx, Conf *conf, const char *host, int port, char **realhost, int nodelay, int keepalive) { @@ -141,13 +142,14 @@ static const char *raw_init(Frontend *frontend, Backend **backend_handle, raw->conf = conf_copy(conf); raw->frontend = frontend; + raw->logctx = logctx; addressfamily = conf_get_int(conf, CONF_addressfamily); /* * Try to find host. */ addr = name_lookup(host, port, realhost, conf, addressfamily, - raw->frontend, "main connection"); + raw->logctx, "main connection"); if ((err = sk_addr_error(addr)) != NULL) { sk_addr_free(addr); return err; @@ -282,11 +284,6 @@ static void raw_provide_ldisc(Backend *be, Ldisc *ldisc) /* This is a stub. */ } -static void raw_provide_logctx(Backend *be, LogContext *logctx) -{ - /* This is a stub. */ -} - static int raw_exitcode(Backend *be) { Raw *raw = container_of(be, Raw, backend); @@ -321,7 +318,6 @@ const struct BackendVtable raw_backend = { raw_sendok, raw_ldisc, raw_provide_ldisc, - raw_provide_logctx, raw_unthrottle, raw_cfg_info, NULL /* test_for_upstream */, diff --git a/rlogin.c b/rlogin.c index e982552b..34232c83 100644 --- a/rlogin.c +++ b/rlogin.c @@ -20,6 +20,7 @@ struct Rlogin { int cansize; int term_width, term_height; Frontend *frontend; + LogContext *logctx; Conf *conf; @@ -40,7 +41,7 @@ static void rlogin_log(Plug *plug, int type, SockAddr *addr, int port, const char *error_msg, int error_code) { Rlogin *rlogin = container_of(plug, Rlogin, plug); - backend_socket_log(rlogin->frontend, type, addr, port, + backend_socket_log(rlogin->frontend, rlogin->logctx, type, addr, port, error_msg, error_code, rlogin->conf, !rlogin->firstbyte); } @@ -65,7 +66,7 @@ static void rlogin_closing(Plug *plug, const char *error_msg, int error_code, } if (error_msg) { /* A socket error has occurred. */ - logevent(rlogin->frontend, error_msg); + logevent(rlogin->logctx, error_msg); connection_fatal(rlogin->frontend, "%s", error_msg); } /* Otherwise, the remote side closed the connection normally. */ } @@ -150,7 +151,7 @@ static const PlugVtable Rlogin_plugvt = { * freed by the caller. */ static const char *rlogin_init(Frontend *frontend, Backend **backend_handle, - Conf *conf, + LogContext *logctx, Conf *conf, const char *host, int port, char **realhost, int nodelay, int keepalive) { @@ -167,6 +168,7 @@ static const char *rlogin_init(Frontend *frontend, Backend **backend_handle, rlogin->s = NULL; rlogin->closed_on_socket_error = FALSE; rlogin->frontend = frontend; + rlogin->logctx = logctx; rlogin->term_width = conf_get_int(conf, CONF_width); rlogin->term_height = conf_get_int(conf, CONF_height); rlogin->firstbyte = 1; @@ -180,7 +182,7 @@ static const char *rlogin_init(Frontend *frontend, Backend **backend_handle, * Try to find host. */ addr = name_lookup(host, port, realhost, conf, addressfamily, - rlogin->frontend, "rlogin connection"); + rlogin->logctx, "rlogin connection"); if ((err = sk_addr_error(addr)) != NULL) { sk_addr_free(addr); return err; @@ -373,11 +375,6 @@ static void rlogin_provide_ldisc(Backend *be, Ldisc *ldisc) /* This is a stub. */ } -static void rlogin_provide_logctx(Backend *be, LogContext *logctx) -{ - /* This is a stub. */ -} - static int rlogin_exitcode(Backend *be) { Rlogin *rlogin = container_of(be, Rlogin, backend); @@ -412,7 +409,6 @@ const struct BackendVtable rlogin_backend = { rlogin_sendok, rlogin_ldisc, rlogin_provide_ldisc, - rlogin_provide_logctx, rlogin_unthrottle, rlogin_cfg_info, NULL /* test_for_upstream */, diff --git a/ssh.c b/ssh.c index 0119d236..69927b65 100644 --- a/ssh.c +++ b/ssh.c @@ -114,15 +114,15 @@ struct Ssh { #define ssh_logevent(params) ( \ - logevent_and_free((ssh)->frontend, dupprintf params)) + logevent_and_free((ssh)->logctx, dupprintf params)) static void ssh_shutdown(Ssh *ssh); static void ssh_throttle_all(Ssh *ssh, int enable, int bufsize); static void ssh_bpp_output_raw_data_callback(void *vctx); -Frontend *ssh_get_frontend(Ssh *ssh) +LogContext *ssh_get_logctx(Ssh *ssh) { - return ssh->frontend; + return ssh->logctx; } static void ssh_connect_bpp(Ssh *ssh) @@ -179,7 +179,7 @@ static void ssh_got_ssh_version(struct ssh_version_receiver *rcv, int is_simple = (conf_get_int(ssh->conf, CONF_ssh_simple) && !ssh->connshare); - ssh->bpp = ssh2_bpp_new(ssh->frontend, &ssh->stats); + ssh->bpp = ssh2_bpp_new(ssh->logctx, &ssh->stats); ssh_connect_bpp(ssh); #ifndef NO_GSSAPI @@ -254,7 +254,7 @@ static void ssh_got_ssh_version(struct ssh_version_receiver *rcv, } else { - ssh->bpp = ssh1_bpp_new(ssh->frontend); + ssh->bpp = ssh1_bpp_new(ssh->logctx); ssh_connect_bpp(ssh); connection_layer = ssh1_connection_new(ssh, ssh->conf, &ssh->cl); @@ -267,7 +267,7 @@ static void ssh_got_ssh_version(struct ssh_version_receiver *rcv, } } else { - ssh->bpp = ssh2_bare_bpp_new(ssh->frontend); + ssh->bpp = ssh2_bare_bpp_new(ssh->logctx); ssh_connect_bpp(ssh); connection_layer = ssh2_connection_new( @@ -407,7 +407,7 @@ void ssh_remote_error(Ssh *ssh, const char *fmt, ...) * closed its end (or is about to). */ ssh_shutdown(ssh); - logevent(ssh->frontend, msg); + logevent(ssh->logctx, msg); connection_fatal(ssh->frontend, "%s", msg); sfree(msg); } @@ -426,7 +426,7 @@ void ssh_remote_eof(Ssh *ssh, const char *fmt, ...) * closed its end. */ ssh_shutdown(ssh); - logevent(ssh->frontend, msg); + logevent(ssh->logctx, msg); sfree(msg); notify_remote_exit(ssh->frontend); } else { @@ -447,7 +447,7 @@ void ssh_proto_error(Ssh *ssh, const char *fmt, ...) SSH2_DISCONNECT_PROTOCOL_ERROR); ssh_initiate_connection_close(ssh); - logevent(ssh->frontend, msg); + logevent(ssh->logctx, msg); connection_fatal(ssh->frontend, "%s", msg); sfree(msg); } @@ -462,7 +462,7 @@ void ssh_sw_abort(Ssh *ssh, const char *fmt, ...) ssh_initiate_connection_close(ssh); - logevent(ssh->frontend, msg); + logevent(ssh->logctx, msg); connection_fatal(ssh->frontend, "%s", msg); sfree(msg); @@ -486,7 +486,7 @@ void ssh_user_close(Ssh *ssh, const char *fmt, ...) ssh_initiate_connection_close(ssh); - logevent(ssh->frontend, msg); + logevent(ssh->logctx, msg); sfree(msg); notify_remote_exit(ssh->frontend); @@ -508,7 +508,7 @@ static void ssh_socket_log(Plug *plug, int type, SockAddr *addr, int port, */ if (!ssh->attempting_connshare) - backend_socket_log(ssh->frontend, type, addr, port, + backend_socket_log(ssh->frontend, ssh->logctx, type, addr, port, error_msg, error_code, ssh->conf, ssh->session_started); } @@ -645,7 +645,7 @@ static const char *connect_to_host(Ssh *ssh, const char *host, int port, ssh->connshare = NULL; ssh->attempting_connshare = TRUE; /* affects socket logging behaviour */ ssh->s = ssh_connection_sharing_init( - ssh->savedhost, ssh->savedport, ssh->conf, ssh->frontend, + ssh->savedhost, ssh->savedport, ssh->conf, ssh->logctx, &ssh->plug, &ssh->connshare); if (ssh->connshare) ssh_connshare_provide_connlayer(ssh->connshare, &ssh->cl_dummy); @@ -677,7 +677,7 @@ static const char *connect_to_host(Ssh *ssh, const char *host, int port, */ addressfamily = conf_get_int(ssh->conf, CONF_addressfamily); addr = name_lookup(host, port, realhost, ssh->conf, addressfamily, - ssh->frontend, "SSH connection"); + ssh->logctx, "SSH connection"); if ((err = sk_addr_error(addr)) != NULL) { sk_addr_free(addr); return err; @@ -715,7 +715,7 @@ static const char *connect_to_host(Ssh *ssh, const char *host, int port, */ ssh->version_receiver.got_ssh_version = ssh_got_ssh_version; ssh->bpp = ssh_verstring_new( - ssh->conf, ssh->frontend, ssh->bare_connection, + ssh->conf, ssh->logctx, ssh->bare_connection, ssh->version == 1 ? "1.5" : "2.0", &ssh->version_receiver); ssh_connect_bpp(ssh); queue_idempotent_callback(&ssh->bpp->ic_in_raw); @@ -789,7 +789,7 @@ static void ssh_cache_conf_values(Ssh *ssh) * Returns an error message, or NULL on success. */ static const char *ssh_init(Frontend *frontend, Backend **backend_handle, - Conf *conf, + LogContext *logctx, Conf *conf, const char *host, int port, char **realhost, int nodelay, int keepalive) { @@ -814,7 +814,7 @@ static const char *ssh_init(Frontend *frontend, Backend **backend_handle, *backend_handle = &ssh->backend; ssh->frontend = frontend; - ssh->cl_dummy.frontend = frontend; + ssh->cl_dummy.logctx = ssh->logctx = logctx; random_ref(); /* do this now - may be needed by sharing setup code */ ssh->need_random_unref = TRUE; @@ -1045,12 +1045,6 @@ static void ssh_provide_ldisc(Backend *be, Ldisc *ldisc) ssh->ldisc = ldisc; } -static void ssh_provide_logctx(Backend *be, LogContext *logctx) -{ - Ssh *ssh = container_of(be, Ssh, backend); - ssh->logctx = logctx; -} - void ssh_got_exitcode(Ssh *ssh, int exitcode) { ssh->exitcode = exitcode; @@ -1111,7 +1105,6 @@ const struct BackendVtable ssh_backend = { ssh_sendok, ssh_ldisc, ssh_provide_ldisc, - ssh_provide_logctx, ssh_unthrottle, ssh_cfg_info, ssh_test_for_upstream, diff --git a/ssh.h b/ssh.h index 3e14aa4c..ea0d6c75 100644 --- a/ssh.h +++ b/ssh.h @@ -163,8 +163,8 @@ int ssh2_censor_packet( PktOut *ssh_new_packet(void); void ssh_free_pktout(PktOut *pkt); -extern Socket *ssh_connection_sharing_init( - const char *host, int port, Conf *conf, Frontend *frontend, +Socket *ssh_connection_sharing_init( + const char *host, int port, Conf *conf, LogContext *logctx, Plug *sshplug, ssh_sharing_state **state); void ssh_connshare_provide_connlayer(ssh_sharing_state *sharestate, ConnectionLayer *cl); @@ -266,7 +266,7 @@ struct ConnectionLayerVtable { }; struct ConnectionLayer { - Frontend *frontend; + LogContext *logctx; const struct ConnectionLayerVtable *vt; }; @@ -309,7 +309,7 @@ char *portfwdmgr_connect(PortFwdManager *mgr, Channel **chan_ret, char *hostname, int port, SshChannel *c, int addressfamily); -Frontend *ssh_get_frontend(Ssh *ssh); +LogContext *ssh_get_logctx(Ssh *ssh); /* Communications back to ssh.c from connection layers */ void ssh_throttle_conn(Ssh *ssh, int adjust); diff --git a/ssh1bpp.c b/ssh1bpp.c index 33482a2c..9ec22ce1 100644 --- a/ssh1bpp.c +++ b/ssh1bpp.c @@ -43,12 +43,12 @@ static const struct BinaryPacketProtocolVtable ssh1_bpp_vtable = { ssh1_bpp_queue_disconnect, }; -BinaryPacketProtocol *ssh1_bpp_new(Frontend *frontend) +BinaryPacketProtocol *ssh1_bpp_new(LogContext *logctx) { struct ssh1_bpp_state *s = snew(struct ssh1_bpp_state); memset(s, 0, sizeof(*s)); s->bpp.vt = &ssh1_bpp_vtable; - s->bpp.frontend = frontend; + s->bpp.logctx = logctx; ssh_bpp_common_setup(&s->bpp); return &s->bpp; } @@ -68,9 +68,6 @@ static void ssh1_bpp_free(BinaryPacketProtocol *bpp) sfree(s); } -#define bpp_logevent(printf_args) \ - logevent_and_free(s->bpp.frontend, dupprintf printf_args) - void ssh1_bpp_new_cipher(BinaryPacketProtocol *bpp, const struct ssh1_cipheralg *cipher, const void *session_key) diff --git a/ssh1connection.c b/ssh1connection.c index 07105176..e89e87f4 100644 --- a/ssh1connection.c +++ b/ssh1connection.c @@ -260,11 +260,11 @@ PacketProtocolLayer *ssh1_connection_new( s->x11authtree = newtree234(x11_authcmp); - /* Need to get the frontend for s->cl now, because we won't be + /* Need to get the log context for s->cl now, because we won't be * helpfully notified when a copy is written into s->ppl by our * owner. */ s->cl.vt = &ssh1_connlayer_vtable; - s->cl.frontend = ssh_get_frontend(ssh); + s->cl.logctx = ssh_get_logctx(ssh); s->portfwdmgr = portfwdmgr_new(&s->cl); s->rportfwds = newtree234(ssh1_rportfwd_cmp); diff --git a/ssh2bpp-bare.c b/ssh2bpp-bare.c index e7c8f8ca..7d3cfed9 100644 --- a/ssh2bpp-bare.c +++ b/ssh2bpp-bare.c @@ -33,12 +33,12 @@ static const struct BinaryPacketProtocolVtable ssh2_bare_bpp_vtable = { ssh2_bpp_queue_disconnect, /* in sshcommon.c */ }; -BinaryPacketProtocol *ssh2_bare_bpp_new(Frontend *frontend) +BinaryPacketProtocol *ssh2_bare_bpp_new(LogContext *logctx) { struct ssh2_bare_bpp_state *s = snew(struct ssh2_bare_bpp_state); memset(s, 0, sizeof(*s)); s->bpp.vt = &ssh2_bare_bpp_vtable; - s->bpp.frontend = frontend; + s->bpp.logctx = logctx; ssh_bpp_common_setup(&s->bpp); return &s->bpp; } diff --git a/ssh2bpp.c b/ssh2bpp.c index c837194a..5b088676 100644 --- a/ssh2bpp.c +++ b/ssh2bpp.c @@ -54,12 +54,12 @@ static const struct BinaryPacketProtocolVtable ssh2_bpp_vtable = { }; BinaryPacketProtocol *ssh2_bpp_new( - Frontend *frontend, struct DataTransferStats *stats) + LogContext *logctx, struct DataTransferStats *stats) { struct ssh2_bpp_state *s = snew(struct ssh2_bpp_state); memset(s, 0, sizeof(*s)); s->bpp.vt = &ssh2_bpp_vtable; - s->bpp.frontend = frontend; + s->bpp.logctx = logctx; s->stats = stats; ssh_bpp_common_setup(&s->bpp); return &s->bpp; @@ -85,9 +85,6 @@ static void ssh2_bpp_free(BinaryPacketProtocol *bpp) sfree(s); } -#define bpp_logevent(printf_args) \ - logevent_and_free(s->bpp.frontend, dupprintf printf_args) - void ssh2_bpp_new_outgoing_crypto( BinaryPacketProtocol *bpp, const struct ssh2_cipheralg *cipher, const void *ckey, const void *iv, diff --git a/ssh2connection.c b/ssh2connection.c index e51d221f..16996d43 100644 --- a/ssh2connection.c +++ b/ssh2connection.c @@ -388,11 +388,11 @@ PacketProtocolLayer *ssh2_connection_new( s->x11authtree = newtree234(x11_authcmp); - /* Need to get the frontend for s->cl now, because we won't be + /* Need to get the log context for s->cl now, because we won't be * helpfully notified when a copy is written into s->ppl by our * owner. */ s->cl.vt = &ssh2_connlayer_vtable; - s->cl.frontend = ssh_get_frontend(ssh); + s->cl.logctx = ssh_get_logctx(ssh); s->portfwdmgr = portfwdmgr_new(&s->cl); s->rportfwds = newtree234(ssh2_rportfwd_cmp); diff --git a/sshbpp.h b/sshbpp.h index e5de4dbc..dc1b995d 100644 --- a/sshbpp.h +++ b/sshbpp.h @@ -23,7 +23,6 @@ struct BinaryPacketProtocol { PacketLogSettings *pls; LogContext *logctx; Ssh *ssh; - Frontend *frontend; /* ic_in_raw is filled in by the BPP (probably by calling * ssh_bpp_common_setup). The BPP's owner triggers it when data is @@ -53,7 +52,7 @@ struct BinaryPacketProtocol { * does centralised parts of the freeing too. */ void ssh_bpp_free(BinaryPacketProtocol *bpp); -BinaryPacketProtocol *ssh1_bpp_new(Frontend *frontend); +BinaryPacketProtocol *ssh1_bpp_new(LogContext *logctx); void ssh1_bpp_new_cipher(BinaryPacketProtocol *bpp, const struct ssh1_cipheralg *cipher, const void *session_key); @@ -72,6 +71,13 @@ void ssh2_bpp_queue_disconnect(BinaryPacketProtocol *bpp, const char *msg, int category); int ssh2_bpp_check_unimplemented(BinaryPacketProtocol *bpp, PktIn *pktin); +/* Convenience macro for BPPs to send formatted strings to the Event + * Log. Assumes a function parameter called 'bpp' is in scope, and + * takes a double pair of parens because it passes a whole argument + * list to dupprintf. */ +#define bpp_logevent(params) ( \ + logevent_and_free((bpp)->logctx, dupprintf params)) + /* * Structure that tracks how much data is sent and received, for * purposes of triggering an SSH-2 rekey when either one gets over a @@ -98,7 +104,7 @@ struct DataTransferStats { ((stats)->direction.remaining -= (size), FALSE)) BinaryPacketProtocol *ssh2_bpp_new( - Frontend *frontend, struct DataTransferStats *stats); + LogContext *logctx, struct DataTransferStats *stats); void ssh2_bpp_new_outgoing_crypto( BinaryPacketProtocol *bpp, const struct ssh2_cipheralg *cipher, const void *ckey, const void *iv, @@ -121,7 +127,7 @@ void ssh2_bpp_new_incoming_crypto( */ int ssh2_bpp_rekey_inadvisable(BinaryPacketProtocol *bpp); -BinaryPacketProtocol *ssh2_bare_bpp_new(Frontend *frontend); +BinaryPacketProtocol *ssh2_bare_bpp_new(LogContext *logctx); /* * The initial code to handle the SSH version exchange is also @@ -134,7 +140,7 @@ struct ssh_version_receiver { int major_version); }; BinaryPacketProtocol *ssh_verstring_new( - Conf *conf, Frontend *frontend, int bare_connection_mode, + Conf *conf, LogContext *logctx, int bare_connection_mode, const char *protoversion, struct ssh_version_receiver *rcv); const char *ssh_verstring_get_remote(BinaryPacketProtocol *); const char *ssh_verstring_get_local(BinaryPacketProtocol *); diff --git a/sshcommon.c b/sshcommon.c index 7679c5bd..16cf9310 100644 --- a/sshcommon.c +++ b/sshcommon.c @@ -638,12 +638,6 @@ const char *ssh2_pkt_type(Pkt_KCtx pkt_kctx, Pkt_ACtx pkt_actx, int type) * PacketProtocolLayer. */ -void ssh_logevent_and_free(void *frontend, char *message) -{ - logevent(frontend, message); - sfree(message); -} - void ssh_ppl_replace(PacketProtocolLayer *old, PacketProtocolLayer *new) { new->bpp = old->bpp; diff --git a/sshppl.h b/sshppl.h index f139263d..f637b0e0 100644 --- a/sshppl.h +++ b/sshppl.h @@ -53,7 +53,8 @@ struct PacketProtocolLayer { bufchain *user_input; /* Logging and error-reporting facilities. */ - void *frontend; /* for logevent, dialog boxes etc */ + LogContext *logctx; + void *frontend; /* for dialog boxes etc */ Ssh *ssh; /* for session termination + assorted connection-layer ops */ /* Known bugs in the remote implementation. */ @@ -122,7 +123,7 @@ void ssh2_userauth_set_transport_layer(PacketProtocolLayer *userauth, * scope, and takes a double pair of parens because it passes a whole * argument list to dupprintf. */ #define ppl_logevent(params) ( \ - logevent_and_free((ppl)->frontend, dupprintf params)) + logevent_and_free((ppl)->logctx, dupprintf params)) /* Convenience macro for protocol layers to send formatted strings to * the terminal. Also expects 'ppl' to be in scope and takes double diff --git a/sshshare.c b/sshshare.c index 688f73b2..b3e5b65d 100644 --- a/sshshare.c +++ b/sshshare.c @@ -703,18 +703,6 @@ static void share_remove_forwarding(struct ssh_sharing_connstate *cs, sfree(fwd); } -static void logeventf(Frontend *frontend, const char *fmt, ...) -{ - va_list ap; - char *buf; - - va_start(ap, fmt); - buf = dupvprintf(fmt, ap); - va_end(ap); - logevent(frontend, buf); - sfree(buf); -} - static void log_downstream(struct ssh_sharing_connstate *cs, const char *logfmt, ...) { @@ -724,7 +712,7 @@ static void log_downstream(struct ssh_sharing_connstate *cs, va_start(ap, logfmt); buf = dupvprintf(logfmt, ap); va_end(ap); - logeventf(cs->parent->cl->frontend, + logeventf(cs->parent->cl->logctx, "Connection sharing downstream #%u: %s", cs->id, buf); sfree(buf); } @@ -738,7 +726,7 @@ static void log_general(struct ssh_sharing_state *sharestate, va_start(ap, logfmt); buf = dupvprintf(logfmt, ap); va_end(ap); - logeventf(sharestate->cl->frontend, "Connection sharing: %s", buf); + logeventf(sharestate->cl->logctx, "Connection sharing: %s", buf); sfree(buf); } @@ -2080,7 +2068,7 @@ void ssh_connshare_provide_connlayer(ssh_sharing_state *sharestate, * upstream) we return NULL. */ Socket *ssh_connection_sharing_init( - const char *host, int port, Conf *conf, Frontend *frontend, + const char *host, int port, Conf *conf, LogContext *logctx, Plug *sshplug, ssh_sharing_state **state) { int result, can_upstream, can_downstream; @@ -2133,16 +2121,16 @@ Socket *ssh_connection_sharing_init( /* For this result, if 'logtext' is not NULL then it is an * error message indicating a reason why connection sharing * couldn't be set up _at all_ */ - logeventf(frontend, + logeventf(logctx, "Could not set up connection sharing: %s", logtext); } else { /* Failing that, ds_err and us_err indicate why we * couldn't be a downstream and an upstream respectively */ if (ds_err) - logeventf(frontend, "Could not set up connection sharing" + logeventf(logctx, "Could not set up connection sharing" " as downstream: %s", ds_err); if (us_err) - logeventf(frontend, "Could not set up connection sharing" + logeventf(logctx, "Could not set up connection sharing" " as upstream: %s", us_err); } @@ -2160,8 +2148,7 @@ Socket *ssh_connection_sharing_init( */ /* 'logtext' is a local endpoint address */ - logeventf(frontend, - "Using existing shared connection at %s", logtext); + logeventf(logctx, "Using existing shared connection at %s", logtext); *state = NULL; sfree(sharestate); @@ -2177,7 +2164,7 @@ Socket *ssh_connection_sharing_init( */ /* 'logtext' is a local endpoint address */ - logeventf(frontend, "Sharing this connection at %s", logtext); + logeventf(logctx, "Sharing this connection at %s", logtext); *state = sharestate; sharestate->listensock = sock; diff --git a/sshverstring.c b/sshverstring.c index 68cee61c..c9412a2f 100644 --- a/sshverstring.c +++ b/sshverstring.c @@ -58,7 +58,7 @@ static int ssh_version_includes_v1(const char *ver); static int ssh_version_includes_v2(const char *ver); BinaryPacketProtocol *ssh_verstring_new( - Conf *conf, Frontend *frontend, int bare_connection_mode, + Conf *conf, LogContext *logctx, int bare_connection_mode, const char *protoversion, struct ssh_version_receiver *rcv) { struct ssh_verstring_state *s = snew(struct ssh_verstring_state); @@ -87,7 +87,7 @@ BinaryPacketProtocol *ssh_verstring_new( assert(s->prefix_wanted.len <= PREFIX_MAXLEN); s->conf = conf_copy(conf); - s->bpp.frontend = frontend; + s->bpp.logctx = logctx; s->our_protoversion = dupstr(protoversion); s->receiver = rcv; @@ -145,11 +145,9 @@ static int ssh_version_includes_v2(const char *ver) return ssh_versioncmp(ver, "1.99") >= 0; } -#define bpp_logevent(printf_args) \ - logevent_and_free(s->bpp.frontend, dupprintf printf_args) - static void ssh_verstring_send(struct ssh_verstring_state *s) { + BinaryPacketProtocol *bpp = &s->bpp; /* for bpp_logevent */ char *p; int sv_pos; @@ -421,6 +419,7 @@ static void ssh_verstring_handle_output(BinaryPacketProtocol *bpp) */ static void ssh_detect_bugs(struct ssh_verstring_state *s) { + BinaryPacketProtocol *bpp = &s->bpp; /* for bpp_logevent */ const char *imp = s->softwareversion; s->remote_bugs = 0; diff --git a/telnet.c b/telnet.c index fcaab876..76d8a943 100644 --- a/telnet.c +++ b/telnet.c @@ -174,6 +174,7 @@ struct Telnet { int closed_on_socket_error; Frontend *frontend; + LogContext *logctx; Ldisc *ldisc; int term_width, term_height; @@ -214,18 +215,15 @@ static void c_write(Telnet *telnet, const void *buf, int len) static void log_option(Telnet *telnet, const char *sender, int cmd, int option) { - char *buf; /* * The strange-looking "" below is there to avoid a * trigraph - a double question mark followed by > maps to a * closing brace character! */ - buf = dupprintf("%s:\t%s %s", sender, - (cmd == WILL ? "WILL" : cmd == WONT ? "WONT" : - cmd == DO ? "DO" : cmd == DONT ? "DONT" : ""), - telopt(option)); - logevent(telnet->frontend, buf); - sfree(buf); + logeventf(telnet->logctx, "%s:\t%s %s", sender, + (cmd == WILL ? "WILL" : cmd == WONT ? "WONT" : + cmd == DO ? "DO" : cmd == DONT ? "DONT" : ""), + telopt(option)); } static void send_opt(Telnet *telnet, int cmd, int option) @@ -366,7 +364,6 @@ static void process_subneg(Telnet *telnet) switch (telnet->sb_opt) { case TELOPT_TSPEED: if (telnet->sb_len == 1 && telnet->sb_buf[0] == TELQUAL_SEND) { - char *logbuf; char *termspeed = conf_get_str(telnet->conf, CONF_termspeed); b = snewn(20 + strlen(termspeed), unsigned char); b[0] = IAC; @@ -378,17 +375,14 @@ static void process_subneg(Telnet *telnet) b[n] = IAC; b[n + 1] = SE; telnet->bufsize = sk_write(telnet->s, b, n + 2); - logevent(telnet->frontend, "server:\tSB TSPEED SEND"); - logbuf = dupprintf("client:\tSB TSPEED IS %s", termspeed); - logevent(telnet->frontend, logbuf); - sfree(logbuf); + logevent(telnet->logctx, "server:\tSB TSPEED SEND"); + logeventf(telnet->logctx, "client:\tSB TSPEED IS %s", termspeed); sfree(b); } else - logevent(telnet->frontend, "server:\tSB TSPEED "); + logevent(telnet->logctx, "server:\tSB TSPEED "); break; case TELOPT_TTYPE: if (telnet->sb_len == 1 && telnet->sb_buf[0] == TELQUAL_SEND) { - char *logbuf; char *termtype = conf_get_str(telnet->conf, CONF_termtype); b = snewn(20 + strlen(termtype), unsigned char); b[0] = IAC; @@ -403,24 +397,20 @@ static void process_subneg(Telnet *telnet) b[n + 5] = SE; telnet->bufsize = sk_write(telnet->s, b, n + 6); b[n + 4] = 0; - logevent(telnet->frontend, "server:\tSB TTYPE SEND"); - logbuf = dupprintf("client:\tSB TTYPE IS %s", b + 4); - logevent(telnet->frontend, logbuf); - sfree(logbuf); + logevent(telnet->logctx, "server:\tSB TTYPE SEND"); + logeventf(telnet->logctx, "client:\tSB TTYPE IS %s", b + 4); sfree(b); } else - logevent(telnet->frontend, "server:\tSB TTYPE \r\n"); + logevent(telnet->logctx, "server:\tSB TTYPE \r\n"); break; case TELOPT_OLD_ENVIRON: case TELOPT_NEW_ENVIRON: p = telnet->sb_buf; q = p + telnet->sb_len; if (p < q && *p == TELQUAL_SEND) { - char *logbuf; p++; - logbuf = dupprintf("server:\tSB %s SEND", telopt(telnet->sb_opt)); - logevent(telnet->frontend, logbuf); - sfree(logbuf); + logeventf(telnet->logctx, "server:\tSB %s SEND", + telopt(telnet->sb_opt)); if (telnet->sb_opt == TELOPT_OLD_ENVIRON) { if (conf_get_int(telnet->conf, CONF_rfc_environ)) { value = RFC_VALUE; @@ -493,29 +483,20 @@ static void process_subneg(Telnet *telnet) b[n++] = SE; telnet->bufsize = sk_write(telnet->s, b, n); if (n == 6) { - logbuf = dupprintf("client:\tSB %s IS ", - telopt(telnet->sb_opt)); - logevent(telnet->frontend, logbuf); - sfree(logbuf); + logeventf(telnet->logctx, "client:\tSB %s IS ", + telopt(telnet->sb_opt)); } else { - logbuf = dupprintf("client:\tSB %s IS:", - telopt(telnet->sb_opt)); - logevent(telnet->frontend, logbuf); - sfree(logbuf); + logeventf(telnet->logctx, "client:\tSB %s IS:", + telopt(telnet->sb_opt)); for (eval = conf_get_str_strs(telnet->conf, CONF_environmt, NULL, &ekey); eval != NULL; eval = conf_get_str_strs(telnet->conf, CONF_environmt, ekey, &ekey)) { - logbuf = dupprintf("\t%s=%s", ekey, eval); - logevent(telnet->frontend, logbuf); - sfree(logbuf); - } - if (user) { - logbuf = dupprintf("\tUSER=%s", user); - logevent(telnet->frontend, logbuf); - sfree(logbuf); + logeventf(telnet->logctx, "\t%s=%s", ekey, eval); } + if (user) + logeventf(telnet->logctx, "\tUSER=%s", user); } sfree(b); sfree(user); @@ -646,7 +627,7 @@ static void telnet_log(Plug *plug, int type, SockAddr *addr, int port, const char *error_msg, int error_code) { Telnet *telnet = container_of(plug, Telnet, plug); - backend_socket_log(telnet->frontend, type, addr, port, + backend_socket_log(telnet->frontend, telnet->logctx, type, addr, port, error_msg, error_code, telnet->conf, telnet->session_started); } @@ -670,7 +651,7 @@ static void telnet_closing(Plug *plug, const char *error_msg, int error_code, notify_remote_exit(telnet->frontend); } if (error_msg) { - logevent(telnet->frontend, error_msg); + logevent(telnet->logctx, error_msg); connection_fatal(telnet->frontend, "%s", error_msg); } /* Otherwise, the remote side closed the connection normally. */ @@ -707,7 +688,8 @@ static const PlugVtable Telnet_plugvt = { * freed by the caller. */ static const char *telnet_init(Frontend *frontend, Backend **backend_handle, - Conf *conf, const char *host, int port, + LogContext *logctx, Conf *conf, + const char *host, int port, char **realhost, int nodelay, int keepalive) { SockAddr *addr; @@ -728,6 +710,7 @@ static const char *telnet_init(Frontend *frontend, Backend **backend_handle, telnet->sb_buf = NULL; telnet->sb_size = 0; telnet->frontend = frontend; + telnet->logctx = logctx; telnet->term_width = conf_get_int(telnet->conf, CONF_width); telnet->term_height = conf_get_int(telnet->conf, CONF_height); telnet->state = TOP_LEVEL; @@ -741,7 +724,7 @@ static const char *telnet_init(Frontend *frontend, Backend **backend_handle, */ addressfamily = conf_get_int(telnet->conf, CONF_addressfamily); addr = name_lookup(host, port, realhost, telnet->conf, addressfamily, - telnet->frontend, "Telnet connection"); + telnet->logctx, "Telnet connection"); if ((err = sk_addr_error(addr)) != NULL) { sk_addr_free(addr); return err; @@ -884,7 +867,6 @@ static void telnet_size(Backend *be, int width, int height) Telnet *telnet = container_of(be, Telnet, backend); unsigned char b[24]; int n; - char *logbuf; telnet->term_width = width; telnet->term_height = height; @@ -906,10 +888,8 @@ static void telnet_size(Backend *be, int width, int height) b[n++] = IAC; b[n++] = SE; telnet->bufsize = sk_write(telnet->s, b, n); - logbuf = dupprintf("client:\tSB NAWS %d,%d", - telnet->term_width, telnet->term_height); - logevent(telnet->frontend, logbuf); - sfree(logbuf); + logeventf(telnet->logctx, "client:\tSB NAWS %d,%d", + telnet->term_width, telnet->term_height); } /* @@ -1054,11 +1034,6 @@ static void telnet_provide_ldisc(Backend *be, Ldisc *ldisc) telnet->ldisc = ldisc; } -static void telnet_provide_logctx(Backend *be, LogContext *logctx) -{ - /* This is a stub. */ -} - static int telnet_exitcode(Backend *be) { Telnet *telnet = container_of(be, Telnet, backend); @@ -1093,7 +1068,6 @@ const struct BackendVtable telnet_backend = { telnet_sendok, telnet_ldisc, telnet_provide_ldisc, - telnet_provide_logctx, telnet_unthrottle, telnet_cfg_info, NULL /* test_for_upstream */, diff --git a/testback.c b/testback.c index 16f6476e..6a89bfc5 100644 --- a/testback.c +++ b/testback.c @@ -50,21 +50,20 @@ static int null_exitcode(Backend *); static int null_sendok(Backend *); static int null_ldisc(Backend *, int); static void null_provide_ldisc(Backend *, Ldisc *); -static void null_provide_logctx(Backend *, LogContext *); static void null_unthrottle(Backend *, int); static int null_cfg_info(Backend *); const struct BackendVtable null_backend = { null_init, null_free, null_reconfig, null_send, null_sendbuffer, null_size, null_special, null_get_specials, null_connected, null_exitcode, null_sendok, - null_ldisc, null_provide_ldisc, null_provide_logctx, null_unthrottle, + null_ldisc, null_provide_ldisc, null_unthrottle, null_cfg_info, NULL /* test_for_upstream */, "null", -1, 0 }; const struct BackendVtable loop_backend = { loop_init, loop_free, null_reconfig, loop_send, null_sendbuffer, null_size, null_special, null_get_specials, null_connected, null_exitcode, null_sendok, - null_ldisc, null_provide_ldisc, null_provide_logctx, null_unthrottle, + null_ldisc, null_provide_ldisc, null_unthrottle, null_cfg_info, NULL /* test_for_upstream */, "loop", -1, 0 }; diff --git a/testbn.c b/testbn.c index 0abe4690..0bc555ee 100644 --- a/testbn.c +++ b/testbn.c @@ -32,7 +32,6 @@ int random_byte(void) return 0; } -void logevent(Frontend *frontend, const char *msg) { assert(0); } void queue_idempotent_callback(IdempotentCallback *ic) { assert(0); } #define fromxdigit(c) ( (c)>'9' ? ((c)&0xDF) - 'A' + 10 : (c) - '0' ) diff --git a/unix/gtkdlg.c b/unix/gtkdlg.c index ccabe1e3..e9d2d6c4 100644 --- a/unix/gtkdlg.c +++ b/unix/gtkdlg.c @@ -4048,8 +4048,8 @@ void logevent_dlg(eventlog_stuff *es, const char *string) } } -int askappend(Frontend *frontend, Filename *filename, - void (*callback)(void *ctx, int result), void *ctx) +int gtkdlg_askappend(Frontend *frontend, Filename *filename, + void (*callback)(void *ctx, int result), void *ctx) { static const char msgtemplate[] = "The session log file \"%.*s\" already exists. " diff --git a/unix/gtkwin.c b/unix/gtkwin.c index 6ec5d639..9ff65c81 100644 --- a/unix/gtkwin.c +++ b/unix/gtkwin.c @@ -180,6 +180,8 @@ struct Frontend { #ifdef OSX_META_KEY_CONFIG int system_mod_mask; #endif + + LogPolicy logpolicy; }; static void cache_conf_values(Frontend *inst) @@ -336,13 +338,38 @@ int get_userpass_input(prompts_t *p, bufchain *input) return ret; } -void logevent(Frontend *inst, const char *string) +static void gtk_eventlog(LogPolicy *lp, const char *string) { - log_eventlog(inst->logctx, string); - + Frontend *inst = container_of(lp, Frontend, logpolicy); logevent_dlg(inst->eventlogstuff, string); } +static int gtk_askappend(LogPolicy *lp, Filename *filename, + void (*callback)(void *ctx, int result), void *ctx) +{ + Frontend *inst = container_of(lp, Frontend, logpolicy); + + int gtkdlg_askappend(Frontend *frontend, Filename *filename, + void (*callback)(void *ctx, int result), void *ctx); + return gtkdlg_askappend(inst, filename, callback, ctx); +} + +static void gtk_logging_error(LogPolicy *lp, const char *event) +{ + Frontend *inst = container_of(lp, Frontend, logpolicy); + + /* Send 'can't open log file' errors to the terminal window. + * (Marked as stderr, although terminal.c won't care.) */ + from_backend(inst, 1, event, strlen(event)); + from_backend(inst, 1, "\r\n", 2); +} + +static const LogPolicyVtable gtk_logpolicy_vt = { + gtk_eventlog, + gtk_askappend, + gtk_logging_error, +}; + int font_dimension(Frontend *inst, int which) /* 0 for width, 1 for height */ { if (which) @@ -4806,7 +4833,7 @@ void restart_session_menuitem(GtkMenuItem *item, gpointer data) Frontend *inst = (Frontend *)data; if (!inst->backend) { - logevent(inst, "----- Session restarted -----"); + logevent(inst->logctx, "----- Session restarted -----"); term_pwron(inst->term, FALSE); start_backend(inst); inst->exited = FALSE; @@ -5011,7 +5038,7 @@ static void start_backend(Frontend *inst) vt = select_backend(inst->conf); error = backend_init(vt, (void *)inst, &inst->backend, - inst->conf, + inst->logctx, inst->conf, conf_get_str(inst->conf, CONF_host), conf_get_int(inst->conf, CONF_port), &realhost, @@ -5037,8 +5064,6 @@ static void start_backend(Frontend *inst) } sfree(realhost); - backend_provide_logctx(inst->backend, inst->logctx); - term_provide_backend(inst->term, inst->backend); inst->ldisc = ldisc_create(inst->conf, inst->term, inst->backend, inst); @@ -5096,6 +5121,8 @@ void new_session_window(Conf *conf, const char *geometry_string) #endif inst->drawing_area_setup_needed = TRUE; + inst->logpolicy.vt = >k_logpolicy_vt; + #ifndef NOT_X_WINDOWS inst->disp = get_x11_display(); if (geometry_string) { @@ -5414,7 +5441,7 @@ void new_session_window(Conf *conf, const char *geometry_string) inst->term = term_init(inst->conf, &inst->ucsdata, inst); setup_clipboards(inst, inst->term, inst->conf); - inst->logctx = log_init(inst, inst->conf); + inst->logctx = log_init(&inst->logpolicy, inst->conf); term_provide_logctx(inst->term, inst->logctx); term_size(inst->term, inst->height, inst->width, diff --git a/unix/uxcons.c b/unix/uxcons.c index c476cbf8..4bcd293c 100644 --- a/unix/uxcons.c +++ b/unix/uxcons.c @@ -23,8 +23,6 @@ int console_batch_mode = FALSE; -static void *console_logctx = NULL; - static struct termios orig_termios_stderr; static int stderr_is_a_tty; @@ -327,8 +325,9 @@ int askhk(Frontend *frontend, const char *algname, const char *betteralgs, * Ask whether to wipe a session log file before writing to it. * Returns 2 for wipe, 1 for append, 0 for cancel (don't log). */ -int askappend(Frontend *frontend, Filename *filename, - void (*callback)(void *ctx, int result), void *ctx) +static int console_askappend(LogPolicy *lp, Filename *filename, + void (*callback)(void *ctx, int result), + void *ctx) { static const char msgtemplate[] = "The session log file \"%.*s\" already exists.\n" @@ -405,22 +404,24 @@ void old_keyfile_warning(void) postmsg(&cf); } -void console_provide_logctx(LogContext *logctx) +static void console_logging_error(LogPolicy *lp, const char *string) { - console_logctx = logctx; + /* Errors setting up logging are considered important, so they're + * displayed to standard error even when not in verbose mode */ + struct termios cf; + premsg(&cf); + fprintf(stderr, "%s\n", string); + fflush(stderr); + postmsg(&cf); } -void logevent(Frontend *frontend, const char *string) + +static void console_eventlog(LogPolicy *lp, const char *string) { - struct termios cf; - if (flags & FLAG_VERBOSE) { - premsg(&cf); - fprintf(stderr, "%s\n", string); - fflush(stderr); - postmsg(&cf); - } - if (console_logctx) - log_eventlog(console_logctx, string); + /* Ordinary Event Log entries are displayed in the same way as + * logging errors, but only in verbose mode */ + if (flags & FLAG_VERBOSE) + console_logging_error(lp, string); } /* @@ -573,3 +574,10 @@ int is_interactive(void) char *platform_get_x_display(void) { return dupstr(getenv("DISPLAY")); } + +static const LogPolicyVtable default_logpolicy_vt = { + console_eventlog, + console_askappend, + console_logging_error, +}; +LogPolicy default_logpolicy[1] = {{ &default_logpolicy_vt }}; diff --git a/unix/uxpgnt.c b/unix/uxpgnt.c index 90a624a8..a3f2356e 100644 --- a/unix/uxpgnt.c +++ b/unix/uxpgnt.c @@ -92,7 +92,6 @@ int platform_default_i(const char *name, int def) { return def; } FontSpec *platform_default_fontspec(const char *name) { return fontspec_new(""); } Filename *platform_default_filename(const char *name) { return filename_from_str(""); } char *x_get_default(const char *key) { return NULL; } -void log_eventlog(LogContext *logctx, const char *event) {} int from_backend(Frontend *fe, int is_stderr, const void *data, int datalen) { assert(!"only here to satisfy notional call from backend_socket_log"); } diff --git a/unix/uxplink.c b/unix/uxplink.c index b1a2ef5d..c26fd43f 100644 --- a/unix/uxplink.c +++ b/unix/uxplink.c @@ -822,8 +822,7 @@ int main(int argc, char **argv) /* * Start up the connection. */ - logctx = log_init(NULL, conf); - console_provide_logctx(logctx); + logctx = log_init(default_logpolicy, conf); { const char *error; char *realhost; @@ -835,7 +834,7 @@ int main(int argc, char **argv) __AFL_INIT(); #endif - error = backend_init(backvt, NULL, &backend, conf, + error = backend_init(backvt, NULL, &backend, logctx, conf, conf_get_str(conf, CONF_host), conf_get_int(conf, CONF_port), &realhost, nodelay, @@ -844,7 +843,6 @@ int main(int argc, char **argv) fprintf(stderr, "Unable to open connection:\n%s\n", error); return 1; } - backend_provide_logctx(backend, logctx); ldisc_create(conf, NULL, backend, NULL); sfree(realhost); } diff --git a/unix/uxpty.c b/unix/uxpty.c index e0951808..31f6b880 100644 --- a/unix/uxpty.c +++ b/unix/uxpty.c @@ -737,7 +737,8 @@ static void pty_uxsel_setup(Pty *pty) * freed by the caller. */ static const char *pty_init(Frontend *frontend, Backend **backend_handle, - Conf *conf, const char *host, int port, + LogContext *logctx, Conf *conf, + const char *host, int port, char **realhost, int nodelay, int keepalive) { int slavefd; @@ -1219,12 +1220,6 @@ static void pty_provide_ldisc(Backend *be, Ldisc *ldisc) /* This is a stub. */ } -static void pty_provide_logctx(Backend *be, LogContext *logctx) -{ - /* Pty *pty = container_of(be, Pty, backend); */ - /* This is a stub. */ -} - static int pty_exitcode(Backend *be) { Pty *pty = container_of(be, Pty, backend); @@ -1254,7 +1249,6 @@ const struct BackendVtable pty_backend = { pty_sendok, pty_ldisc, pty_provide_ldisc, - pty_provide_logctx, pty_unthrottle, pty_cfg_info, NULL /* test_for_upstream */, diff --git a/unix/uxser.c b/unix/uxser.c index 0b53d859..6c837625 100644 --- a/unix/uxser.c +++ b/unix/uxser.c @@ -20,6 +20,7 @@ typedef struct Serial Serial; struct Serial { Frontend *frontend; + LogContext *logctx; int fd; int finished; int inbufsize; @@ -67,7 +68,6 @@ static const char *serial_configure(Serial *serial, Conf *conf) struct termios options; int bflag, bval, speed, flow, parity; const char *str; - char *msg; if (serial->fd < 0) return "Unable to reconfigure already-closed serial connection"; @@ -181,9 +181,7 @@ static const char *serial_configure(Serial *serial, Conf *conf) #undef SETBAUD cfsetispeed(&options, bflag); cfsetospeed(&options, bflag); - msg = dupprintf("Configuring baud rate %d", bval); - logevent(serial->frontend, msg); - sfree(msg); + logeventf(serial->logctx, "Configuring baud rate %d", bval); options.c_cflag &= ~CSIZE; switch (conf_get_int(conf, CONF_serdatabits)) { @@ -193,20 +191,16 @@ static const char *serial_configure(Serial *serial, Conf *conf) case 8: options.c_cflag |= CS8; break; default: return "Invalid number of data bits (need 5, 6, 7 or 8)"; } - msg = dupprintf("Configuring %d data bits", - conf_get_int(conf, CONF_serdatabits)); - logevent(serial->frontend, msg); - sfree(msg); + logeventf(serial->logctx, "Configuring %d data bits", + conf_get_int(conf, CONF_serdatabits)); if (conf_get_int(conf, CONF_serstopbits) >= 4) { options.c_cflag |= CSTOPB; } else { options.c_cflag &= ~CSTOPB; } - msg = dupprintf("Configuring %d stop bits", - (options.c_cflag & CSTOPB ? 2 : 1)); - logevent(serial->frontend, msg); - sfree(msg); + logeventf(serial->logctx, "Configuring %d stop bits", + (options.c_cflag & CSTOPB ? 2 : 1)); options.c_iflag &= ~(IXON|IXOFF); #ifdef CRTSCTS @@ -229,9 +223,7 @@ static const char *serial_configure(Serial *serial, Conf *conf) str = "RTS/CTS"; } else str = "no"; - msg = dupprintf("Configuring %s flow control", str); - logevent(serial->frontend, msg); - sfree(msg); + logeventf(serial->logctx, "Configuring %s flow control", str); /* Parity */ parity = conf_get_int(conf, CONF_serparity); @@ -247,9 +239,7 @@ static const char *serial_configure(Serial *serial, Conf *conf) options.c_cflag &= ~PARENB; str = "no"; } - msg = dupprintf("Configuring %s parity", str); - logevent(serial->frontend, msg); - sfree(msg); + logeventf(serial->logctx, "Configuring %s parity", str); options.c_cflag |= CLOCAL | CREAD; options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); @@ -290,7 +280,7 @@ static const char *serial_configure(Serial *serial, Conf *conf) * freed by the caller. */ static const char *serial_init(Frontend *frontend, Backend **backend_handle, - Conf *conf, + LogContext *logctx, Conf *conf, const char *host, int port, char **realhost, int nodelay, int keepalive) { @@ -303,16 +293,13 @@ static const char *serial_init(Frontend *frontend, Backend **backend_handle, *backend_handle = &serial->backend; serial->frontend = frontend; + serial->logctx = logctx; serial->finished = FALSE; serial->inbufsize = 0; bufchain_init(&serial->output_data); line = conf_get_str(conf, CONF_serline); - { - char *msg = dupprintf("Opening serial device %s", line); - logevent(serial->frontend, msg); - sfree(msg); - } + logeventf(serial->logctx, "Opening serial device %s", line); serial->fd = open(line, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK); if (serial->fd < 0) @@ -503,7 +490,7 @@ static void serial_special(Backend *be, SessionSpecialCode code, int arg) if (serial->fd >= 0 && code == SS_BRK) { tcsendbreak(serial->fd, 0); - logevent(serial->frontend, "Sending serial break at user request"); + logevent(serial->logctx, "Sending serial break at user request"); } return; @@ -552,11 +539,6 @@ static void serial_provide_ldisc(Backend *be, Ldisc *ldisc) /* This is a stub. */ } -static void serial_provide_logctx(Backend *be, LogContext *logctx) -{ - /* This is a stub. */ -} - static int serial_exitcode(Backend *be) { Serial *serial = container_of(be, Serial, backend); @@ -589,7 +571,6 @@ const struct BackendVtable serial_backend = { serial_sendok, serial_ldisc, serial_provide_ldisc, - serial_provide_logctx, serial_unthrottle, serial_cfg_info, NULL /* test_for_upstream */, diff --git a/windows/wincons.c b/windows/wincons.c index 7fb3e90b..e2296e23 100644 --- a/windows/wincons.c +++ b/windows/wincons.c @@ -13,8 +13,6 @@ int console_batch_mode = FALSE; -static void *console_logctx = NULL; - /* * Clean up and exit. */ @@ -247,8 +245,9 @@ int askhk(Frontend *frontend, const char *algname, const char *betteralgs, * Ask whether to wipe a session log file before writing to it. * Returns 2 for wipe, 1 for append, 0 for cancel (don't log). */ -int askappend(Frontend *frontend, Filename *filename, - void (*callback)(void *ctx, int result), void *ctx) +static int console_askappend(LogPolicy *lp, Filename *filename, + void (*callback)(void *ctx, int result), + void *ctx) { HANDLE hin; DWORD savemode, i; @@ -335,18 +334,20 @@ void pgp_fingerprints(void) " " PGP_PREV_MASTER_KEY_FP "\n", stdout); } -void console_provide_logctx(LogContext *logctx) +static void console_logging_error(LogPolicy *lp, const char *string) { - console_logctx = logctx; + /* Ordinary Event Log entries are displayed in the same way as + * logging errors, but only in verbose mode */ + fprintf(stderr, "%s\n", string); + fflush(stderr); } -void logevent(Frontend *frontend, const char *string) +static void console_eventlog(LogPolicy *lp, const char *string) { - if (flags & FLAG_VERBOSE) { - fprintf(stderr, "%s\n", string); - fflush(stderr); - } - log_eventlog(console_logctx, string); + /* Ordinary Event Log entries are displayed in the same way as + * logging errors, but only in verbose mode */ + if (flags & FLAG_VERBOSE) + console_logging_error(lp, string); } static void console_data_untrusted(HANDLE hout, const char *data, int len) @@ -486,3 +487,10 @@ void frontend_keypress(Frontend *frontend) */ return; } + +static const LogPolicyVtable default_logpolicy_vt = { + console_eventlog, + console_askappend, + console_logging_error, +}; +LogPolicy default_logpolicy[1] = {{ &default_logpolicy_vt }}; diff --git a/windows/windlg.c b/windows/windlg.c index 05ddfdd2..d0843754 100644 --- a/windows/windlg.c +++ b/windows/windlg.c @@ -761,14 +761,12 @@ int do_reconfig(HWND hwnd, int protcfginfo) return ret; } -void logevent(Frontend *frontend, const char *string) +static void win_gui_eventlog(LogPolicy *lp, const char *string) { char timebuf[40]; char **location; struct tm tm; - log_eventlog(logctx, string); - tm=ltime(); strftime(timebuf, sizeof(timebuf), "%Y-%m-%d %H:%M:%S\t", &tm); @@ -798,6 +796,14 @@ void logevent(Frontend *frontend, const char *string) } } +static void win_gui_logging_error(LogPolicy *lp, const char *event) +{ + /* Send 'can't open log file' errors to the terminal window. + * (Marked as stderr, although terminal.c won't care.) */ + from_backend(NULL, 1, event, strlen(event)); + from_backend(NULL, 1, "\r\n", 2); +} + void showeventlog(HWND hwnd) { if (!logbox) { @@ -953,8 +959,9 @@ int askhk(Frontend *frontend, const char *algname, const char *betteralgs, * Ask whether to wipe a session log file before writing to it. * Returns 2 for wipe, 1 for append, 0 for cancel (don't log). */ -int askappend(Frontend *frontend, Filename *filename, - void (*callback)(void *ctx, int result), void *ctx) +static int win_gui_askappend(LogPolicy *lp, Filename *filename, + void (*callback)(void *ctx, int result), + void *ctx) { static const char msgtemplate[] = "The session log file \"%.*s\" already exists.\n" @@ -986,6 +993,13 @@ int askappend(Frontend *frontend, Filename *filename, return 0; } +static const LogPolicyVtable default_logpolicy_vt = { + win_gui_eventlog, + win_gui_askappend, + win_gui_logging_error, +}; +LogPolicy default_logpolicy[1] = {{ &default_logpolicy_vt }}; + /* * Warn about the obsolescent key file format. * diff --git a/windows/window.c b/windows/window.c index 7bef7ee6..1c5cfc64 100644 --- a/windows/window.c +++ b/windows/window.c @@ -266,13 +266,12 @@ static void start_backend(void) cleanup_exit(1); } - error = backend_init(vt, NULL, &backend, conf, + error = backend_init(vt, NULL, &backend, logctx, conf, conf_get_str(conf, CONF_host), conf_get_int(conf, CONF_port), &realhost, conf_get_int(conf, CONF_tcp_nodelay), conf_get_int(conf, CONF_tcp_keepalives)); - backend_provide_logctx(backend, logctx); if (error) { char *str = dupprintf("%s Error", appname); sprintf(msg, "Unable to open connection to\n" @@ -635,7 +634,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) */ term = term_init(conf, &ucsdata, NULL); setup_clipboards(term, conf); - logctx = log_init(NULL, conf); + logctx = log_init(default_logpolicy, conf); term_provide_logctx(term, logctx); term_size(term, conf_get_int(conf, CONF_height), conf_get_int(conf, CONF_width), @@ -743,7 +742,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) } if (restricted_acl) { - logevent(NULL, "Running with restricted process ACL"); + lp_eventlog(default_logpolicy, "Running with restricted process ACL"); } start_backend(); @@ -2162,7 +2161,8 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, break; case IDM_RESTART: if (!backend) { - logevent(NULL, "----- Session restarted -----"); + lp_eventlog(default_logpolicy, + "----- Session restarted -----"); term_pwron(term, FALSE); start_backend(); } diff --git a/windows/winnet.c b/windows/winnet.c index 458ee4ec..0ddb62d4 100644 --- a/windows/winnet.c +++ b/windows/winnet.c @@ -220,13 +220,6 @@ int sk_startup(int hi, int lo) return FALSE; } -#ifdef NET_SETUP_DIAGNOSTICS - { - char buf[80]; - sprintf(buf, "Using WinSock %d.%d", hi, lo); - logevent(NULL, buf); - } -#endif return TRUE; } @@ -252,9 +245,6 @@ void sk_init(void) #ifndef NO_IPV6 /* Check if we have getaddrinfo in Winsock */ if (GetProcAddress(winsock_module, "getaddrinfo") != NULL) { -#ifdef NET_SETUP_DIAGNOSTICS - logevent(NULL, "Native WinSock IPv6 support detected"); -#endif GET_WINDOWS_FUNCTION(winsock_module, getaddrinfo); GET_WINDOWS_FUNCTION(winsock_module, freeaddrinfo); GET_WINDOWS_FUNCTION(winsock_module, getnameinfo); @@ -266,25 +256,15 @@ void sk_init(void) /* Fall back to wship6.dll for Windows 2000 */ wship6_module = load_system32_dll("wship6.dll"); if (wship6_module) { -#ifdef NET_SETUP_DIAGNOSTICS - logevent(NULL, "WSH IPv6 support detected"); -#endif GET_WINDOWS_FUNCTION(wship6_module, getaddrinfo); GET_WINDOWS_FUNCTION(wship6_module, freeaddrinfo); GET_WINDOWS_FUNCTION(wship6_module, getnameinfo); /* See comment above about type check */ GET_WINDOWS_FUNCTION_NO_TYPECHECK(winsock_module, gai_strerror); } else { -#ifdef NET_SETUP_DIAGNOSTICS - logevent(NULL, "No IPv6 support detected"); -#endif } } GET_WINDOWS_FUNCTION(winsock2_module, WSAAddressToStringA); -#else -#ifdef NET_SETUP_DIAGNOSTICS - logevent(NULL, "PuTTY was built without IPv6 support"); -#endif #endif GET_WINDOWS_FUNCTION(winsock_module, WSAAsyncSelect); @@ -559,9 +539,6 @@ SockAddr *sk_namelookup(const char *host, char **canonicalname, */ if (p_getaddrinfo) { struct addrinfo hints; -#ifdef NET_SETUP_DIAGNOSTICS - logevent(NULL, "Using getaddrinfo() for resolving"); -#endif memset(&hints, 0, sizeof(hints)); hints.ai_family = hint_family; hints.ai_flags = AI_CANONNAME; @@ -576,9 +553,6 @@ SockAddr *sk_namelookup(const char *host, char **canonicalname, } else #endif { -#ifdef NET_SETUP_DIAGNOSTICS - logevent(NULL, "Using gethostbyname() for resolving"); -#endif /* * Otherwise use the IPv4-only gethostbyname... * (NOTE: we don't use gethostbyname as a fallback!) @@ -796,7 +770,7 @@ static int ipv4_is_local_addr(struct in_addr addr) &retbytes, NULL, NULL) == 0) n_local_interfaces = retbytes / sizeof(INTERFACE_INFO); else - logevent(NULL, "Unable to get list of local IP addresses"); + n_local_interfaces = -1; } if (n_local_interfaces > 0) { int i; diff --git a/windows/winpgen.c b/windows/winpgen.c index ecb28ac4..11b438dc 100644 --- a/windows/winpgen.c +++ b/windows/winpgen.c @@ -61,7 +61,6 @@ void nonfatal(const char *fmt, ...) } /* Stubs needed to link against misc.c */ -void logevent(Frontend *frontend, const char *msg) { assert(0); } void queue_idempotent_callback(IdempotentCallback *ic) { assert(0); } /* ---------------------------------------------------------------------- diff --git a/windows/winpgnt.c b/windows/winpgnt.c index 2fa53654..b5e9fcbb 100644 --- a/windows/winpgnt.c +++ b/windows/winpgnt.c @@ -114,7 +114,6 @@ static void unmungestr(char *in, char *out, int outlen) } /* Stubs needed to link against misc.c */ -void logevent(Frontend *frontend, const char *msg) { assert(0); } void queue_idempotent_callback(IdempotentCallback *ic) { assert(0); } static int has_security; diff --git a/windows/winplink.c b/windows/winplink.c index 255fb2fd..2d4b74fa 100644 --- a/windows/winplink.c +++ b/windows/winplink.c @@ -446,8 +446,7 @@ int main(int argc, char **argv) !conf_get_str_nthstrkey(conf, CONF_portfwd, 0)) conf_set_int(conf, CONF_ssh_simple, TRUE); - logctx = log_init(NULL, conf); - console_provide_logctx(logctx); + logctx = log_init(default_logpolicy, conf); if (just_test_share_exists) { if (!vt->test_for_upstream) { @@ -463,7 +462,7 @@ int main(int argc, char **argv) } if (restricted_acl) { - logevent(NULL, "Running with restricted process ACL"); + lp_eventlog(default_logpolicy, "Running with restricted process ACL"); } /* @@ -477,7 +476,7 @@ int main(int argc, char **argv) int nodelay = conf_get_int(conf, CONF_tcp_nodelay) && (GetFileType(GetStdHandle(STD_INPUT_HANDLE)) == FILE_TYPE_CHAR); - error = backend_init(vt, NULL, &backend, conf, + error = backend_init(vt, NULL, &backend, logctx, conf, conf_get_str(conf, CONF_host), conf_get_int(conf, CONF_port), &realhost, nodelay, @@ -486,7 +485,6 @@ int main(int argc, char **argv) fprintf(stderr, "Unable to open connection:\n%s", error); return 1; } - backend_provide_logctx(backend, logctx); sfree(realhost); } diff --git a/windows/winser.c b/windows/winser.c index db53d24e..e1f40369 100644 --- a/windows/winser.c +++ b/windows/winser.c @@ -15,6 +15,7 @@ struct Serial { HANDLE port; struct handle *out, *in; Frontend *frontend; + LogContext *logctx; int bufsize; long clearbreak_time; int break_in_progress; @@ -61,7 +62,7 @@ static int serial_gotdata(struct handle *h, void *data, int len) notify_remote_exit(serial->frontend); - logevent(serial->frontend, error_msg); + logevent(serial->logctx, error_msg); connection_fatal(serial->frontend, "%s", error_msg); @@ -81,7 +82,7 @@ static void serial_sentdata(struct handle *h, int new_backlog) notify_remote_exit(serial->frontend); - logevent(serial->frontend, error_msg); + logevent(serial->logctx, error_msg); connection_fatal(serial->frontend, "%s", error_msg); } else { @@ -101,7 +102,6 @@ static const char *serial_configure(Serial *serial, HANDLE serport, Conf *conf) * device instead of a serial port. */ if (GetCommState(serport, &dcb)) { - char *msg; const char *str; /* @@ -124,14 +124,10 @@ static const char *serial_configure(Serial *serial, HANDLE serport, Conf *conf) * Configurable parameters. */ dcb.BaudRate = conf_get_int(conf, CONF_serspeed); - msg = dupprintf("Configuring baud rate %lu", dcb.BaudRate); - logevent(serial->frontend, msg); - sfree(msg); + logeventf(serial->logctx, "Configuring baud rate %lu", dcb.BaudRate); dcb.ByteSize = conf_get_int(conf, CONF_serdatabits); - msg = dupprintf("Configuring %u data bits", dcb.ByteSize); - logevent(serial->frontend, msg); - sfree(msg); + logeventf(serial->logctx, "Configuring %u data bits", dcb.ByteSize); switch (conf_get_int(conf, CONF_serstopbits)) { case 2: dcb.StopBits = ONESTOPBIT; str = "1"; break; @@ -139,9 +135,7 @@ static const char *serial_configure(Serial *serial, HANDLE serport, Conf *conf) case 4: dcb.StopBits = TWOSTOPBITS; str = "2"; break; default: return "Invalid number of stop bits (need 1, 1.5 or 2)"; } - msg = dupprintf("Configuring %s data bits", str); - logevent(serial->frontend, msg); - sfree(msg); + logeventf(serial->logctx, "Configuring %s data bits", str); switch (conf_get_int(conf, CONF_serparity)) { case SER_PAR_NONE: dcb.Parity = NOPARITY; str = "no"; break; @@ -150,9 +144,7 @@ static const char *serial_configure(Serial *serial, HANDLE serport, Conf *conf) case SER_PAR_MARK: dcb.Parity = MARKPARITY; str = "mark"; break; case SER_PAR_SPACE: dcb.Parity = SPACEPARITY; str = "space"; break; } - msg = dupprintf("Configuring %s parity", str); - logevent(serial->frontend, msg); - sfree(msg); + logeventf(serial->logctx, "Configuring %s parity", str); switch (conf_get_int(conf, CONF_serflow)) { case SER_FLOW_NONE: @@ -173,9 +165,7 @@ static const char *serial_configure(Serial *serial, HANDLE serport, Conf *conf) str = "DSR/DTR"; break; } - msg = dupprintf("Configuring %s flow control", str); - logevent(serial->frontend, msg); - sfree(msg); + logeventf(serial->logctx, "Configuring %s flow control", str); if (!SetCommState(serport, &dcb)) return "Unable to configure serial port"; @@ -201,7 +191,8 @@ static const char *serial_configure(Serial *serial, HANDLE serport, Conf *conf) * freed by the caller. */ static const char *serial_init(Frontend *frontend, Backend **backend_handle, - Conf *conf, const char *host, int port, + LogContext *logctx, Conf *conf, + const char *host, int port, char **realhost, int nodelay, int keepalive) { Serial *serial; @@ -218,13 +209,10 @@ static const char *serial_init(Frontend *frontend, Backend **backend_handle, *backend_handle = &serial->backend; serial->frontend = frontend; + serial->logctx = logctx; serline = conf_get_str(conf, CONF_serline); - { - char *msg = dupprintf("Opening serial device %s", serline); - logevent(serial->frontend, msg); - sfree(msg); - } + logeventf(serial->logctx, "Opening serial device %s", serline); { /* @@ -342,7 +330,7 @@ static void serbreak_timer(void *ctx, unsigned long now) if (now == serial->clearbreak_time && serial->port) { ClearCommBreak(serial->port); serial->break_in_progress = FALSE; - logevent(serial->frontend, "Finished serial break"); + logevent(serial->logctx, "Finished serial break"); } } @@ -354,7 +342,7 @@ static void serial_special(Backend *be, SessionSpecialCode code, int arg) Serial *serial = container_of(be, Serial, backend); if (serial->port && code == SS_BRK) { - logevent(serial->frontend, "Starting serial break at user request"); + logevent(serial->logctx, "Starting serial break at user request"); SetCommBreak(serial->port); /* * To send a serial break on Windows, we call SetCommBreak @@ -417,11 +405,6 @@ static void serial_provide_ldisc(Backend *be, Ldisc *ldisc) /* This is a stub. */ } -static void serial_provide_logctx(Backend *be, LogContext *logctx) -{ - /* This is a stub. */ -} - static int serial_exitcode(Backend *be) { Serial *serial = container_of(be, Serial, backend); @@ -454,7 +437,6 @@ const struct BackendVtable serial_backend = { serial_sendok, serial_ldisc, serial_provide_ldisc, - serial_provide_logctx, serial_unthrottle, serial_cfg_info, NULL /* test_for_upstream */, diff --git a/windows/winsftp.c b/windows/winsftp.c index 580e8d95..48235cd9 100644 --- a/windows/winsftp.c +++ b/windows/winsftp.c @@ -751,7 +751,7 @@ char *ssh_sftp_get_cmdline(const char *prompt, int no_fds_ok) void platform_psftp_pre_conn_setup(void) { if (restricted_acl) { - logevent(NULL, "Running with restricted process ACL"); + lp_eventlog(default_logpolicy, "Running with restricted process ACL"); } } From e053ea9a2ef828725dac992c80c3b112a9970a96 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Wed, 10 Oct 2018 19:32:41 +0100 Subject: [PATCH 513/607] Remove two useless declarations. One quite recent - an unused variable in the Windows code that was obsoleted by commit cea1329b9 last month - and one not recent at all, namely the obsolete declaration of begin_session() in putty.h that hasn't existed since commit 7a79df8fe replaced it with the ldisc system in *2001*! --- putty.h | 1 - windows/winnpc.c | 1 - 2 files changed, 2 deletions(-) diff --git a/putty.h b/putty.h index f1d78473..e74673df 100644 --- a/putty.h +++ b/putty.h @@ -728,7 +728,6 @@ void modalfatalbox(const char *, ...); #pragma noreturn(modalfatalbox) #endif void do_beep(Frontend *frontend, int); -void begin_session(Frontend *frontend); void sys_cursor(Frontend *frontend, int x, int y); void frontend_request_paste(Frontend *frontend, int clipboard); void frontend_keypress(Frontend *frontend); diff --git a/windows/winnpc.c b/windows/winnpc.c index 63387230..624757a4 100644 --- a/windows/winnpc.c +++ b/windows/winnpc.c @@ -23,7 +23,6 @@ Socket *new_named_pipe_client(const char *pipename, Plug *plug) HANDLE pipehandle; PSID usersid, pipeowner; PSECURITY_DESCRIPTOR psd; - Socket *ret; assert(strncmp(pipename, "\\\\.\\pipe\\", 9) == 0); assert(strchr(pipename + 9, '\\') == NULL); From 109df9f46b6a0ff19190839d8d62f72f8dedce87 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Thu, 11 Oct 2018 18:14:05 +0100 Subject: [PATCH 514/607] Remove frontend_keypress(). This was used by ldisc to communicate back to the front end that a key had been pressed (or rather, that a keypress had caused a nonzero amount of session input data). Its only nontrivial implementation was in gtkwin.c, which used that notification to implement the Unix GUI's "close window on keypress, if the session was already over" policy. (Which in turn is Unix-specific, because the rationale is that sometimes X servers don't have a functioning window manager, so it's useful to have a way of telling any application to close without using WM-provided facilities like a close button.) But gtkwin.c doesn't need to be told by the ldisc that a keypress happened - it's the one _sending_ those keypresses to ldisc in the first place! So I've thrown away the three stub implementations of frontend_keypress, removed the call to it in ldisc.c, and replaced it with calls in gtkwin.c at all the points during keypress handling that call ldisc_send. A visible effect is that pterm's close-on-keypress behaviour will now only trigger on an actual (input-generating) _keypress_, and not on other input generation such as a paste action. I think that's an improvement. --- ldisc.c | 7 ------- putty.h | 1 - unix/gtkwin.c | 20 +++++++++++++++++++- unix/uxcons.c | 8 -------- windows/wincons.c | 8 -------- windows/window.c | 11 ----------- 6 files changed, 19 insertions(+), 36 deletions(-) diff --git a/ldisc.c b/ldisc.c index f411174a..2225318e 100644 --- a/ldisc.c +++ b/ldisc.c @@ -135,13 +135,6 @@ void ldisc_send(Ldisc *ldisc, const void *vbuf, int len, int interactive) assert(ldisc->term); assert(len); - /* - * Notify the front end that something was pressed, in case - * it's depending on finding out (e.g. keypress termination for - * Close On Exit). - */ - frontend_keypress(ldisc->frontend); - if (interactive) { /* * Interrupt a paste from the clipboard, if one was in diff --git a/putty.h b/putty.h index e74673df..679e2e00 100644 --- a/putty.h +++ b/putty.h @@ -730,7 +730,6 @@ void modalfatalbox(const char *, ...); void do_beep(Frontend *frontend, int); void sys_cursor(Frontend *frontend, int x, int y); void frontend_request_paste(Frontend *frontend, int clipboard); -void frontend_keypress(Frontend *frontend); void frontend_echoedit_update(Frontend *frontend, int echo, int edit); /* It's the backend's responsibility to invoke this at the start of a * connection, if necessary; it can also invoke it later if the set of diff --git a/unix/gtkwin.c b/unix/gtkwin.c index 9ff65c81..1b56d859 100644 --- a/unix/gtkwin.c +++ b/unix/gtkwin.c @@ -923,6 +923,7 @@ char *dup_keyval_name(guint keyval) #endif static void change_font_size(Frontend *inst, int increment); +static void key_pressed(Frontend *inst); gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) { @@ -931,6 +932,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) wchar_t ucsoutput[2]; int ucsval, start, end, special, output_charset, use_ucsoutput; int nethack_mode, app_keypad_mode; + int generated_something = FALSE; #ifdef OSX_META_KEY_CONFIG if (event->state & inst->system_mod_mask) @@ -2076,6 +2078,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) * should never matter. */ output[end] = '\0'; /* NUL-terminate */ + generated_something = TRUE; if (inst->ldisc) ldisc_send(inst->ldisc, output+start, -2, 1); } else if (!inst->direct_to_font) { @@ -2095,6 +2098,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) charset_to_localenc(output_charset), string_string)); sfree(string_string); #endif + generated_something = TRUE; if (inst->ldisc) lpage_send(inst->ldisc, output_charset, output+start, end-start, 1); @@ -2119,6 +2123,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) * We generated our own Unicode key data from the * keysym, so use that instead. */ + generated_something = TRUE; if (inst->ldisc) luni_send(inst->ldisc, ucsoutput+start, end-start, 1); } @@ -2142,6 +2147,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) string_string)); sfree(string_string); #endif + generated_something = TRUE; if (inst->ldisc) ldisc_send(inst->ldisc, output+start, end-start, 1); } @@ -2150,6 +2156,8 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) term_seen_key_event(inst->term); } + if (generated_something) + key_pressed(inst); return TRUE; } @@ -2177,6 +2185,7 @@ void input_method_commit_event(GtkIMContext *imc, gchar *str, gpointer data) lpage_send(inst->ldisc, CS_UTF8, str, strlen(str), 1); show_mouseptr(inst, 0); term_seen_key_event(inst->term); + key_pressed(inst); } #endif @@ -2390,11 +2399,20 @@ gint motion_event(GtkWidget *widget, GdkEventMotion *event, gpointer data) return TRUE; } -void frontend_keypress(Frontend *inst) +static void key_pressed(Frontend *inst) { /* * If our child process has exited but not closed, terminate on * any keypress. + * + * This is a UI feature specific to GTK PuTTY, because GTK PuTTY + * will (at least sometimes) be running under X, and under X the + * window manager is sometimes absent (very occasionally on + * purpose, more usually temporarily because it's crashed). So + * it's useful to have a way to close an application window + * without depending on protocols like WM_DELETE_WINDOW that are + * typically generated by the WM (e.g. in response to a close + * button in the window frame). */ if (inst->exited) gtk_widget_destroy(inst->window); diff --git a/unix/uxcons.c b/unix/uxcons.c index 4bcd293c..fb75743c 100644 --- a/unix/uxcons.c +++ b/unix/uxcons.c @@ -554,14 +554,6 @@ int console_get_userpass_input(prompts_t *p) return 1; /* success */ } -void frontend_keypress(Frontend *frontend) -{ - /* - * This is nothing but a stub, in console code. - */ - return; -} - int is_interactive(void) { return isatty(0); diff --git a/windows/wincons.c b/windows/wincons.c index e2296e23..83146968 100644 --- a/windows/wincons.c +++ b/windows/wincons.c @@ -480,14 +480,6 @@ int console_get_userpass_input(prompts_t *p) return 1; /* success */ } -void frontend_keypress(Frontend *frontend) -{ - /* - * This is nothing but a stub, in console code. - */ - return; -} - static const LogPolicyVtable default_logpolicy_vt = { console_eventlog, console_askappend, diff --git a/windows/window.c b/windows/window.c index 1c5cfc64..5133a0ad 100644 --- a/windows/window.c +++ b/windows/window.c @@ -5907,17 +5907,6 @@ static void flip_full_screen() } } -void frontend_keypress(Frontend *frontend) -{ - /* - * Keypress termination in non-Close-On-Exit mode is not - * currently supported in PuTTY proper, because the window - * always has a perfectly good Close button anyway. So we do - * nothing here. - */ - return; -} - int from_backend(Frontend *frontend, int is_stderr, const void *data, int len) { return term_data(term, is_stderr, data, len); From b4c8fd9d86fdebac075967aa233128449da7ed57 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Thu, 11 Oct 2018 19:58:42 +0100 Subject: [PATCH 515/607] New abstraction 'Seat', to pass to backends. This is a new vtable-based abstraction which is passed to a backend in place of Frontend, and it implements only the subset of the Frontend functions needed by a backend. (Many other Frontend functions still exist, notably the wide range of things called by terminal.c providing platform-independent operations on the GUI terminal window.) The purpose of making it a vtable is that this opens up the possibility of creating a backend as an internal implementation detail of some other activity, by providing just that one backend with a custom Seat that implements the methods differently. For example, this refactoring should make it feasible to directly implement an SSH proxy type, aka the 'jump host' feature supported by OpenSSH, aka 'open a secondary SSH session in MAINCHAN_DIRECT_TCP mode, and then expose the main channel of that as the Socket for the primary connection'. (Which of course you can already do by spawning 'plink -nc' as a separate proxy process, but this would permit it in the _same_ process without anything getting confused.) I've centralised a full set of stub methods in misc.c for the new abstraction, which allows me to get rid of several annoying stubs in the previous code. Also, while I'm here, I've moved a lot of duplicated modalfatalbox() type functions from application main program files into wincons.c / uxcons.c, which I think saves duplication overall. (A minor visible effect is that the prefixes on those console-based fatal error messages will now be more consistent between applications.) --- be_misc.c | 4 +- cmdgen.c | 23 +-- cmdline.c | 4 +- defs.h | 3 + fuzzterm.c | 3 - ldisc.c | 9 +- ldisc.h | 2 +- misc.c | 44 +++++- network.h | 2 +- pscp.c | 107 +++++-------- psftp.c | 103 ++++++------- putty.h | 377 +++++++++++++++++++++++++++++++++++++-------- raw.c | 18 +-- rlogin.c | 20 +-- ssh.c | 32 ++-- ssh.h | 2 +- ssh1connection.c | 6 +- ssh1login.c | 36 +++-- ssh2connection.c | 19 ++- ssh2transport.c | 63 ++++---- ssh2userauth.c | 55 ++++--- sshcommon.c | 8 +- sshppl.h | 2 +- telnet.c | 16 +- terminal.h | 12 +- testback.c | 32 ++-- unix/gtkdlg.c | 51 +++--- unix/gtkwin.c | 145 +++++++++++------ unix/unix.h | 23 ++- unix/uxcons.c | 69 +++++++-- unix/uxpgnt.c | 41 +---- unix/uxplink.c | 96 ++++-------- unix/uxpty.c | 29 ++-- unix/uxser.c | 12 +- unix/uxsftp.c | 4 +- windows/wincons.c | 72 +++++++-- windows/windlg.c | 22 +-- windows/window.c | 81 +++++++--- windows/winplink.c | 78 ++++------ windows/winser.c | 18 +-- windows/winsftp.c | 4 +- windows/winstuff.h | 16 +- 42 files changed, 1045 insertions(+), 718 deletions(-) diff --git a/be_misc.c b/be_misc.c index 1e8026ea..8c1ff481 100644 --- a/be_misc.c +++ b/be_misc.c @@ -8,7 +8,7 @@ #include "putty.h" #include "network.h" -void backend_socket_log(Frontend *frontend, LogContext *logctx, +void backend_socket_log(Seat *seat, LogContext *logctx, int type, SockAddr *addr, int port, const char *error_msg, int error_code, Conf *conf, int session_started) @@ -43,7 +43,7 @@ void backend_socket_log(Frontend *frontend, LogContext *logctx, if (log_to_term == AUTO) log_to_term = session_started ? FORCE_OFF : FORCE_ON; if (log_to_term == FORCE_ON) - from_backend(frontend, TRUE, msg, len); + seat_stderr(seat, msg, len); msg[len-2] = '\0'; /* remove the \r\n again */ } diff --git a/cmdgen.c b/cmdgen.c index 7e98ef24..a08e7de9 100644 --- a/cmdgen.c +++ b/cmdgen.c @@ -92,27 +92,6 @@ static void no_progress(void *param, int action, int phase, int iprogress) { } -void modalfatalbox(const char *p, ...) -{ - va_list ap; - fprintf(stderr, "FATAL ERROR: "); - va_start(ap, p); - vfprintf(stderr, p, ap); - va_end(ap); - fputc('\n', stderr); - cleanup_exit(1); -} - -void nonfatal(const char *p, ...) -{ - va_list ap; - fprintf(stderr, "ERROR: "); - va_start(ap, p); - vfprintf(stderr, p, ap); - va_end(ap); - fputc('\n', stderr); -} - /* * Stubs to let everything else link sensibly. */ @@ -775,7 +754,7 @@ int main(int argc, char **argv) */ if (encrypted && load_encrypted) { if (!old_passphrase) { - prompts_t *p = new_prompts(NULL); + prompts_t *p = new_prompts(); int ret; p->to_server = FALSE; p->name = dupstr("SSH key passphrase"); diff --git a/cmdline.c b/cmdline.c index 85586176..cf25e584 100644 --- a/cmdline.c +++ b/cmdline.c @@ -81,8 +81,8 @@ void cmdline_cleanup(void) } while (0) /* - * Similar interface to get_userpass_input(), except that here a -1 - * return means that we aren't capable of processing the prompt and + * Similar interface to seat_get_userpass_input(), except that here a + * -1 return means that we aren't capable of processing the prompt and * someone else should do it. */ int cmdline_get_passwd_input(prompts_t *p) diff --git a/defs.h b/defs.h index f524378e..ec31c246 100644 --- a/defs.h +++ b/defs.h @@ -53,6 +53,9 @@ typedef struct LogContext LogContext; typedef struct LogPolicy LogPolicy; typedef struct LogPolicyVtable LogPolicyVtable; +typedef struct Seat Seat; +typedef struct SeatVtable SeatVtable; + typedef struct Frontend Frontend; typedef struct Ssh Ssh; diff --git a/fuzzterm.c b/fuzzterm.c index d6152661..32608d9f 100644 --- a/fuzzterm.c +++ b/fuzzterm.c @@ -38,9 +38,6 @@ int main(int argc, char **argv) return 0; } -int from_backend(Frontend *frontend, int is_stderr, const void *data, int len) -{ return 0; } - /* functions required by terminal.c */ void request_resize(Frontend *frontend, int x, int y) { } diff --git a/ldisc.c b/ldisc.c index 2225318e..a72adbcb 100644 --- a/ldisc.c +++ b/ldisc.c @@ -24,7 +24,7 @@ static void c_write(Ldisc *ldisc, const void *buf, int len) { - from_backend(ldisc->frontend, 0, buf, len); + seat_stdout(ldisc->seat, buf, len); } static int plen(Ldisc *ldisc, unsigned char c) @@ -77,8 +77,7 @@ static void bsb(Ldisc *ldisc, int n) #define CTRL(x) (x^'@') #define KCTRL(x) ((x^'@') | 0x100) -Ldisc *ldisc_create(Conf *conf, Terminal *term, - Backend *backend, Frontend *frontend) +Ldisc *ldisc_create(Conf *conf, Terminal *term, Backend *backend, Seat *seat) { Ldisc *ldisc = snew(Ldisc); @@ -89,7 +88,7 @@ Ldisc *ldisc_create(Conf *conf, Terminal *term, ldisc->backend = backend; ldisc->term = term; - ldisc->frontend = frontend; + ldisc->seat = seat; ldisc_configure(ldisc, conf); @@ -124,7 +123,7 @@ void ldisc_free(Ldisc *ldisc) void ldisc_echoedit_update(Ldisc *ldisc) { - frontend_echoedit_update(ldisc->frontend, ECHOING, EDITING); + seat_echoedit_update(ldisc->seat, ECHOING, EDITING); } void ldisc_send(Ldisc *ldisc, const void *vbuf, int len, int interactive) diff --git a/ldisc.h b/ldisc.h index e3d043b5..3b5e8249 100644 --- a/ldisc.h +++ b/ldisc.h @@ -11,7 +11,7 @@ struct Ldisc_tag { Terminal *term; Backend *backend; - Frontend *frontend; + Seat *seat; /* * Values cached out of conf. diff --git a/misc.c b/misc.c index 0b9e6c25..18edfb80 100644 --- a/misc.c +++ b/misc.c @@ -216,12 +216,24 @@ char *host_strduptrim(const char *s) return dupstr(s); } -prompts_t *new_prompts(Frontend *frontend) +void seat_connection_fatal(Seat *seat, const char *fmt, ...) +{ + va_list ap; + char *msg; + + va_start(ap, fmt); + msg = dupvprintf(fmt, ap); + va_end(ap); + + seat->vt->connection_fatal(seat, msg); + sfree(msg); /* if we return */ +} + +prompts_t *new_prompts(void) { prompts_t *p = snew(prompts_t); p->prompts = NULL; p->n_prompts = 0; - p->frontend = frontend; p->data = NULL; p->to_server = TRUE; /* to be on the safe side */ p->name = p->instruction = NULL; @@ -1348,3 +1360,31 @@ char *buildinfo(const char *newline) return strbuf_to_str(buf); } + +int nullseat_output( + Seat *seat, int is_stderr, const void *data, int len) { return 0; } +int nullseat_eof(Seat *seat) { return TRUE; } +int nullseat_get_userpass_input( + Seat *seat, prompts_t *p, bufchain *input) { return 0; } +void nullseat_notify_remote_exit(Seat *seat) {} +void nullseat_connection_fatal(Seat *seat, const char *message) {} +void nullseat_update_specials_menu(Seat *seat) {} +char *nullseat_get_ttymode(Seat *seat, const char *mode) { return NULL; } +void nullseat_set_busy_status(Seat *seat, BusyStatus status) {} +int nullseat_verify_ssh_host_key( + Seat *seat, const char *host, int port, + const char *keytype, char *keystr, char *key_fingerprint, + void (*callback)(void *ctx, int result), void *ctx) { return 0; } +int nullseat_confirm_weak_crypto_primitive( + Seat *seat, const char *algtype, const char *algname, + void (*callback)(void *ctx, int result), void *ctx) { return 0; } +int nullseat_confirm_weak_cached_hostkey( + Seat *seat, const char *algname, const char *betteralgs, + void (*callback)(void *ctx, int result), void *ctx) { return 0; } +int nullseat_is_never_utf8(Seat *seat) { return FALSE; } +int nullseat_is_always_utf8(Seat *seat) { return TRUE; } +void nullseat_echoedit_update(Seat *seat, int echoing, int editing) {} +const char *nullseat_get_x_display(Seat *seat) { return NULL; } +int nullseat_get_windowid(Seat *seat, long *id_out) { return FALSE; } +int nullseat_get_char_cell_size( + Seat *seat, int *width, int *height) { return FALSE; } diff --git a/network.h b/network.h index 9a1b2383..4799a337 100644 --- a/network.h +++ b/network.h @@ -235,7 +235,7 @@ extern Plug *const nullplug; /* * Exports from be_misc.c. */ -void backend_socket_log(Frontend *frontend, LogContext *logctx, +void backend_socket_log(Seat *seat, LogContext *logctx, int type, SockAddr *addr, int port, const char *error_msg, int error_code, Conf *conf, int session_started); diff --git a/pscp.c b/pscp.c index 1b9e7c34..9fc0c3e0 100644 --- a/pscp.c +++ b/pscp.c @@ -61,6 +61,29 @@ const char *const appname = "PSCP"; void ldisc_echoedit_update(Ldisc *ldisc) { } +static int pscp_output(Seat *, int is_stderr, const void *, int); +static int pscp_eof(Seat *); + +static const SeatVtable pscp_seat_vt = { + pscp_output, + pscp_eof, + filexfer_get_userpass_input, + nullseat_notify_remote_exit, + console_connection_fatal, + nullseat_update_specials_menu, + nullseat_get_ttymode, + nullseat_set_busy_status, + console_verify_ssh_host_key, + console_confirm_weak_crypto_primitive, + console_confirm_weak_cached_hostkey, + nullseat_is_never_utf8, + nullseat_echoedit_update, + nullseat_get_x_display, + nullseat_get_windowid, + nullseat_get_char_cell_size, +}; +static Seat pscp_seat[1] = {{ &pscp_seat_vt }}; + static void tell_char(FILE *stream, char c) { fputc(c, stream); @@ -103,56 +126,6 @@ static void tell_user(FILE *stream, const char *fmt, ...) sfree(str2); } -/* - * Print an error message and perform a fatal exit. - */ -void modalfatalbox(const char *fmt, ...) -{ - char *str, *str2; - va_list ap; - va_start(ap, fmt); - str = dupvprintf(fmt, ap); - str2 = dupcat("Fatal: ", str, "\n", NULL); - sfree(str); - va_end(ap); - abandon_stats(); - tell_str(stderr, str2); - sfree(str2); - errs++; - - cleanup_exit(1); -} -void nonfatal(const char *fmt, ...) -{ - char *str, *str2; - va_list ap; - va_start(ap, fmt); - str = dupvprintf(fmt, ap); - str2 = dupcat("Error: ", str, "\n", NULL); - sfree(str); - va_end(ap); - abandon_stats(); - tell_str(stderr, str2); - sfree(str2); - errs++; -} -void connection_fatal(Frontend *frontend, const char *fmt, ...) -{ - char *str, *str2; - va_list ap; - va_start(ap, fmt); - str = dupvprintf(fmt, ap); - str2 = dupcat("Fatal: ", str, "\n", NULL); - sfree(str); - va_end(ap); - abandon_stats(); - tell_str(stderr, str2); - sfree(str2); - errs++; - - cleanup_exit(1); -} - /* * In pscp, all agent requests should be synchronous, so this is a * never-called stub. @@ -168,16 +141,16 @@ void agent_schedule_callback(void (*callback)(void *, void *, int), * is available. * * To do this, we repeatedly call the SSH protocol module, with our - * own trap in from_backend() to catch the data that comes back. We - * do this until we have enough data. + * own pscp_output() function to catch the data that comes back. We do + * this until we have enough data. */ static unsigned char *outptr; /* where to put the data */ static unsigned outlen; /* how much data required */ static unsigned char *pending = NULL; /* any spare data */ static unsigned pendlen = 0, pendsize = 0; /* length and phys. size of buffer */ -int from_backend(Frontend *frontend, int is_stderr, - const void *data, int datalen) +static int pscp_output(Seat *seat, int is_stderr, + const void *data, int datalen) { unsigned char *p = (unsigned char *) data; unsigned len = (unsigned) datalen; @@ -215,7 +188,7 @@ int from_backend(Frontend *frontend, int is_stderr, return 0; } -int from_backend_eof(Frontend *frontend) +static int pscp_eof(Seat *seat) { /* * We usually expect to be the party deciding when to close the @@ -224,8 +197,8 @@ int from_backend_eof(Frontend *frontend) * downloading rather than uploading. */ if ((using_sftp || uploading) && !sent_eof) { - connection_fatal(frontend, - "Received unexpected end-of-file from server"); + seat_connection_fatal( + pscp_seat, "Received unexpected end-of-file from server"); } return FALSE; } @@ -325,7 +298,7 @@ static void bump(const char *fmt, ...) * Wait for the reply to a single SFTP request. Parallels the same * function in psftp.c (but isn't centralised into sftp.c because the * latter module handles SFTP only and shouldn't assume that SFTP is - * the only thing going on by calling connection_fatal). + * the only thing going on by calling seat_connection_fatal). */ struct sftp_packet *sftp_wait_for_reply(struct sftp_request *req) { @@ -334,13 +307,17 @@ struct sftp_packet *sftp_wait_for_reply(struct sftp_request *req) sftp_register(req); pktin = sftp_recv(); - if (pktin == NULL) - connection_fatal(NULL, "did not receive SFTP response packet " - "from server"); + if (pktin == NULL) { + seat_connection_fatal( + pscp_seat, "did not receive SFTP response packet from server"); + } rreq = sftp_find_request(pktin); - if (rreq != req) - connection_fatal(NULL, "unable to understand SFTP response packet " - "from server: %s", fxp_error()); + if (rreq != req) { + seat_connection_fatal( + pscp_seat, + "unable to understand SFTP response packet from server: %s", + fxp_error()); + } return pktin; } @@ -513,7 +490,7 @@ static void do_cmd(char *host, char *user, char *cmd) platform_psftp_pre_conn_setup(); - err = backend_init(&ssh_backend, NULL, &backend, logctx, conf, + err = backend_init(&ssh_backend, pscp_seat, &backend, logctx, conf, conf_get_str(conf, CONF_host), conf_get_int(conf, CONF_port), &realhost, 0, diff --git a/psftp.c b/psftp.c index 4caabe76..08f5d5bd 100644 --- a/psftp.c +++ b/psftp.c @@ -38,6 +38,33 @@ static Backend *backend; static Conf *conf; int sent_eof = FALSE; +/* ------------------------------------------------------------ + * Seat vtable. + */ + +static int psftp_output(Seat *, int is_stderr, const void *, int); +static int psftp_eof(Seat *); + +static const SeatVtable psftp_seat_vt = { + psftp_output, + psftp_eof, + filexfer_get_userpass_input, + nullseat_notify_remote_exit, + console_connection_fatal, + nullseat_update_specials_menu, + nullseat_get_ttymode, + nullseat_set_busy_status, + console_verify_ssh_host_key, + console_confirm_weak_crypto_primitive, + console_confirm_weak_cached_hostkey, + nullseat_is_never_utf8, + nullseat_echoedit_update, + nullseat_get_x_display, + nullseat_get_windowid, + nullseat_get_char_cell_size, +}; +static Seat psftp_seat[1] = {{ &psftp_seat_vt }}; + /* ---------------------------------------------------------------------- * Manage sending requests and waiting for replies. */ @@ -48,13 +75,17 @@ struct sftp_packet *sftp_wait_for_reply(struct sftp_request *req) sftp_register(req); pktin = sftp_recv(); - if (pktin == NULL) - connection_fatal(NULL, "did not receive SFTP response packet " - "from server"); + if (pktin == NULL) { + seat_connection_fatal( + psftp_seat, "did not receive SFTP response packet from server"); + } rreq = sftp_find_request(pktin); - if (rreq != req) - connection_fatal(NULL, "unable to understand SFTP response packet " - "from server: %s", fxp_error()); + if (rreq != req) { + seat_connection_fatal( + psftp_seat, + "unable to understand SFTP response packet from server: %s", + fxp_error()); + } return pktin; } @@ -2437,50 +2468,6 @@ int do_sftp(int mode, int modeflags, char *batchfile) static int verbose = 0; -/* - * Print an error message and perform a fatal exit. - */ -void modalfatalbox(const char *fmt, ...) -{ - char *str, *str2; - va_list ap; - va_start(ap, fmt); - str = dupvprintf(fmt, ap); - str2 = dupcat("Fatal: ", str, "\n", NULL); - sfree(str); - va_end(ap); - fputs(str2, stderr); - sfree(str2); - - cleanup_exit(1); -} -void nonfatal(const char *fmt, ...) -{ - char *str, *str2; - va_list ap; - va_start(ap, fmt); - str = dupvprintf(fmt, ap); - str2 = dupcat("Error: ", str, "\n", NULL); - sfree(str); - va_end(ap); - fputs(str2, stderr); - sfree(str2); -} -void connection_fatal(Frontend *frontend, const char *fmt, ...) -{ - char *str, *str2; - va_list ap; - va_start(ap, fmt); - str = dupvprintf(fmt, ap); - str2 = dupcat("Fatal: ", str, "\n", NULL); - sfree(str); - va_end(ap); - fputs(str2, stderr); - sfree(str2); - - cleanup_exit(1); -} - void ldisc_echoedit_update(Ldisc *ldisc) { } /* @@ -2498,7 +2485,7 @@ void agent_schedule_callback(void (*callback)(void *, void *, int), * is available. * * To do this, we repeatedly call the SSH protocol module, with our - * own trap in from_backend() to catch the data that comes back. We + * own psftp_output() function to catch the data that comes back. We * do this until we have enough data. */ @@ -2506,8 +2493,8 @@ static unsigned char *outptr; /* where to put the data */ static unsigned outlen; /* how much data required */ static unsigned char *pending = NULL; /* any spare data */ static unsigned pendlen = 0, pendsize = 0; /* length and phys. size of buffer */ -int from_backend(Frontend *frontend, int is_stderr, - const void *data, int datalen) +static int psftp_output(Seat *seat, int is_stderr, + const void *data, int datalen) { unsigned char *p = (unsigned char *) data; unsigned len = (unsigned) datalen; @@ -2551,7 +2538,8 @@ int from_backend(Frontend *frontend, int is_stderr, return 0; } -int from_backend_eof(Frontend *frontend) + +static int psftp_eof(Seat *seat) { /* * We expect to be the party deciding when to close the @@ -2559,11 +2547,12 @@ int from_backend_eof(Frontend *frontend) * should panic. */ if (!sent_eof) { - connection_fatal(frontend, - "Received unexpected end-of-file from SFTP server"); + seat_connection_fatal( + psftp_seat, "Received unexpected end-of-file from SFTP server"); } return FALSE; } + int sftp_recvdata(char *buf, int len) { outptr = (unsigned char *) buf; @@ -2820,7 +2809,7 @@ static int psftp_connect(char *userhost, char *user, int portnumber) platform_psftp_pre_conn_setup(); - err = backend_init(&ssh_backend, NULL, &backend, logctx, conf, + err = backend_init(&ssh_backend, psftp_seat, &backend, logctx, conf, conf_get_str(conf, CONF_host), conf_get_int(conf, CONF_port), &realhost, 0, diff --git a/putty.h b/putty.h index 679e2e00..492d87e1 100644 --- a/putty.h +++ b/putty.h @@ -479,7 +479,7 @@ struct Backend { const BackendVtable *vt; }; struct BackendVtable { - const char *(*init) (Frontend *frontend, Backend **backend_out, + const char *(*init) (Seat *seat, Backend **backend_out, LogContext *logctx, Conf *conf, const char *host, int port, char **realhost, int nodelay, int keepalive); @@ -515,8 +515,8 @@ struct BackendVtable { int default_port; }; -#define backend_init(vt, fe, out, logctx, conf, host, port, rhost, nd, ka) \ - ((vt)->init(fe, out, logctx, conf, host, port, rhost, nd, ka)) +#define backend_init(vt, seat, out, logctx, conf, host, port, rhost, nd, ka) \ + ((vt)->init(seat, out, logctx, conf, host, port, rhost, nd, ka)) #define backend_free(be) ((be)->vt->free(be)) #define backend_reconfig(be, conf) ((be)->vt->reconfig(be, conf)) #define backend_send(be, buf, len) ((be)->vt->send(be, buf, len)) @@ -635,11 +635,10 @@ typedef struct { size_t n_prompts; /* May be zero (in which case display the foregoing, * if any, and return success) */ prompt_t **prompts; - Frontend *frontend; void *data; /* slot for housekeeping data, managed by - * get_userpass_input(); initially NULL */ + * seat_get_userpass_input(); initially NULL */ } prompts_t; -prompts_t *new_prompts(Frontend *frontend); +prompts_t *new_prompts(); void add_prompt(prompts_t *p, char *promptstr, int echo); void prompt_set_result(prompt_t *pr, const char *newstr); void prompt_ensure_result_size(prompt_t *pr, int len); @@ -697,6 +696,306 @@ typedef struct truecolour { enum { ALL_CLIPBOARDS(CLIP_ID) N_CLIPBOARDS }; #undef CLIP_ID +/* Hint from backend to frontend about time-consuming operations, used + * by seat_set_busy_status. Initial state is assumed to be + * BUSY_NOT. */ +typedef enum BusyStatus { + BUSY_NOT, /* Not busy, all user interaction OK */ + BUSY_WAITING, /* Waiting for something; local event loops still + running so some local interaction (e.g. menus) + OK, but network stuff is suspended */ + BUSY_CPU /* Locally busy (e.g. crypto); user interaction + * suspended */ +} BusyStatus; + +/* + * Data type 'Seat', which is an API intended to contain essentially + * everything that a back end might need to talk to its client for: + * session output, password prompts, SSH warnings about host keys and + * weak cryptography, notifications of events like the remote process + * exiting or the GUI specials menu needing an update. + */ +struct Seat { + const struct SeatVtable *vt; +}; +struct SeatVtable { + /* + * Provide output from the remote session. 'is_stderr' indicates + * that the output should be sent to a separate error message + * channel, if the seat has one. But combining both channels into + * one is OK too; that's what terminal-window based seats do. + * + * The return value is the current size of the output backlog. + */ + int (*output)(Seat *seat, int is_stderr, const void *data, int len); + + /* + * Called when the back end wants to indicate that EOF has arrived + * on the server-to-client stream. Returns FALSE to indicate that + * we intend to keep the session open in the other direction, or + * TRUE to indicate that if they're closing so are we. + */ + int (*eof)(Seat *seat); + + /* + * Try to get answers from a set of interactive login prompts. The + * prompts are provided in 'p'; the bufchain 'input' holds the + * data currently outstanding in the session's normal standard- + * input channel. Seats may implement this function by consuming + * data from 'input' (e.g. password prompts in GUI PuTTY, + * displayed in the same terminal as the subsequent session), or + * by doing something entirely different (e.g. directly + * interacting with standard I/O, or putting up a dialog box). + * + * A positive return value means that all prompts have had answers + * filled in. A zero return means that the user performed a + * deliberate 'cancel' UI action. A negative return means that no + * answer can be given yet but please try again later. + * + * (FIXME: it would be nice to distinguish two classes of cancel + * action, so the user could specify 'I want to abandon this + * entire attempt to start a session' or the milder 'I want to + * abandon this particular form of authentication and fall back to + * a different one' - e.g. if you turn out not to be able to + * remember your private key passphrase then perhaps you'd rather + * fall back to password auth rather than aborting the whole + * session.) + * + * (Also FIXME: currently, backends' only response to the 'try + * again later' is to try again when more input data becomes + * available, because they assume that a seat is returning that + * value because it's consuming keyboard input. But a seat that + * handled this function by putting up a dialog box might want to + * put it up non-modally, and therefore would want to proactively + * notify the backend to retry once the dialog went away. So if I + * ever do want to move password prompts into a dialog box, I'll + * want a backend method for sending that notification.) + */ + int (*get_userpass_input)(Seat *seat, prompts_t *p, bufchain *input); + + /* + * Notify the seat that the process running at the other end of + * the connection has finished. + */ + void (*notify_remote_exit)(Seat *seat); + + /* + * Notify the seat that the connection has suffered a fatal error. + */ + void (*connection_fatal)(Seat *seat, const char *message); + + /* + * Notify the seat that the list of special commands available + * from backend_get_specials() has changed, so that it might want + * to call that function to repopulate its menu. + * + * Seats are not expected to call backend_get_specials() + * proactively; they may start by assuming that the backend + * provides no special commands at all, so if the backend does + * provide any, then it should use this notification at startup + * time. Of course it can also invoke it later if the set of + * special commands changes. + * + * It does not need to invoke it at session shutdown. + */ + void (*update_specials_menu)(Seat *seat); + + /* + * Get the seat's preferred value for an SSH terminal mode + * setting. Returning NULL indicates no preference (i.e. the SSH + * connection will not attempt to set the mode at all). + * + * The returned value is dynamically allocated, and the caller + * should free it. + */ + char *(*get_ttymode)(Seat *seat, const char *mode); + + /* + * Tell the seat whether the backend is currently doing anything + * CPU-intensive (typically a cryptographic key exchange). See + * BusyStatus enumeration above. + */ + void (*set_busy_status)(Seat *seat, BusyStatus status); + + /* + * Ask the seat whether a given SSH host key should be accepted. + * This may return immediately after checking saved configuration + * or command-line options, or it may have to present a prompt to + * the user and return asynchronously later. + * + * Return values: + * + * - +1 means `key was OK' (either already known or the user just + * approved it) `so continue with the connection' + * + * - 0 means `key was not OK, abandon the connection' + * + * - -1 means `I've initiated enquiries, please wait to be called + * back via the provided function with a result that's either 0 + * or +1'. + */ + int (*verify_ssh_host_key)( + Seat *seat, const char *host, int port, + const char *keytype, char *keystr, char *key_fingerprint, + void (*callback)(void *ctx, int result), void *ctx); + + /* + * Check with the seat whether it's OK to use a cryptographic + * primitive from below the 'warn below this line' threshold in + * the input Conf. Return values are the same as + * verify_ssh_host_key above. + */ + int (*confirm_weak_crypto_primitive)( + Seat *seat, const char *algtype, const char *algname, + void (*callback)(void *ctx, int result), void *ctx); + + /* + * Variant form of confirm_weak_crypto_primitive, which prints a + * slightly different message but otherwise has the same + * semantics. + * + * This form is used in the case where we're using a host key + * below the warning threshold because that's the best one we have + * cached, but at least one host key algorithm *above* the + * threshold is available that we don't have cached. 'betteralgs' + * lists the better algorithm(s). + */ + int (*confirm_weak_cached_hostkey)( + Seat *seat, const char *algname, const char *betteralgs, + void (*callback)(void *ctx, int result), void *ctx); + + /* + * Indicates whether the seat is expecting to interact with the + * user in the UTF-8 character set. (Affects e.g. visual erase + * handling in local line editing.) + */ + int (*is_utf8)(Seat *seat); + + /* + * Notify the seat that the back end, and/or the ldisc between + * them, have changed their idea of whether they currently want + * local echo and/or local line editing enabled. + */ + void (*echoedit_update)(Seat *seat, int echoing, int editing); + + /* + * Return the local X display string relevant to a seat, or NULL + * if there isn't one or if the concept is meaningless. + */ + const char *(*get_x_display)(Seat *seat); + + /* + * Return the X11 id of the X terminal window relevant to a seat, + * by returning TRUE and filling in the output pointer. Return + * FALSE if there isn't one or if the concept is meaningless. + */ + int (*get_windowid)(Seat *seat, long *id_out); + + /* + * Return the pixel size of a terminal character cell. If the + * concept is meaningless or the information is unavailable, + * return FALSE; otherwise fill in the output pointers and return + * TRUE. + */ + int (*get_char_cell_size)(Seat *seat, int *width, int *height); +}; + +#define seat_output(seat, is_stderr, data, len) \ + ((seat)->vt->output(seat, is_stderr, data, len)) +#define seat_eof(seat) \ + ((seat)->vt->eof(seat)) +#define seat_get_userpass_input(seat, p, input) \ + ((seat)->vt->get_userpass_input(seat, p, input)) +#define seat_notify_remote_exit(seat) \ + ((seat)->vt->notify_remote_exit(seat)) +#define seat_update_specials_menu(seat) \ + ((seat)->vt->update_specials_menu(seat)) +#define seat_get_ttymode(seat, mode) \ + ((seat)->vt->get_ttymode(seat, mode)) +#define seat_set_busy_status(seat, status) \ + ((seat)->vt->set_busy_status(seat, status)) +#define seat_verify_ssh_host_key(seat, h, p, typ, str, fp, cb, ctx) \ + ((seat)->vt->verify_ssh_host_key(seat, h, p, typ, str, fp, cb, ctx)) +#define seat_confirm_weak_crypto_primitive(seat, typ, alg, cb, ctx) \ + ((seat)->vt->confirm_weak_crypto_primitive(seat, typ, alg, cb, ctx)) +#define seat_confirm_weak_cached_hostkey(seat, alg, better, cb, ctx) \ + ((seat)->vt->confirm_weak_cached_hostkey(seat, alg, better, cb, ctx)) +#define seat_is_utf8(seat) \ + ((seat)->vt->is_utf8(seat)) +#define seat_echoedit_update(seat, echoing, editing) \ + ((seat)->vt->echoedit_update(seat, echoing, editing)) +#define seat_get_x_display(seat) \ + ((seat)->vt->get_x_display(seat)) +#define seat_get_windowid(seat, out) \ + ((seat)->vt->get_windowid(seat, out)) +#define seat_get_char_cell_size(seat, width, height) \ + ((seat)->vt->get_char_cell_size(seat, width, height)) + +/* Unlike the seat's actual method, the public entry point + * seat_connection_fatal is a wrapper function with a printf-like API, + * defined in misc.c. */ +void seat_connection_fatal(Seat *seat, const char *fmt, ...); + +/* Handy aliases for seat_output which set is_stderr to a fixed value. */ +#define seat_stdout(seat, data, len) \ + seat_output(seat, FALSE, data, len) +#define seat_stderr(seat, data, len) \ + seat_output(seat, TRUE, data, len) + +/* + * Stub methods for seat implementations that want to use the obvious + * null handling for a given method. + * + * These are generally obvious, except for is_utf8, where you might + * plausibly want to return either fixed answer 'no' or 'yes'. + */ +int nullseat_output(Seat *seat, int is_stderr, const void *data, int len); +int nullseat_eof(Seat *seat); +int nullseat_get_userpass_input(Seat *seat, prompts_t *p, bufchain *input); +void nullseat_notify_remote_exit(Seat *seat); +void nullseat_connection_fatal(Seat *seat, const char *message); +void nullseat_update_specials_menu(Seat *seat); +char *nullseat_get_ttymode(Seat *seat, const char *mode); +void nullseat_set_busy_status(Seat *seat, BusyStatus status); +int nullseat_verify_ssh_host_key( + Seat *seat, const char *host, int port, + const char *keytype, char *keystr, char *key_fingerprint, + void (*callback)(void *ctx, int result), void *ctx); +int nullseat_confirm_weak_crypto_primitive( + Seat *seat, const char *algtype, const char *algname, + void (*callback)(void *ctx, int result), void *ctx); +int nullseat_confirm_weak_cached_hostkey( + Seat *seat, const char *algname, const char *betteralgs, + void (*callback)(void *ctx, int result), void *ctx); +int nullseat_is_never_utf8(Seat *seat); +int nullseat_is_always_utf8(Seat *seat); +void nullseat_echoedit_update(Seat *seat, int echoing, int editing); +const char *nullseat_get_x_display(Seat *seat); +int nullseat_get_windowid(Seat *seat, long *id_out); +int nullseat_get_char_cell_size(Seat *seat, int *width, int *height); + +/* + * Seat functions provided by the platform's console-application + * support module (wincons.c, uxcons.c). + */ + +void console_connection_fatal(Seat *seat, const char *message); +int console_verify_ssh_host_key( + Seat *seat, const char *host, int port, + const char *keytype, char *keystr, char *key_fingerprint, + void (*callback)(void *ctx, int result), void *ctx); +int console_confirm_weak_crypto_primitive( + Seat *seat, const char *algtype, const char *algname, + void (*callback)(void *ctx, int result), void *ctx); +int console_confirm_weak_cached_hostkey( + Seat *seat, const char *algname, const char *betteralgs, + void (*callback)(void *ctx, int result), void *ctx); + +/* + * Other centralised seat functions. + */ +int filexfer_get_userpass_input(Seat *seat, prompts_t *p, bufchain *input); + /* * Exports from the front end. */ @@ -721,7 +1020,6 @@ void write_clip(Frontend *frontend, int clipboard, wchar_t *, int *, truecolour *, int, int); void optimised_move(Frontend *frontend, int, int, int); void set_raw_mouse_mode(Frontend *frontend, int); -void connection_fatal(Frontend *frontend, const char *, ...); void nonfatal(const char *, ...); void modalfatalbox(const char *, ...); #ifdef macintosh @@ -730,28 +1028,6 @@ void modalfatalbox(const char *, ...); void do_beep(Frontend *frontend, int); void sys_cursor(Frontend *frontend, int x, int y); void frontend_request_paste(Frontend *frontend, int clipboard); -void frontend_echoedit_update(Frontend *frontend, int echo, int edit); -/* It's the backend's responsibility to invoke this at the start of a - * connection, if necessary; it can also invoke it later if the set of - * special commands changes. It does not need to invoke it at session - * shutdown. */ -void update_specials_menu(Frontend *frontend); -int from_backend(Frontend *frontend, int is_stderr, const void *data, int len); -/* Called when the back end wants to indicate that EOF has arrived on - * the server-to-client stream. Returns FALSE to indicate that we - * intend to keep the session open in the other direction, or TRUE to - * indicate that if they're closing so are we. */ -int from_backend_eof(Frontend *frontend); -void notify_remote_exit(Frontend *frontend); -/* Get a sensible value for a tty mode. NULL return = don't set. - * Otherwise, returned value should be freed by caller. */ -char *get_ttymode(Frontend *frontend, const char *mode); -/* - * >0 = `got all results, carry on' - * 0 = `user cancelled' (FIXME distinguish "give up entirely" and "next auth"?) - * <0 = `please call back later with a fuller bufchain' - */ -int get_userpass_input(prompts_t *p, bufchain *input); #define OPTIMISE_IS_SCROLL 1 void set_iconic(Frontend *frontend, int iconic); @@ -763,16 +1039,6 @@ int is_iconic(Frontend *frontend); void get_window_pos(Frontend *frontend, int *x, int *y); void get_window_pixels(Frontend *frontend, int *x, int *y); char *get_window_title(Frontend *frontend, int icon); -/* Hint from backend to frontend about time-consuming operations. - * Initial state is assumed to be BUSY_NOT. */ -enum { - BUSY_NOT, /* Not busy, all user interaction OK */ - BUSY_WAITING, /* Waiting for something; local event loops still running - so some local interaction (e.g. menus) OK, but network - stuff is suspended */ - BUSY_CPU /* Locally busy (e.g. crypto); user interaction suspended */ -}; -void set_busy_status(Frontend *frontend, int status); int frontend_is_utf8(Frontend *frontend); void cleanup_exit(int); @@ -1274,7 +1540,7 @@ extern const struct BackendVtable ssh_backend; /* * Exports from ldisc.c. */ -Ldisc *ldisc_create(Conf *, Terminal *, Backend *, Frontend *); +Ldisc *ldisc_create(Conf *, Terminal *, Backend *, Seat *); void ldisc_configure(Ldisc *, Conf *); void ldisc_free(Ldisc *); void ldisc_send(Ldisc *, const void *buf, int len, int interactive); @@ -1403,38 +1669,11 @@ int wc_unescape(char *output, const char *wildcard); * Exports from frontend (windlg.c etc) */ void pgp_fingerprints(void); -/* - * verify_ssh_host_key() can return one of three values: - * - * - +1 means `key was OK' (either already known or the user just - * approved it) `so continue with the connection' - * - * - 0 means `key was not OK, abandon the connection' - * - * - -1 means `I've initiated enquiries, please wait to be called - * back via the provided function with a result that's either 0 - * or +1'. - */ -int verify_ssh_host_key(Frontend *frontend, char *host, int port, - const char *keytype, char *keystr, char *fingerprint, - void (*callback)(void *ctx, int result), void *ctx); /* * have_ssh_host_key() just returns true if a key of that type is * already cached and false otherwise. */ int have_ssh_host_key(const char *host, int port, const char *keytype); -/* - * askalg and askhk have the same set of return values as - * verify_ssh_host_key. - * - * (askhk is used in the case where we're using a host key below the - * warning threshold because that's all we have cached, but at least - * one acceptable algorithm is available that we don't have cached.) - */ -int askalg(Frontend *frontend, const char *algtype, const char *algname, - void (*callback)(void *ctx, int result), void *ctx); -int askhk(Frontend *frontend, const char *algname, const char *betteralgs, - void (*callback)(void *ctx, int result), void *ctx); /* * Exports from console frontends (wincons.c, uxcons.c) @@ -1443,6 +1682,10 @@ int askhk(Frontend *frontend, const char *algname, const char *betteralgs, extern int console_batch_mode; int console_get_userpass_input(prompts_t *p); int is_interactive(void); +void console_print_error_msg(const char *prefix, const char *msg); +void console_print_error_msg_fmt_v( + const char *prefix, const char *fmt, va_list ap); +void console_print_error_msg_fmt(const char *prefix, const char *fmt, ...); /* * Exports from printing.c. diff --git a/raw.c b/raw.c index 09cdb1d3..b6fcbe96 100644 --- a/raw.c +++ b/raw.c @@ -15,7 +15,7 @@ struct Raw { Socket *s; int closed_on_socket_error; int bufsize; - Frontend *frontend; + Seat *seat; LogContext *logctx; int sent_console_eof, sent_socket_eof, session_started; @@ -29,7 +29,7 @@ static void raw_size(Backend *be, int width, int height); static void c_write(Raw *raw, const void *buf, int len) { - int backlog = from_backend(raw->frontend, 0, buf, len); + int backlog = seat_stdout(raw->seat, buf, len); sk_set_frozen(raw->s, backlog > RAW_MAX_BACKLOG); } @@ -37,7 +37,7 @@ static void raw_log(Plug *plug, int type, SockAddr *addr, int port, const char *error_msg, int error_code) { Raw *raw = container_of(plug, Raw, plug); - backend_socket_log(raw->frontend, raw->logctx, type, addr, port, + backend_socket_log(raw->seat, raw->logctx, type, addr, port, error_msg, error_code, raw->conf, raw->session_started); } @@ -51,7 +51,7 @@ static void raw_check_close(Raw *raw) if (raw->s) { sk_close(raw->s); raw->s = NULL; - notify_remote_exit(raw->frontend); + seat_notify_remote_exit(raw->seat); } } } @@ -67,13 +67,13 @@ static void raw_closing(Plug *plug, const char *error_msg, int error_code, sk_close(raw->s); raw->s = NULL; raw->closed_on_socket_error = TRUE; - notify_remote_exit(raw->frontend); + seat_notify_remote_exit(raw->seat); } logevent(raw->logctx, error_msg); - connection_fatal(raw->frontend, "%s", error_msg); + seat_connection_fatal(raw->seat, "%s", error_msg); } else { /* Otherwise, the remote side closed the connection normally. */ - if (!raw->sent_console_eof && from_backend_eof(raw->frontend)) { + if (!raw->sent_console_eof && seat_eof(raw->seat)) { /* * The front end wants us to close the outgoing side of the * connection as soon as we see EOF from the far end. @@ -119,7 +119,7 @@ static const PlugVtable Raw_plugvt = { * Also places the canonical host name into `realhost'. It must be * freed by the caller. */ -static const char *raw_init(Frontend *frontend, Backend **backend_handle, +static const char *raw_init(Seat *seat, Backend **backend_handle, LogContext *logctx, Conf *conf, const char *host, int port, char **realhost, int nodelay, int keepalive) @@ -141,7 +141,7 @@ static const char *raw_init(Frontend *frontend, Backend **backend_handle, raw->session_started = FALSE; raw->conf = conf_copy(conf); - raw->frontend = frontend; + raw->seat = seat; raw->logctx = logctx; addressfamily = conf_get_int(conf, CONF_addressfamily); diff --git a/rlogin.c b/rlogin.c index 34232c83..d91b93cc 100644 --- a/rlogin.c +++ b/rlogin.c @@ -19,7 +19,7 @@ struct Rlogin { int firstbyte; int cansize; int term_width, term_height; - Frontend *frontend; + Seat *seat; LogContext *logctx; Conf *conf; @@ -33,7 +33,7 @@ struct Rlogin { static void c_write(Rlogin *rlogin, const void *buf, int len) { - int backlog = from_backend(rlogin->frontend, 0, buf, len); + int backlog = seat_stdout(rlogin->seat, buf, len); sk_set_frozen(rlogin->s, backlog > RLOGIN_MAX_BACKLOG); } @@ -41,7 +41,7 @@ static void rlogin_log(Plug *plug, int type, SockAddr *addr, int port, const char *error_msg, int error_code) { Rlogin *rlogin = container_of(plug, Rlogin, plug); - backend_socket_log(rlogin->frontend, rlogin->logctx, type, addr, port, + backend_socket_log(rlogin->seat, rlogin->logctx, type, addr, port, error_msg, error_code, rlogin->conf, !rlogin->firstbyte); } @@ -62,12 +62,12 @@ static void rlogin_closing(Plug *plug, const char *error_msg, int error_code, rlogin->s = NULL; if (error_msg) rlogin->closed_on_socket_error = TRUE; - notify_remote_exit(rlogin->frontend); + seat_notify_remote_exit(rlogin->seat); } if (error_msg) { /* A socket error has occurred. */ logevent(rlogin->logctx, error_msg); - connection_fatal(rlogin->frontend, "%s", error_msg); + seat_connection_fatal(rlogin->seat, "%s", error_msg); } /* Otherwise, the remote side closed the connection normally. */ } @@ -150,7 +150,7 @@ static const PlugVtable Rlogin_plugvt = { * Also places the canonical host name into `realhost'. It must be * freed by the caller. */ -static const char *rlogin_init(Frontend *frontend, Backend **backend_handle, +static const char *rlogin_init(Seat *seat, Backend **backend_handle, LogContext *logctx, Conf *conf, const char *host, int port, char **realhost, int nodelay, int keepalive) @@ -167,7 +167,7 @@ static const char *rlogin_init(Frontend *frontend, Backend **backend_handle, rlogin->backend.vt = &rlogin_backend; rlogin->s = NULL; rlogin->closed_on_socket_error = FALSE; - rlogin->frontend = frontend; + rlogin->seat = seat; rlogin->logctx = logctx; rlogin->term_width = conf_get_int(conf, CONF_width); rlogin->term_height = conf_get_int(conf, CONF_height); @@ -223,11 +223,11 @@ static const char *rlogin_init(Frontend *frontend, Backend **backend_handle, } else { int ret; - rlogin->prompt = new_prompts(rlogin->frontend); + rlogin->prompt = new_prompts(); rlogin->prompt->to_server = TRUE; rlogin->prompt->name = dupstr("Rlogin login name"); add_prompt(rlogin->prompt, dupstr("rlogin username: "), TRUE); - ret = get_userpass_input(rlogin->prompt, NULL); + ret = seat_get_userpass_input(rlogin->seat, rlogin->prompt, NULL); if (ret >= 0) { rlogin_startup(rlogin, rlogin->prompt->prompts[0]->result); } @@ -274,7 +274,7 @@ static int rlogin_send(Backend *be, const char *buf, int len) * We're still prompting for a username, and aren't talking * directly to the network connection yet. */ - int ret = get_userpass_input(rlogin->prompt, &bc); + int ret = seat_get_userpass_input(rlogin->seat, rlogin->prompt, &bc); if (ret >= 0) { rlogin_startup(rlogin, rlogin->prompt->prompts[0]->result); /* that nulls out rlogin->prompt, so then we'll start sending diff --git a/ssh.c b/ssh.c index 69927b65..000bee65 100644 --- a/ssh.c +++ b/ssh.c @@ -31,7 +31,7 @@ struct Ssh { Socket *s; - Frontend *frontend; + Seat *seat; Conf *conf; struct ssh_version_receiver version_receiver; @@ -140,7 +140,7 @@ static void ssh_connect_ppl(Ssh *ssh, PacketProtocolLayer *ppl) { ppl->bpp = ssh->bpp; ppl->user_input = &ssh->user_input; - ppl->frontend = ssh->frontend; + ppl->seat = ssh->seat; ppl->ssh = ssh; ppl->remote_bugs = ssh->remote_bugs; } @@ -282,7 +282,7 @@ static void ssh_got_ssh_version(struct ssh_version_receiver *rcv, ssh->base_layer->selfptr = &ssh->base_layer; ssh_ppl_setup_queues(ssh->base_layer, &ssh->bpp->in_pq, &ssh->bpp->out_pq); - update_specials_menu(ssh->frontend); + seat_update_specials_menu(ssh->seat); ssh->pinger = pinger_new(ssh->conf, &ssh->backend); queue_idempotent_callback(&ssh->bpp->ic_in_raw); @@ -408,7 +408,7 @@ void ssh_remote_error(Ssh *ssh, const char *fmt, ...) ssh_shutdown(ssh); logevent(ssh->logctx, msg); - connection_fatal(ssh->frontend, "%s", msg); + seat_connection_fatal(ssh->seat, "%s", msg); sfree(msg); } } @@ -428,7 +428,7 @@ void ssh_remote_eof(Ssh *ssh, const char *fmt, ...) logevent(ssh->logctx, msg); sfree(msg); - notify_remote_exit(ssh->frontend); + seat_notify_remote_exit(ssh->seat); } else { /* This is responding to EOF after we've already seen some * other reason for terminating the session. */ @@ -448,7 +448,7 @@ void ssh_proto_error(Ssh *ssh, const char *fmt, ...) ssh_initiate_connection_close(ssh); logevent(ssh->logctx, msg); - connection_fatal(ssh->frontend, "%s", msg); + seat_connection_fatal(ssh->seat, "%s", msg); sfree(msg); } } @@ -463,10 +463,10 @@ void ssh_sw_abort(Ssh *ssh, const char *fmt, ...) ssh_initiate_connection_close(ssh); logevent(ssh->logctx, msg); - connection_fatal(ssh->frontend, "%s", msg); + seat_connection_fatal(ssh->seat, "%s", msg); sfree(msg); - notify_remote_exit(ssh->frontend); + seat_notify_remote_exit(ssh->seat); } } @@ -489,7 +489,7 @@ void ssh_user_close(Ssh *ssh, const char *fmt, ...) logevent(ssh->logctx, msg); sfree(msg); - notify_remote_exit(ssh->frontend); + seat_notify_remote_exit(ssh->seat); } } @@ -508,7 +508,7 @@ static void ssh_socket_log(Plug *plug, int type, SockAddr *addr, int port, */ if (!ssh->attempting_connshare) - backend_socket_log(ssh->frontend, ssh->logctx, type, addr, port, + backend_socket_log(ssh->seat, ssh->logctx, type, addr, port, error_msg, error_code, ssh->conf, ssh->session_started); } @@ -665,7 +665,7 @@ static const char *connect_to_host(Ssh *ssh, const char *host, int port, * behave in quite the usual way. */ const char *msg = "Reusing a shared connection to this server.\r\n"; - from_backend(ssh->frontend, TRUE, msg, strlen(msg)); + seat_stderr(ssh->seat, msg, strlen(msg)); } } else { /* @@ -689,7 +689,7 @@ static const char *connect_to_host(Ssh *ssh, const char *host, int port, &ssh->plug, ssh->conf); if ((err = sk_socket_error(ssh->s)) != NULL) { ssh->s = NULL; - notify_remote_exit(ssh->frontend); + seat_notify_remote_exit(ssh->seat); return err; } } @@ -788,7 +788,7 @@ static void ssh_cache_conf_values(Ssh *ssh) * * Returns an error message, or NULL on success. */ -static const char *ssh_init(Frontend *frontend, Backend **backend_handle, +static const char *ssh_init(Seat *seat, Backend **backend_handle, LogContext *logctx, Conf *conf, const char *host, int port, char **realhost, int nodelay, int keepalive) @@ -813,7 +813,7 @@ static const char *ssh_init(Frontend *frontend, Backend **backend_handle, ssh->backend.vt = &ssh_backend; *backend_handle = &ssh->backend; - ssh->frontend = frontend; + ssh->seat = seat; ssh->cl_dummy.logctx = ssh->logctx = logctx; random_ref(); /* do this now - may be needed by sharing setup code */ @@ -1003,8 +1003,8 @@ static void ssh_special(Backend *be, SessionSpecialCode code, int arg) } /* - * This is called when stdout/stderr (the entity to which - * from_backend sends data) manages to clear some backlog. + * This is called when the seat's output channel manages to clear some + * backlog. */ static void ssh_unthrottle(Backend *be, int bufsize) { diff --git a/ssh.h b/ssh.h index ea0d6c75..0ed25b2a 100644 --- a/ssh.h +++ b/ssh.h @@ -1397,7 +1397,7 @@ enum { SSH_IMPL_BUG_LIST(TMP_DECLARE_REAL_ENUM) }; /* Shared function that writes tty modes into a pty request */ void write_ttymodes_to_packet_from_conf( - BinarySink *bs, Frontend *frontend, Conf *conf, + BinarySink *bs, Seat *seat, Conf *conf, int ssh_version, int ospeed, int ispeed); /* Shared system for allocating local SSH channel ids. Expects to be diff --git a/ssh1connection.c b/ssh1connection.c index e89e87f4..e493b513 100644 --- a/ssh1connection.c +++ b/ssh1connection.c @@ -579,8 +579,8 @@ static int ssh1_connection_filter_queue(struct ssh1_connection_state *s) case SSH1_SMSG_STDERR_DATA: data = get_string(pktin); if (!get_err(pktin)) { - int bufsize = from_backend( - s->ppl.frontend, pktin->type == SSH1_SMSG_STDERR_DATA, + int bufsize = seat_output( + s->ppl.seat, pktin->type == SSH1_SMSG_STDERR_DATA, data.ptr, data.len); if (!s->stdout_throttling && bufsize > SSH1_BUFFER_LIMIT) { s->stdout_throttling = 1; @@ -706,7 +706,7 @@ static void ssh1_connection_process_queue(PacketProtocolLayer *ppl) put_uint32(pktout, 0); /* width in pixels */ put_uint32(pktout, 0); /* height in pixels */ write_ttymodes_to_packet_from_conf( - BinarySink_UPCAST(pktout), s->ppl.frontend, s->conf, + BinarySink_UPCAST(pktout), s->ppl.seat, s->conf, 1, s->ospeed, s->ispeed); pq_push(s->ppl.out_pq, pktout); crMaybeWaitUntilV((pktin = ssh1_connection_pop(s)) != NULL); diff --git a/ssh1login.c b/ssh1login.c index 0b8ea448..08282d5b 100644 --- a/ssh1login.c +++ b/ssh1login.c @@ -279,8 +279,8 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl) "configured list"); return; } else if (s->dlgret < 0) { /* none configured; use standard handling */ - s->dlgret = verify_ssh_host_key( - s->ppl.frontend, s->savedhost, s->savedport, + s->dlgret = seat_verify_ssh_host_key( + s->ppl.seat, s->savedhost, s->savedport, "rsa", keystr, fingerprint, ssh1_login_dialog_callback, s); sfree(keystr); #ifdef FUZZING @@ -359,8 +359,9 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl) /* Warn about chosen cipher if necessary. */ if (warn) { - s->dlgret = askalg(s->ppl.frontend, "cipher", cipher_string, - ssh1_login_dialog_callback, s); + s->dlgret = seat_confirm_weak_crypto_primitive( + s->ppl.seat, "cipher", cipher_string, + ssh1_login_dialog_callback, s); crMaybeWaitUntilV(s->dlgret >= 0); if (s->dlgret == 0) { ssh_user_close(s->ppl.ssh, "User aborted at cipher warning"); @@ -434,16 +435,17 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl) ppl_logevent(("Successfully started encryption")); if ((s->username = get_remote_username(s->conf)) == NULL) { - s->cur_prompt = new_prompts(s->ppl.frontend); + s->cur_prompt = new_prompts(); s->cur_prompt->to_server = TRUE; s->cur_prompt->name = dupstr("SSH login name"); add_prompt(s->cur_prompt, dupstr("login as: "), TRUE); - s->userpass_ret = get_userpass_input(s->cur_prompt, NULL); + s->userpass_ret = seat_get_userpass_input( + s->ppl.seat, s->cur_prompt, NULL); while (1) { while (s->userpass_ret < 0 && bufchain_size(s->ppl.user_input) > 0) - s->userpass_ret = get_userpass_input( - s->cur_prompt, s->ppl.user_input); + s->userpass_ret = seat_get_userpass_input( + s->ppl.seat, s->cur_prompt, s->ppl.user_input); if (s->userpass_ret >= 0) break; @@ -691,18 +693,19 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl) ppl_printf(("No passphrase required.\r\n")); passphrase = NULL; } else { - s->cur_prompt = new_prompts(s->ppl.frontend); + s->cur_prompt = new_prompts(s->ppl.seat); s->cur_prompt->to_server = FALSE; s->cur_prompt->name = dupstr("SSH key passphrase"); add_prompt(s->cur_prompt, dupprintf("Passphrase for key \"%.100s\": ", s->publickey_comment), FALSE); - s->userpass_ret = get_userpass_input(s->cur_prompt, NULL); + s->userpass_ret = seat_get_userpass_input( + s->ppl.seat, s->cur_prompt, NULL); while (1) { while (s->userpass_ret < 0 && bufchain_size(s->ppl.user_input) > 0) - s->userpass_ret = get_userpass_input( - s->cur_prompt, s->ppl.user_input); + s->userpass_ret = seat_get_userpass_input( + s->ppl.seat, s->cur_prompt, s->ppl.user_input); if (s->userpass_ret >= 0) break; @@ -830,7 +833,7 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl) /* * Otherwise, try various forms of password-like authentication. */ - s->cur_prompt = new_prompts(s->ppl.frontend); + s->cur_prompt = new_prompts(s->ppl.seat); if (conf_get_int(s->conf, CONF_try_tis_auth) && (s->supported_auths_mask & (1 << SSH1_AUTH_TIS)) && @@ -950,12 +953,13 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl) * or CryptoCard exchange if we're doing TIS or CryptoCard * authentication. */ - s->userpass_ret = get_userpass_input(s->cur_prompt, NULL); + s->userpass_ret = seat_get_userpass_input( + s->ppl.seat, s->cur_prompt, NULL); while (1) { while (s->userpass_ret < 0 && bufchain_size(s->ppl.user_input) > 0) - s->userpass_ret = get_userpass_input( - s->cur_prompt, s->ppl.user_input); + s->userpass_ret = seat_get_userpass_input( + s->ppl.seat, s->cur_prompt, s->ppl.user_input); if (s->userpass_ret >= 0) break; diff --git a/ssh2connection.c b/ssh2connection.c index 16996d43..a5c293ff 100644 --- a/ssh2connection.c +++ b/ssh2connection.c @@ -1689,7 +1689,7 @@ static void ssh2_setup_pty(struct ssh2_channel *c, PktIn *pktin, void *ctx) { strbuf *modebuf = strbuf_new(); write_ttymodes_to_packet_from_conf( - BinarySink_UPCAST(modebuf), cs->ppl.frontend, cs->conf, + BinarySink_UPCAST(modebuf), cs->ppl.seat, cs->conf, 2, s->ospeed, s->ispeed); put_stringsb(pktout, modebuf); } @@ -2224,7 +2224,7 @@ static void mainchan_open_confirmation(Channel *chan) struct ssh2_connection_state *s = mc->connlayer; PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */ - update_specials_menu(s->ppl.frontend); + seat_update_specials_menu(s->ppl.seat); ppl_logevent(("Opened main channel")); } @@ -2248,7 +2248,7 @@ static int mainchan_send(Channel *chan, int is_stderr, assert(chan->vt == &mainchan_channelvt); mainchan *mc = container_of(chan, mainchan, chan); struct ssh2_connection_state *s = mc->connlayer; - return from_backend(s->ppl.frontend, is_stderr, data, length); + return seat_output(s->ppl.seat, is_stderr, data, length); } static void mainchan_send_eof(Channel *chan) @@ -2258,14 +2258,13 @@ static void mainchan_send_eof(Channel *chan) struct ssh2_connection_state *s = mc->connlayer; PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */ - if (!s->mainchan_eof_sent && - (from_backend_eof(s->ppl.frontend) || s->got_pty)) { + if (!s->mainchan_eof_sent && (seat_eof(s->ppl.seat) || s->got_pty)) { /* - * Either from_backend_eof told us that the front end wants us - * to close the outgoing side of the connection as soon as we - * see EOF from the far end, or else we've unilaterally - * decided to do that because we've allocated a remote pty and - * hence EOF isn't a particularly meaningful concept. + * Either seat_eof told us that the front end wants us to + * close the outgoing side of the connection as soon as we see + * EOF from the far end, or else we've unilaterally decided to + * do that because we've allocated a remote pty and hence EOF + * isn't a particularly meaningful concept. */ sshfwd_write_eof(mc->sc); ppl_logevent(("Sent EOF message")); diff --git a/ssh2transport.c b/ssh2transport.c index 0b1f6506..343d6787 100644 --- a/ssh2transport.c +++ b/ssh2transport.c @@ -1136,9 +1136,9 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) BinarySource_UPCAST(pktin)->len + 1); if (s->warn_kex) { - s->dlgret = askalg(s->ppl.frontend, "key-exchange algorithm", - s->kex_alg->name, - ssh2_transport_dialog_callback, s); + s->dlgret = seat_confirm_weak_crypto_primitive( + s->ppl.seat, "key-exchange algorithm", s->kex_alg->name, + ssh2_transport_dialog_callback, s); crMaybeWaitUntilV(s->dlgret >= 0); if (s->dlgret == 0) { ssh_user_close(s->ppl.ssh, "User aborted at kex warning"); @@ -1153,9 +1153,9 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) /* * Change warning box wording depending on why we chose a * warning-level host key algorithm. If it's because - * that's all we have *cached*, use the askhk mechanism, - * and list the host keys we could usefully cross-certify. - * Otherwise, use askalg for the standard wording. + * that's all we have *cached*, list the host keys we + * could usefully cross-certify. Otherwise, use the same + * standard wording as any other weak crypto primitive. */ betteralgs = NULL; for (j = 0; j < s->n_uncert_hostkeys; j++) { @@ -1184,14 +1184,18 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) } } if (betteralgs) { - s->dlgret = askhk( - s->ppl.frontend, s->hostkey_alg->ssh_id, betteralgs, + /* Use the special warning prompt that lets us provide + * a list of better algorithms */ + s->dlgret = seat_confirm_weak_cached_hostkey( + s->ppl.seat, s->hostkey_alg->ssh_id, betteralgs, ssh2_transport_dialog_callback, s); sfree(betteralgs); } else { - s->dlgret = askalg(s->ppl.frontend, "host key type", - s->hostkey_alg->ssh_id, - ssh2_transport_dialog_callback, s); + /* If none exist, use the more general 'weak crypto' + * warning prompt */ + s->dlgret = seat_confirm_weak_crypto_primitive( + s->ppl.seat, "host key type", s->hostkey_alg->ssh_id, + ssh2_transport_dialog_callback, s); } crMaybeWaitUntilV(s->dlgret >= 0); if (s->dlgret == 0) { @@ -1201,10 +1205,9 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) } if (s->warn_cscipher) { - s->dlgret = askalg(s->ppl.frontend, - "client-to-server cipher", - s->out.cipher->name, - ssh2_transport_dialog_callback, s); + s->dlgret = seat_confirm_weak_crypto_primitive( + s->ppl.seat, "client-to-server cipher", s->out.cipher->name, + ssh2_transport_dialog_callback, s); crMaybeWaitUntilV(s->dlgret >= 0); if (s->dlgret == 0) { ssh_user_close(s->ppl.ssh, "User aborted at cipher warning"); @@ -1213,10 +1216,9 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) } if (s->warn_sccipher) { - s->dlgret = askalg(s->ppl.frontend, - "server-to-client cipher", - s->in.cipher->name, - ssh2_transport_dialog_callback, s); + s->dlgret = seat_confirm_weak_crypto_primitive( + s->ppl.seat, "server-to-client cipher", s->in.cipher->name, + ssh2_transport_dialog_callback, s); crMaybeWaitUntilV(s->dlgret >= 0); if (s->dlgret == 0) { ssh_user_close(s->ppl.ssh, "User aborted at cipher warning"); @@ -1309,13 +1311,13 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) /* * Now generate and send e for Diffie-Hellman. */ - set_busy_status(s->ppl.frontend, BUSY_CPU); /* this can take a while */ + seat_set_busy_status(s->ppl.seat, BUSY_CPU); s->e = dh_create_e(s->dh_ctx, s->nbits * 2); pktout = ssh_bpp_new_pktout(s->ppl.bpp, s->kex_init_value); put_mp_ssh2(pktout, s->e); pq_push(s->ppl.out_pq, pktout); - set_busy_status(s->ppl.frontend, BUSY_WAITING); /* wait for server */ + seat_set_busy_status(s->ppl.seat, BUSY_WAITING); crMaybeWaitUntilV((pktin = ssh2_transport_pop(s)) != NULL); if (pktin->type != s->kex_reply_value) { ssh_proto_error(s->ppl.ssh, "Received unexpected packet when " @@ -1326,7 +1328,7 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) pktin->type)); return; } - set_busy_status(s->ppl.frontend, BUSY_CPU); /* cogitate */ + seat_set_busy_status(s->ppl.seat, BUSY_CPU); s->hostkeydata = get_string(pktin); s->hkey = ssh_key_new_pub(s->hostkey_alg, s->hostkeydata); s->f = get_mp_ssh2(pktin); @@ -1349,7 +1351,7 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) /* We assume everything from now on will be quick, and it might * involve user interaction. */ - set_busy_status(s->ppl.frontend, BUSY_NOT); + seat_set_busy_status(s->ppl.seat, BUSY_NOT); put_stringpl(s->exhash, s->hostkeydata); if (dh_is_gex(s->kex_alg)) { @@ -1505,7 +1507,7 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) ppl_logevent(("Doing GSSAPI (with Kerberos V5) Diffie-Hellman key " "exchange with hash %s", s->kex_alg->hash->text_name)); /* Now generate e for Diffie-Hellman. */ - set_busy_status(s->ppl.frontend, BUSY_CPU); /* this can take a while */ + seat_set_busy_status(s->ppl.seat, BUSY_CPU); s->e = dh_create_e(s->dh_ctx, s->nbits * 2); if (s->shgss->lib->gsslogmsg) @@ -1664,7 +1666,7 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) /* We assume everything from now on will be quick, and it might * involve user interaction. */ - set_busy_status(s->ppl.frontend, BUSY_NOT); + seat_set_busy_status(s->ppl.seat, BUSY_NOT); if (!s->hkey) put_stringz(s->exhash, ""); @@ -2021,11 +2023,10 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) "configured list"); return; } else if (s->dlgret < 0) { /* none configured; use standard handling */ - s->dlgret = verify_ssh_host_key(s->ppl.frontend, - s->savedhost, s->savedport, - ssh_key_cache_id(s->hkey), - s->keystr, s->fingerprint, - ssh2_transport_dialog_callback, s); + s->dlgret = seat_verify_ssh_host_key( + s->ppl.seat, s->savedhost, s->savedport, + ssh_key_cache_id(s->hkey), s->keystr, s->fingerprint, + ssh2_transport_dialog_callback, s); #ifdef FUZZING s->dlgret = 1; #endif @@ -2205,7 +2206,7 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) * Update the specials menu to list the remaining uncertified host * keys. */ - update_specials_menu(s->ppl.frontend); + seat_update_specials_menu(s->ppl.seat); /* * Key exchange is over. Loop straight back round if we have a diff --git a/ssh2userauth.c b/ssh2userauth.c index 1be98be2..10a2d171 100644 --- a/ssh2userauth.c +++ b/ssh2userauth.c @@ -362,16 +362,17 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) * it again. */ } else if ((s->username = s->default_username) == NULL) { - s->cur_prompt = new_prompts(s->ppl.frontend); + s->cur_prompt = new_prompts(); s->cur_prompt->to_server = TRUE; s->cur_prompt->name = dupstr("SSH login name"); add_prompt(s->cur_prompt, dupstr("login as: "), TRUE); - s->userpass_ret = get_userpass_input(s->cur_prompt, NULL); + s->userpass_ret = seat_get_userpass_input( + s->ppl.seat, s->cur_prompt, NULL); while (1) { while (s->userpass_ret < 0 && bufchain_size(s->ppl.user_input) > 0) - s->userpass_ret = get_userpass_input( - s->cur_prompt, s->ppl.user_input); + s->userpass_ret = seat_get_userpass_input( + s->ppl.seat, s->cur_prompt, s->ppl.user_input); if (s->userpass_ret >= 0) break; @@ -382,7 +383,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) } if (!s->userpass_ret) { /* - * get_userpass_input() failed to get a username. + * seat_get_userpass_input() failed to get a username. * Terminate. */ free_prompts(s->cur_prompt); @@ -453,7 +454,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) * * The banner data has been sanitised already by this * point, so we can safely pass it straight to - * from_backend. + * seat_stderr. */ if (bufchain_size(&s->banner) && (flags & (FLAG_VERBOSE | FLAG_INTERACTIVE))) { @@ -461,7 +462,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) void *data; int len; bufchain_prefix(&s->banner, &data, &len); - from_backend(s->ppl.frontend, TRUE, data, len); + seat_stderr(s->ppl.seat, data, len); bufchain_consume(&s->banner, len); } } @@ -766,20 +767,21 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) /* * Get a passphrase from the user. */ - s->cur_prompt = new_prompts(s->ppl.frontend); + s->cur_prompt = new_prompts(); s->cur_prompt->to_server = FALSE; s->cur_prompt->name = dupstr("SSH key passphrase"); add_prompt(s->cur_prompt, dupprintf("Passphrase for key \"%.100s\": ", s->publickey_comment), FALSE); - s->userpass_ret = get_userpass_input( - s->cur_prompt, NULL); + s->userpass_ret = seat_get_userpass_input( + s->ppl.seat, s->cur_prompt, NULL); while (1) { while (s->userpass_ret < 0 && bufchain_size(s->ppl.user_input) > 0) - s->userpass_ret = get_userpass_input( - s->cur_prompt, s->ppl.user_input); + s->userpass_ret = seat_get_userpass_input( + s->ppl.seat, s->cur_prompt, + s->ppl.user_input); if (s->userpass_ret >= 0) break; @@ -1089,7 +1091,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) name = get_string(pktin); inst = get_string(pktin); get_string(pktin); /* skip language tag */ - s->cur_prompt = new_prompts(s->ppl.frontend); + s->cur_prompt = new_prompts(); s->cur_prompt->to_server = TRUE; /* @@ -1144,12 +1146,13 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) * Display any instructions, and get the user's * response(s). */ - s->userpass_ret = get_userpass_input(s->cur_prompt, NULL); + s->userpass_ret = seat_get_userpass_input( + s->ppl.seat, s->cur_prompt, NULL); while (1) { while (s->userpass_ret < 0 && bufchain_size(s->ppl.user_input) > 0) - s->userpass_ret = get_userpass_input( - s->cur_prompt, s->ppl.user_input); + s->userpass_ret = seat_get_userpass_input( + s->ppl.seat, s->cur_prompt, s->ppl.user_input); if (s->userpass_ret >= 0) break; @@ -1213,19 +1216,20 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) s->ppl.bpp->pls->actx = SSH2_PKTCTX_PASSWORD; - s->cur_prompt = new_prompts(s->ppl.frontend); + s->cur_prompt = new_prompts(); s->cur_prompt->to_server = TRUE; s->cur_prompt->name = dupstr("SSH password"); add_prompt(s->cur_prompt, dupprintf("%s@%s's password: ", s->username, s->hostname), FALSE); - s->userpass_ret = get_userpass_input(s->cur_prompt, NULL); + s->userpass_ret = seat_get_userpass_input( + s->ppl.seat, s->cur_prompt, NULL); while (1) { while (s->userpass_ret < 0 && bufchain_size(s->ppl.user_input) > 0) - s->userpass_ret = get_userpass_input( - s->cur_prompt, s->ppl.user_input); + s->userpass_ret = seat_get_userpass_input( + s->ppl.seat, s->cur_prompt, s->ppl.user_input); if (s->userpass_ret >= 0) break; @@ -1306,7 +1310,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) prompt = get_string(pktin); - s->cur_prompt = new_prompts(s->ppl.frontend); + s->cur_prompt = new_prompts(); s->cur_prompt->to_server = TRUE; s->cur_prompt->name = dupstr("New SSH password"); s->cur_prompt->instruction = mkstr(prompt); @@ -1336,13 +1340,14 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) * password twice. */ while (!got_new) { - s->userpass_ret = get_userpass_input( - s->cur_prompt, NULL); + s->userpass_ret = seat_get_userpass_input( + s->ppl.seat, s->cur_prompt, NULL); while (1) { while (s->userpass_ret < 0 && bufchain_size(s->ppl.user_input) > 0) - s->userpass_ret = get_userpass_input( - s->cur_prompt, s->ppl.user_input); + s->userpass_ret = seat_get_userpass_input( + s->ppl.seat, s->cur_prompt, + s->ppl.user_input); if (s->userpass_ret >= 0) break; diff --git a/sshcommon.c b/sshcommon.c index 16cf9310..6095930a 100644 --- a/sshcommon.c +++ b/sshcommon.c @@ -345,7 +345,7 @@ int chan_no_eager_close(Channel *chan, int sent_local_eof, int rcvd_remote_eof) */ void write_ttymodes_to_packet_from_conf( - BinarySink *bs, Frontend *frontend, Conf *conf, + BinarySink *bs, Seat *seat, Conf *conf, int ssh_version, int ospeed, int ispeed) { int i; @@ -446,7 +446,7 @@ void write_ttymodes_to_packet_from_conf( * mode. */ if (sval[0] == 'A') { - sval = to_free = get_ttymode(frontend, mode->mode); + sval = to_free = seat_get_ttymode(seat, mode->mode); } else if (sval[0] == 'V') { sval++; /* skip the 'V' */ } else { @@ -644,7 +644,7 @@ void ssh_ppl_replace(PacketProtocolLayer *old, PacketProtocolLayer *new) ssh_ppl_setup_queues(new, old->in_pq, old->out_pq); new->selfptr = old->selfptr; new->user_input = old->user_input; - new->frontend = old->frontend; + new->seat = old->seat; new->ssh = old->ssh; *new->selfptr = new; @@ -689,7 +689,7 @@ void ssh_ppl_user_output_string_and_free(PacketProtocolLayer *ppl, char *text) /* Messages sent via this function are from the SSH layer, not * from the server-side process, so they always have the stderr * flag set. */ - from_backend(ppl->frontend, TRUE, text, strlen(text)); + seat_stderr(ppl->seat, text, strlen(text)); sfree(text); } diff --git a/sshppl.h b/sshppl.h index f637b0e0..2536c0ec 100644 --- a/sshppl.h +++ b/sshppl.h @@ -54,7 +54,7 @@ struct PacketProtocolLayer { /* Logging and error-reporting facilities. */ LogContext *logctx; - void *frontend; /* for dialog boxes etc */ + Seat *seat; /* for dialog boxes, session output etc */ Ssh *ssh; /* for session termination + assorted connection-layer ops */ /* Known bugs in the remote implementation. */ diff --git a/telnet.c b/telnet.c index 76d8a943..bdb24e2f 100644 --- a/telnet.c +++ b/telnet.c @@ -173,7 +173,7 @@ struct Telnet { Socket *s; int closed_on_socket_error; - Frontend *frontend; + Seat *seat; LogContext *logctx; Ldisc *ldisc; int term_width, term_height; @@ -209,7 +209,7 @@ struct Telnet { static void c_write(Telnet *telnet, const void *buf, int len) { int backlog; - backlog = from_backend(telnet->frontend, 0, buf, len); + backlog = seat_stdout(telnet->seat, buf, len); sk_set_frozen(telnet->s, backlog > TELNET_MAX_BACKLOG); } @@ -627,7 +627,7 @@ static void telnet_log(Plug *plug, int type, SockAddr *addr, int port, const char *error_msg, int error_code) { Telnet *telnet = container_of(plug, Telnet, plug); - backend_socket_log(telnet->frontend, telnet->logctx, type, addr, port, + backend_socket_log(telnet->seat, telnet->logctx, type, addr, port, error_msg, error_code, telnet->conf, telnet->session_started); } @@ -648,11 +648,11 @@ static void telnet_closing(Plug *plug, const char *error_msg, int error_code, telnet->s = NULL; if (error_msg) telnet->closed_on_socket_error = TRUE; - notify_remote_exit(telnet->frontend); + seat_notify_remote_exit(telnet->seat); } if (error_msg) { logevent(telnet->logctx, error_msg); - connection_fatal(telnet->frontend, "%s", error_msg); + seat_connection_fatal(telnet->seat, "%s", error_msg); } /* Otherwise, the remote side closed the connection normally. */ } @@ -687,7 +687,7 @@ static const PlugVtable Telnet_plugvt = { * Also places the canonical host name into `realhost'. It must be * freed by the caller. */ -static const char *telnet_init(Frontend *frontend, Backend **backend_handle, +static const char *telnet_init(Seat *seat, Backend **backend_handle, LogContext *logctx, Conf *conf, const char *host, int port, char **realhost, int nodelay, int keepalive) @@ -709,7 +709,7 @@ static const char *telnet_init(Frontend *frontend, Backend **backend_handle, telnet->activated = FALSE; telnet->sb_buf = NULL; telnet->sb_size = 0; - telnet->frontend = frontend; + telnet->seat = seat; telnet->logctx = logctx; telnet->term_width = conf_get_int(telnet->conf, CONF_width); telnet->term_height = conf_get_int(telnet->conf, CONF_height); @@ -770,7 +770,7 @@ static const char *telnet_init(Frontend *frontend, Backend **backend_handle, /* * We can send special commands from the start. */ - update_specials_menu(telnet->frontend); + seat_update_specials_menu(telnet->seat); /* * loghost overrides realhost, if specified. diff --git a/terminal.h b/terminal.h index f0727cf2..be3c589f 100644 --- a/terminal.h +++ b/terminal.h @@ -249,12 +249,12 @@ struct terminal_tag { Conf *conf; /* - * from_backend calls term_out, but it can also be called from - * the ldisc if the ldisc is called _within_ term_out. So we - * have to guard against re-entrancy - if from_backend is - * called recursively like this, it will simply add data to the - * end of the buffer term_out is in the process of working - * through. + * GUI implementations of seat_output call term_out, but it can + * also be called from the ldisc if the ldisc is called _within_ + * term_out. So we have to guard against re-entrancy - if + * seat_output is called recursively like this, it will simply add + * data to the end of the buffer term_out is in the process of + * working through. */ int in_term_out; diff --git a/testback.c b/testback.c index 6a89bfc5..b54c682e 100644 --- a/testback.c +++ b/testback.c @@ -32,10 +32,10 @@ #include "putty.h" -static const char *null_init(Frontend *, Backend **, Conf *, const char *, int, - char **, int, int); -static const char *loop_init(Frontend *, Backend **, Conf *, const char *, int, - char **, int, int); +static const char *null_init(Seat *, Backend **, LogContext *, Conf *, + const char *, int, char **, int, int); +static const char *loop_init(Seat *, Backend **, LogContext *, Conf *, + const char *, int, char **, int, int); static void null_free(Backend *); static void loop_free(Backend *); static void null_reconfig(Backend *, Conf *); @@ -68,23 +68,25 @@ const struct BackendVtable loop_backend = { }; struct loop_state { - Frontend *frontend; + Seat *seat; Backend backend; }; -static const char *null_init(Frontend *frontend, Backend **backend_handle, - Conf *conf, const char *host, int port, - char **realhost, int nodelay, int keepalive) { +static const char *null_init(Seat *seat, Backend **backend_handle, + LogContext *logctx, Conf *conf, + const char *host, int port, char **realhost, + int nodelay, int keepalive) { *backend_handle = NULL; return NULL; } -static const char *loop_init(Frontend *frontend, Backend **backend_handle, - Conf *conf, const char *host, int port, - char **realhost, int nodelay, int keepalive) { +static const char *loop_init(Seat *seat, Backend **backend_handle, + LogContext *logctx, Conf *conf, + const char *host, int port, char **realhost, + int nodelay, int keepalive) { struct loop_state *st = snew(struct loop_state); - st->frontend = frontend; + st->seat = seat; *backend_handle = &st->backend; return NULL; } @@ -113,7 +115,7 @@ static int null_send(Backend *be, const char *buf, int len) { static int loop_send(Backend *be, const char *buf, int len) { struct loop_state *st = container_of(be, struct loop_state, backend); - return from_backend(st->frontend, 0, buf, len); + return seat_output(st->seat, 0, buf, len); } static int null_sendbuffer(Backend *be) { @@ -162,10 +164,6 @@ static void null_provide_ldisc (Backend *be, Ldisc *ldisc) { } -static void null_provide_logctx(Backend *be, LogContext *logctx) { - -} - static int null_cfg_info(Backend *be) { return 0; diff --git a/unix/gtkdlg.c b/unix/gtkdlg.c index e9d2d6c4..39c91c61 100644 --- a/unix/gtkdlg.c +++ b/unix/gtkdlg.c @@ -3416,7 +3416,7 @@ struct verify_ssh_host_key_result_ctx { char *keystr; void (*callback)(void *callback_ctx, int result); void *callback_ctx; - Frontend *frontend; + Seat *seat; }; static void verify_ssh_host_key_result_callback(void *vctx, int result) @@ -3449,7 +3449,7 @@ static void verify_ssh_host_key_result_callback(void *vctx, int result) * Clean up this context structure, whether or not a result was * ever actually delivered from the dialog box. */ - unregister_dialog(ctx->frontend, DIALOG_SLOT_NETWORK_PROMPT); + unregister_dialog(ctx->seat, DIALOG_SLOT_NETWORK_PROMPT); sfree(ctx->host); sfree(ctx->keytype); @@ -3457,9 +3457,10 @@ static void verify_ssh_host_key_result_callback(void *vctx, int result) sfree(ctx); } -int verify_ssh_host_key(Frontend *frontend, char *host, int port, - const char *keytype, char *keystr, char *fingerprint, - void (*callback)(void *ctx, int result), void *ctx) +int gtk_seat_verify_ssh_host_key( + Seat *seat, const char *host, int port, + const char *keytype, char *keystr, char *fingerprint, + void (*callback)(void *ctx, int result), void *ctx) { static const char absenttxt[] = "The server's host key is not cached. You have no guarantee " @@ -3518,13 +3519,13 @@ int verify_ssh_host_key(Frontend *frontend, char *host, int port, result_ctx->port = port; result_ctx->keytype = dupstr(keytype); result_ctx->keystr = dupstr(keystr); - result_ctx->frontend = frontend; + result_ctx->seat = seat; - mainwin = GTK_WIDGET(get_window(frontend)); + mainwin = GTK_WIDGET(gtk_seat_get_window(seat)); msgbox = create_message_box( mainwin, "PuTTY Security Alert", text, string_width(fingerprint), TRUE, &buttons_hostkey, verify_ssh_host_key_result_callback, result_ctx); - register_dialog(frontend, DIALOG_SLOT_NETWORK_PROMPT, msgbox); + register_dialog(seat, DIALOG_SLOT_NETWORK_PROMPT, msgbox); sfree(text); @@ -3534,7 +3535,7 @@ int verify_ssh_host_key(Frontend *frontend, char *host, int port, struct simple_prompt_result_ctx { void (*callback)(void *callback_ctx, int result); void *callback_ctx; - Frontend *frontend; + Seat *seat; enum DialogSlot dialog_slot; }; @@ -3550,7 +3551,7 @@ static void simple_prompt_result_callback(void *vctx, int result) * Clean up this context structure, whether or not a result was * ever actually delivered from the dialog box. */ - unregister_dialog(ctx->frontend, ctx->dialog_slot); + unregister_dialog(ctx->seat, ctx->dialog_slot); sfree(ctx); } @@ -3558,8 +3559,9 @@ static void simple_prompt_result_callback(void *vctx, int result) * Ask whether the selected algorithm is acceptable (since it was * below the configured 'warn' threshold). */ -int askalg(Frontend *frontend, const char *algtype, const char *algname, - void (*callback)(void *ctx, int result), void *ctx) +int gtk_seat_confirm_weak_crypto_primitive( + Seat *seat, const char *algtype, const char *algname, + void (*callback)(void *ctx, int result), void *ctx) { static const char msg[] = "The first %s supported by the server is " @@ -3575,23 +3577,24 @@ int askalg(Frontend *frontend, const char *algtype, const char *algname, result_ctx = snew(struct simple_prompt_result_ctx); result_ctx->callback = callback; result_ctx->callback_ctx = ctx; - result_ctx->frontend = frontend; + result_ctx->seat = seat; result_ctx->dialog_slot = DIALOG_SLOT_NETWORK_PROMPT; - mainwin = GTK_WIDGET(get_window(frontend)); + mainwin = GTK_WIDGET(gtk_seat_get_window(seat)); msgbox = create_message_box( mainwin, "PuTTY Security Alert", text, string_width("Reasonably long line of text as a width template"), FALSE, &buttons_yn, simple_prompt_result_callback, result_ctx); - register_dialog(frontend, result_ctx->dialog_slot, msgbox); + register_dialog(seat, result_ctx->dialog_slot, msgbox); sfree(text); return -1; /* dialog still in progress */ } -int askhk(Frontend *frontend, const char *algname, const char *betteralgs, - void (*callback)(void *ctx, int result), void *ctx) +int gtk_seat_confirm_weak_cached_hostkey( + Seat *seat, const char *algname, const char *betteralgs, + void (*callback)(void *ctx, int result), void *ctx) { static const char msg[] = "The first host key type we have stored for this server\n" @@ -3610,16 +3613,16 @@ int askhk(Frontend *frontend, const char *algname, const char *betteralgs, result_ctx = snew(struct simple_prompt_result_ctx); result_ctx->callback = callback; result_ctx->callback_ctx = ctx; - result_ctx->frontend = frontend; + result_ctx->seat = seat; result_ctx->dialog_slot = DIALOG_SLOT_NETWORK_PROMPT; - mainwin = GTK_WIDGET(get_window(frontend)); + mainwin = GTK_WIDGET(gtk_seat_get_window(seat)); msgbox = create_message_box( mainwin, "PuTTY Security Alert", text, string_width("is ecdsa-nistp521, which is below the configured" " warning threshold."), FALSE, &buttons_yn, simple_prompt_result_callback, result_ctx); - register_dialog(frontend, result_ctx->dialog_slot, msgbox); + register_dialog(seat, result_ctx->dialog_slot, msgbox); sfree(text); @@ -4048,7 +4051,7 @@ void logevent_dlg(eventlog_stuff *es, const char *string) } } -int gtkdlg_askappend(Frontend *frontend, Filename *filename, +int gtkdlg_askappend(Seat *seat, Filename *filename, void (*callback)(void *ctx, int result), void *ctx) { static const char msgtemplate[] = @@ -4076,15 +4079,15 @@ int gtkdlg_askappend(Frontend *frontend, Filename *filename, result_ctx = snew(struct simple_prompt_result_ctx); result_ctx->callback = callback; result_ctx->callback_ctx = ctx; - result_ctx->frontend = frontend; + result_ctx->seat = seat; result_ctx->dialog_slot = DIALOG_SLOT_LOGFILE_PROMPT; - mainwin = GTK_WIDGET(get_window(frontend)); + mainwin = GTK_WIDGET(gtk_seat_get_window(seat)); msgbox = create_message_box( mainwin, mbtitle, message, string_width("LINE OF TEXT SUITABLE FOR THE ASKAPPEND WIDTH"), FALSE, &buttons_append, simple_prompt_result_callback, result_ctx); - register_dialog(frontend, result_ctx->dialog_slot, msgbox); + register_dialog(seat, result_ctx->dialog_slot, msgbox); sfree(message); sfree(mbtitle); diff --git a/unix/gtkwin.c b/unix/gtkwin.c index 1b56d859..63ae311c 100644 --- a/unix/gtkwin.c +++ b/unix/gtkwin.c @@ -152,7 +152,7 @@ struct Frontend { int width, height, scale; int ignore_sbar; int mouseptr_visible; - int busy_status; + BusyStatus busy_status; int alt_keycode; int alt_digits; char *wintitle; @@ -181,6 +181,7 @@ struct Frontend { int system_mod_mask; #endif + Seat seat; LogPolicy logpolicy; }; @@ -222,7 +223,7 @@ static void post_fatal_message_box_toplevel(void *vctx) static void post_fatal_message_box(void *vctx, int result) { Frontend *inst = (Frontend *)vctx; - unregister_dialog(inst, DIALOG_SLOT_CONNECTION_FATAL); + unregister_dialog(&inst->seat, DIALOG_SLOT_CONNECTION_FATAL); queue_toplevel_callback(post_fatal_message_box_toplevel, inst); } @@ -234,7 +235,7 @@ static void common_connfatal_message_box( inst->window, title, msg, string_width("REASONABLY LONG LINE OF TEXT FOR BASIC SANITY"), FALSE, &buttons_ok, postfn, inst); - register_dialog(inst, DIALOG_SLOT_CONNECTION_FATAL, dialog); + register_dialog(&inst->seat, DIALOG_SLOT_CONNECTION_FATAL, dialog); sfree(title); } @@ -252,22 +253,17 @@ static void connection_fatal_callback(void *vctx) static void post_nonfatal_message_box(void *vctx, int result) { Frontend *inst = (Frontend *)vctx; - unregister_dialog(inst, DIALOG_SLOT_CONNECTION_FATAL); + unregister_dialog(&inst->seat, DIALOG_SLOT_CONNECTION_FATAL); } -void connection_fatal(Frontend *inst, const char *p, ...) +static void gtk_seat_connection_fatal(Seat *seat, const char *msg) { - va_list ap; - char *msg; - va_start(ap, p); - msg = dupvprintf(p, ap); - va_end(ap); + Frontend *inst = container_of(seat, Frontend, seat); if (conf_get_int(inst->conf, CONF_close_on_exit) == FORCE_ON) { fatal_message_box(inst, msg); } else { common_connfatal_message_box(inst, msg, post_nonfatal_message_box); } - sfree(msg); inst->exited = TRUE; /* suppress normal exit handling */ queue_toplevel_callback(connection_fatal_callback, inst); @@ -308,29 +304,29 @@ int platform_default_i(const char *name, int def) return def; } -/* Dummy routine, only required in plink. */ -void frontend_echoedit_update(Frontend *inst, int echo, int edit) -{ -} - -char *get_ttymode(Frontend *inst, const char *mode) +static char *gtk_seat_get_ttymode(Seat *seat, const char *mode) { + Frontend *inst = container_of(seat, Frontend, seat); return term_get_ttymode(inst->term, mode); } -int from_backend(Frontend *inst, int is_stderr, const void *data, int len) +static int gtk_seat_output(Seat *seat, int is_stderr, + const void *data, int len) { + Frontend *inst = container_of(seat, Frontend, seat); return term_data(inst->term, is_stderr, data, len); } -int from_backend_eof(Frontend *inst) +static int gtk_seat_eof(Seat *seat) { + /* Frontend *inst = container_of(seat, Frontend, seat); */ return TRUE; /* do respond to incoming EOF with outgoing */ } -int get_userpass_input(prompts_t *p, bufchain *input) +static int gtk_seat_get_userpass_input(Seat *seat, prompts_t *p, + bufchain *input) { - Frontend *inst = p->frontend; + Frontend *inst = container_of(seat, Frontend, seat); int ret; ret = cmdline_get_passwd_input(p); if (ret == -1) @@ -338,6 +334,51 @@ int get_userpass_input(prompts_t *p, bufchain *input) return ret; } +static int gtk_seat_is_utf8(Seat *seat) +{ + Frontend *inst = container_of(seat, Frontend, seat); + return frontend_is_utf8(inst); +} + +static int gtk_seat_get_char_cell_size(Seat *seat, int *w, int *h) +{ + Frontend *inst = container_of(seat, Frontend, seat); + *w = inst->font_width; + *h = inst->font_height; + return TRUE; +} + +static void gtk_seat_notify_remote_exit(Seat *seat); +static void gtk_seat_update_specials_menu(Seat *seat); +static void gtk_seat_set_busy_status(Seat *seat, BusyStatus status); +static const char *gtk_seat_get_x_display(Seat *seat); +#ifndef NOT_X_WINDOWS +static int gtk_seat_get_windowid(Seat *seat, long *id); +#endif + +static const SeatVtable gtk_seat_vt = { + gtk_seat_output, + gtk_seat_eof, + gtk_seat_get_userpass_input, + gtk_seat_notify_remote_exit, + gtk_seat_connection_fatal, + gtk_seat_update_specials_menu, + gtk_seat_get_ttymode, + gtk_seat_set_busy_status, + gtk_seat_verify_ssh_host_key, + gtk_seat_confirm_weak_crypto_primitive, + gtk_seat_confirm_weak_cached_hostkey, + gtk_seat_is_utf8, + nullseat_echoedit_update, + gtk_seat_get_x_display, +#ifdef NOT_X_WINDOWS + nullseat_get_windowid, +#else + gtk_seat_get_windowid, +#endif + gtk_seat_get_char_cell_size, +}; + static void gtk_eventlog(LogPolicy *lp, const char *string) { Frontend *inst = container_of(lp, Frontend, logpolicy); @@ -348,10 +389,7 @@ static int gtk_askappend(LogPolicy *lp, Filename *filename, void (*callback)(void *ctx, int result), void *ctx) { Frontend *inst = container_of(lp, Frontend, logpolicy); - - int gtkdlg_askappend(Frontend *frontend, Filename *filename, - void (*callback)(void *ctx, int result), void *ctx); - return gtkdlg_askappend(inst, filename, callback, ctx); + return gtkdlg_askappend(&inst->seat, filename, callback, ctx); } static void gtk_logging_error(LogPolicy *lp, const char *event) @@ -360,8 +398,8 @@ static void gtk_logging_error(LogPolicy *lp, const char *event) /* Send 'can't open log file' errors to the terminal window. * (Marked as stderr, although terminal.c won't care.) */ - from_backend(inst, 1, event, strlen(event)); - from_backend(inst, 1, "\r\n", 2); + seat_stderr(&inst->seat, event, strlen(event)); + seat_stderr(&inst->seat, "\r\n", 2); } static const LogPolicyVtable gtk_logpolicy_vt = { @@ -370,14 +408,6 @@ static const LogPolicyVtable gtk_logpolicy_vt = { gtk_logging_error, }; -int font_dimension(Frontend *inst, int which) /* 0 for width, 1 for height */ -{ - if (which) - return inst->font_height; - else - return inst->font_width; -} - /* * Translate a raw mouse button designation (LEFT, MIDDLE, RIGHT) * into a cooked one (SELECT, EXTEND, PASTE). @@ -402,8 +432,9 @@ static Mouse_Button translate_button(Mouse_Button button) * Return the top-level GtkWindow associated with a particular * front end instance. */ -GtkWidget *get_window(Frontend *inst) +GtkWidget *gtk_seat_get_window(Seat *seat) { + Frontend *inst = container_of(seat, Frontend, seat); return inst->window; } @@ -412,14 +443,20 @@ GtkWidget *get_window(Frontend *inst) * network code wanting to ask an asynchronous user question (e.g. * 'what about this dodgy host key, then?'). */ -void register_dialog(Frontend *inst, enum DialogSlot slot, GtkWidget *dialog) +void register_dialog(Seat *seat, enum DialogSlot slot, GtkWidget *dialog) { + Frontend *inst; + assert(seat->vt == >k_seat_vt); + inst = container_of(seat, Frontend, seat); assert(slot < DIALOG_SLOT_LIMIT); assert(!inst->dialogs[slot]); inst->dialogs[slot] = dialog; } -void unregister_dialog(Frontend *inst, enum DialogSlot slot) +void unregister_dialog(Seat *seat, enum DialogSlot slot) { + Frontend *inst; + assert(seat->vt == >k_seat_vt); + inst = container_of(seat, Frontend, seat); assert(slot < DIALOG_SLOT_LIMIT); assert(inst->dialogs[slot]); inst->dialogs[slot] = NULL; @@ -570,7 +607,7 @@ char *get_window_title(Frontend *inst, int icon) static void warn_on_close_callback(void *vctx, int result) { Frontend *inst = (Frontend *)vctx; - unregister_dialog(inst, DIALOG_SLOT_WARN_ON_CLOSE); + unregister_dialog(&inst->seat, DIALOG_SLOT_WARN_ON_CLOSE); if (result) gtk_widget_destroy(inst->window); } @@ -600,7 +637,7 @@ gint delete_window(GtkWidget *widget, GdkEvent *event, Frontend *inst) "Are you sure you want to close this session?", string_width("Most of the width of the above text"), FALSE, &buttons_yn, warn_on_close_callback, inst); - register_dialog(inst, DIALOG_SLOT_WARN_ON_CLOSE, dialog); + register_dialog(&inst->seat, DIALOG_SLOT_WARN_ON_CLOSE, dialog); sfree(title); } return TRUE; @@ -2435,8 +2472,9 @@ static void exit_callback(void *vctx) } } -void notify_remote_exit(Frontend *inst) +static void gtk_seat_notify_remote_exit(Seat *seat) { + Frontend *inst = container_of(seat, Frontend, seat); queue_toplevel_callback(exit_callback, inst); } @@ -2454,7 +2492,7 @@ static void destroy_inst_connection(Frontend *inst) if (inst->term) term_provide_backend(inst->term, NULL); if (inst->menu) { - update_specials_menu(inst); + seat_update_specials_menu(&inst->seat); gtk_widget_set_sensitive(inst->restartitem, TRUE); } } @@ -2537,8 +2575,9 @@ gint focus_event(GtkWidget *widget, GdkEventFocus *event, gpointer data) return FALSE; } -void set_busy_status(Frontend *inst, int status) +static void gtk_seat_set_busy_status(Seat *seat, BusyStatus status) { + Frontend *inst = container_of(seat, Frontend, seat); inst->busy_status = status; update_mouseptr(inst); } @@ -4190,14 +4229,15 @@ void modalfatalbox(const char *p, ...) exit(1); } -const char *get_x_display(Frontend *frontend) +static const char *gtk_seat_get_x_display(Seat *seat) { return gdk_get_display(); } #ifndef NOT_X_WINDOWS -int get_windowid(Frontend *inst, long *id) +static int gtk_seat_get_windowid(Seat *seat, long *id) { + Frontend *inst = container_of(seat, Frontend, seat); GdkWindow *window = gtk_widget_get_window(inst->area); if (!GDK_IS_X11_WINDOW(window)) return FALSE; @@ -4583,7 +4623,7 @@ void change_settings_menuitem(GtkMenuItem *item, gpointer data) title, ctx->newconf, 1, inst->backend ? backend_cfg_info(inst->backend) : 0, after_change_settings_dialog, ctx); - register_dialog(inst, DIALOG_SLOT_RECONFIGURE, dialog); + register_dialog(&inst->seat, DIALOG_SLOT_RECONFIGURE, dialog); sfree(title); } @@ -4613,7 +4653,7 @@ static void after_change_settings_dialog(void *vctx, int retval) assert(lenof(ww) == NCFGCOLOURS); - unregister_dialog(inst, DIALOG_SLOT_RECONFIGURE); + unregister_dialog(&inst->seat, DIALOG_SLOT_RECONFIGURE); if (retval) { inst->conf = newconf; @@ -4979,8 +5019,9 @@ void set_window_icon(GtkWidget *window, const char *const *const *icon, static void free_special_cmd(gpointer data) { sfree(data); } -void update_specials_menu(Frontend *inst) +static void gtk_seat_update_specials_menu(Seat *seat) { + Frontend *inst = container_of(seat, Frontend, seat); const SessionSpecial *specials; if (inst->backend) @@ -5055,7 +5096,7 @@ static void start_backend(Frontend *inst) vt = select_backend(inst->conf); - error = backend_init(vt, (void *)inst, &inst->backend, + error = backend_init(vt, &inst->seat, &inst->backend, inst->logctx, inst->conf, conf_get_str(inst->conf, CONF_host), conf_get_int(inst->conf, CONF_port), @@ -5067,7 +5108,7 @@ static void start_backend(Frontend *inst) char *msg = dupprintf("Unable to open connection to %s:\n%s", conf_dest(inst->conf), error); inst->exited = TRUE; - connection_fatal(inst, msg); + seat_connection_fatal(&inst->seat, msg); sfree(msg); return; } @@ -5084,7 +5125,8 @@ static void start_backend(Frontend *inst) term_provide_backend(inst->term, inst->backend); - inst->ldisc = ldisc_create(inst->conf, inst->term, inst->backend, inst); + inst->ldisc = ldisc_create(inst->conf, inst->term, inst->backend, + &inst->seat); gtk_widget_set_sensitive(inst->restartitem, FALSE); } @@ -5139,6 +5181,7 @@ void new_session_window(Conf *conf, const char *geometry_string) #endif inst->drawing_area_setup_needed = TRUE; + inst->seat.vt = >k_seat_vt; inst->logpolicy.vt = >k_logpolicy_vt; #ifndef NOT_X_WINDOWS diff --git a/unix/unix.h b/unix/unix.h index c85c8470..f222928e 100644 --- a/unix/unix.h +++ b/unix/unix.h @@ -191,14 +191,8 @@ enum MenuAction { }; void app_menu_action(Frontend *frontend, enum MenuAction); -/* Things pty.c needs from pterm.c */ -const char *get_x_display(Frontend *frontend); -int font_dimension(Frontend *frontend, int which);/* 0 for width, 1 for height */ -int get_windowid(Frontend *frontend, long *id); - /* Things gtkdlg.c needs from pterm.c */ #ifdef MAY_REFER_TO_GTK_IN_HEADERS -GtkWidget *get_window(Frontend *frontend); enum DialogSlot { DIALOG_SLOT_RECONFIGURE, DIALOG_SLOT_NETWORK_PROMPT, @@ -207,8 +201,9 @@ enum DialogSlot { DIALOG_SLOT_CONNECTION_FATAL, DIALOG_SLOT_LIMIT /* must remain last */ }; -void register_dialog(Frontend *frontend, enum DialogSlot slot, GtkWidget *dialog); -void unregister_dialog(Frontend *frontend, enum DialogSlot slot); +GtkWidget *gtk_seat_get_window(Seat *seat); +void register_dialog(Seat *seat, enum DialogSlot slot, GtkWidget *dialog); +void unregister_dialog(Seat *seat, enum DialogSlot slot); #endif /* Things pterm.c needs from gtkdlg.c */ @@ -224,6 +219,18 @@ eventlog_stuff *eventlogstuff_new(void); void eventlogstuff_free(eventlog_stuff *); void showeventlog(eventlog_stuff *estuff, void *parentwin); void logevent_dlg(eventlog_stuff *estuff, const char *string); +int gtkdlg_askappend(Seat *seat, Filename *filename, + void (*callback)(void *ctx, int result), void *ctx); +int gtk_seat_verify_ssh_host_key( + Seat *seat, const char *host, int port, + const char *keytype, char *keystr, char *fingerprint, + void (*callback)(void *ctx, int result), void *ctx); +int gtk_seat_confirm_weak_crypto_primitive( + Seat *seat, const char *algtype, const char *algname, + void (*callback)(void *ctx, int result), void *ctx); +int gtk_seat_confirm_weak_cached_hostkey( + Seat *seat, const char *algname, const char *betteralgs, + void (*callback)(void *ctx, int result), void *ctx); #ifdef MAY_REFER_TO_GTK_IN_HEADERS struct message_box_button { const char *title; diff --git a/unix/uxcons.c b/unix/uxcons.c index fb75743c..b44d34b8 100644 --- a/unix/uxcons.c +++ b/unix/uxcons.c @@ -61,16 +61,58 @@ void cleanup_exit(int code) exit(code); } -void set_busy_status(Frontend *frontend, int status) +/* + * Various error message and/or fatal exit functions. + */ +void console_print_error_msg(const char *prefix, const char *msg) +{ + struct termios cf; + premsg(&cf); + fputs(prefix, stderr); + fputs(": ", stderr); + fputs(msg, stderr); + fputc('\n', stderr); + fflush(stderr); + postmsg(&cf); +} + +void console_print_error_msg_fmt_v( + const char *prefix, const char *fmt, va_list ap) { + char *msg = dupvprintf(fmt, ap); + console_print_error_msg(prefix, msg); + sfree(msg); } -void update_specials_menu(Frontend *frontend) +void console_print_error_msg_fmt(const char *prefix, const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + console_print_error_msg_fmt_v(prefix, fmt, ap); + va_end(ap); } -void notify_remote_exit(Frontend *frontend) +void modalfatalbox(const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + console_print_error_msg_fmt_v("FATAL ERROR", fmt, ap); + va_end(ap); + cleanup_exit(1); +} + +void nonfatal(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + console_print_error_msg_fmt_v("ERROR", fmt, ap); + va_end(ap); +} + +void console_connection_fatal(Seat *seat, const char *msg) +{ + console_print_error_msg("FATAL ERROR", msg); + cleanup_exit(1); } void timer_change_notify(unsigned long next) @@ -111,9 +153,10 @@ static int block_and_read(int fd, void *buf, size_t len) return ret; } -int verify_ssh_host_key(Frontend *frontend, char *host, int port, - const char *keytype, char *keystr, char *fingerprint, - void (*callback)(void *ctx, int result), void *ctx) +int console_verify_ssh_host_key( + Seat *seat, const char *host, int port, + const char *keytype, char *keystr, char *fingerprint, + void (*callback)(void *ctx, int result), void *ctx) { int ret; @@ -217,12 +260,9 @@ int verify_ssh_host_key(Frontend *frontend, char *host, int port, } } -/* - * Ask whether the selected algorithm is acceptable (since it was - * below the configured 'warn' threshold). - */ -int askalg(Frontend *frontend, const char *algtype, const char *algname, - void (*callback)(void *ctx, int result), void *ctx) +int console_confirm_weak_crypto_primitive( + Seat *seat, const char *algtype, const char *algname, + void (*callback)(void *ctx, int result), void *ctx) { static const char msg[] = "The first %s supported by the server is\n" @@ -268,8 +308,9 @@ int askalg(Frontend *frontend, const char *algtype, const char *algname, } } -int askhk(Frontend *frontend, const char *algname, const char *betteralgs, - void (*callback)(void *ctx, int result), void *ctx) +int console_confirm_weak_cached_hostkey( + Seat *seat, const char *algname, const char *betteralgs, + void (*callback)(void *ctx, int result), void *ctx) { static const char msg[] = "The first host key type we have stored for this server\n" diff --git a/unix/uxpgnt.c b/unix/uxpgnt.c index a3f2356e..06efb0bc 100644 --- a/unix/uxpgnt.c +++ b/unix/uxpgnt.c @@ -23,43 +23,12 @@ SockAddr *unix_sock_addr(const char *path); Socket *new_unix_listener(SockAddr *listenaddr, Plug *plug); -void modalfatalbox(const char *p, ...) +void cmdline_error(const char *fmt, ...) { va_list ap; - fprintf(stderr, "FATAL ERROR: "); - va_start(ap, p); - vfprintf(stderr, p, ap); + va_start(ap, fmt); + console_print_error_msg_fmt_v("pageant", fmt, ap); va_end(ap); - fputc('\n', stderr); - exit(1); -} -void nonfatal(const char *p, ...) -{ - va_list ap; - fprintf(stderr, "ERROR: "); - va_start(ap, p); - vfprintf(stderr, p, ap); - va_end(ap); - fputc('\n', stderr); -} -void connection_fatal(Frontend *frontend, const char *p, ...) -{ - va_list ap; - fprintf(stderr, "FATAL ERROR: "); - va_start(ap, p); - vfprintf(stderr, p, ap); - va_end(ap); - fputc('\n', stderr); - exit(1); -} -void cmdline_error(const char *p, ...) -{ - va_list ap; - fprintf(stderr, "pageant: "); - va_start(ap, p); - vfprintf(stderr, p, ap); - va_end(ap); - fputc('\n', stderr); exit(1); } @@ -92,8 +61,6 @@ int platform_default_i(const char *name, int def) { return def; } FontSpec *platform_default_fontspec(const char *name) { return fontspec_new(""); } Filename *platform_default_filename(const char *name) { return filename_from_str(""); } char *x_get_default(const char *key) { return NULL; } -int from_backend(Frontend *fe, int is_stderr, const void *data, int datalen) -{ assert(!"only here to satisfy notional call from backend_socket_log"); } /* * Short description of parameters. @@ -338,7 +305,7 @@ enum { static char *askpass_tty(const char *prompt) { int ret; - prompts_t *p = new_prompts(NULL); + prompts_t *p = new_prompts(); p->to_server = FALSE; p->name = dupstr("Pageant passphrase prompt"); add_prompt(p, dupcat(prompt, ": ", (const char *)NULL), FALSE); diff --git a/unix/uxplink.c b/unix/uxplink.c index c26fd43f..6f3e7bea 100644 --- a/unix/uxplink.c +++ b/unix/uxplink.c @@ -29,63 +29,12 @@ static LogContext *logctx; static struct termios orig_termios; -void modalfatalbox(const char *p, ...) +void cmdline_error(const char *fmt, ...) { - struct termios cf; va_list ap; - premsg(&cf); - fprintf(stderr, "FATAL ERROR: "); - va_start(ap, p); - vfprintf(stderr, p, ap); + va_start(ap, fmt); + console_print_error_msg_fmt_v("plink", fmt, ap); va_end(ap); - fputc('\n', stderr); - postmsg(&cf); - if (logctx) { - log_free(logctx); - logctx = NULL; - } - cleanup_exit(1); -} -void nonfatal(const char *p, ...) -{ - struct termios cf; - va_list ap; - premsg(&cf); - fprintf(stderr, "ERROR: "); - va_start(ap, p); - vfprintf(stderr, p, ap); - va_end(ap); - fputc('\n', stderr); - postmsg(&cf); -} -void connection_fatal(Frontend *frontend, const char *p, ...) -{ - struct termios cf; - va_list ap; - premsg(&cf); - fprintf(stderr, "FATAL ERROR: "); - va_start(ap, p); - vfprintf(stderr, p, ap); - va_end(ap); - fputc('\n', stderr); - postmsg(&cf); - if (logctx) { - log_free(logctx); - logctx = NULL; - } - cleanup_exit(1); -} -void cmdline_error(const char *p, ...) -{ - struct termios cf; - va_list ap; - premsg(&cf); - fprintf(stderr, "plink: "); - va_start(ap, p); - vfprintf(stderr, p, ap); - va_end(ap); - fputc('\n', stderr); - postmsg(&cf); exit(1); } @@ -132,7 +81,7 @@ int term_ldisc(Terminal *term, int mode) { return FALSE; } -void frontend_echoedit_update(Frontend *frontend, int echo, int edit) +static void plink_echoedit_update(Seat *seat, int echo, int edit) { /* Update stdin read mode to reflect changes in line discipline. */ struct termios mode; @@ -158,7 +107,7 @@ void frontend_echoedit_update(Frontend *frontend, int echo, int edit) mode.c_cc[VMIN] = 1; mode.c_cc[VTIME] = 0; /* FIXME: perhaps what we do with IXON/IXOFF should be an - * argument to frontend_echoedit_update(), to allow + * argument to the echoedit_update() method, to allow * implementation of SSH-2 "xon-xoff" and Rlogin's * equivalent? */ mode.c_iflag &= ~IXON; @@ -190,7 +139,7 @@ static char *get_ttychar(struct termios *t, int index) return dupprintf("^<%d>", c); } -char *get_ttymode(Frontend *frontend, const char *mode) +static char *plink_get_ttymode(Seat *seat, const char *mode) { /* * Propagate appropriate terminal modes from the local terminal, @@ -400,8 +349,7 @@ int try_output(int is_stderr) return bufchain_size(&stdout_data) + bufchain_size(&stderr_data); } -int from_backend(Frontend *frontend, int is_stderr, - const void *data, int len) +static int plink_output(Seat *seat, int is_stderr, const void *data, int len) { if (is_stderr) { bufchain_add(&stderr_data, data, len); @@ -413,7 +361,7 @@ int from_backend(Frontend *frontend, int is_stderr, } } -int from_backend_eof(Frontend *frontend) +static int plink_eof(Seat *seat) { assert(outgoingeof == EOF_NO); outgoingeof = EOF_PENDING; @@ -421,7 +369,7 @@ int from_backend_eof(Frontend *frontend) return FALSE; /* do not respond to incoming EOF with outgoing */ } -int get_userpass_input(prompts_t *p, bufchain *input) +static int plink_get_userpass_input(Seat *seat, prompts_t *p, bufchain *input) { int ret; ret = cmdline_get_passwd_input(p); @@ -430,6 +378,26 @@ int get_userpass_input(prompts_t *p, bufchain *input) return ret; } +static const SeatVtable plink_seat_vt = { + plink_output, + plink_eof, + plink_get_userpass_input, + nullseat_notify_remote_exit, + console_connection_fatal, + nullseat_update_specials_menu, + plink_get_ttymode, + nullseat_set_busy_status, + console_verify_ssh_host_key, + console_confirm_weak_crypto_primitive, + console_confirm_weak_cached_hostkey, + nullseat_is_never_utf8, + plink_echoedit_update, + nullseat_get_x_display, + nullseat_get_windowid, + nullseat_get_char_cell_size, +}; +static Seat plink_seat[1] = {{ &plink_seat_vt }}; + /* * Handle data from a local tty in PARMRK format. */ @@ -834,7 +802,7 @@ int main(int argc, char **argv) __AFL_INIT(); #endif - error = backend_init(backvt, NULL, &backend, logctx, conf, + error = backend_init(backvt, plink_seat, &backend, logctx, conf, conf_get_str(conf, CONF_host), conf_get_int(conf, CONF_port), &realhost, nodelay, @@ -843,7 +811,7 @@ int main(int argc, char **argv) fprintf(stderr, "Unable to open connection:\n%s\n", error); return 1; } - ldisc_create(conf, NULL, backend, NULL); + ldisc_create(conf, NULL, backend, plink_seat); sfree(realhost); } @@ -854,7 +822,7 @@ int main(int argc, char **argv) */ local_tty = (tcgetattr(STDIN_FILENO, &orig_termios) == 0); atexit(cleanup_termios); - frontend_echoedit_update(NULL, 1, 1); + seat_echoedit_update(plink_seat, 1, 1); sending = FALSE; now = GETTICKCOUNT(); diff --git a/unix/uxpty.c b/unix/uxpty.c index 31f6b880..c80dde6b 100644 --- a/unix/uxpty.c +++ b/unix/uxpty.c @@ -71,7 +71,7 @@ static int pty_signal_pipe[2] = { -1, -1 }; /* obviously bogus initial val */ struct Pty { Conf *conf; int master_fd, slave_fd; - Frontend *frontend; + Seat *seat; char name[FILENAME_MAX]; pid_t child_pid; int term_width, term_height; @@ -633,7 +633,7 @@ void pty_real_select_result(Pty *pty, int event, int status) perror("read pty master"); exit(1); } else if (ret > 0) { - from_backend(pty->frontend, 0, buf, ret); + seat_stdout(pty->seat, buf, ret); } } else if (event == 2) { /* @@ -675,10 +675,10 @@ void pty_real_select_result(Pty *pty, int event, int status) " %d (%.400s)]\r\n", WTERMSIG(pty->exit_code), strsignal(WTERMSIG(pty->exit_code))); #endif - from_backend(pty->frontend, 0, message, strlen(message)); + seat_stdout(pty->seat, message, strlen(message)); } - notify_remote_exit(pty->frontend); + seat_notify_remote_exit(pty->seat); } } @@ -736,7 +736,7 @@ static void pty_uxsel_setup(Pty *pty) * Also places the canonical host name into `realhost'. It must be * freed by the caller. */ -static const char *pty_init(Frontend *frontend, Backend **backend_handle, +static const char *pty_init(Seat *seat, Backend **backend_handle, LogContext *logctx, Conf *conf, const char *host, int port, char **realhost, int nodelay, int keepalive) @@ -760,7 +760,7 @@ static const char *pty_init(Frontend *frontend, Backend **backend_handle, #endif } - pty->frontend = frontend; + pty->seat = seat; pty->backend.vt = &pty_backend; *backend_handle = &pty->backend; @@ -781,7 +781,7 @@ static const char *pty_init(Frontend *frontend, Backend **backend_handle, close(pty_utmp_helper_pipe); /* just let the child process die */ pty_utmp_helper_pipe = -1; } else { - const char *location = get_x_display(pty->frontend); + const char *location = seat_get_x_display(pty->seat); int len = strlen(location)+1, pos = 0; /* +1 to include NUL */ while (pos < len) { int ret = write(pty_utmp_helper_pipe, location+pos, len - pos); @@ -798,7 +798,7 @@ static const char *pty_init(Frontend *frontend, Backend **backend_handle, #endif #ifndef NOT_X_WINDOWS /* for Mac OS X native compilation */ - got_windowid = get_windowid(pty->frontend, &windowid); + got_windowid = seat_get_windowid(pty->seat, &windowid); #endif /* @@ -888,7 +888,7 @@ static const char *pty_init(Frontend *frontend, Backend **backend_handle, * Set the IUTF8 bit iff the character set is UTF-8. */ #ifdef IUTF8 - if (frontend_is_utf8(frontend)) + if (seat_is_utf8(seat)) attrs.c_iflag |= IUTF8; else attrs.c_iflag &= ~IUTF8; @@ -928,7 +928,7 @@ static const char *pty_init(Frontend *frontend, Backend **backend_handle, * terminal to match the display the terminal itself is * on. */ - const char *x_display = get_x_display(pty->frontend); + const char *x_display = seat_get_x_display(pty->seat); char *x_display_env_var = dupprintf("DISPLAY=%s", x_display); putenv(x_display_env_var); /* As above, we don't free this. */ @@ -1150,16 +1150,17 @@ static void pty_size(Backend *be, int width, int height) { Pty *pty = container_of(be, Pty, backend); struct winsize size; + int xpixel = 0, ypixel = 0; pty->term_width = width; pty->term_height = height; + seat_get_char_cell_size(pty->seat, &xpixel, &ypixel); + size.ws_row = (unsigned short)pty->term_height; size.ws_col = (unsigned short)pty->term_width; - size.ws_xpixel = (unsigned short) pty->term_width * - font_dimension(pty->frontend, 0); - size.ws_ypixel = (unsigned short) pty->term_height * - font_dimension(pty->frontend, 1); + size.ws_xpixel = (unsigned short)pty->term_width * xpixel; + size.ws_ypixel = (unsigned short)pty->term_height * ypixel; ioctl(pty->master_fd, TIOCSWINSZ, (void *)&size); return; } diff --git a/unix/uxser.c b/unix/uxser.c index 6c837625..2f9251b7 100644 --- a/unix/uxser.c +++ b/unix/uxser.c @@ -19,7 +19,7 @@ typedef struct Serial Serial; struct Serial { - Frontend *frontend; + Seat *seat; LogContext *logctx; int fd; int finished; @@ -279,7 +279,7 @@ static const char *serial_configure(Serial *serial, Conf *conf) * Also places the canonical host name into `realhost'. It must be * freed by the caller. */ -static const char *serial_init(Frontend *frontend, Backend **backend_handle, +static const char *serial_init(Seat *seat, Backend **backend_handle, LogContext *logctx, Conf *conf, const char *host, int port, char **realhost, int nodelay, int keepalive) @@ -292,7 +292,7 @@ static const char *serial_init(Frontend *frontend, Backend **backend_handle, serial->backend.vt = &serial_backend; *backend_handle = &serial->backend; - serial->frontend = frontend; + serial->seat = seat; serial->logctx = logctx; serial->finished = FALSE; serial->inbufsize = 0; @@ -322,7 +322,7 @@ static const char *serial_init(Frontend *frontend, Backend **backend_handle, /* * Specials are always available. */ - update_specials_menu(serial->frontend); + seat_update_specials_menu(serial->seat); return NULL; } @@ -390,7 +390,7 @@ static void serial_select_result(int fd, int event) perror("read serial port"); exit(1); } else if (ret > 0) { - serial->inbufsize = from_backend(serial->frontend, 0, buf, ret); + serial->inbufsize = seat_stdout(serial->seat, buf, ret); serial_uxsel_setup(serial); /* might acquire backlog and freeze */ } } else if (event == 2) { @@ -405,7 +405,7 @@ static void serial_select_result(int fd, int event) serial->finished = TRUE; - notify_remote_exit(serial->frontend); + seat_notify_remote_exit(serial->seat); } } diff --git a/unix/uxsftp.c b/unix/uxsftp.c index a0d5c71e..f6ac2bbb 100644 --- a/unix/uxsftp.c +++ b/unix/uxsftp.c @@ -66,9 +66,7 @@ Filename *platform_default_filename(const char *name) return filename_from_str(""); } -char *get_ttymode(Frontend *frontend, const char *mode) { return NULL; } - -int get_userpass_input(prompts_t *p, bufchain *input) +int filexfer_get_userpass_input(Seat *seat, prompts_t *p, bufchain *input) { int ret; ret = cmdline_get_passwd_input(p); diff --git a/windows/wincons.c b/windows/wincons.c index 83146968..9a542571 100644 --- a/windows/wincons.c +++ b/windows/wincons.c @@ -28,21 +28,65 @@ void cleanup_exit(int code) exit(code); } -void set_busy_status(Frontend *frontend, int status) +/* + * Various error message and/or fatal exit functions. + */ +void console_print_error_msg(const char *prefix, const char *msg) +{ + fputs(prefix, stderr); + fputs(": ", stderr); + fputs(msg, stderr); + fputc('\n', stderr); + fflush(stderr); +} + +void console_print_error_msg_fmt_v( + const char *prefix, const char *fmt, va_list ap) +{ + char *msg = dupvprintf(fmt, ap); + console_print_error_msg(prefix, msg); + sfree(msg); +} + +void console_print_error_msg_fmt(const char *prefix, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + console_print_error_msg_fmt_v(prefix, fmt, ap); + va_end(ap); +} + +void modalfatalbox(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + console_print_error_msg_fmt_v("FATAL ERROR", fmt, ap); + va_end(ap); + cleanup_exit(1); +} + +void nonfatal(const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + console_print_error_msg_fmt_v("ERROR", fmt, ap); + va_end(ap); } -void notify_remote_exit(Frontend *frontend) +void console_connection_fatal(Seat *seat, const char *msg) { + console_print_error_msg("FATAL ERROR", msg); + cleanup_exit(1); } void timer_change_notify(unsigned long next) { } -int verify_ssh_host_key(Frontend *frontend, char *host, int port, - const char *keytype, char *keystr, char *fingerprint, - void (*callback)(void *ctx, int result), void *ctx) +int console_verify_ssh_host_key( + Seat *seat, const char *host, int port, + const char *keytype, char *keystr, char *fingerprint, + void (*callback)(void *ctx, int result), void *ctx) { int ret; HANDLE hin; @@ -145,16 +189,9 @@ int verify_ssh_host_key(Frontend *frontend, char *host, int port, } } -void update_specials_menu(Frontend *frontend) -{ -} - -/* - * Ask whether the selected algorithm is acceptable (since it was - * below the configured 'warn' threshold). - */ -int askalg(Frontend *frontend, const char *algtype, const char *algname, - void (*callback)(void *ctx, int result), void *ctx) +int console_confirm_weak_crypto_primitive( + Seat *seat, const char *algtype, const char *algname, + void (*callback)(void *ctx, int result), void *ctx) { HANDLE hin; DWORD savemode, i; @@ -194,8 +231,9 @@ int askalg(Frontend *frontend, const char *algtype, const char *algname, } } -int askhk(Frontend *frontend, const char *algname, const char *betteralgs, - void (*callback)(void *ctx, int result), void *ctx) +int console_confirm_weak_cached_hostkey( + Seat *seat, const char *algname, const char *betteralgs, + void (*callback)(void *ctx, int result), void *ctx) { HANDLE hin; DWORD savemode, i; diff --git a/windows/windlg.c b/windows/windlg.c index d0843754..6dd8bf98 100644 --- a/windows/windlg.c +++ b/windows/windlg.c @@ -798,10 +798,11 @@ static void win_gui_eventlog(LogPolicy *lp, const char *string) static void win_gui_logging_error(LogPolicy *lp, const char *event) { + extern Seat win_seat[1]; /* Send 'can't open log file' errors to the terminal window. * (Marked as stderr, although terminal.c won't care.) */ - from_backend(NULL, 1, event, strlen(event)); - from_backend(NULL, 1, "\r\n", 2); + seat_stderr(win_seat, event, strlen(event)); + seat_stderr(win_seat, "\r\n", 2); } void showeventlog(HWND hwnd) @@ -819,9 +820,10 @@ void showabout(HWND hwnd) DialogBox(hinst, MAKEINTRESOURCE(IDD_ABOUTBOX), hwnd, AboutProc); } -int verify_ssh_host_key(Frontend *frontend, char *host, int port, - const char *keytype, char *keystr, char *fingerprint, - void (*callback)(void *ctx, int result), void *ctx) +int win_seat_verify_ssh_host_key( + Seat *seat, const char *host, int port, + const char *keytype, char *keystr, char *fingerprint, + void (*callback)(void *ctx, int result), void *ctx) { int ret; @@ -903,8 +905,9 @@ int verify_ssh_host_key(Frontend *frontend, char *host, int port, * Ask whether the selected algorithm is acceptable (since it was * below the configured 'warn' threshold). */ -int askalg(Frontend *frontend, const char *algtype, const char *algname, - void (*callback)(void *ctx, int result), void *ctx) +int win_seat_confirm_weak_crypto_primitive( + Seat *seat, const char *algtype, const char *algname, + void (*callback)(void *ctx, int result), void *ctx) { static const char mbtitle[] = "%s Security Alert"; static const char msg[] = @@ -928,8 +931,9 @@ int askalg(Frontend *frontend, const char *algtype, const char *algname, return 0; } -int askhk(Frontend *frontend, const char *algname, const char *betteralgs, - void (*callback)(void *ctx, int result), void *ctx) +int win_seat_confirm_weak_cached_hostkey( + Seat *seat, const char *algname, const char *betteralgs, + void (*callback)(void *ctx, int result), void *ctx) { static const char mbtitle[] = "%s Security Alert"; static const char msg[] = diff --git a/windows/window.c b/windows/window.c index 5133a0ad..d0320433 100644 --- a/windows/window.c +++ b/windows/window.c @@ -213,7 +213,7 @@ static Mouse_Button lastbtn; static int send_raw_mouse = 0; static int wheel_accumulator = 0; -static int busy_status = BUSY_NOT; +static BusyStatus busy_status = BUSY_NOT; static char *window_name, *icon_name; @@ -230,21 +230,57 @@ static UINT wm_mousewheel = WM_MOUSEWHEEL; const int share_can_be_downstream = TRUE; const int share_can_be_upstream = TRUE; -/* Dummy routine, only required in plink. */ -void frontend_echoedit_update(Frontend *frontend, int echo, int edit) +int frontend_is_utf8(Frontend *frontend) { + return ucsdata.line_codepage == CP_UTF8; } -int frontend_is_utf8(Frontend *frontend) +static int win_seat_is_utf8(Seat *seat) { - return ucsdata.line_codepage == CP_UTF8; + return frontend_is_utf8(NULL); } -char *get_ttymode(Frontend *frontend, const char *mode) +char *win_seat_get_ttymode(Seat *seat, const char *mode) { return term_get_ttymode(term, mode); } +int win_seat_get_char_cell_size(Seat *seat, int *x, int *y) +{ + *x = font_width; + *y = font_height; + return TRUE; +} + +static int win_seat_output(Seat *seat, int is_stderr, const void *, int); +static int win_seat_eof(Seat *seat); +static int win_seat_get_userpass_input( + Seat *seat, prompts_t *p, bufchain *input); +static void win_seat_notify_remote_exit(Seat *seat); +static void win_seat_connection_fatal(Seat *seat, const char *msg); +static void win_seat_update_specials_menu(Seat *seat); +static void win_seat_set_busy_status(Seat *seat, BusyStatus status); + +static const SeatVtable win_seat_vt = { + win_seat_output, + win_seat_eof, + win_seat_get_userpass_input, + win_seat_notify_remote_exit, + win_seat_connection_fatal, + win_seat_update_specials_menu, + win_seat_get_ttymode, + win_seat_set_busy_status, + win_seat_verify_ssh_host_key, + win_seat_confirm_weak_crypto_primitive, + win_seat_confirm_weak_cached_hostkey, + win_seat_is_utf8, + nullseat_echoedit_update, + nullseat_get_x_display, + nullseat_get_windowid, + win_seat_get_char_cell_size, +}; +Seat win_seat[1] = {{ &win_seat_vt }}; + static void start_backend(void) { const struct BackendVtable *vt; @@ -266,7 +302,7 @@ static void start_backend(void) cleanup_exit(1); } - error = backend_init(vt, NULL, &backend, logctx, conf, + error = backend_init(vt, win_seat, &backend, logctx, conf, conf_get_str(conf, CONF_host), conf_get_int(conf, CONF_port), &realhost, @@ -298,7 +334,7 @@ static void start_backend(void) /* * Set up a line discipline. */ - ldisc = ldisc_create(conf, term, backend, NULL); + ldisc = ldisc_create(conf, term, backend, win_seat); /* * Destroy the Restart Session menu item. (This will return @@ -332,7 +368,7 @@ static void close_session(void *ignored_context) backend_free(backend); backend = NULL; term_provide_backend(term, NULL); - update_specials_menu(NULL); + seat_update_specials_menu(win_seat); } /* @@ -945,7 +981,7 @@ static void update_savedsess_menu(void) /* * Update the Special Commands submenu. */ -void update_specials_menu(Frontend *frontend) +static void win_seat_update_specials_menu(Seat *seat) { HMENU new_menu; int i, j; @@ -1051,7 +1087,7 @@ static void update_mouse_pointer(void) } } -void set_busy_status(Frontend *frontend, int status) +static void win_seat_set_busy_status(Seat *seat, BusyStatus status) { busy_status = status; update_mouse_pointer(); @@ -1070,17 +1106,12 @@ void set_raw_mouse_mode(Frontend *frontend, int activate) /* * Print a message box and close the connection. */ -void connection_fatal(Frontend *frontend, const char *fmt, ...) +static void win_seat_connection_fatal(Seat *seat, const char *msg) { - va_list ap; - char *stuff, morestuff[100]; + char title[100]; - va_start(ap, fmt); - stuff = dupvprintf(fmt, ap); - va_end(ap); - sprintf(morestuff, "%.70s Fatal Error", appname); - MessageBox(hwnd, stuff, morestuff, MB_ICONERROR | MB_OK); - sfree(stuff); + sprintf(title, "%.70s Fatal Error", appname); + MessageBox(hwnd, msg, title, MB_ICONERROR | MB_OK); if (conf_get_int(conf, CONF_close_on_exit) == FORCE_ON) PostQuitMessage(1); @@ -1969,7 +2000,7 @@ static int is_alt_pressed(void) static int resizing; -void notify_remote_exit(Frontend *frontend) +static void win_seat_notify_remote_exit(Seat *seat) { int exitcode, close_on_exit; @@ -5907,17 +5938,19 @@ static void flip_full_screen() } } -int from_backend(Frontend *frontend, int is_stderr, const void *data, int len) +static int win_seat_output(Seat *seat, int is_stderr, + const void *data, int len) { return term_data(term, is_stderr, data, len); } -int from_backend_eof(Frontend *frontend) +static int win_seat_eof(Seat *seat) { return TRUE; /* do respond to incoming EOF with outgoing */ } -int get_userpass_input(prompts_t *p, bufchain *input) +static int win_seat_get_userpass_input( + Seat *seat, prompts_t *p, bufchain *input) { int ret; ret = cmdline_get_passwd_input(p); diff --git a/windows/winplink.c b/windows/winplink.c index 2d4b74fa..4c173182 100644 --- a/windows/winplink.c +++ b/windows/winplink.c @@ -22,51 +22,12 @@ struct agent_callback { int len; }; -void modalfatalbox(const char *p, ...) +void cmdline_error(const char *fmt, ...) { va_list ap; - fprintf(stderr, "FATAL ERROR: "); - va_start(ap, p); - vfprintf(stderr, p, ap); + va_start(ap, fmt); + console_print_error_msg_fmt_v("plink", fmt, ap); va_end(ap); - fputc('\n', stderr); - if (logctx) { - log_free(logctx); - logctx = NULL; - } - cleanup_exit(1); -} -void nonfatal(const char *p, ...) -{ - va_list ap; - fprintf(stderr, "ERROR: "); - va_start(ap, p); - vfprintf(stderr, p, ap); - va_end(ap); - fputc('\n', stderr); -} -void connection_fatal(Frontend *frontend, const char *p, ...) -{ - va_list ap; - fprintf(stderr, "FATAL ERROR: "); - va_start(ap, p); - vfprintf(stderr, p, ap); - va_end(ap); - fputc('\n', stderr); - if (logctx) { - log_free(logctx); - logctx = NULL; - } - cleanup_exit(1); -} -void cmdline_error(const char *p, ...) -{ - va_list ap; - fprintf(stderr, "plink: "); - va_start(ap, p); - vfprintf(stderr, p, ap); - va_end(ap); - fputc('\n', stderr); exit(1); } @@ -83,7 +44,7 @@ int term_ldisc(Terminal *term, int mode) { return FALSE; } -void frontend_echoedit_update(Frontend *frontend, int echo, int edit) +static void plink_echoedit_update(Seat *seat, int echo, int edit) { /* Update stdin read mode to reflect changes in line discipline. */ DWORD mode; @@ -100,10 +61,7 @@ void frontend_echoedit_update(Frontend *frontend, int echo, int edit) SetConsoleMode(inhandle, mode); } -char *get_ttymode(Frontend *frontend, const char *mode) { return NULL; } - -int from_backend(Frontend *frontend, int is_stderr, - const void *data, int len) +static int plink_output(Seat *seat, int is_stderr, const void *data, int len) { if (is_stderr) { handle_write(stderr_handle, data, len); @@ -114,13 +72,13 @@ int from_backend(Frontend *frontend, int is_stderr, return handle_backlog(stdout_handle) + handle_backlog(stderr_handle); } -int from_backend_eof(Frontend *frontend) +static int plink_eof(Seat *seat) { handle_write_eof(stdout_handle); return FALSE; /* do not respond to incoming EOF with outgoing */ } -int get_userpass_input(prompts_t *p, bufchain *input) +static int plink_get_userpass_input(Seat *seat, prompts_t *p, bufchain *input) { int ret; ret = cmdline_get_passwd_input(p); @@ -129,6 +87,26 @@ int get_userpass_input(prompts_t *p, bufchain *input) return ret; } +static const SeatVtable plink_seat_vt = { + plink_output, + plink_eof, + plink_get_userpass_input, + nullseat_notify_remote_exit, + console_connection_fatal, + nullseat_update_specials_menu, + nullseat_get_ttymode, + nullseat_set_busy_status, + console_verify_ssh_host_key, + console_confirm_weak_crypto_primitive, + console_confirm_weak_cached_hostkey, + nullseat_is_never_utf8, + plink_echoedit_update, + nullseat_get_x_display, + nullseat_get_windowid, + nullseat_get_char_cell_size, +}; +static Seat plink_seat[1] = {{ &plink_seat_vt }}; + static DWORD main_thread_id; void agent_schedule_callback(void (*callback)(void *, void *, int), @@ -476,7 +454,7 @@ int main(int argc, char **argv) int nodelay = conf_get_int(conf, CONF_tcp_nodelay) && (GetFileType(GetStdHandle(STD_INPUT_HANDLE)) == FILE_TYPE_CHAR); - error = backend_init(vt, NULL, &backend, logctx, conf, + error = backend_init(vt, plink_seat, &backend, logctx, conf, conf_get_str(conf, CONF_host), conf_get_int(conf, CONF_port), &realhost, nodelay, diff --git a/windows/winser.c b/windows/winser.c index e1f40369..3fba2989 100644 --- a/windows/winser.c +++ b/windows/winser.c @@ -14,7 +14,7 @@ typedef struct Serial Serial; struct Serial { HANDLE port; struct handle *out, *in; - Frontend *frontend; + Seat *seat; LogContext *logctx; int bufsize; long clearbreak_time; @@ -60,15 +60,15 @@ static int serial_gotdata(struct handle *h, void *data, int len) serial_terminate(serial); - notify_remote_exit(serial->frontend); + seat_notify_remote_exit(serial->seat); logevent(serial->logctx, error_msg); - connection_fatal(serial->frontend, "%s", error_msg); + seat_connection_fatal(serial->seat, "%s", error_msg); return 0; /* placate optimiser */ } else { - return from_backend(serial->frontend, 0, data, len); + return seat_stdout(serial->seat, data, len); } } @@ -80,11 +80,11 @@ static void serial_sentdata(struct handle *h, int new_backlog) serial_terminate(serial); - notify_remote_exit(serial->frontend); + seat_notify_remote_exit(serial->seat); logevent(serial->logctx, error_msg); - connection_fatal(serial->frontend, "%s", error_msg); + seat_connection_fatal(serial->seat, "%s", error_msg); } else { serial->bufsize = new_backlog; } @@ -190,7 +190,7 @@ static const char *serial_configure(Serial *serial, HANDLE serport, Conf *conf) * Also places the canonical host name into `realhost'. It must be * freed by the caller. */ -static const char *serial_init(Frontend *frontend, Backend **backend_handle, +static const char *serial_init(Seat *seat, Backend **backend_handle, LogContext *logctx, Conf *conf, const char *host, int port, char **realhost, int nodelay, int keepalive) @@ -208,7 +208,7 @@ static const char *serial_init(Frontend *frontend, Backend **backend_handle, serial->backend.vt = &serial_backend; *backend_handle = &serial->backend; - serial->frontend = frontend; + serial->seat = seat; serial->logctx = logctx; serline = conf_get_str(conf, CONF_serline); @@ -265,7 +265,7 @@ static const char *serial_init(Frontend *frontend, Backend **backend_handle, /* * Specials are always available. */ - update_specials_menu(serial->frontend); + seat_update_specials_menu(serial->seat); return NULL; } diff --git a/windows/winsftp.c b/windows/winsftp.c index 48235cd9..6a8aba77 100644 --- a/windows/winsftp.c +++ b/windows/winsftp.c @@ -13,9 +13,7 @@ #include "int64.h" #include "winsecur.h" -char *get_ttymode(Frontend *frontend, const char *mode) { return NULL; } - -int get_userpass_input(prompts_t *p, bufchain *input) +int filexfer_get_userpass_input(Seat *seat, prompts_t *p, bufchain *input) { int ret; ret = cmdline_get_passwd_input(p); diff --git a/windows/winstuff.h b/windows/winstuff.h index bb64ac07..3708e2e6 100644 --- a/windows/winstuff.h +++ b/windows/winstuff.h @@ -237,11 +237,25 @@ void quit_help(HWND hwnd); /* * The terminal and logging context are notionally local to the * Windows front end, but they must be shared between window.c and - * windlg.c. Likewise the saved-sessions list. + * windlg.c. Likewise the Seat structure for the Windows GUI. */ GLOBAL Terminal *term; GLOBAL LogContext *logctx; +/* + * GUI seat methods in windlg.c. + */ +int win_seat_verify_ssh_host_key( + Seat *seat, const char *host, int port, + const char *keytype, char *keystr, char *key_fingerprint, + void (*callback)(void *ctx, int result), void *ctx); +int win_seat_confirm_weak_crypto_primitive( + Seat *seat, const char *algtype, const char *algname, + void (*callback)(void *ctx, int result), void *ctx); +int win_seat_confirm_weak_cached_hostkey( + Seat *seat, const char *algname, const char *betteralgs, + void (*callback)(void *ctx, int result), void *ctx); + /* * Windows-specific clipboard helper function shared with windlg.c, * which takes the data string in the system code page instead of From dff3cd562db1a5673a68bec172b566d640cf41f9 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Fri, 12 Oct 2018 23:27:53 +0100 Subject: [PATCH 516/607] Fix assertion failure if server won't start a shell. In the recent refactoring, when I rewrote the loop in the SSH-2 connection layer startup which tries the primary and then the fallback command, I failed to reproduce a subtlety of the previous code, namely that if CONF_remote_cmd2 holds the empty string, we don't even look for CONF_ssh_subsys2. This is because no application other than pscp will have set the latter, and looking it up when it's absent triggers an assertion failure in conf.c. --- ssh2connection.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/ssh2connection.c b/ssh2connection.c index a5c293ff..c0fe4961 100644 --- a/ssh2connection.c +++ b/ssh2connection.c @@ -1288,13 +1288,19 @@ static void ssh2_connection_process_queue(PacketProtocolLayer *ppl) char *cmd; if (s->session_attempt == 0) { - subsys = conf_get_int(s->conf, CONF_ssh_subsys); cmd = conf_get_str(s->conf, CONF_remote_cmd); + subsys = conf_get_int(s->conf, CONF_ssh_subsys); } else { - subsys = conf_get_int(s->conf, CONF_ssh_subsys2); cmd = conf_get_str(s->conf, CONF_remote_cmd2); - if (!*cmd) + if (!*cmd) { + /* If there's no remote_cmd2 configured, then we + * have no fallback command, and we should quit + * this loop before even trying to look up + * CONF_ssh_subsys2, which is one of the few conf + * keys that is not guaranteed to be populated. */ break; + } + subsys = conf_get_int(s->conf, CONF_ssh_subsys2); ppl_logevent(("Primary command failed; attempting fallback")); } From 554e8f3991e2f74cc43d5f65b3e6e3b740b323c8 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Fri, 12 Oct 2018 23:42:44 +0100 Subject: [PATCH 517/607] Restore missing Event Log entries from SSH layers. In commit ad0c502ce I forgot to arrange for ssh_connect_ppl to fill in ppl->logctx, and without it, logevent() was cheerfully throwing away all those log messages. --- ssh.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ssh.c b/ssh.c index 000bee65..2f81d9f6 100644 --- a/ssh.c +++ b/ssh.c @@ -142,6 +142,7 @@ static void ssh_connect_ppl(Ssh *ssh, PacketProtocolLayer *ppl) ppl->user_input = &ssh->user_input; ppl->seat = ssh->seat; ppl->ssh = ssh; + ppl->logctx = ssh->logctx; ppl->remote_bugs = ssh->remote_bugs; } From 1986ee2d9ce1f29bbb9a6d0d41ef07d185213eac Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 13 Oct 2018 17:16:07 +0100 Subject: [PATCH 518/607] Add missing pq_pop when handling SSH_MSG_DISCONNECT. Somehow I managed to leave that line out in both SSH-1 and SSH-2's functions for handling DISCONNECT, IGNORE and DEBUG, and in both cases, only for DISCONNECT. Oops. --- ssh1login.c | 1 + ssh2transport.c | 1 + 2 files changed, 2 insertions(+) diff --git a/ssh1login.c b/ssh1login.c index 08282d5b..8b6f1d7b 100644 --- a/ssh1login.c +++ b/ssh1login.c @@ -132,6 +132,7 @@ int ssh1_common_filter_queue(PacketProtocolLayer *ppl) ssh_remote_error(ppl->ssh, "Server sent disconnect message:\n\"%.*s\"", PTRLEN_PRINTF(msg)); + pq_pop(ppl->in_pq); return TRUE; /* indicate that we've been freed */ case SSH1_MSG_DEBUG: diff --git a/ssh2transport.c b/ssh2transport.c index 343d6787..7f316ec0 100644 --- a/ssh2transport.c +++ b/ssh2transport.c @@ -530,6 +530,7 @@ int ssh2_common_filter_queue(PacketProtocolLayer *ppl) ((reason > 0 && reason < lenof(ssh2_disconnect_reasons)) ? ssh2_disconnect_reasons[reason] : "unknown"), PTRLEN_PRINTF(msg)); + pq_pop(ppl->in_pq); return TRUE; /* indicate that we've been freed */ case SSH2_MSG_DEBUG: From e966df071cba720318a3b87d4be38b41edfba7a6 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 13 Oct 2018 17:23:29 +0100 Subject: [PATCH 519/607] Avoid Event Log entries with newlines in. When logging an SSH_MSG_DISCONNECT, the log message has newlines in, because it's also displayed in the GUI dialog box or on Plink's standard error, where that makes some sense. But in the Event Log, all messages should be one-liners: anything else makes the GUI list boxes go weird, and also breaks convenient parsability of packet lot files. So we turn newlines into spaces for Event Log purposes, which is conveniently easy now that Event Log entries always go through logging.c first. --- logging.c | 40 +++++++++++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/logging.c b/logging.c index eb1aeec2..8f46500d 100644 --- a/logging.c +++ b/logging.c @@ -209,14 +209,8 @@ void logtraffic(LogContext *ctx, unsigned char c, int logmode) } } -/* - * Log an Event Log entry. Used in SSH packet logging mode, to copy - * the Event Log entries into the same log file as the packet data. - */ -void logevent(LogContext *ctx, const char *event) +static void logevent_internal(LogContext *ctx, const char *event) { - if (!ctx) - return; if (ctx->logtype == LGTYP_PACKETS || ctx->logtype == LGTYP_SSHRAW) { logprintf(ctx, "Event Log: %s\r\n", event); logflush(ctx); @@ -224,6 +218,38 @@ void logevent(LogContext *ctx, const char *event) lp_eventlog(ctx->lp, event); } +void logevent(LogContext *ctx, const char *event) +{ + if (!ctx) + return; + + /* + * Replace newlines in Event Log messages with spaces. (Sometimes + * the same message string is reused for the Event Log and a GUI + * dialog box; newlines are sometimes appropriate in the latter, + * but never in the former.) + */ + if (strchr(event, '\n') || strchr(event, '\r')) { + char *dup = dupstr(event); + char *p = dup, *q = dup; + while (*p) { + if (*p == '\r' || *p == '\n') { + do { + p++; + } while (*p == '\r' || *p == '\n'); + *q++ = ' '; + } else { + *q++ = *p++; + } + } + *q = '\0'; + logevent_internal(ctx, dup); + sfree(dup); + } else { + logevent_internal(ctx, event); + } +} + void logevent_and_free(LogContext *ctx, char *event) { logevent(ctx, event); From 35a4283615ab07ab122feabd0444c86f0ab495ca Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Mon, 15 Oct 2018 18:53:25 +0100 Subject: [PATCH 520/607] Loosen the validity check in get_mp_ssh1. The SSH-1 spec says that it's legitimate to write an mp-int in which the prefixed uint16 bit count is greater than the minimum number of bits required to represent the number. I was enforcing that they had to be actually equal, on pain of a BinarySource decoding error. --- sshbn.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sshbn.c b/sshbn.c index 9c36f531..17293762 100644 --- a/sshbn.c +++ b/sshbn.c @@ -1588,7 +1588,9 @@ Bignum BinarySource_get_mp_ssh1(BinarySource *src) return bignum_from_long(0); } else { Bignum toret = bignum_from_bytes(bytes.ptr, bytes.len); - if (bignum_bitcount(toret) != bitc) { + /* SSH-1.5 spec says that it's OK for the prefix uint16 to be + * _greater_ than the actual number of bits */ + if (bignum_bitcount(toret) > bitc) { src->err = BSE_INVALID; freebn(toret); toret = bignum_from_long(0); From b9bfc81531a897e0160f3914152eca6be4307c3e Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Mon, 15 Oct 2018 22:26:20 +0100 Subject: [PATCH 521/607] cmdgen: fix segfault on failing to open the output file. D'oh - simply forgot to check the return value of fopen for NULL. --- cmdgen.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/cmdgen.c b/cmdgen.c index a08e7de9..5216e753 100644 --- a/cmdgen.c +++ b/cmdgen.c @@ -959,10 +959,15 @@ int main(int argc, char **argv) { FILE *fp; - if (outfile) + if (outfile) { fp = f_open(outfilename, "w", FALSE); - else + if (!fp) { + fprintf(stderr, "unable to open output file\n"); + exit(1); + } + } else { fp = stdout; + } if (sshver == 1) { ssh1_write_pubkey(fp, ssh1key); @@ -1003,10 +1008,15 @@ int main(int argc, char **argv) } } - if (outfile) + if (outfile) { fp = f_open(outfilename, "w", FALSE); - else + if (!fp) { + fprintf(stderr, "unable to open output file\n"); + exit(1); + } + } else { fp = stdout; + } fprintf(fp, "%s\n", fingerprint); if (outfile) fclose(fp); From 56096ba558727ab88edfac1d2f3adec0183430c4 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 13 Oct 2018 16:30:59 +0100 Subject: [PATCH 522/607] New utility functions to make ptrlens. One to make one from a NUL-terminated string, and another to make one from a strbuf. I've switched over all the obvious cases where I should have been using these functions. --- cmdgen.c | 2 +- misc.c | 10 ++++++++++ misc.h | 2 ++ ssh2userauth.c | 4 ++-- sshpubk.c | 6 +++--- 5 files changed, 18 insertions(+), 6 deletions(-) diff --git a/cmdgen.c b/cmdgen.c index 5216e753..78ac274e 100644 --- a/cmdgen.c +++ b/cmdgen.c @@ -816,7 +816,7 @@ int main(int argc, char **argv) const ssh_keyalg *alg = find_pubkey_alg(ssh2alg); if (alg) bits = ssh_key_public_bits( - alg, make_ptrlen(ssh2blob->s, ssh2blob->len)); + alg, ptrlen_from_strbuf(ssh2blob)); else bits = -1; } else { diff --git a/misc.c b/misc.c index 18edfb80..f360eebb 100644 --- a/misc.c +++ b/misc.c @@ -1243,6 +1243,16 @@ ptrlen make_ptrlen(const void *ptr, size_t len) return pl; } +ptrlen ptrlen_from_asciz(const char *str) +{ + return make_ptrlen(str, strlen(str)); +} + +ptrlen ptrlen_from_strbuf(strbuf *sb) +{ + return make_ptrlen(sb->u, sb->len); +} + int ptrlen_eq_string(ptrlen pl, const char *str) { size_t len = strlen(str); diff --git a/misc.h b/misc.h index 968c3d5d..fd63b335 100644 --- a/misc.h +++ b/misc.h @@ -97,6 +97,8 @@ struct tm ltime(void); int nullstrcmp(const char *a, const char *b); ptrlen make_ptrlen(const void *ptr, size_t len); +ptrlen ptrlen_from_asciz(const char *str); +ptrlen ptrlen_from_strbuf(strbuf *sb); int ptrlen_eq_string(ptrlen pl, const char *str); char *mkstr(ptrlen pl); int string_length_for_printf(size_t); diff --git a/ssh2userauth.c b/ssh2userauth.c index 10a2d171..1d526d02 100644 --- a/ssh2userauth.c +++ b/ssh2userauth.c @@ -867,8 +867,8 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) BinarySink_UPCAST(sigblob)); strbuf_free(sigdata); ssh2_userauth_add_sigblob( - s, s->pktout, make_ptrlen(pkblob->s, pkblob->len), - make_ptrlen(sigblob->s, sigblob->len)); + s, s->pktout, ptrlen_from_strbuf(pkblob), + ptrlen_from_strbuf(sigblob)); strbuf_free(pkblob); strbuf_free(sigblob); diff --git a/sshpubk.c b/sshpubk.c index 510eb585..309e634d 100644 --- a/sshpubk.c +++ b/sshpubk.c @@ -584,7 +584,7 @@ const ssh_keyalg *find_pubkey_alg_len(ptrlen name) const ssh_keyalg *find_pubkey_alg(const char *name) { - return find_pubkey_alg_len(make_ptrlen(name, strlen(name))); + return find_pubkey_alg_len(ptrlen_from_asciz(name)); } struct ssh2_userkey *ssh2_load_userkey(const Filename *filename, @@ -798,8 +798,8 @@ struct ssh2_userkey *ssh2_load_userkey(const Filename *filename, ret = snew(struct ssh2_userkey); ret->comment = comment; ret->key = ssh_key_new_priv( - alg, make_ptrlen(public_blob->u, public_blob->len), - make_ptrlen(private_blob->u, private_blob->len)); + alg, ptrlen_from_strbuf(public_blob), + ptrlen_from_strbuf(private_blob)); if (!ret->key) { sfree(ret); ret = NULL; From 8d7150b1ac56a33caec3b64c4adad0cf431b2b2c Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 13 Oct 2018 16:30:59 +0100 Subject: [PATCH 523/607] Fix segfault in SSH-1 X forwarding. The SSH-1 SshChannel vtable didn't bother to provide the window_override_removed method, because I wrongly remembered that it was only called when connection sharing. In fact, it's _called_ in any X forwarding, but it only has to _do_ anything when connection sharing: SSH-1 has to provide an empty implementation to avoid segfaulting by calling a null function pointer. --- ssh1connection.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ssh1connection.c b/ssh1connection.c index e493b513..9a5eb363 100644 --- a/ssh1connection.c +++ b/ssh1connection.c @@ -177,6 +177,7 @@ static void ssh1channel_write_eof(SshChannel *c); static void ssh1channel_unclean_close(SshChannel *c, const char *err); static void ssh1channel_unthrottle(SshChannel *c, int bufsize); static Conf *ssh1channel_get_conf(SshChannel *c); +static void ssh1channel_window_override_removed(SshChannel *c) { /* ignore */ } static const struct SshChannelVtable ssh1channel_vtable = { ssh1channel_write, @@ -184,8 +185,7 @@ static const struct SshChannelVtable ssh1channel_vtable = { ssh1channel_unclean_close, ssh1channel_unthrottle, ssh1channel_get_conf, - NULL /* window_override_removed is only used by SSH-2 sharing */, - NULL /* x11_sharing_handover, likewise */, + ssh1channel_window_override_removed, }; static void ssh1_channel_init(struct ssh1_channel *c); From 3229d468b9a1ac26ec5485213b442364fdf8919c Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Wed, 17 Oct 2018 19:28:19 +0100 Subject: [PATCH 524/607] Remove an obsolete declaration. ssh1_bpp_requested_compression was removed in commit 344ec3aec, but its header-file declaration outlived it by mistake. --- sshbpp.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/sshbpp.h b/sshbpp.h index dc1b995d..e1b4622d 100644 --- a/sshbpp.h +++ b/sshbpp.h @@ -56,11 +56,6 @@ BinaryPacketProtocol *ssh1_bpp_new(LogContext *logctx); void ssh1_bpp_new_cipher(BinaryPacketProtocol *bpp, const struct ssh1_cipheralg *cipher, const void *session_key); -/* requested_compression() notifies the SSH-1 BPP that we've just sent - * a request to enable compression, which means that on receiving the - * next SSH1_SMSG_SUCCESS or SSH1_SMSG_FAILURE message, it should set - * up zlib compression if it was SUCCESS. */ -void ssh1_bpp_requested_compression(BinaryPacketProtocol *bpp); /* Helper routine which does common BPP initialisation, e.g. setting * up in_pq and out_pq, and initialising input_consumer. */ From 14f797305a4db049c48bf6189b0db19e9d851f0b Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 13 Oct 2018 17:03:27 +0100 Subject: [PATCH 525/607] A few new minor utility functions. A function to compare two strings _both_ in ptrlen form (I've had ptrlen_eq_string for ages, but for some reason, never quite needed ptrlen_eq_ptrlen). A function to ask whether one ptrlen starts with another (and, optionally, return a ptrlen giving the remaining part of the longer string). And the va_list version of logeventf, which I really ought to have written in the first place by sheer habit, even if it was only needed by logeventf itself. --- logging.c | 9 ++++++--- misc.c | 18 ++++++++++++++++++ misc.h | 2 ++ putty.h | 2 ++ 4 files changed, 28 insertions(+), 3 deletions(-) diff --git a/logging.c b/logging.c index 8f46500d..a04ca633 100644 --- a/logging.c +++ b/logging.c @@ -256,15 +256,18 @@ void logevent_and_free(LogContext *ctx, char *event) sfree(event); } +void logeventvf(LogContext *ctx, const char *fmt, va_list ap) +{ + logevent_and_free(ctx, dupvprintf(fmt, ap)); +} + void logeventf(LogContext *ctx, const char *fmt, ...) { va_list ap; - char *buf; va_start(ap, fmt); - buf = dupvprintf(fmt, ap); + logeventvf(ctx, fmt, ap); va_end(ap); - logevent_and_free(ctx, buf); } /* diff --git a/misc.c b/misc.c index f360eebb..274f8aa8 100644 --- a/misc.c +++ b/misc.c @@ -1259,6 +1259,24 @@ int ptrlen_eq_string(ptrlen pl, const char *str) return (pl.len == len && !memcmp(pl.ptr, str, len)); } +int ptrlen_eq_ptrlen(ptrlen pl1, ptrlen pl2) +{ + return (pl1.len == pl2.len && !memcmp(pl1.ptr, pl2.ptr, pl1.len)); +} + +int ptrlen_startswith(ptrlen whole, ptrlen prefix, ptrlen *tail) +{ + if (whole.len >= prefix.len && + !memcmp(whole.ptr, prefix.ptr, prefix.len)) { + if (tail) { + tail->ptr = (const char *)whole.ptr + prefix.len; + tail->len = whole.len - prefix.len; + } + return TRUE; + } + return FALSE; +} + char *mkstr(ptrlen pl) { char *p = snewn(pl.len + 1, char); diff --git a/misc.h b/misc.h index fd63b335..90322092 100644 --- a/misc.h +++ b/misc.h @@ -100,6 +100,8 @@ ptrlen make_ptrlen(const void *ptr, size_t len); ptrlen ptrlen_from_asciz(const char *str); ptrlen ptrlen_from_strbuf(strbuf *sb); int ptrlen_eq_string(ptrlen pl, const char *str); +int ptrlen_eq_ptrlen(ptrlen pl1, ptrlen pl2); +int ptrlen_startswith(ptrlen whole, ptrlen prefix, ptrlen *tail); char *mkstr(ptrlen pl); int string_length_for_printf(size_t); /* Derive two printf arguments from a ptrlen, suitable for "%.*s" */ diff --git a/putty.h b/putty.h index 492d87e1..46b8be54 100644 --- a/putty.h +++ b/putty.h @@ -1484,6 +1484,8 @@ void logtraffic(LogContext *logctx, unsigned char c, int logmode); void logflush(LogContext *logctx); void logevent(LogContext *logctx, const char *event); void logeventf(LogContext *logctx, const char *fmt, ...); +void logeventvf(LogContext *logctx, const char *fmt, va_list ap); + /* * Pass a dynamically allocated string to logevent and immediately * free it. Intended for use by wrapper macros which pass the return From dfb8d5da527468d7b19fc29aff8dcf465314c461 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 20 Oct 2018 22:46:24 +0100 Subject: [PATCH 526/607] Add some missing 'const' in pfl_listen. --- portfwd.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/portfwd.c b/portfwd.c index 5d8250ca..6165df15 100644 --- a/portfwd.c +++ b/portfwd.c @@ -516,8 +516,9 @@ static const PlugVtable PortListener_plugvt = { * On success, returns NULL and fills in *pl_ret. On error, returns a * dynamically allocated error message string. */ -static char *pfl_listen(char *desthost, int destport, char *srcaddr, - int port, ConnectionLayer *cl, Conf *conf, +static char *pfl_listen(const char *desthost, int destport, + const char *srcaddr, int port, + ConnectionLayer *cl, Conf *conf, struct PortListener **pl_ret, int address_family) { const char *err; From 1b2f39c24bb6591a4192377d9393f5c3e45cb5bd Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Mon, 8 Oct 2018 19:36:25 +0100 Subject: [PATCH 527/607] settings.c: allow load_open_settings(NULL). All the lowest-level helper functions in settings.c that read a single setting from a settings_r are now prepared to tolerate being passed a null settings_r pointer, which will be treated as if reading from it always failed. This means you can call load_open_settings(NULL, conf) to populate a Conf with all of the _built-in_ internal defaults, without ever loading from the saved-session storage at all (not even Default Settings). (Doing this will still call the platform_default_foo function family, if nothing else because Filenames and FontSpecs can't be constructed in any platform-independent way at all.) --- settings.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/settings.c b/settings.c index 6ba04720..e5d40714 100644 --- a/settings.c +++ b/settings.c @@ -107,7 +107,7 @@ char *get_remote_username(Conf *conf) static char *gpps_raw(settings_r *sesskey, const char *name, const char *def) { - char *ret = read_setting_s(sesskey, name); + char *ret = sesskey ? read_setting_s(sesskey, name) : NULL; if (!ret) ret = platform_default_s(name); if (!ret) @@ -131,7 +131,7 @@ static void gpps(settings_r *sesskey, const char *name, const char *def, static void gppfont(settings_r *sesskey, char *name, Conf *conf, int primary) { - FontSpec *result = read_setting_fontspec(sesskey, name); + FontSpec *result = sesskey ? read_setting_fontspec(sesskey, name) : NULL; if (!result) result = platform_default_fontspec(name); conf_set_fontspec(conf, primary, result); @@ -140,7 +140,7 @@ static void gppfont(settings_r *sesskey, char *name, static void gppfile(settings_r *sesskey, const char *name, Conf *conf, int primary) { - Filename *result = read_setting_filename(sesskey, name); + Filename *result = sesskey ? read_setting_filename(sesskey, name) : NULL; if (!result) result = platform_default_filename(name); conf_set_filename(conf, primary, result); @@ -150,7 +150,7 @@ static void gppfile(settings_r *sesskey, const char *name, static int gppi_raw(settings_r *sesskey, const char *name, int def) { def = platform_default_i(name, def); - return read_setting_i(sesskey, name, def); + return sesskey ? read_setting_i(sesskey, name, def) : def; } static void gppi(settings_r *sesskey, const char *name, int def, From 2339efcd83254776e46868bc7d6f5c8bda0e6319 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Wed, 26 Sep 2018 17:34:20 +0100 Subject: [PATCH 528/607] Devolve channel-request handling to Channel vtable. Instead of the central code in ssh2_connection_filter_queue doing both the job of parsing the channel request and deciding whether it's acceptable, each Channel vtable now has a method for every channel request type we recognise. --- agentf.c | 3 + portfwd.c | 3 + ssh2connection.c | 325 ++++++++++++++++++++++++++--------------------- sshchan.h | 19 +++ sshcommon.c | 20 +++ unix/uxpgnt.c | 5 + x11fwd.c | 3 + 7 files changed, 236 insertions(+), 142 deletions(-) diff --git a/agentf.c b/agentf.c index 3b3407fa..fd1e8b72 100644 --- a/agentf.c +++ b/agentf.c @@ -156,6 +156,9 @@ static const struct ChannelVtable agentf_channelvt = { agentf_set_input_wanted, agentf_log_close_msg, chan_no_eager_close, + chan_no_exit_status, + chan_no_exit_signal, + chan_no_exit_signal_numeric, }; Channel *agentf_new(SshChannel *c) diff --git a/portfwd.c b/portfwd.c index 6165df15..f1ced29c 100644 --- a/portfwd.c +++ b/portfwd.c @@ -451,6 +451,9 @@ static const struct ChannelVtable PortForwarding_channelvt = { pfd_set_input_wanted, pfd_log_close_msg, chan_no_eager_close, + chan_no_exit_status, + chan_no_exit_signal, + chan_no_exit_signal_numeric, }; /* diff --git a/ssh2connection.c b/ssh2connection.c index c0fe4961..047e4041 100644 --- a/ssh2connection.c +++ b/ssh2connection.c @@ -444,7 +444,7 @@ static int ssh2_connection_filter_queue(struct ssh2_connection_state *s) struct ssh2_channel *c; struct outstanding_channel_request *ocr; unsigned localid, remid, winsize, pktsize, ext_type; - int want_reply, reply_type, expect_halfopen; + int want_reply, reply_success, expect_halfopen; const char *error; PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */ @@ -466,13 +466,7 @@ static int ssh2_connection_filter_queue(struct ssh2_connection_state *s) /* type = */ get_string(pktin); want_reply = get_bool(pktin); - /* - * 'reply_type' is the message type we'll send in - * response, if want_reply is set. Initialise it to the - * default value of REQUEST_FAILURE, for any request we - * don't recognise and handle below. - */ - reply_type = SSH2_MSG_REQUEST_FAILURE; + reply_success = FALSE; /* * We currently don't support any incoming global requests @@ -481,7 +475,9 @@ static int ssh2_connection_filter_queue(struct ssh2_connection_state *s) */ if (want_reply) { - pktout = ssh_bpp_new_pktout(s->ppl.bpp, reply_type); + int type = (reply_success ? SSH2_MSG_REQUEST_SUCCESS : + SSH2_MSG_REQUEST_FAILURE); + pktout = ssh_bpp_new_pktout(s->ppl.bpp, type); pq_push(s->ppl.out_pq, pktout); } pq_pop(s->ppl.in_pq); @@ -773,13 +769,7 @@ static int ssh2_connection_filter_queue(struct ssh2_connection_state *s) type = get_string(pktin); want_reply = get_bool(pktin); - /* - * 'reply_type' is the message type we'll send in - * response, if want_reply is set. Initialise it to - * the default value of CHANNEL_FAILURE, for any - * request we don't recognise and handle below. - */ - reply_type = SSH2_MSG_CHANNEL_FAILURE; + reply_success = FALSE; if (c->closes & CLOSES_SENT_CLOSE) { /* @@ -793,141 +783,71 @@ static int ssh2_connection_filter_queue(struct ssh2_connection_state *s) } /* - * Having got the channel number, we now look at the - * request type string to see if it's something we - * recognise. + * Try every channel request name we recognise, no + * matter what the channel, and see if the Channel + * instance will accept it. */ - if (c == s->mainchan) { - int exitcode; + if (ptrlen_eq_string(type, "exit-status")) { + int exitcode = toint(get_uint32(pktin)); + reply_success = chan_rcvd_exit_status(c->chan, exitcode); + } else if (ptrlen_eq_string(type, "exit-signal")) { + ptrlen signame; + int signum; + int core = FALSE; + ptrlen errmsg; + int format; /* - * We recognise "exit-status" and "exit-signal" on - * the primary channel. + * ICK: older versions of OpenSSH (e.g. 3.4p1) + * provide an `int' for the signal, despite its + * having been a `string' in the drafts of RFC + * 4254 since at least 2001. (Fixed in session.c + * 1.147.) Try to infer which we can safely parse + * it as. */ - if (ptrlen_eq_string(type, "exit-status")) { - exitcode = toint(get_uint32(pktin)); - ssh_got_exitcode(s->ppl.ssh, exitcode); - ppl_logevent(("Server sent command exit status %d", - exitcode)); - reply_type = SSH2_MSG_CHANNEL_SUCCESS; - } else if (ptrlen_eq_string(type, "exit-signal")) { - char *fmt_sig = NULL, *fmt_msg = NULL; - ptrlen errmsg; - int core = FALSE; - int format; - /* - * ICK: older versions of OpenSSH (e.g. 3.4p1) - * provide an `int' for the signal, despite - * its having been a `string' in the drafts of - * RFC 4254 since at least 2001. (Fixed in - * session.c 1.147.) Try to infer which we can - * safely parse it as. - */ + size_t startpos = BinarySource_UPCAST(pktin)->pos; - size_t startpos = BinarySource_UPCAST(pktin)->pos; - - for (format = 0; format < 2; format++) { - BinarySource_UPCAST(pktin)->pos = startpos; - BinarySource_UPCAST(pktin)->err = BSE_NO_ERROR; - - if (format == 0) { - /* standard string-based format */ - ptrlen signame = get_string(pktin); - fmt_sig = dupprintf(" \"%.*s\"", - PTRLEN_PRINTF(signame)); - - /* - * Really hideous method of translating the - * signal description back into a locally - * meaningful number. - */ - - if (0) - ; -#define TRANSLATE_SIGNAL(s) \ - else if (ptrlen_eq_string(signame, #s)) \ - exitcode = 128 + SIG ## s -#ifdef SIGABRT - TRANSLATE_SIGNAL(ABRT); -#endif -#ifdef SIGALRM - TRANSLATE_SIGNAL(ALRM); -#endif -#ifdef SIGFPE - TRANSLATE_SIGNAL(FPE); -#endif -#ifdef SIGHUP - TRANSLATE_SIGNAL(HUP); -#endif -#ifdef SIGILL - TRANSLATE_SIGNAL(ILL); -#endif -#ifdef SIGINT - TRANSLATE_SIGNAL(INT); -#endif -#ifdef SIGKILL - TRANSLATE_SIGNAL(KILL); -#endif -#ifdef SIGPIPE - TRANSLATE_SIGNAL(PIPE); -#endif -#ifdef SIGQUIT - TRANSLATE_SIGNAL(QUIT); -#endif -#ifdef SIGSEGV - TRANSLATE_SIGNAL(SEGV); -#endif -#ifdef SIGTERM - TRANSLATE_SIGNAL(TERM); -#endif -#ifdef SIGUSR1 - TRANSLATE_SIGNAL(USR1); -#endif -#ifdef SIGUSR2 - TRANSLATE_SIGNAL(USR2); -#endif -#undef TRANSLATE_SIGNAL - else - exitcode = 128; - } else { - /* nonstandard integer format */ - unsigned signum = get_uint32(pktin); - fmt_sig = dupprintf(" %u", signum); - exitcode = 128 + signum; - } - - core = get_bool(pktin); - errmsg = get_string(pktin); /* error message */ - get_string(pktin); /* language tag */ - if (!get_err(pktin) && get_avail(pktin) == 0) - break; /* successful parse */ - - sfree(fmt_sig); - } - - if (format == 2) { - fmt_sig = NULL; - exitcode = 128; - } - - if (errmsg.len) { - fmt_msg = dupprintf(" (\"%.*s\")", - PTRLEN_PRINTF(errmsg)); - } - - ssh_got_exitcode(s->ppl.ssh, exitcode); - ppl_logevent(("Server exited on signal%s%s%s", - fmt_sig ? fmt_sig : "", - core ? " (core dumped)" : "", - fmt_msg ? fmt_msg : "")); - sfree(fmt_sig); - sfree(fmt_msg); - reply_type = SSH2_MSG_CHANNEL_SUCCESS; + for (format = 0; format < 2; format++) { + BinarySource_UPCAST(pktin)->pos = startpos; + BinarySource_UPCAST(pktin)->err = BSE_NO_ERROR; + + /* placate compiler warnings about unin */ + signame = make_ptrlen(NULL, 0); + signum = 0; + + if (format == 0) /* standard string-based format */ + signame = get_string(pktin); + else /* nonstandard integer format */ + signum = toint(get_uint32(pktin)); + + core = get_bool(pktin); + errmsg = get_string(pktin); /* error message */ + get_string(pktin); /* language tag */ + + if (!get_err(pktin) && get_avail(pktin) == 0) + break; /* successful parse */ + } + + switch (format) { + case 0: + reply_success = chan_rcvd_exit_signal( + c->chan, signame, core, errmsg); + break; + case 1: + reply_success = chan_rcvd_exit_signal_numeric( + c->chan, signum, core, errmsg); + break; + default: + /* Couldn't parse this message in either format */ + reply_success = FALSE; + break; } } if (want_reply) { - pktout = ssh_bpp_new_pktout(s->ppl.bpp, reply_type); + int type = (reply_success ? SSH2_MSG_CHANNEL_SUCCESS : + SSH2_MSG_CHANNEL_FAILURE); + pktout = ssh_bpp_new_pktout(s->ppl.bpp, type); put_uint32(pktout, c->remoteid); pq_push(s->ppl.out_pq, pktout); } @@ -2193,6 +2113,11 @@ static int mainchan_send(Channel *chan, int is_stderr, const void *, int); static void mainchan_send_eof(Channel *chan); static void mainchan_set_input_wanted(Channel *chan, int wanted); static char *mainchan_log_close_msg(Channel *chan); +static int mainchan_rcvd_exit_status(Channel *chan, int status); +static int mainchan_rcvd_exit_signal( + Channel *chan, ptrlen signame, int core_dumped, ptrlen msg); +static int mainchan_rcvd_exit_signal_numeric( + Channel *chan, int signum, int core_dumped, ptrlen msg); static const struct ChannelVtable mainchan_channelvt = { mainchan_free, @@ -2203,6 +2128,9 @@ static const struct ChannelVtable mainchan_channelvt = { mainchan_set_input_wanted, mainchan_log_close_msg, chan_no_eager_close, + mainchan_rcvd_exit_status, + mainchan_rcvd_exit_signal, + mainchan_rcvd_exit_signal_numeric, }; static mainchan *mainchan_new(struct ssh2_connection_state *s) @@ -2299,6 +2227,119 @@ static char *mainchan_log_close_msg(Channel *chan) return dupstr("Main session channel closed"); } +static int mainchan_rcvd_exit_status(Channel *chan, int status) +{ + assert(chan->vt == &mainchan_channelvt); + mainchan *mc = container_of(chan, mainchan, chan); + struct ssh2_connection_state *s = mc->connlayer; + PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */ + + ssh_got_exitcode(s->ppl.ssh, status); + ppl_logevent(("Session sent command exit status %d", status)); + return TRUE; +} + +static void ssh2_log_exit_signal_common( + struct ssh2_connection_state *s, const char *sigdesc, + int core_dumped, ptrlen msg) +{ + PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */ + + const char *core_msg = core_dumped ? " (core dumped)" : ""; + const char *msg_pre = (msg.len ? " (" : ""); + const char *msg_post = (msg.len ? ")" : ""); + ppl_logevent(("Session exited on %s%s%s%.*s%s", + sigdesc, core_msg, msg_pre, PTRLEN_PRINTF(msg), msg_post)); +} + +static int mainchan_rcvd_exit_signal( + Channel *chan, ptrlen signame, int core_dumped, ptrlen msg) +{ + assert(chan->vt == &mainchan_channelvt); + mainchan *mc = container_of(chan, mainchan, chan); + struct ssh2_connection_state *s = mc->connlayer; + int exitcode; + char *signame_str; + + /* + * Translate the signal description back into a locally + * meaningful number. + */ + + if (0) + ; +#define TRANSLATE_SIGNAL(s) \ + else if (ptrlen_eq_string(signame, #s)) \ + exitcode = 128 + SIG ## s +#ifdef SIGABRT + TRANSLATE_SIGNAL(ABRT); +#endif +#ifdef SIGALRM + TRANSLATE_SIGNAL(ALRM); +#endif +#ifdef SIGFPE + TRANSLATE_SIGNAL(FPE); +#endif +#ifdef SIGHUP + TRANSLATE_SIGNAL(HUP); +#endif +#ifdef SIGILL + TRANSLATE_SIGNAL(ILL); +#endif +#ifdef SIGINT + TRANSLATE_SIGNAL(INT); +#endif +#ifdef SIGKILL + TRANSLATE_SIGNAL(KILL); +#endif +#ifdef SIGPIPE + TRANSLATE_SIGNAL(PIPE); +#endif +#ifdef SIGQUIT + TRANSLATE_SIGNAL(QUIT); +#endif +#ifdef SIGSEGV + TRANSLATE_SIGNAL(SEGV); +#endif +#ifdef SIGTERM + TRANSLATE_SIGNAL(TERM); +#endif +#ifdef SIGUSR1 + TRANSLATE_SIGNAL(USR1); +#endif +#ifdef SIGUSR2 + TRANSLATE_SIGNAL(USR2); +#endif +#undef TRANSLATE_SIGNAL + else + exitcode = 128; + + ssh_got_exitcode(s->ppl.ssh, exitcode); + if (exitcode == 128) + signame_str = dupprintf("unrecognised signal \"%.*s\"", + PTRLEN_PRINTF(signame)); + else + signame_str = dupprintf("signal SIG%.*s", PTRLEN_PRINTF(signame)); + ssh2_log_exit_signal_common(s, signame_str, core_dumped, msg); + sfree(signame_str); + return TRUE; +} + +static int mainchan_rcvd_exit_signal_numeric( + Channel *chan, int signum, int core_dumped, ptrlen msg) +{ + assert(chan->vt == &mainchan_channelvt); + mainchan *mc = container_of(chan, mainchan, chan); + struct ssh2_connection_state *s = mc->connlayer; + char *signum_str; + + ssh_got_exitcode(s->ppl.ssh, 128 + signum); + signum_str = dupprintf("signal %d", signum); + ssh2_log_exit_signal_common(s, signum_str, core_dumped, msg); + sfree(signum_str); + return TRUE; +} + /* * List of signal names defined by RFC 4254. These include all the ISO * C signals, but are a subset of the POSIX required signals. diff --git a/sshchan.h b/sshchan.h index e2bc28b0..8cf8914a 100644 --- a/sshchan.h +++ b/sshchan.h @@ -26,6 +26,14 @@ struct ChannelVtable { char *(*log_close_msg)(Channel *); int (*want_close)(Channel *, int sent_local_eof, int rcvd_remote_eof); + + /* A method for every channel request we know of. All of these + * return TRUE for success or FALSE for failure. */ + int (*rcvd_exit_status)(Channel *, int status); + int (*rcvd_exit_signal)( + Channel *chan, ptrlen signame, int core_dumped, ptrlen msg); + int (*rcvd_exit_signal_numeric)( + Channel *chan, int signum, int core_dumped, ptrlen msg); }; struct Channel { @@ -42,6 +50,12 @@ struct Channel { ((ch)->vt->set_input_wanted(ch, wanted)) #define chan_log_close_msg(ch) ((ch)->vt->log_close_msg(ch)) #define chan_want_close(ch, leof, reof) ((ch)->vt->want_close(ch, leof, reof)) +#define chan_rcvd_exit_status(ch, status) \ + ((ch)->vt->rcvd_exit_status(ch, status)) +#define chan_rcvd_exit_signal(ch, sig, core, msg) \ + ((ch)->vt->rcvd_exit_signal(ch, sig, core, msg)) +#define chan_rcvd_exit_signal_numeric(ch, sig, core, msg) \ + ((ch)->vt->rcvd_exit_signal_numeric(ch, sig, core, msg)) /* * Reusable methods you can put in vtables to give default handling of @@ -56,6 +70,11 @@ void chan_remotely_opened_failure(Channel *chan, const char *errtext); * closing until both directions have had an EOF */ int chan_no_eager_close(Channel *, int, int); +/* default implementations that refuse all the channel requests */ +int chan_no_exit_status(Channel *, int); +int chan_no_exit_signal(Channel *, ptrlen, int, ptrlen); +int chan_no_exit_signal_numeric(Channel *, int, int, ptrlen); + /* * Constructor for a trivial do-nothing implementation of * ChannelVtable. Used for 'zombie' channels, i.e. channels whose diff --git a/sshcommon.c b/sshcommon.c index 6095930a..8a6f524c 100644 --- a/sshcommon.c +++ b/sshcommon.c @@ -277,6 +277,9 @@ static const struct ChannelVtable zombiechan_channelvt = { zombiechan_set_input_wanted, zombiechan_log_close_msg, zombiechan_want_close, + chan_no_exit_status, + chan_no_exit_signal, + chan_no_exit_signal_numeric, }; Channel *zombiechan_new(void) @@ -340,6 +343,23 @@ int chan_no_eager_close(Channel *chan, int sent_local_eof, int rcvd_remote_eof) return FALSE; /* default: never proactively ask for a close */ } +int chan_no_exit_status(Channel *chan, int status) +{ + return FALSE; +} + +int chan_no_exit_signal( + Channel *chan, ptrlen signame, int core_dumped, ptrlen msg) +{ + return FALSE; +} + +int chan_no_exit_signal_numeric( + Channel *chan, int signum, int core_dumped, ptrlen msg) +{ + return FALSE; +} + /* ---------------------------------------------------------------------- * Common routine to marshal tty modes into an SSH packet. */ diff --git a/unix/uxpgnt.c b/unix/uxpgnt.c index 06efb0bc..09c6892e 100644 --- a/unix/uxpgnt.c +++ b/unix/uxpgnt.c @@ -125,6 +125,11 @@ static int time_to_die = FALSE; void chan_remotely_opened_confirmation(Channel *chan) { } void chan_remotely_opened_failure(Channel *chan, const char *err) { } int chan_no_eager_close(Channel *chan, int s, int r) { return FALSE; } +int chan_no_exit_status(Channel *ch, int s) { return FALSE; } +int chan_no_exit_signal(Channel *ch, ptrlen s, int c, ptrlen m) +{ return FALSE; } +int chan_no_exit_signal_numeric(Channel *ch, int s, int c, ptrlen m) +{ return FALSE; } /* * These functions are part of the plug for our connection to the X diff --git a/x11fwd.c b/x11fwd.c index 0aaa3a60..75105eae 100644 --- a/x11fwd.c +++ b/x11fwd.c @@ -731,6 +731,9 @@ static const struct ChannelVtable X11Connection_channelvt = { x11_set_input_wanted, x11_log_close_msg, chan_no_eager_close, + chan_no_exit_status, + chan_no_exit_signal, + chan_no_exit_signal_numeric, }; /* From d1cd8b2591ccdf7be19c693b4d04865da3609f7c Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Wed, 26 Sep 2018 18:02:33 +0100 Subject: [PATCH 529/607] Move channel-opening logic out into subroutines. Each of the new subroutines corresponds to one of the channel types for which we know how to parse a CHANNEL_OPEN, and has a collection of parameters corresponding to the fields of that message structure. ssh2_connection_filter_queue now confines itself to parsing the message, calling one of those functions, and constructing an appropriate reply message if any. --- agentf.c | 1 + portfwd.c | 1 + ssh1connection.c | 12 + ssh2connection.c | 1095 +++++++++++++++++++++++++--------------------- sshchan.h | 69 +++ sshcommon.c | 6 + unix/uxpgnt.c | 1 + x11fwd.c | 1 + 8 files changed, 696 insertions(+), 490 deletions(-) diff --git a/agentf.c b/agentf.c index fd1e8b72..69ede15e 100644 --- a/agentf.c +++ b/agentf.c @@ -159,6 +159,7 @@ static const struct ChannelVtable agentf_channelvt = { chan_no_exit_status, chan_no_exit_signal, chan_no_exit_signal_numeric, + chan_no_request_response, }; Channel *agentf_new(SshChannel *c) diff --git a/portfwd.c b/portfwd.c index f1ced29c..03c30dc2 100644 --- a/portfwd.c +++ b/portfwd.c @@ -454,6 +454,7 @@ static const struct ChannelVtable PortForwarding_channelvt = { chan_no_exit_status, chan_no_exit_signal, chan_no_exit_signal_numeric, + chan_no_request_response, }; /* diff --git a/ssh1connection.c b/ssh1connection.c index 9a5eb363..0260ec7b 100644 --- a/ssh1connection.c +++ b/ssh1connection.c @@ -186,6 +186,18 @@ static const struct SshChannelVtable ssh1channel_vtable = { ssh1channel_unthrottle, ssh1channel_get_conf, ssh1channel_window_override_removed, + NULL /* x11_sharing_handover is only used by SSH-2 connection sharing */, + NULL /* request_x11_forwarding */, + NULL /* request_agent_forwarding */, + NULL /* request_pty */, + NULL /* send_env_var */, + NULL /* start_shell */, + NULL /* start_command */, + NULL /* start_subsystem */, + NULL /* send_serial_break */, + NULL /* send_signal */, + NULL /* send_terminal_size_change */, + NULL /* hint_channel_is_simple */, }; static void ssh1_channel_init(struct ssh1_channel *c); diff --git a/ssh2connection.c b/ssh2connection.c index 047e4041..624a4291 100644 --- a/ssh2connection.c +++ b/ssh2connection.c @@ -13,10 +13,6 @@ struct ssh2_channel; -typedef enum MainChanType { - MAINCHAN_DIRECT_TCPIP, MAINCHAN_SESSION, MAINCHAN_NONE -} MainChanType; - struct outstanding_global_request; struct ssh2_connection_state { @@ -28,7 +24,6 @@ struct ssh2_connection_state { char *peer_verstring; struct ssh2_channel *mainchan; /* primary session channel */ - MainChanType mctype; char *mainchan_open_error; int mainchan_ready; int echoedit; @@ -38,6 +33,7 @@ struct ssh2_connection_state { int want_user_input; int ssh_is_simple; + int persistent; Conf *conf; @@ -45,8 +41,6 @@ struct ssh2_connection_state { int all_channels_throttled; int X11_fwd_enabled; - struct X11Display *x11disp; - struct X11FakeAuth *x11auth; tree234 *x11authtree; int got_pty; @@ -261,6 +255,30 @@ static void ssh2channel_x11_sharing_handover( SshChannel *c, ssh_sharing_connstate *share_cs, share_channel *share_chan, const char *peer_addr, int peer_port, int endian, int protomajor, int protominor, const void *initial_data, int initial_len); +static void ssh2channel_request_x11_forwarding( + SshChannel *c, int want_reply, const char *authproto, + const char *authdata, int screen_number, int oneshot); +static void ssh2channel_request_agent_forwarding( + SshChannel *c, int want_reply); +static void ssh2channel_request_pty( + SshChannel *c, int want_reply, Conf *conf, int w, int h); +static int ssh2channel_send_env_var( + SshChannel *c, int want_reply, const char *var, const char *value); +static void ssh2channel_start_shell( + SshChannel *c, int want_reply); +static void ssh2channel_start_command( + SshChannel *c, int want_reply, const char *command); +static int ssh2channel_start_subsystem( + SshChannel *c, int want_reply, const char *subsystem); +static int ssh2channel_send_env_var( + SshChannel *c, int want_reply, const char *var, const char *value); +static int ssh2channel_send_serial_break( + SshChannel *c, int want_reply, int length); +static int ssh2channel_send_signal( + SshChannel *c, int want_reply, const char *signame); +static void ssh2channel_send_terminal_size_change( + SshChannel *c, int w, int h); +static void ssh2channel_hint_channel_is_simple(SshChannel *c); static const struct SshChannelVtable ssh2channel_vtable = { ssh2channel_write, @@ -270,6 +288,17 @@ static const struct SshChannelVtable ssh2channel_vtable = { ssh2channel_get_conf, ssh2channel_window_override_removed, ssh2channel_x11_sharing_handover, + ssh2channel_request_x11_forwarding, + ssh2channel_request_agent_forwarding, + ssh2channel_request_pty, + ssh2channel_send_env_var, + ssh2channel_start_shell, + ssh2channel_start_command, + ssh2channel_start_subsystem, + ssh2channel_send_serial_break, + ssh2channel_send_signal, + ssh2channel_send_terminal_size_change, + ssh2channel_hint_channel_is_simple, }; typedef void (*cr_handler_fn_t)(struct ssh2_channel *, PktIn *, void *); @@ -311,18 +340,7 @@ static void ssh2_queue_global_request_handler( s->globreq_tail = ogr; } -typedef struct mainchan { - struct ssh2_connection_state *connlayer; - SshChannel *sc; - - Channel chan; -} mainchan; -static mainchan *mainchan_new(struct ssh2_connection_state *s); -static void ssh2_setup_x11(struct ssh2_channel *c, PktIn *pktin, void *ctx); -static void ssh2_setup_agent(struct ssh2_channel *c, PktIn *pktin, void *ctx); -static void ssh2_setup_pty(struct ssh2_channel *c, PktIn *pktin, void *ctx); -static void ssh2_setup_env(struct ssh2_channel *c, PktIn *pktin, void *ctx); -static void ssh2_response_session(struct ssh2_channel *c, PktIn *, void *); +static void create_mainchan(struct ssh2_connection_state *s, Conf *conf); static int ssh2_channelcmp(void *av, void *bv) { @@ -381,6 +399,14 @@ PacketProtocolLayer *ssh2_connection_new( s->ssh_is_simple = is_simple; + /* + * If the ssh_no_shell option is enabled, we disable the usual + * termination check, so that we persist even in the absence of + * any at all channels (because our purpose is probably to be a + * background port forwarder). + */ + s->persistent = conf_get_int(s->conf, CONF_ssh_no_shell); + s->connshare = connshare; s->peer_verstring = dupstr(peer_verstring); @@ -422,10 +448,11 @@ static void ssh2_connection_free(PacketProtocolLayer *ppl) ssh2_channel_free(c); freetree234(s->channels); - if (s->x11disp) - x11_free_display(s->x11disp); - while ((auth = delpos234(s->x11authtree, 0)) != NULL) + while ((auth = delpos234(s->x11authtree, 0)) != NULL) { + if (auth->disp) + x11_free_display(auth->disp); x11_free_fake_auth(auth); + } freetree234(s->x11authtree); while ((rpf = delpos234(s->rportfwds, 0)) != NULL) @@ -436,16 +463,27 @@ static void ssh2_connection_free(PacketProtocolLayer *ppl) sfree(s); } +static char *chan_open_x11( + struct ssh2_connection_state *s, Channel **ch, SshChannel *sc, + ptrlen peeraddr, int peerport); +static char *chan_open_forwarded_tcpip( + struct ssh2_connection_state *s, Channel **ch, SshChannel *sc, + ssh_sharing_connstate **share_ctx, + ptrlen fwdaddr, int fwdport, ptrlen peeraddr, int peerport); +static char *chan_open_auth_agent( + struct ssh2_connection_state *s, Channel **ch, SshChannel *sc); + static int ssh2_connection_filter_queue(struct ssh2_connection_state *s) { PktIn *pktin; PktOut *pktout; ptrlen type, data; struct ssh2_channel *c; + ssh_sharing_connstate *share_ctx; struct outstanding_channel_request *ocr; unsigned localid, remid, winsize, pktsize, ext_type; int want_reply, reply_success, expect_halfopen; - const char *error; + char *error; PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */ /* Cross-reference to ssh2transport.c to handle the common packets @@ -515,78 +553,42 @@ static int ssh2_connection_filter_queue(struct ssh2_connection_state *s) winsize = get_uint32(pktin); pktsize = get_uint32(pktin); + share_ctx = NULL; + if (ptrlen_eq_string(type, "x11")) { - char *addrstr = mkstr(get_string(pktin)); + ptrlen peeraddr = get_string(pktin); int peerport = get_uint32(pktin); - ppl_logevent(("Received X11 connect request from %s:%d", - addrstr, peerport)); - - if (!s->X11_fwd_enabled && !s->connshare) { - error = "X11 forwarding is not enabled"; - } else { - c->chan = x11_new_channel( - s->x11authtree, &c->sc, addrstr, peerport, - s->connshare != NULL); - ppl_logevent(("Opened X11 forward channel")); - } - - sfree(addrstr); + error = chan_open_x11( + s, &c->chan, &c->sc, peeraddr, peerport); } else if (ptrlen_eq_string(type, "forwarded-tcpip")) { - struct ssh_rportfwd pf, *realpf; - ptrlen peeraddr; - int peerport; - - pf.shost = mkstr(get_string(pktin)); - pf.sport = get_uint32(pktin); - peeraddr = get_string(pktin); - peerport = get_uint32(pktin); - realpf = find234(s->rportfwds, &pf, NULL); - ppl_logevent(("Received remote port %s:%d open request " - "from %.*s:%d", pf.shost, pf.sport, - PTRLEN_PRINTF(peeraddr), peerport)); - sfree(pf.shost); - - if (realpf == NULL) { - error = "Remote port is not recognised"; - } else { - char *err; - - if (realpf->share_ctx) { - /* - * This port forwarding is on behalf of a - * connection-sharing downstream, so abandon our own - * channel-open procedure and just pass the message on - * to sshshare.c. - */ - share_got_pkt_from_server( - realpf->share_ctx, pktin->type, - BinarySource_UPCAST(pktin)->data, - BinarySource_UPCAST(pktin)->len); - sfree(c); - break; - } - - err = portfwdmgr_connect( - s->portfwdmgr, &c->chan, realpf->dhost, realpf->dport, - &c->sc, realpf->addressfamily); - ppl_logevent(("Attempting to forward remote port to " - "%s:%d", realpf->dhost, realpf->dport)); - if (err != NULL) { - ppl_logevent(("Port open failed: %s", err)); - sfree(err); - error = "Port open failed"; - } else { - ppl_logevent(("Forwarded port opened successfully")); - } - } + ptrlen fwdaddr = get_string(pktin); + int fwdport = toint(get_uint32(pktin)); + ptrlen peeraddr = get_string(pktin); + int peerport = toint(get_uint32(pktin)); + + error = chan_open_forwarded_tcpip( + s, &c->chan, &c->sc, &share_ctx, + fwdaddr, fwdport, peeraddr, peerport); } else if (ptrlen_eq_string(type, "auth-agent@openssh.com")) { - if (!s->agent_fwd_enabled) - error = "Agent forwarding is not enabled"; - else - c->chan = agentf_new(&c->sc); + error = chan_open_auth_agent(s, &c->chan, &c->sc); } else { - error = "Unsupported channel type requested"; + error = dupstr("Unsupported channel type requested"); + } + + if (share_ctx) { + /* + * This channel-open request needs to go to a + * connection-sharing downstream, so abandon our own + * channel-open procedure and just pass the message on + * to sshshare.c. + */ + assert(!error); + share_got_pkt_from_server(share_ctx, pktin->type, + BinarySource_UPCAST(pktin)->data, + BinarySource_UPCAST(pktin)->len); + sfree(c); + break; } c->remoteid = remid; @@ -600,6 +602,7 @@ static int ssh2_connection_filter_queue(struct ssh2_connection_state *s) put_stringz(pktout, "en"); /* language tag */ pq_push(s->ppl.out_pq, pktout); ppl_logevent(("Rejected channel open: %s", error)); + sfree(error); sfree(c); } else { ssh2_channel_init(c); @@ -1075,211 +1078,25 @@ static void ssh2_connection_process_queue(PacketProtocolLayer *ppl) struct ssh2_connection_state *s = container_of(ppl, struct ssh2_connection_state, ppl); PktIn *pktin; - PktOut *pktout; if (ssh2_connection_filter_queue(s)) /* no matter why we were called */ return; crBegin(s->crState); - /* - * Create the main session channel, if any. - */ - if (conf_get_int(s->conf, CONF_ssh_no_shell)) { - s->mctype = MAINCHAN_NONE; - } else if (*conf_get_str(s->conf, CONF_ssh_nc_host)) { - s->mctype = MAINCHAN_DIRECT_TCPIP; - } else { - s->mctype = MAINCHAN_SESSION; - } - - if (s->mctype != MAINCHAN_NONE) { - mainchan *mc = mainchan_new(s); - - switch (s->mctype) { - case MAINCHAN_NONE: - assert(0 && "Unreachable"); - break; - - case MAINCHAN_SESSION: - s->mainchan = snew(struct ssh2_channel); - mc->sc = &s->mainchan->sc; - s->mainchan->connlayer = s; - ssh2_channel_init(s->mainchan); - s->mainchan->chan = &mc->chan; - s->mainchan->halfopen = TRUE; - pktout = ssh2_chanopen_init(s->mainchan, "session"); - ppl_logevent(("Opening session as main channel")); - pq_push(s->ppl.out_pq, pktout); - break; - - case MAINCHAN_DIRECT_TCPIP: - mc->sc = ssh_lportfwd_open( - &s->cl, conf_get_str(s->conf, CONF_ssh_nc_host), - conf_get_int(s->conf, CONF_ssh_nc_port), - "main channel", &mc->chan); - s->mainchan = container_of(mc->sc, struct ssh2_channel, sc); - break; - } - - /* - * Wait until that channel has been successfully opened (or - * not). - */ - crMaybeWaitUntilV(!s->mainchan || !s->mainchan->halfopen); - if (!s->mainchan) { - ssh_sw_abort(s->ppl.ssh, "Server refused to open main channel: %s", - s->mainchan_open_error); - return; - } - } - - /* - * Now the connection protocol is properly up and running, with - * all those dispatch table entries, so it's safe to let - * downstreams start trying to open extra channels through us. - */ if (s->connshare) share_activate(s->connshare, s->peer_verstring); - if (s->mainchan && s->ssh_is_simple) { - /* - * This message indicates to the server that we promise - * not to try to run any other channel in parallel with - * this one, so it's safe for it to advertise a very large - * window and leave the flow control to TCP. - */ - pktout = ssh2_chanreq_init( - s->mainchan, "simple@putty.projects.tartarus.org", NULL, NULL); - pq_push(s->ppl.out_pq, pktout); - } - /* * Enable port forwardings. */ portfwdmgr_config(s->portfwdmgr, s->conf); s->portfwdmgr_configured = TRUE; - if (s->mainchan && s->mctype == MAINCHAN_SESSION) { - /* - * Send the CHANNEL_REQUESTS for the main session channel. - * Each one is handled by its own little asynchronous - * co-routine. - */ - - /* Potentially enable X11 forwarding. */ - if (conf_get_int(s->conf, CONF_x11_forward)) { - char *x11_setup_err; - s->x11disp = x11_setup_display( - conf_get_str(s->conf, CONF_x11_display), - s->conf, &x11_setup_err); - if (!s->x11disp) { - ppl_logevent(("X11 forwarding not enabled: unable to" - " initialise X display: %s", x11_setup_err)); - sfree(x11_setup_err); - } else { - s->x11auth = x11_invent_fake_auth( - s->x11authtree, conf_get_int(s->conf, CONF_x11_auth)); - s->x11auth->disp = s->x11disp; - - ssh2_setup_x11(s->mainchan, NULL, NULL); - } - } - - /* Potentially enable agent forwarding. */ - if (ssh_agent_forwarding_permitted(&s->cl)) - ssh2_setup_agent(s->mainchan, NULL, NULL); - - /* Now allocate a pty for the session. */ - if (!conf_get_int(s->conf, CONF_nopty)) - ssh2_setup_pty(s->mainchan, NULL, NULL); - - /* Send environment variables. */ - ssh2_setup_env(s->mainchan, NULL, NULL); - - /* - * Start a shell or a remote command. We may have to attempt - * this twice if the config data has provided a second choice - * of command. - */ - for (s->session_attempt = 0; s->session_attempt < 2; - s->session_attempt++) { - int subsys; - char *cmd; - - if (s->session_attempt == 0) { - cmd = conf_get_str(s->conf, CONF_remote_cmd); - subsys = conf_get_int(s->conf, CONF_ssh_subsys); - } else { - cmd = conf_get_str(s->conf, CONF_remote_cmd2); - if (!*cmd) { - /* If there's no remote_cmd2 configured, then we - * have no fallback command, and we should quit - * this loop before even trying to look up - * CONF_ssh_subsys2, which is one of the few conf - * keys that is not guaranteed to be populated. */ - break; - } - subsys = conf_get_int(s->conf, CONF_ssh_subsys2); - ppl_logevent(("Primary command failed; attempting fallback")); - } - - if (subsys) { - pktout = ssh2_chanreq_init(s->mainchan, "subsystem", - ssh2_response_session, s); - put_stringz(pktout, cmd); - } else if (*cmd) { - pktout = ssh2_chanreq_init(s->mainchan, "exec", - ssh2_response_session, s); - put_stringz(pktout, cmd); - } else { - pktout = ssh2_chanreq_init(s->mainchan, "shell", - ssh2_response_session, s); - } - pq_push(s->ppl.out_pq, pktout); - s->session_status = 0; - - /* Wait for success or failure message to be passed to - * ssh2_response_session, which will set session_status to - * +1 for success or -1 for failure */ - crMaybeWaitUntilV(s->session_status != 0); - - if (s->session_status > 0) { - if (s->session_attempt == 1) - ssh_got_fallback_cmd(s->ppl.ssh); - ppl_logevent(("Started a shell/command")); - break; - } - } - - if (s->session_status < 0) { - /* - * We failed to start either the primary or the fallback - * command. - */ - ssh_sw_abort(s->ppl.ssh, - "Server refused to start a shell/command"); - return; - } - } else { - s->echoedit = TRUE; - } - - s->mainchan_ready = TRUE; - if (s->mainchan) { - s->want_user_input = TRUE; - ssh_ppl_got_user_input(&s->ppl); /* in case any is already queued */ - } - - /* If an EOF or a window-size change arrived before we were ready - * to handle either one, handle them now. */ - if (s->mainchan_eof_pending) - ssh_ppl_special_cmd(&s->ppl, SS_EOF, 0); - if (s->term_width_orig != s->term_width || - s->term_height_orig != s->term_height) - ssh_terminal_size(&s->cl, s->term_width, s->term_height); - - ssh_ldisc_update(s->ppl.ssh); + /* + * Create the main session channel, if any. + */ + create_mainchan(s, s->conf); /* * Transfer data! @@ -1494,14 +1311,8 @@ static void ssh2_check_termination(struct ssh2_connection_state *s) * policy is that we terminate when none of either is left. */ - if (s->mctype == MAINCHAN_NONE) { - /* - * Exception: in ssh_no_shell mode we persist even in the - * absence of any channels (because our purpose is probably to - * be a background port forwarder). - */ - return; - } + if (s->persistent) + return; /* persistent mode: never proactively terminate */ if (count234(s->channels) == 0 && !(s->connshare && share_ndownstreams(s->connshare) > 0)) { @@ -1519,200 +1330,6 @@ static void ssh2_check_termination(struct ssh2_connection_state *s) } } -static void ssh2_setup_x11(struct ssh2_channel *c, PktIn *pktin, void *ctx) -{ - struct ssh2_setup_x11_state { - int crLine; - }; - struct ssh2_connection_state *cs = c->connlayer; - PacketProtocolLayer *ppl = &cs->ppl; /* for ppl_logevent */ - PktOut *pktout; - crStateP(ssh2_setup_x11_state, ctx); - - crBeginState; - - ppl_logevent(("Requesting X11 forwarding")); - pktout = ssh2_chanreq_init(cs->mainchan, "x11-req", ssh2_setup_x11, s); - put_bool(pktout, 0); /* many connections */ - put_stringz(pktout, cs->x11auth->protoname); - put_stringz(pktout, cs->x11auth->datastring); - put_uint32(pktout, cs->x11disp->screennum); - pq_push(cs->ppl.out_pq, pktout); - - /* Wait to be called back with either a response packet, or NULL - * meaning clean up and free our data */ - crReturnV; - - if (pktin) { - if (pktin->type == SSH2_MSG_CHANNEL_SUCCESS) { - ppl_logevent(("X11 forwarding enabled")); - cs->X11_fwd_enabled = TRUE; - } else - ppl_logevent(("X11 forwarding refused")); - } - - crFinishFreeV; -} - -static void ssh2_setup_agent(struct ssh2_channel *c, PktIn *pktin, void *ctx) -{ - struct ssh2_setup_agent_state { - int crLine; - }; - struct ssh2_connection_state *cs = c->connlayer; - PacketProtocolLayer *ppl = &cs->ppl; /* for ppl_logevent */ - PktOut *pktout; - crStateP(ssh2_setup_agent_state, ctx); - - crBeginState; - - ppl_logevent(("Requesting OpenSSH-style agent forwarding")); - pktout = ssh2_chanreq_init(cs->mainchan, "auth-agent-req@openssh.com", - ssh2_setup_agent, s); - pq_push(cs->ppl.out_pq, pktout); - - /* Wait to be called back with either a response packet, or NULL - * meaning clean up and free our data */ - crReturnV; - - if (pktin) { - if (pktin->type == SSH2_MSG_CHANNEL_SUCCESS) { - ppl_logevent(("Agent forwarding enabled")); - cs->agent_fwd_enabled = TRUE; - } else - ppl_logevent(("Agent forwarding refused")); - } - - crFinishFreeV; -} - -static void ssh2_setup_pty(struct ssh2_channel *c, PktIn *pktin, void *ctx) -{ - struct ssh2_setup_pty_state { - int crLine; - int ospeed, ispeed; - }; - struct ssh2_connection_state *cs = c->connlayer; - PacketProtocolLayer *ppl = &cs->ppl; /* for ppl_logevent, ppl_printf */ - PktOut *pktout; - crStateP(ssh2_setup_pty_state, ctx); - - crBeginState; - - /* Unpick the terminal-speed string. */ - s->ospeed = 38400; s->ispeed = 38400; /* last-resort defaults */ - sscanf(conf_get_str(cs->conf, CONF_termspeed), "%d,%d", - &s->ospeed, &s->ispeed); - /* Build the pty request. */ - pktout = ssh2_chanreq_init(cs->mainchan, "pty-req", ssh2_setup_pty, s); - put_stringz(pktout, conf_get_str(cs->conf, CONF_termtype)); - put_uint32(pktout, cs->term_width); - put_uint32(pktout, cs->term_height); - cs->term_width_orig = cs->term_width; - cs->term_height_orig = cs->term_height; - put_uint32(pktout, 0); /* pixel width */ - put_uint32(pktout, 0); /* pixel height */ - { - strbuf *modebuf = strbuf_new(); - write_ttymodes_to_packet_from_conf( - BinarySink_UPCAST(modebuf), cs->ppl.seat, cs->conf, - 2, s->ospeed, s->ispeed); - put_stringsb(pktout, modebuf); - } - pq_push(cs->ppl.out_pq, pktout); - - /* Wait to be called back with either a response packet, or NULL - * meaning clean up and free our data */ - crReturnV; - - if (pktin) { - if (pktin->type == SSH2_MSG_CHANNEL_SUCCESS) { - ppl_logevent(("Allocated pty (ospeed %dbps, ispeed %dbps)", - s->ospeed, s->ispeed)); - cs->got_pty = TRUE; - } else { - ppl_printf(("Server refused to allocate pty\r\n")); - cs->echoedit = TRUE; - } - } - - crFinishFreeV; -} - -static void ssh2_setup_env(struct ssh2_channel *c, PktIn *pktin, void *ctx) -{ - struct ssh2_setup_env_state { - int crLine; - int num_env, env_left, env_ok; - }; - struct ssh2_connection_state *cs = c->connlayer; - PacketProtocolLayer *ppl = &cs->ppl; /* for ppl_logevent, ppl_printf */ - PktOut *pktout; - crStateP(ssh2_setup_env_state, ctx); - - crBeginState; - - /* - * Send environment variables. - * - * Simplest thing here is to send all the requests at once, and - * then wait for a whole bunch of successes or failures. - */ - s->num_env = 0; - { - char *key, *val; - - for (val = conf_get_str_strs(cs->conf, CONF_environmt, NULL, &key); - val != NULL; - val = conf_get_str_strs(cs->conf, CONF_environmt, key, &key)) { - pktout = ssh2_chanreq_init(cs->mainchan, "env", ssh2_setup_env, s); - put_stringz(pktout, key); - put_stringz(pktout, val); - pq_push(cs->ppl.out_pq, pktout); - - s->num_env++; - } - if (s->num_env) - ppl_logevent(("Sent %d environment variables", s->num_env)); - } - - if (s->num_env) { - s->env_ok = 0; - s->env_left = s->num_env; - - while (s->env_left > 0) { - /* Wait to be called back with either a response packet, - * or NULL meaning clean up and free our data */ - crReturnV; - if (!pktin) goto out; - if (pktin->type == SSH2_MSG_CHANNEL_SUCCESS) - s->env_ok++; - s->env_left--; - } - - if (s->env_ok == s->num_env) { - ppl_logevent(("All environment variables successfully set")); - } else if (s->env_ok == 0) { - ppl_logevent(("All environment variables refused")); - ppl_printf(("Server refused to set environment variables\r\n")); - } else { - ppl_logevent(("%d environment variables refused", - s->num_env - s->env_ok)); - ppl_printf(("Server refused to set all environment " - "variables\r\n")); - } - } - out:; - crFinishFreeV; -} - -static void ssh2_response_session(struct ssh2_channel *c, PktIn *pktin, - void *ctx) -{ - struct ssh2_connection_state *s = c->connlayer; - s->session_status = (pktin->type == SSH2_MSG_CHANNEL_SUCCESS ? +1 : -1); -} - /* * Set up most of a new ssh2_channel. Nulls out sharectx, but leaves * chan untouched (since it will sometimes have been filled in before @@ -1884,6 +1501,170 @@ static void ssh2channel_window_override_removed(SshChannel *sc) ssh2_set_window(c, s->ssh_is_simple ? OUR_V2_BIGWIN : OUR_V2_WINSIZE); } +static void ssh2_channel_response( + struct ssh2_channel *c, PktIn *pkt, void *ctx) +{ + chan_request_response(c->chan, pkt->type == SSH2_MSG_CHANNEL_SUCCESS); +} + +static void ssh2channel_start_shell( + SshChannel *sc, int want_reply) +{ + struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc); + struct ssh2_connection_state *s = c->connlayer; + + PktOut *pktout = ssh2_chanreq_init( + c, "shell", want_reply ? ssh2_channel_response : NULL, NULL); + pq_push(s->ppl.out_pq, pktout); +} + +static void ssh2channel_start_command( + SshChannel *sc, int want_reply, const char *command) +{ + struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc); + struct ssh2_connection_state *s = c->connlayer; + + PktOut *pktout = ssh2_chanreq_init( + c, "exec", want_reply ? ssh2_channel_response : NULL, NULL); + put_stringz(pktout, command); + pq_push(s->ppl.out_pq, pktout); +} + +static int ssh2channel_start_subsystem( + SshChannel *sc, int want_reply, const char *subsystem) +{ + struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc); + struct ssh2_connection_state *s = c->connlayer; + + PktOut *pktout = ssh2_chanreq_init( + c, "subsystem", want_reply ? ssh2_channel_response : NULL, NULL); + put_stringz(pktout, subsystem); + pq_push(s->ppl.out_pq, pktout); + + return TRUE; +} + +static void ssh2channel_request_x11_forwarding( + SshChannel *sc, int want_reply, const char *authproto, + const char *authdata, int screen_number, int oneshot) +{ + struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc); + struct ssh2_connection_state *s = c->connlayer; + + PktOut *pktout = ssh2_chanreq_init( + c, "x11-req", want_reply ? ssh2_channel_response : NULL, NULL); + put_bool(pktout, oneshot); + put_stringz(pktout, authproto); + put_stringz(pktout, authdata); + put_uint32(pktout, screen_number); + pq_push(s->ppl.out_pq, pktout); +} + +static void ssh2channel_request_agent_forwarding( + SshChannel *sc, int want_reply) +{ + struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc); + struct ssh2_connection_state *s = c->connlayer; + + PktOut *pktout = ssh2_chanreq_init( + c, "auth-agent-req@openssh.com", + want_reply ? ssh2_channel_response : NULL, NULL); + pq_push(s->ppl.out_pq, pktout); +} + +static void ssh2channel_request_pty( + SshChannel *sc, int want_reply, Conf *conf, int w, int h) +{ + struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc); + struct ssh2_connection_state *s = c->connlayer; + int ospeed, ispeed; + strbuf *modebuf; + + ospeed = ispeed = 38400; /* last-resort defaults */ + sscanf(conf_get_str(conf, CONF_termspeed), "%d,%d", + &ospeed, &ispeed); + + PktOut *pktout = ssh2_chanreq_init( + c, "pty-req", want_reply ? ssh2_channel_response : NULL, NULL); + put_stringz(pktout, conf_get_str(conf, CONF_termtype)); + put_uint32(pktout, w); + put_uint32(pktout, h); + put_uint32(pktout, 0); /* pixel width */ + put_uint32(pktout, 0); /* pixel height */ + modebuf = strbuf_new(); + write_ttymodes_to_packet_from_conf( + BinarySink_UPCAST(modebuf), s->ppl.seat, conf, + 2, ospeed, ispeed); + put_stringsb(pktout, modebuf); + pq_push(s->ppl.out_pq, pktout); +} + +static int ssh2channel_send_env_var( + SshChannel *sc, int want_reply, const char *var, const char *value) +{ + struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc); + struct ssh2_connection_state *s = c->connlayer; + + PktOut *pktout = ssh2_chanreq_init( + c, "env", want_reply ? ssh2_channel_response : NULL, NULL); + put_stringz(pktout, var); + put_stringz(pktout, value); + pq_push(s->ppl.out_pq, pktout); + + return TRUE; +} + +static int ssh2channel_send_serial_break( + SshChannel *sc, int want_reply, int length) +{ + struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc); + struct ssh2_connection_state *s = c->connlayer; + + PktOut *pktout = ssh2_chanreq_init( + c, "break", want_reply ? ssh2_channel_response : NULL, NULL); + put_uint32(pktout, length); + pq_push(s->ppl.out_pq, pktout); + + return TRUE; +} + +static int ssh2channel_send_signal( + SshChannel *sc, int want_reply, const char *signame) +{ + struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc); + struct ssh2_connection_state *s = c->connlayer; + + PktOut *pktout = ssh2_chanreq_init( + c, "signal", want_reply ? ssh2_channel_response : NULL, NULL); + put_stringz(pktout, signame); + pq_push(s->ppl.out_pq, pktout); + + return TRUE; +} + +static void ssh2channel_send_terminal_size_change(SshChannel *sc, int w, int h) +{ + struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc); + struct ssh2_connection_state *s = c->connlayer; + + PktOut *pktout = ssh2_chanreq_init(c, "window-change", NULL, NULL); + put_uint32(pktout, w); + put_uint32(pktout, h); + put_uint32(pktout, 0); /* pixel width */ + put_uint32(pktout, 0); /* pixel height */ + pq_push(s->ppl.out_pq, pktout); +} + +static void ssh2channel_hint_channel_is_simple(SshChannel *sc) +{ + struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc); + struct ssh2_connection_state *s = c->connlayer; + + PktOut *pktout = ssh2_chanreq_init( + c, "simple@putty.projects.tartarus.org", NULL, NULL); + pq_push(s->ppl.out_pq, pktout); +} + static SshChannel *ssh2_lportfwd_open( ConnectionLayer *cl, const char *hostname, int port, const char *org, Channel *chan) @@ -2118,6 +1899,7 @@ static int mainchan_rcvd_exit_signal( Channel *chan, ptrlen signame, int core_dumped, ptrlen msg); static int mainchan_rcvd_exit_signal_numeric( Channel *chan, int signum, int core_dumped, ptrlen msg); +static void mainchan_request_response(Channel *chan, int success); static const struct ChannelVtable mainchan_channelvt = { mainchan_free, @@ -2131,16 +1913,60 @@ static const struct ChannelVtable mainchan_channelvt = { mainchan_rcvd_exit_status, mainchan_rcvd_exit_signal, mainchan_rcvd_exit_signal_numeric, + mainchan_request_response, }; -static mainchan *mainchan_new(struct ssh2_connection_state *s) +typedef enum MainChanType { + MAINCHAN_SESSION, MAINCHAN_DIRECT_TCPIP +} MainChanType; + +typedef struct mainchan { + struct ssh2_connection_state *connlayer; + SshChannel *sc; + MainChanType type; + Conf *conf; + int req_x11, req_agent, req_pty, req_cmd_primary, req_cmd_fallback; + int n_req_env, n_env_replies, n_env_fails; + + Channel chan; +} mainchan; + +static void create_mainchan(struct ssh2_connection_state *s, Conf *conf) { - mainchan *mc = snew(mainchan); + PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */ + mainchan *mc; + PktOut *pktout; + + if (conf_get_int(s->conf, CONF_ssh_no_shell)) + return; /* do nothing */ + + mc = snew(mainchan); + memset(mc, 0, sizeof(mainchan)); mc->connlayer = s; mc->sc = NULL; mc->chan.vt = &mainchan_channelvt; mc->chan.initial_fixed_window_size = 0; - return mc; + mc->conf = conf_copy(conf); + + if (*conf_get_str(mc->conf, CONF_ssh_nc_host)) { + mc->sc = ssh_lportfwd_open( + &s->cl, conf_get_str(mc->conf, CONF_ssh_nc_host), + conf_get_int(mc->conf, CONF_ssh_nc_port), + "main channel", &mc->chan); + s->mainchan = container_of(mc->sc, struct ssh2_channel, sc); + mc->type = MAINCHAN_DIRECT_TCPIP; + } else { + s->mainchan = snew(struct ssh2_channel); + mc->sc = &s->mainchan->sc; + s->mainchan->connlayer = s; + ssh2_channel_init(s->mainchan); + s->mainchan->chan = &mc->chan; + s->mainchan->halfopen = TRUE; + pktout = ssh2_chanopen_init(s->mainchan, "session"); + ppl_logevent(("Opening session as main channel")); + pq_push(s->ppl.out_pq, pktout); + mc->type = MAINCHAN_SESSION; + } } static void mainchan_free(Channel *chan) @@ -2149,9 +1975,13 @@ static void mainchan_free(Channel *chan) mainchan *mc = container_of(chan, mainchan, chan); struct ssh2_connection_state *s = mc->connlayer; s->mainchan = NULL; + conf_free(mc->conf); sfree(mc); } +static void mainchan_try_fallback_command(mainchan *mc); +static void mainchan_ready(mainchan *mc); + static void mainchan_open_confirmation(Channel *chan) { mainchan *mc = container_of(chan, mainchan, chan); @@ -2160,6 +1990,218 @@ static void mainchan_open_confirmation(Channel *chan) seat_update_specials_menu(s->ppl.seat); ppl_logevent(("Opened main channel")); + + if (s->ssh_is_simple) + sshfwd_hint_channel_is_simple(mc->sc); + + if (mc->type == MAINCHAN_SESSION) { + /* + * Send the CHANNEL_REQUESTS for the main session channel. + */ + char *key, *val, *cmd; + struct X11Display *x11disp; + struct X11FakeAuth *x11auth; + int retry_cmd_now = FALSE; + + if (conf_get_int(mc->conf, CONF_x11_forward)) {; + char *x11_setup_err; + if ((x11disp = x11_setup_display( + conf_get_str(mc->conf, CONF_x11_display), + mc->conf, &x11_setup_err)) == NULL) { + ppl_logevent(("X11 forwarding not enabled: unable to" + " initialise X display: %s", x11_setup_err)); + sfree(x11_setup_err); + } else { + x11auth = x11_invent_fake_auth( + s->x11authtree, conf_get_int(mc->conf, CONF_x11_auth)); + x11auth->disp = x11disp; + + sshfwd_request_x11_forwarding( + mc->sc, TRUE, x11auth->protoname, x11auth->datastring, + x11disp->screennum, FALSE); + mc->req_x11 = TRUE; + } + } + + if (ssh_agent_forwarding_permitted(&s->cl)) { + sshfwd_request_agent_forwarding(mc->sc, TRUE); + mc->req_agent = TRUE; + } + + if (!conf_get_int(mc->conf, CONF_nopty)) { + sshfwd_request_pty( + mc->sc, TRUE, mc->conf, s->term_width, s->term_height); + /* Record the initial width/height we requested, so we + * know whether we need to send a change later once + * everything is set up (if the window is resized in + * between) */ + s->term_width_orig = s->term_width; + s->term_height_orig = s->term_height; + mc->req_pty = TRUE; + } + + for (val = conf_get_str_strs(mc->conf, CONF_environmt, NULL, &key); + val != NULL; + val = conf_get_str_strs(mc->conf, CONF_environmt, key, &key)) { + sshfwd_send_env_var(mc->sc, TRUE, key, val); + mc->n_req_env++; + } + if (mc->n_req_env) + ppl_logevent(("Sent %d environment variables", mc->n_req_env)); + + cmd = conf_get_str(s->conf, CONF_remote_cmd); + if (conf_get_int(s->conf, CONF_ssh_subsys)) { + retry_cmd_now = !sshfwd_start_subsystem(mc->sc, TRUE, cmd); + } else if (*cmd) { + sshfwd_start_command(mc->sc, TRUE, cmd); + } else { + sshfwd_start_shell(mc->sc, TRUE); + } + + if (retry_cmd_now) + mainchan_try_fallback_command(mc); + else + mc->req_cmd_primary = TRUE; + + } else { + s->echoedit = TRUE; + mainchan_ready(mc); + } +} + +static void mainchan_try_fallback_command(mainchan *mc) +{ + const char *cmd = conf_get_str(mc->conf, CONF_remote_cmd2); + if (conf_get_int(mc->conf, CONF_ssh_subsys2)) { + sshfwd_start_subsystem(mc->sc, TRUE, cmd); + } else { + sshfwd_start_command(mc->sc, TRUE, cmd); + } + mc->req_cmd_fallback = TRUE; +} + +static void mainchan_request_response(Channel *chan, int success) +{ + assert(chan->vt == &mainchan_channelvt); + mainchan *mc = container_of(chan, mainchan, chan); + struct ssh2_connection_state *s = mc->connlayer; + PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */ + + if (mc->req_x11) { + mc->req_x11 = FALSE; + + if (success) { + ppl_logevent(("X11 forwarding enabled")); + s->X11_fwd_enabled = TRUE; + } else { + ppl_logevent(("X11 forwarding refused")); + } + return; + } + + if (mc->req_agent) { + mc->req_agent = FALSE; + + if (success) { + ppl_logevent(("Agent forwarding enabled")); + } else { + ppl_logevent(("Agent forwarding refused")); + } + return; + } + + if (mc->req_pty) { + mc->req_pty = FALSE; + + if (success) { + ppl_logevent(("Allocated pty")); + s->agent_fwd_enabled = TRUE; + } else { + ppl_logevent(("Server refused to allocate pty")); + ppl_printf(("Server refused to allocate pty\r\n")); + s->echoedit = TRUE; + } + return; + } + + if (mc->n_env_replies < mc->n_req_env) { + int j = mc->n_env_replies++; + if (!success) { + ppl_logevent(("Server refused to set environment variable %s", + conf_get_str_nthstrkey(mc->conf, + CONF_environmt, j))); + mc->n_env_fails++; + } + + if (mc->n_env_replies == mc->n_req_env) { + if (mc->n_env_fails == 0) { + ppl_logevent(("All environment variables successfully set")); + } else if (mc->n_env_fails == mc->n_req_env) { + ppl_logevent(("All environment variables refused")); + ppl_printf(("Server refused to set environment " + "variables\r\n")); + } else { + ppl_printf(("Server refused to set all environment " + "variables\r\n")); + } + } + return; + } + + if (mc->req_cmd_primary) { + mc->req_cmd_primary = FALSE; + + if (success) { + ppl_logevent(("Started a shell/command")); + mainchan_ready(mc); + queue_idempotent_callback(&s->ppl.ic_process_queue); + } else if (*conf_get_str(mc->conf, CONF_remote_cmd2)) { + ppl_logevent(("Primary command failed; attempting fallback")); + mainchan_try_fallback_command(mc); + } else { + /* + * If there's no remote_cmd2 configured, then we have no + * fallback command, so we've run out of options. + */ + ssh_sw_abort(s->ppl.ssh, + "Server refused to start a shell/command"); + } + return; + } + + if (mc->req_cmd_fallback) { + mc->req_cmd_fallback = FALSE; + + if (success) { + ppl_logevent(("Started a shell/command")); + ssh_got_fallback_cmd(s->ppl.ssh); + mainchan_ready(mc); + queue_idempotent_callback(&s->ppl.ic_process_queue); + } else { + ssh_sw_abort(s->ppl.ssh, + "Server refused to start a shell/command"); + } + return; + } +} + +static void mainchan_ready(mainchan *mc) +{ + struct ssh2_connection_state *s = mc->connlayer; + + s->mainchan_ready = TRUE; + s->want_user_input = TRUE; + ssh_ppl_got_user_input(&s->ppl); /* in case any is already queued */ + + /* If an EOF or a window-size change arrived before we were ready + * to handle either one, handle them now. */ + if (s->mainchan_eof_pending) + ssh_ppl_special_cmd(&s->ppl, SS_EOF, 0); + if (s->term_width_orig != s->term_width || + s->term_height_orig != s->term_height) + ssh_terminal_size(&s->cl, s->term_width, s->term_height); + + ssh_ldisc_update(s->ppl.ssh); } static void mainchan_open_failure(Channel *chan, const char *errtext) @@ -2168,12 +2210,8 @@ static void mainchan_open_failure(Channel *chan, const char *errtext) mainchan *mc = container_of(chan, mainchan, chan); struct ssh2_connection_state *s = mc->connlayer; - /* - * Record the failure reason we're given, and let the main - * coroutine handle closing the SSH session. - */ - s->mainchan_open_error = dupstr(errtext); - queue_idempotent_callback(&s->ppl.ic_process_queue); + ssh_sw_abort( + s->ppl.ssh, "Server refused to open main channel: %s", errtext); } static int mainchan_send(Channel *chan, int is_stderr, @@ -2340,6 +2378,83 @@ static int mainchan_rcvd_exit_signal_numeric( return TRUE; } +static char *chan_open_x11( + struct ssh2_connection_state *s, Channel **ch, SshChannel *sc, + ptrlen peeraddr, int peerport) +{ + PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */ + char *peeraddr_str; + + ppl_logevent(("Received X11 connect request from %.*s:%d", + PTRLEN_PRINTF(peeraddr), peerport)); + + if (!s->X11_fwd_enabled && !s->connshare) + return dupstr("X11 forwarding is not enabled"); + + peeraddr_str = peeraddr.ptr ? mkstr(peeraddr) : NULL; + *ch = x11_new_channel( + s->x11authtree, sc, peeraddr_str, peerport, s->connshare != NULL); + sfree(peeraddr_str); + ppl_logevent(("Opened X11 forward channel")); + + return NULL; +} + +static char *chan_open_forwarded_tcpip( + struct ssh2_connection_state *s, Channel **ch, SshChannel *sc, + ssh_sharing_connstate **share_ctx, + ptrlen fwdaddr, int fwdport, ptrlen peeraddr, int peerport) +{ + PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */ + struct ssh_rportfwd pf, *realpf; + char *err; + + ppl_logevent(("Received remote port %.*s:%d open request from %.*s:%d", + PTRLEN_PRINTF(fwdaddr), fwdport, + PTRLEN_PRINTF(peeraddr), peerport)); + + pf.shost = mkstr(fwdaddr); + pf.sport = fwdport; + realpf = find234(s->rportfwds, &pf, NULL); + sfree(pf.shost); + + if (realpf == NULL) + return dupstr("Remote port is not recognised"); + + if (realpf->share_ctx) { + /* + * This port forwarding is on behalf of a connection-sharing + * downstream. + */ + *share_ctx = realpf->share_ctx; + return NULL; + } + + err = portfwdmgr_connect( + s->portfwdmgr, ch, realpf->dhost, realpf->dport, + sc, realpf->addressfamily); + ppl_logevent(("Attempting to forward remote port to %s:%d", + realpf->dhost, realpf->dport)); + if (err != NULL) { + ppl_logevent(("Port open failed: %s", err)); + sfree(err); + return dupstr("Port open failed"); + } + + ppl_logevent(("Forwarded port opened successfully")); + return NULL; +} + +static char *chan_open_auth_agent( + struct ssh2_connection_state *s, Channel **ch, SshChannel *sc) +{ + if (!s->agent_fwd_enabled) + return dupstr("Agent forwarding is not enabled"); + + *ch = agentf_new(sc); + return NULL; +} + /* * List of signal names defined by RFC 4254. These include all the ISO * C signals, but are a subset of the POSIX required signals. diff --git a/sshchan.h b/sshchan.h index 8cf8914a..aab37f35 100644 --- a/sshchan.h +++ b/sshchan.h @@ -34,6 +34,11 @@ struct ChannelVtable { Channel *chan, ptrlen signame, int core_dumped, ptrlen msg); int (*rcvd_exit_signal_numeric)( Channel *chan, int signum, int core_dumped, ptrlen msg); + + /* A method for signalling success/failure responses to channel + * requests initiated from the SshChannel vtable with want_reply + * true. */ + void (*request_response)(Channel *, int success); }; struct Channel { @@ -56,6 +61,8 @@ struct Channel { ((ch)->vt->rcvd_exit_signal(ch, sig, core, msg)) #define chan_rcvd_exit_signal_numeric(ch, sig, core, msg) \ ((ch)->vt->rcvd_exit_signal_numeric(ch, sig, core, msg)) +#define chan_request_response(ch, success) \ + ((ch)->vt->request_response(ch, success)) /* * Reusable methods you can put in vtables to give default handling of @@ -75,6 +82,9 @@ int chan_no_exit_status(Channel *, int); int chan_no_exit_signal(Channel *, ptrlen, int, ptrlen); int chan_no_exit_signal_numeric(Channel *, int, int, ptrlen); +/* default implementation that never expects to receive a response */ +void chan_no_request_response(Channel *, int); + /* * Constructor for a trivial do-nothing implementation of * ChannelVtable. Used for 'zombie' channels, i.e. channels whose @@ -106,6 +116,43 @@ struct SshChannelVtable { const char *peer_addr, int peer_port, int endian, int protomajor, int protominor, const void *initial_data, int initial_len); + + /* + * All the outgoing channel requests we support. Each one has a + * want_reply flag, which will cause a callback to + * chan_request_response when the result is available. + * + * The ones that return 'int' use it to indicate that the SSH + * protocol in use doesn't support this request at all. + * + * (It's also intentional that not all of them have a want_reply + * flag: the ones that don't are because SSH-1 has no method for + * signalling success or failure of that request, or because we + * wouldn't do anything usefully different with the reply in any + * case.) + */ + void (*request_x11_forwarding)( + SshChannel *c, int want_reply, const char *authproto, + const char *authdata, int screen_number, int oneshot); + void (*request_agent_forwarding)( + SshChannel *c, int want_reply); + void (*request_pty)( + SshChannel *c, int want_reply, Conf *conf, int w, int h); + int (*send_env_var)( + SshChannel *c, int want_reply, const char *var, const char *value); + void (*start_shell)( + SshChannel *c, int want_reply); + void (*start_command)( + SshChannel *c, int want_reply, const char *command); + int (*start_subsystem)( + SshChannel *c, int want_reply, const char *subsystem); + int (*send_serial_break)( + SshChannel *c, int want_reply, int length); /* length=0 for default */ + int (*send_signal)( + SshChannel *c, int want_reply, const char *signame); + void (*send_terminal_size_change)( + SshChannel *c, int w, int h); + void (*hint_channel_is_simple)(SshChannel *c); }; struct SshChannel { @@ -120,5 +167,27 @@ struct SshChannel { #define sshfwd_window_override_removed(c) ((c)->vt->window_override_removed(c)) #define sshfwd_x11_sharing_handover(c, cs, ch, pa, pp, e, pmaj, pmin, d, l) \ ((c)->vt->x11_sharing_handover(c, cs, ch, pa, pp, e, pmaj, pmin, d, l)) +#define sshfwd_request_x11_forwarding(c, wr, ap, ad, scr, oneshot) \ + ((c)->vt->request_x11_forwarding(c, wr, ap, ad, scr, oneshot)) +#define sshfwd_request_agent_forwarding(c, wr) \ + ((c)->vt->request_agent_forwarding(c, wr)) +#define sshfwd_request_pty(c, wr, conf, w, h) \ + ((c)->vt->request_pty(c, wr, conf, w, h)) +#define sshfwd_send_env_var(c, wr, var, value) \ + ((c)->vt->send_env_var(c, wr, var, value)) +#define sshfwd_start_shell(c, wr) \ + ((c)->vt->start_shell(c, wr)) +#define sshfwd_start_command(c, wr, cmd) \ + ((c)->vt->start_command(c, wr, cmd)) +#define sshfwd_start_subsystem(c, wr, subsys) \ + ((c)->vt->start_subsystem(c, wr, subsys)) +#define sshfwd_send_serial_break(c, wr, length) \ + ((c)->vt->send_serial_break(c, wr, length)) +#define sshfwd_send_signal(c, wr, sig) \ + ((c)->vt->send_signal(c, wr, sig)) +#define sshfwd_send_terminal_size_change(c, w, h) \ + ((c)->vt->send_terminal_size_change(c, w, h)) +#define sshfwd_hint_channel_is_simple(c) \ + ((c)->vt->hint_channel_is_simple(c)) #endif /* PUTTY_SSHCHAN_H */ diff --git a/sshcommon.c b/sshcommon.c index 8a6f524c..bd718dee 100644 --- a/sshcommon.c +++ b/sshcommon.c @@ -280,6 +280,7 @@ static const struct ChannelVtable zombiechan_channelvt = { chan_no_exit_status, chan_no_exit_signal, chan_no_exit_signal_numeric, + chan_no_request_response, }; Channel *zombiechan_new(void) @@ -360,6 +361,11 @@ int chan_no_exit_signal_numeric( return FALSE; } +void chan_no_request_response(Channel *chan, int success) +{ + assert(0 && "this channel type should never send a want-reply request"); +} + /* ---------------------------------------------------------------------- * Common routine to marshal tty modes into an SSH packet. */ diff --git a/unix/uxpgnt.c b/unix/uxpgnt.c index 09c6892e..55e7981a 100644 --- a/unix/uxpgnt.c +++ b/unix/uxpgnt.c @@ -130,6 +130,7 @@ int chan_no_exit_signal(Channel *ch, ptrlen s, int c, ptrlen m) { return FALSE; } int chan_no_exit_signal_numeric(Channel *ch, int s, int c, ptrlen m) { return FALSE; } +void chan_no_request_response(Channel *chan, int success) {} /* * These functions are part of the plug for our connection to the X diff --git a/x11fwd.c b/x11fwd.c index 75105eae..708f8d0e 100644 --- a/x11fwd.c +++ b/x11fwd.c @@ -734,6 +734,7 @@ static const struct ChannelVtable X11Connection_channelvt = { chan_no_exit_status, chan_no_exit_signal, chan_no_exit_signal_numeric, + chan_no_request_response, }; /* From 8db76dc3d7718875b79f2fb76eb6846935797e36 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 14 Oct 2018 17:17:48 +0100 Subject: [PATCH 530/607] Give SshChannel a pointer to its owning ConnectionLayer. In my future plans, some SshChannels are going to need to be able to ask favours from the connection layer as a whole. And an SshChannel is inextricably tied to an instance of the connection layer, so there's no real reason _not_ to make the pointer generally available. --- ssh1connection.c | 1 + ssh2connection.c | 1 + sshchan.h | 1 + 3 files changed, 3 insertions(+) diff --git a/ssh1connection.c b/ssh1connection.c index 0260ec7b..51e2a262 100644 --- a/ssh1connection.c +++ b/ssh1connection.c @@ -950,6 +950,7 @@ static void ssh1_channel_init(struct ssh1_channel *c) c->pending_eof = FALSE; c->throttling_conn = FALSE; c->sc.vt = &ssh1channel_vtable; + c->sc.cl = &s->cl; c->localid = alloc_channel_id(s->channels, struct ssh1_channel); add234(s->channels, c); } diff --git a/ssh2connection.c b/ssh2connection.c index 624a4291..790f4dd3 100644 --- a/ssh2connection.c +++ b/ssh2connection.c @@ -1348,6 +1348,7 @@ static void ssh2_channel_init(struct ssh2_channel *c) c->throttle_state = UNTHROTTLED; bufchain_init(&c->outbuffer); c->sc.vt = &ssh2channel_vtable; + c->sc.cl = &s->cl; c->localid = alloc_channel_id(s->channels, struct ssh2_channel); add234(s->channels, c); } diff --git a/sshchan.h b/sshchan.h index aab37f35..e29e00d0 100644 --- a/sshchan.h +++ b/sshchan.h @@ -157,6 +157,7 @@ struct SshChannelVtable { struct SshChannel { const struct SshChannelVtable *vt; + ConnectionLayer *cl; }; #define sshfwd_write(c, buf, len) ((c)->vt->write(c, buf, len)) From 431f92ade98cfd334e495e24ddc312b4dadd6383 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 30 Sep 2018 07:16:38 +0100 Subject: [PATCH 531/607] Move mainchan into its own file, like agentf. This gets another big pile of logic out of ssh2connection and puts it somewhere more central. Now the only thing left in ssh2connection is the formatting and parsing of the various channel requests; the logic deciding which ones to issue and what to do about them is devolved to the Channel implementation, as it properly should be. --- Recipe | 2 +- defs.h | 1 + mainchan.c | 609 ++++++++++++++++++++++++++++++++++++++++ putty.h | 8 +- ssh.h | 34 +++ ssh1connection.c | 6 + ssh2connection.c | 708 +++++++---------------------------------------- sshchan.h | 15 + sshppl.h | 2 - 9 files changed, 778 insertions(+), 607 deletions(-) create mode 100644 mainchan.c diff --git a/Recipe b/Recipe index 581d030c..4aff0ab8 100644 --- a/Recipe +++ b/Recipe @@ -256,7 +256,7 @@ SSH = ssh sshcommon ssh1bpp ssh2bpp ssh2bpp-bare ssh1censor ssh2censor + sshdh sshcrcda sshpubk sshzlib sshdss x11fwd portfwd + sshaes sshccp sshsh256 sshsh512 sshbn wildcard pinger ssharcf + sshgssc pgssapi sshshare sshecc aqsync marshal nullplug agentf - + sshmac + + sshmac mainchan WINSSH = SSH winnoise wincapi winpgntc wingss winshare winnps winnpc + winhsock errsock UXSSH = SSH uxnoise uxagentc uxgss uxshare diff --git a/defs.h b/defs.h index ec31c246..84df209a 100644 --- a/defs.h +++ b/defs.h @@ -62,6 +62,7 @@ typedef struct Ssh Ssh; typedef struct Channel Channel; typedef struct SshChannel SshChannel; +typedef struct mainchan mainchan; typedef struct ssh_sharing_state ssh_sharing_state; typedef struct ssh_sharing_connstate ssh_sharing_connstate; diff --git a/mainchan.c b/mainchan.c new file mode 100644 index 00000000..e1b75eb6 --- /dev/null +++ b/mainchan.c @@ -0,0 +1,609 @@ +/* + * SSH main session channel handling. + */ + +#include +#include +#include + +#include "putty.h" +#include "ssh.h" +#include "sshppl.h" +#include "sshchan.h" + +static void mainchan_free(Channel *chan); +static void mainchan_open_confirmation(Channel *chan); +static void mainchan_open_failure(Channel *chan, const char *errtext); +static int mainchan_send(Channel *chan, int is_stderr, const void *, int); +static void mainchan_send_eof(Channel *chan); +static void mainchan_set_input_wanted(Channel *chan, int wanted); +static char *mainchan_log_close_msg(Channel *chan); +static int mainchan_rcvd_exit_status(Channel *chan, int status); +static int mainchan_rcvd_exit_signal( + Channel *chan, ptrlen signame, int core_dumped, ptrlen msg); +static int mainchan_rcvd_exit_signal_numeric( + Channel *chan, int signum, int core_dumped, ptrlen msg); +static void mainchan_request_response(Channel *chan, int success); + +static const struct ChannelVtable mainchan_channelvt = { + mainchan_free, + mainchan_open_confirmation, + mainchan_open_failure, + mainchan_send, + mainchan_send_eof, + mainchan_set_input_wanted, + mainchan_log_close_msg, + chan_no_eager_close, + mainchan_rcvd_exit_status, + mainchan_rcvd_exit_signal, + mainchan_rcvd_exit_signal_numeric, + mainchan_request_response, +}; + +typedef enum MainChanType { + MAINCHAN_SESSION, MAINCHAN_DIRECT_TCPIP +} MainChanType; + +typedef struct mainchan { + SshChannel *sc; + Conf *conf; + PacketProtocolLayer *ppl; + ConnectionLayer *cl; + + MainChanType type; + int is_simple; + + int req_x11, req_agent, req_pty, req_cmd_primary, req_cmd_fallback; + int n_req_env, n_env_replies, n_env_fails; + int eof_pending, eof_sent, got_pty, ready; + + int term_width, term_height; + + Channel chan; +} mainchan; + +mainchan *mainchan_new( + PacketProtocolLayer *ppl, ConnectionLayer *cl, Conf *conf, + int term_width, int term_height, int is_simple, SshChannel **sc_out) +{ + mainchan *mc; + + if (conf_get_int(conf, CONF_ssh_no_shell)) + return NULL; /* no main channel at all */ + + mc = snew(mainchan); + memset(mc, 0, sizeof(mainchan)); + mc->ppl = ppl; + mc->cl = cl; + mc->conf = conf_copy(conf); + mc->term_width = term_width; + mc->term_height = term_height; + mc->is_simple = is_simple; + + mc->sc = NULL; + mc->chan.vt = &mainchan_channelvt; + mc->chan.initial_fixed_window_size = 0; + + if (*conf_get_str(mc->conf, CONF_ssh_nc_host)) { + const char *host = conf_get_str(mc->conf, CONF_ssh_nc_host); + int port = conf_get_int(mc->conf, CONF_ssh_nc_port); + + mc->sc = ssh_lportfwd_open(cl, host, port, "main channel", &mc->chan); + mc->type = MAINCHAN_DIRECT_TCPIP; + } else { + mc->sc = ssh_session_open(cl, &mc->chan); + mc->type = MAINCHAN_SESSION; + } + + *sc_out = mc->sc; + return mc; +} + +static void mainchan_free(Channel *chan) +{ + assert(chan->vt == &mainchan_channelvt); + mainchan *mc = container_of(chan, mainchan, chan); + conf_free(mc->conf); + sfree(mc); +} + +static void mainchan_try_fallback_command(mainchan *mc); +static void mainchan_ready(mainchan *mc); + +static void mainchan_open_confirmation(Channel *chan) +{ + mainchan *mc = container_of(chan, mainchan, chan); + PacketProtocolLayer *ppl = mc->ppl; /* for ppl_logevent */ + + seat_update_specials_menu(mc->ppl->seat); + ppl_logevent(("Opened main channel")); + + if (mc->is_simple) + sshfwd_hint_channel_is_simple(mc->sc); + + if (mc->type == MAINCHAN_SESSION) { + /* + * Send the CHANNEL_REQUESTS for the main session channel. + */ + char *key, *val, *cmd; + struct X11Display *x11disp; + struct X11FakeAuth *x11auth; + int retry_cmd_now = FALSE; + + if (conf_get_int(mc->conf, CONF_x11_forward)) {; + char *x11_setup_err; + if ((x11disp = x11_setup_display( + conf_get_str(mc->conf, CONF_x11_display), + mc->conf, &x11_setup_err)) == NULL) { + ppl_logevent(("X11 forwarding not enabled: unable to" + " initialise X display: %s", x11_setup_err)); + sfree(x11_setup_err); + } else { + x11auth = ssh_add_x11_display( + mc->cl, conf_get_int(mc->conf, CONF_x11_auth), x11disp); + + sshfwd_request_x11_forwarding( + mc->sc, TRUE, x11auth->protoname, x11auth->datastring, + x11disp->screennum, FALSE); + mc->req_x11 = TRUE; + } + } + + if (ssh_agent_forwarding_permitted(mc->cl)) { + sshfwd_request_agent_forwarding(mc->sc, TRUE); + mc->req_agent = TRUE; + } + + if (!conf_get_int(mc->conf, CONF_nopty)) { + sshfwd_request_pty( + mc->sc, TRUE, mc->conf, mc->term_width, mc->term_height); + mc->req_pty = TRUE; + } + + for (val = conf_get_str_strs(mc->conf, CONF_environmt, NULL, &key); + val != NULL; + val = conf_get_str_strs(mc->conf, CONF_environmt, key, &key)) { + sshfwd_send_env_var(mc->sc, TRUE, key, val); + mc->n_req_env++; + } + if (mc->n_req_env) + ppl_logevent(("Sent %d environment variables", mc->n_req_env)); + + cmd = conf_get_str(mc->conf, CONF_remote_cmd); + if (conf_get_int(mc->conf, CONF_ssh_subsys)) { + retry_cmd_now = !sshfwd_start_subsystem(mc->sc, TRUE, cmd); + } else if (*cmd) { + sshfwd_start_command(mc->sc, TRUE, cmd); + } else { + sshfwd_start_shell(mc->sc, TRUE); + } + + if (retry_cmd_now) + mainchan_try_fallback_command(mc); + else + mc->req_cmd_primary = TRUE; + + } else { + ssh_set_ldisc_option(mc->cl, LD_ECHO, TRUE); + ssh_set_ldisc_option(mc->cl, LD_EDIT, TRUE); + mainchan_ready(mc); + } +} + +static void mainchan_try_fallback_command(mainchan *mc) +{ + const char *cmd = conf_get_str(mc->conf, CONF_remote_cmd2); + if (conf_get_int(mc->conf, CONF_ssh_subsys2)) { + sshfwd_start_subsystem(mc->sc, TRUE, cmd); + } else { + sshfwd_start_command(mc->sc, TRUE, cmd); + } + mc->req_cmd_fallback = TRUE; +} + +static void mainchan_request_response(Channel *chan, int success) +{ + assert(chan->vt == &mainchan_channelvt); + mainchan *mc = container_of(chan, mainchan, chan); + PacketProtocolLayer *ppl = mc->ppl; /* for ppl_logevent */ + + if (mc->req_x11) { + mc->req_x11 = FALSE; + + if (success) { + ppl_logevent(("X11 forwarding enabled")); + ssh_enable_x_fwd(mc->cl); + } else { + ppl_logevent(("X11 forwarding refused")); + } + return; + } + + if (mc->req_agent) { + mc->req_agent = FALSE; + + if (success) { + ppl_logevent(("Agent forwarding enabled")); + ssh_enable_agent_fwd(mc->cl); + } else { + ppl_logevent(("Agent forwarding refused")); + } + return; + } + + if (mc->req_pty) { + mc->req_pty = FALSE; + + if (success) { + ppl_logevent(("Allocated pty")); + mc->got_pty = TRUE; + } else { + ppl_logevent(("Server refused to allocate pty")); + ppl_printf(("Server refused to allocate pty\r\n")); + ssh_set_ldisc_option(mc->cl, LD_ECHO, TRUE); + ssh_set_ldisc_option(mc->cl, LD_EDIT, TRUE); + } + return; + } + + if (mc->n_env_replies < mc->n_req_env) { + int j = mc->n_env_replies++; + if (!success) { + ppl_logevent(("Server refused to set environment variable %s", + conf_get_str_nthstrkey(mc->conf, + CONF_environmt, j))); + mc->n_env_fails++; + } + + if (mc->n_env_replies == mc->n_req_env) { + if (mc->n_env_fails == 0) { + ppl_logevent(("All environment variables successfully set")); + } else if (mc->n_env_fails == mc->n_req_env) { + ppl_logevent(("All environment variables refused")); + ppl_printf(("Server refused to set environment " + "variables\r\n")); + } else { + ppl_printf(("Server refused to set all environment " + "variables\r\n")); + } + } + return; + } + + if (mc->req_cmd_primary) { + mc->req_cmd_primary = FALSE; + + if (success) { + ppl_logevent(("Started a shell/command")); + mainchan_ready(mc); + } else if (*conf_get_str(mc->conf, CONF_remote_cmd2)) { + ppl_logevent(("Primary command failed; attempting fallback")); + mainchan_try_fallback_command(mc); + } else { + /* + * If there's no remote_cmd2 configured, then we have no + * fallback command, so we've run out of options. + */ + ssh_sw_abort(mc->ppl->ssh, + "Server refused to start a shell/command"); + } + return; + } + + if (mc->req_cmd_fallback) { + mc->req_cmd_fallback = FALSE; + + if (success) { + ppl_logevent(("Started a shell/command")); + ssh_got_fallback_cmd(mc->ppl->ssh); + mainchan_ready(mc); + } else { + ssh_sw_abort(mc->ppl->ssh, + "Server refused to start a shell/command"); + } + return; + } +} + +static void mainchan_ready(mainchan *mc) +{ + mc->ready = TRUE; + + ssh_set_wants_user_input(mc->cl, TRUE); + ssh_ppl_got_user_input(mc->ppl); /* in case any is already queued */ + + /* If an EOF arrived before we were ready, handle it now. */ + if (mc->eof_pending) { + mc->eof_pending = FALSE; + mainchan_special_cmd(mc, SS_EOF, 0); + } + + ssh_ldisc_update(mc->ppl->ssh); + queue_idempotent_callback(&mc->ppl->ic_process_queue); +} + +struct mainchan_open_failure_abort_ctx { + Ssh *ssh; + char *abort_message; +}; + +static void mainchan_open_failure_abort(void *vctx) +{ + struct mainchan_open_failure_abort_ctx *ctx = + (struct mainchan_open_failure_abort_ctx *)vctx; + ssh_sw_abort( + ctx->ssh, "Server refused to open main channel: %s", + ctx->abort_message); + sfree(ctx->abort_message); + sfree(ctx); +} + +static void mainchan_open_failure(Channel *chan, const char *errtext) +{ + assert(chan->vt == &mainchan_channelvt); + mainchan *mc = container_of(chan, mainchan, chan); + + struct mainchan_open_failure_abort_ctx *ctx = + snew(struct mainchan_open_failure_abort_ctx); + + ctx->ssh = mc->ppl->ssh; + ctx->abort_message = dupstr(errtext); + queue_toplevel_callback(mainchan_open_failure_abort, ctx); +} + +static int mainchan_send(Channel *chan, int is_stderr, + const void *data, int length) +{ + assert(chan->vt == &mainchan_channelvt); + mainchan *mc = container_of(chan, mainchan, chan); + return seat_output(mc->ppl->seat, is_stderr, data, length); +} + +static void mainchan_send_eof(Channel *chan) +{ + assert(chan->vt == &mainchan_channelvt); + mainchan *mc = container_of(chan, mainchan, chan); + PacketProtocolLayer *ppl = mc->ppl; /* for ppl_logevent */ + + if (!mc->eof_sent & (seat_eof(mc->ppl->seat) || mc->got_pty)) { + /* + * Either seat_eof told us that the front end wants us to + * close the outgoing side of the connection as soon as we see + * EOF from the far end, or else we've unilaterally decided to + * do that because we've allocated a remote pty and hence EOF + * isn't a particularly meaningful concept. + */ + sshfwd_write_eof(mc->sc); + ppl_logevent(("Sent EOF message")); + } + mc->eof_sent = TRUE; + ssh_set_wants_user_input(mc->cl, FALSE); /* now stop reading from stdin */ +} + +static void mainchan_set_input_wanted(Channel *chan, int wanted) +{ + assert(chan->vt == &mainchan_channelvt); + mainchan *mc = container_of(chan, mainchan, chan); + + /* + * This is the main channel of the SSH session, i.e. the one tied + * to the standard input (or GUI) of the primary SSH client user + * interface. So ssh->send_ok is how we control whether we're + * reading from that input. + */ + ssh_set_wants_user_input(mc->cl, wanted); +} + +static char *mainchan_log_close_msg(Channel *chan) +{ + return dupstr("Main session channel closed"); +} + +static int mainchan_rcvd_exit_status(Channel *chan, int status) +{ + assert(chan->vt == &mainchan_channelvt); + mainchan *mc = container_of(chan, mainchan, chan); + PacketProtocolLayer *ppl = mc->ppl; /* for ppl_logevent */ + + ssh_got_exitcode(mc->ppl->ssh, status); + ppl_logevent(("Session sent command exit status %d", status)); + return TRUE; +} + +static void mainchan_log_exit_signal_common( + mainchan *mc, const char *sigdesc, + int core_dumped, ptrlen msg) +{ + PacketProtocolLayer *ppl = mc->ppl; /* for ppl_logevent */ + + const char *core_msg = core_dumped ? " (core dumped)" : ""; + const char *msg_pre = (msg.len ? " (" : ""); + const char *msg_post = (msg.len ? ")" : ""); + ppl_logevent(("Session exited on %s%s%s%.*s%s", + sigdesc, core_msg, msg_pre, PTRLEN_PRINTF(msg), msg_post)); +} + +static int mainchan_rcvd_exit_signal( + Channel *chan, ptrlen signame, int core_dumped, ptrlen msg) +{ + assert(chan->vt == &mainchan_channelvt); + mainchan *mc = container_of(chan, mainchan, chan); + int exitcode; + char *signame_str; + + /* + * Translate the signal description back into a locally + * meaningful number. + */ + + if (0) + ; +#define TRANSLATE_SIGNAL(s) \ + else if (ptrlen_eq_string(signame, #s)) \ + exitcode = 128 + SIG ## s +#ifdef SIGABRT + TRANSLATE_SIGNAL(ABRT); +#endif +#ifdef SIGALRM + TRANSLATE_SIGNAL(ALRM); +#endif +#ifdef SIGFPE + TRANSLATE_SIGNAL(FPE); +#endif +#ifdef SIGHUP + TRANSLATE_SIGNAL(HUP); +#endif +#ifdef SIGILL + TRANSLATE_SIGNAL(ILL); +#endif +#ifdef SIGINT + TRANSLATE_SIGNAL(INT); +#endif +#ifdef SIGKILL + TRANSLATE_SIGNAL(KILL); +#endif +#ifdef SIGPIPE + TRANSLATE_SIGNAL(PIPE); +#endif +#ifdef SIGQUIT + TRANSLATE_SIGNAL(QUIT); +#endif +#ifdef SIGSEGV + TRANSLATE_SIGNAL(SEGV); +#endif +#ifdef SIGTERM + TRANSLATE_SIGNAL(TERM); +#endif +#ifdef SIGUSR1 + TRANSLATE_SIGNAL(USR1); +#endif +#ifdef SIGUSR2 + TRANSLATE_SIGNAL(USR2); +#endif +#undef TRANSLATE_SIGNAL + else + exitcode = 128; + + ssh_got_exitcode(mc->ppl->ssh, exitcode); + if (exitcode == 128) + signame_str = dupprintf("unrecognised signal \"%.*s\"", + PTRLEN_PRINTF(signame)); + else + signame_str = dupprintf("signal SIG%.*s", PTRLEN_PRINTF(signame)); + mainchan_log_exit_signal_common(mc, signame_str, core_dumped, msg); + sfree(signame_str); + return TRUE; +} + +static int mainchan_rcvd_exit_signal_numeric( + Channel *chan, int signum, int core_dumped, ptrlen msg) +{ + assert(chan->vt == &mainchan_channelvt); + mainchan *mc = container_of(chan, mainchan, chan); + char *signum_str; + + ssh_got_exitcode(mc->ppl->ssh, 128 + signum); + signum_str = dupprintf("signal %d", signum); + mainchan_log_exit_signal_common(mc, signum_str, core_dumped, msg); + sfree(signum_str); + return TRUE; +} + +/* + * List of signal names defined by RFC 4254. These include all the ISO + * C signals, but are a subset of the POSIX required signals. + * + * The list macro takes parameters MAIN and SUB, which is an arbitrary + * UI decision to expose the signals we think users are most likely to + * want, with extra descriptive text, and relegate the less probable + * ones to a submenu for people who know what they're doing. + */ +#define SIGNAL_LIST(MAIN, SUB) \ + MAIN(INT, "Interrupt") \ + MAIN(TERM, "Terminate") \ + MAIN(KILL, "Kill") \ + MAIN(QUIT, "Quit") \ + MAIN(HUP, "Hangup") \ + SUB(ABRT) \ + SUB(ALRM) \ + SUB(FPE) \ + SUB(ILL) \ + SUB(PIPE) \ + SUB(SEGV) \ + SUB(USR1) \ + SUB(USR2) \ + /* end of list */ + +void mainchan_get_specials( + mainchan *mc, add_special_fn_t add_special, void *ctx) +{ + /* FIXME: this _does_ depend on whether these services are supported */ + + add_special(ctx, "Break", SS_BRK, 0); + + #define ADD_MAIN(name, desc) \ + add_special(ctx, "SIG" #name " (" desc ")", SS_SIG ## name, 0); + #define ADD_SUB(name) \ + add_special(ctx, "SIG" #name, SS_SIG ## name, 0); + + #define NO_ADD_SUB(name) + #define NO_ADD_MAIN(name, desc) + + SIGNAL_LIST(ADD_MAIN, NO_ADD_SUB); + add_special(ctx, "More signals", SS_SUBMENU, 0); + SIGNAL_LIST(NO_ADD_MAIN, ADD_SUB); + add_special(ctx, NULL, SS_EXITMENU, 0); + + #undef ADD_MAIN + #undef ADD_SUB + #undef NO_ADD_MAIN + #undef NO_ADD_SUB +} + +static const char *ssh_signal_lookup(SessionSpecialCode code) +{ + #define CHECK_SUB(name) \ + if (code == SS_SIG ## name) return #name; + #define CHECK_MAIN(name, desc) CHECK_SUB(name) + + SIGNAL_LIST(CHECK_MAIN, CHECK_SUB); + return NULL; + + #undef CHECK_MAIN + #undef CHECK_SUB +} + +void mainchan_special_cmd(mainchan *mc, SessionSpecialCode code, int arg) +{ + PacketProtocolLayer *ppl = mc->ppl; /* for ppl_logevent */ + const char *signame; + + if (code == SS_EOF) { + if (!mc->ready) { + /* + * Buffer the EOF to send as soon as the main channel is + * fully set up. + */ + mc->eof_pending = TRUE; + } else if (!mc->eof_sent) { + sshfwd_write_eof(mc->sc); + mc->eof_sent = TRUE; + } + } else if (code == SS_BRK) { + sshfwd_send_serial_break( + mc->sc, FALSE, 0 /* default break length */); + } else if ((signame = ssh_signal_lookup(code)) != NULL) { + /* It's a signal. */ + sshfwd_send_signal(mc->sc, FALSE, signame); + ppl_logevent(("Sent signal SIG%s", signame)); + } +} + +void mainchan_terminal_size(mainchan *mc, int width, int height) +{ + mc->term_width = width; + mc->term_height = height; + + if (mc->req_pty || mc->got_pty) + sshfwd_send_terminal_size_change(mc->sc, width, height); +} diff --git a/putty.h b/putty.h index 46b8be54..dcf37286 100644 --- a/putty.h +++ b/putty.h @@ -216,6 +216,7 @@ typedef enum { SS_SIGINT, SS_SIGKILL, SS_SIGPIPE, SS_SIGQUIT, SS_SIGSEGV, SS_SIGTERM, SS_SIGUSR1, SS_SIGUSR2, + /* * These aren't really special commands, but they appear in the * enumeration because the list returned from @@ -236,6 +237,10 @@ struct SessionSpecial { int arg; }; +/* Needed by both sshchan.h and sshppl.h */ +typedef void (*add_special_fn_t)( + void *ctx, const char *text, SessionSpecialCode code, int arg); + typedef enum { MBT_NOTHING, MBT_LEFT, MBT_MIDDLE, MBT_RIGHT, /* `raw' button designations */ @@ -357,7 +362,8 @@ enum { * Line discipline options which the backend might try to control. */ LD_EDIT, /* local line editing */ - LD_ECHO /* local echo */ + LD_ECHO, /* local echo */ + LD_N_OPTIONS }; enum { diff --git a/ssh.h b/ssh.h index 0ed25b2a..9c198109 100644 --- a/ssh.h +++ b/ssh.h @@ -186,6 +186,9 @@ void share_setup_x11_channel(ssh_sharing_connstate *cs, share_channel *chan, int protomajor, int protominor, const void *initial_data, int initial_len); +struct X11Display; +struct X11FakeAuth; + /* Structure definition centralised here because the SSH-1 and SSH-2 * connection layers both use it. But the client module (portfwd.c) * should not try to look inside here. */ @@ -215,6 +218,13 @@ struct ConnectionLayerVtable { ConnectionLayer *cl, const char *hostname, int port, const char *org, Channel *chan); + /* Initiate opening of a 'session'-type channel */ + SshChannel *(*session_open)(ConnectionLayer *cl, Channel *chan); + + /* Add an X11 display for ordinary X forwarding */ + struct X11FakeAuth *(*add_x11_display)( + ConnectionLayer *cl, int authtype, struct X11Display *x11disp); + /* Add and remove X11 displays for connection sharing downstreams */ struct X11FakeAuth *(*add_sharing_x11_display)( ConnectionLayer *cl, int authtype, ssh_sharing_connstate *share_cs, @@ -263,6 +273,20 @@ struct ConnectionLayerVtable { /* Ask the connection layer about its current preference for * line-discipline options. */ int (*ldisc_option)(ConnectionLayer *cl, int option); + + /* Communicate _to_ the connection layer (from the main session + * channel) what its preference for line-discipline options is. */ + void (*set_ldisc_option)(ConnectionLayer *cl, int option, int value); + + /* Communicate to the connection layer whether X and agent + * forwarding were successfully enabled (for purposes of + * knowing whether to accept subsequent channel-opens). */ + void (*enable_x_fwd)(ConnectionLayer *cl); + void (*enable_agent_fwd)(ConnectionLayer *cl); + + /* Communicate to the connection layer whether the main session + * channel currently wants user input. */ + void (*set_wants_user_input)(ConnectionLayer *cl, int wanted); }; struct ConnectionLayer { @@ -275,6 +299,10 @@ struct ConnectionLayer { #define ssh_rportfwd_remove(cl, rpf) ((cl)->vt->rportfwd_remove(cl, rpf)) #define ssh_lportfwd_open(cl, h, p, org, chan) \ ((cl)->vt->lportfwd_open(cl, h, p, org, chan)) +#define ssh_session_open(cl, chan) \ + ((cl)->vt->session_open(cl, chan)) +#define ssh_add_x11_display(cl, auth, disp) \ + ((cl)->vt->add_x11_display(cl, auth, disp)) #define ssh_add_sharing_x11_display(cl, auth, cs, ch) \ ((cl)->vt->add_sharing_x11_display(cl, auth, cs, ch)) #define ssh_remove_sharing_x11_display(cl, fa) \ @@ -298,6 +326,12 @@ struct ConnectionLayer { #define ssh_throttle_all_channels(cl, throttled) \ ((cl)->vt->throttle_all_channels(cl, throttled)) #define ssh_ldisc_option(cl, option) ((cl)->vt->ldisc_option(cl, option)) +#define ssh_set_ldisc_option(cl, opt, val) \ + ((cl)->vt->set_ldisc_option(cl, opt, val)) +#define ssh_enable_x_fwd(cl) ((cl)->vt->enable_x_fwd(cl)) +#define ssh_enable_agent_fwd(cl) ((cl)->vt->enable_agent_fwd(cl)) +#define ssh_set_wants_user_input(cl, wanted) \ + ((cl)->vt->set_wants_user_input(cl, wanted)) /* Exports from portfwd.c */ PortFwdManager *portfwdmgr_new(ConnectionLayer *cl); diff --git a/ssh1connection.c b/ssh1connection.c index 51e2a262..34ba5bff 100644 --- a/ssh1connection.c +++ b/ssh1connection.c @@ -113,6 +113,8 @@ static const struct ConnectionLayerVtable ssh1_connlayer_vtable = { ssh1_rportfwd_alloc, ssh1_rportfwd_remove, ssh1_lportfwd_open, + NULL /* session_open */, + NULL /* add_x11_display */, NULL /* add_sharing_x11_display */, NULL /* remove_sharing_x11_display */, NULL /* send_packet_from_downstream */, @@ -126,6 +128,10 @@ static const struct ConnectionLayerVtable ssh1_connlayer_vtable = { ssh1_stdin_backlog, ssh1_throttle_all_channels, ssh1_ldisc_option, + NULL /* set_ldisc_option */, + NULL /* enable_x_fwd */, + NULL /* enable_agent_fwd */, + NULL /* set_wants_user_input */, }; struct ssh1_channel { diff --git a/ssh2connection.c b/ssh2connection.c index 790f4dd3..1307a6b1 100644 --- a/ssh2connection.c +++ b/ssh2connection.c @@ -23,13 +23,11 @@ struct ssh2_connection_state { ssh_sharing_state *connshare; char *peer_verstring; - struct ssh2_channel *mainchan; /* primary session channel */ - char *mainchan_open_error; - int mainchan_ready; - int echoedit; - int mainchan_eof_pending, mainchan_eof_sent; + mainchan *mainchan; + SshChannel *mainchan_sc; + int ldisc_opts[LD_N_OPTIONS]; int session_attempt, session_status; - int term_width, term_height, term_width_orig, term_height_orig; + int term_width, term_height; int want_user_input; int ssh_is_simple; @@ -107,6 +105,9 @@ static void ssh2_rportfwd_remove( static SshChannel *ssh2_lportfwd_open( ConnectionLayer *cl, const char *hostname, int port, const char *org, Channel *chan); +static SshChannel *ssh2_session_open(ConnectionLayer *cl, Channel *chan); +static struct X11FakeAuth *ssh2_add_x11_display( + ConnectionLayer *cl, int authtype, struct X11Display *x11disp); static struct X11FakeAuth *ssh2_add_sharing_x11_display( ConnectionLayer *cl, int authtype, ssh_sharing_connstate *share_cs, share_channel *share_chan); @@ -128,11 +129,17 @@ static void ssh2_stdout_unthrottle(ConnectionLayer *cl, int bufsize); static int ssh2_stdin_backlog(ConnectionLayer *cl); static void ssh2_throttle_all_channels(ConnectionLayer *cl, int throttled); static int ssh2_ldisc_option(ConnectionLayer *cl, int option); +static void ssh2_set_ldisc_option(ConnectionLayer *cl, int option, int value); +static void ssh2_enable_x_fwd(ConnectionLayer *cl); +static void ssh2_enable_agent_fwd(ConnectionLayer *cl); +static void ssh2_set_wants_user_input(ConnectionLayer *cl, int wanted); static const struct ConnectionLayerVtable ssh2_connlayer_vtable = { ssh2_rportfwd_alloc, ssh2_rportfwd_remove, ssh2_lportfwd_open, + ssh2_session_open, + ssh2_add_x11_display, ssh2_add_sharing_x11_display, ssh2_remove_sharing_x11_display, ssh2_send_packet_from_downstream, @@ -146,6 +153,10 @@ static const struct ConnectionLayerVtable ssh2_connlayer_vtable = { ssh2_stdin_backlog, ssh2_throttle_all_channels, ssh2_ldisc_option, + ssh2_set_ldisc_option, + ssh2_enable_x_fwd, + ssh2_enable_agent_fwd, + ssh2_set_wants_user_input, }; static char *ssh2_channel_open_failure_error_text(PktIn *pktin) @@ -340,8 +351,6 @@ static void ssh2_queue_global_request_handler( s->globreq_tail = ogr; } -static void create_mainchan(struct ssh2_connection_state *s, Conf *conf); - static int ssh2_channelcmp(void *av, void *bv) { const struct ssh2_channel *a = (const struct ssh2_channel *) av; @@ -382,8 +391,14 @@ static void ssh2_channel_free(struct ssh2_channel *c) c->chanreq_head = c->chanreq_head->next; sfree(chanreq); } - if (c->chan) + if (c->chan) { + struct ssh2_connection_state *s = c->connlayer; + if (s->mainchan_sc == &c->sc) { + s->mainchan = NULL; + s->mainchan_sc = NULL; + } chan_free(c->chan); + } sfree(c); } @@ -442,8 +457,6 @@ static void ssh2_connection_free(PacketProtocolLayer *ppl) conf_free(s->conf); - sfree(s->mainchan_open_error); - while ((c = delpos234(s->channels, 0)) != NULL) ssh2_channel_free(c); freetree234(s->channels); @@ -574,6 +587,7 @@ static int ssh2_connection_filter_queue(struct ssh2_connection_state *s) error = chan_open_auth_agent(s, &c->chan, &c->sc); } else { error = dupstr("Unsupported channel type requested"); + c->chan = NULL; } if (share_ctx) { @@ -706,7 +720,6 @@ static int ssh2_connection_filter_queue(struct ssh2_connection_state *s) chan_open_failed(c->chan, err); sfree(err); } - chan_free(c->chan); del234(s->channels, c); ssh2_channel_free(c); @@ -1096,7 +1109,9 @@ static void ssh2_connection_process_queue(PacketProtocolLayer *ppl) /* * Create the main session channel, if any. */ - create_mainchan(s, s->conf); + s->mainchan = mainchan_new( + &s->ppl, &s->cl, s->conf, s->term_width, s->term_height, + s->ssh_is_simple, &s->mainchan_sc); /* * Transfer data! @@ -1705,6 +1720,27 @@ static SshChannel *ssh2_lportfwd_open( return &c->sc; } +static SshChannel *ssh2_session_open(ConnectionLayer *cl, Channel *chan) +{ + struct ssh2_connection_state *s = + container_of(cl, struct ssh2_connection_state, cl); + PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */ + struct ssh2_channel *c = snew(struct ssh2_channel); + PktOut *pktout; + + c->connlayer = s; + ssh2_channel_init(c); + c->halfopen = TRUE; + c->chan = chan; + + ppl_logevent(("Opening main session channel")); + + pktout = ssh2_chanopen_init(c, "session"); + pq_push(s->ppl.out_pq, pktout); + + return &c->sc; +} + static void ssh2_rportfwd_globreq_response(struct ssh2_connection_state *s, PktIn *pktin, void *ctx) { @@ -1816,6 +1852,16 @@ static void ssh2_sharing_no_more_downstreams(ConnectionLayer *cl) queue_toplevel_callback(ssh2_check_termination_callback, s); } +static struct X11FakeAuth *ssh2_add_x11_display( + ConnectionLayer *cl, int authtype, struct X11Display *disp) +{ + struct ssh2_connection_state *s = + container_of(cl, struct ssh2_connection_state, cl); + struct X11FakeAuth *auth = x11_invent_fake_auth(s->x11authtree, authtype); + auth->disp = disp; + return auth; +} + static struct X11FakeAuth *ssh2_add_sharing_x11_display( ConnectionLayer *cl, int authtype, ssh_sharing_connstate *share_cs, share_channel *share_chan) @@ -1888,497 +1934,6 @@ static int ssh2_agent_forwarding_permitted(ConnectionLayer *cl) return conf_get_int(s->conf, CONF_agentfwd) && agent_exists(); } -static void mainchan_free(Channel *chan); -static void mainchan_open_confirmation(Channel *chan); -static void mainchan_open_failure(Channel *chan, const char *errtext); -static int mainchan_send(Channel *chan, int is_stderr, const void *, int); -static void mainchan_send_eof(Channel *chan); -static void mainchan_set_input_wanted(Channel *chan, int wanted); -static char *mainchan_log_close_msg(Channel *chan); -static int mainchan_rcvd_exit_status(Channel *chan, int status); -static int mainchan_rcvd_exit_signal( - Channel *chan, ptrlen signame, int core_dumped, ptrlen msg); -static int mainchan_rcvd_exit_signal_numeric( - Channel *chan, int signum, int core_dumped, ptrlen msg); -static void mainchan_request_response(Channel *chan, int success); - -static const struct ChannelVtable mainchan_channelvt = { - mainchan_free, - mainchan_open_confirmation, - mainchan_open_failure, - mainchan_send, - mainchan_send_eof, - mainchan_set_input_wanted, - mainchan_log_close_msg, - chan_no_eager_close, - mainchan_rcvd_exit_status, - mainchan_rcvd_exit_signal, - mainchan_rcvd_exit_signal_numeric, - mainchan_request_response, -}; - -typedef enum MainChanType { - MAINCHAN_SESSION, MAINCHAN_DIRECT_TCPIP -} MainChanType; - -typedef struct mainchan { - struct ssh2_connection_state *connlayer; - SshChannel *sc; - MainChanType type; - Conf *conf; - int req_x11, req_agent, req_pty, req_cmd_primary, req_cmd_fallback; - int n_req_env, n_env_replies, n_env_fails; - - Channel chan; -} mainchan; - -static void create_mainchan(struct ssh2_connection_state *s, Conf *conf) -{ - PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */ - mainchan *mc; - PktOut *pktout; - - if (conf_get_int(s->conf, CONF_ssh_no_shell)) - return; /* do nothing */ - - mc = snew(mainchan); - memset(mc, 0, sizeof(mainchan)); - mc->connlayer = s; - mc->sc = NULL; - mc->chan.vt = &mainchan_channelvt; - mc->chan.initial_fixed_window_size = 0; - mc->conf = conf_copy(conf); - - if (*conf_get_str(mc->conf, CONF_ssh_nc_host)) { - mc->sc = ssh_lportfwd_open( - &s->cl, conf_get_str(mc->conf, CONF_ssh_nc_host), - conf_get_int(mc->conf, CONF_ssh_nc_port), - "main channel", &mc->chan); - s->mainchan = container_of(mc->sc, struct ssh2_channel, sc); - mc->type = MAINCHAN_DIRECT_TCPIP; - } else { - s->mainchan = snew(struct ssh2_channel); - mc->sc = &s->mainchan->sc; - s->mainchan->connlayer = s; - ssh2_channel_init(s->mainchan); - s->mainchan->chan = &mc->chan; - s->mainchan->halfopen = TRUE; - pktout = ssh2_chanopen_init(s->mainchan, "session"); - ppl_logevent(("Opening session as main channel")); - pq_push(s->ppl.out_pq, pktout); - mc->type = MAINCHAN_SESSION; - } -} - -static void mainchan_free(Channel *chan) -{ - assert(chan->vt == &mainchan_channelvt); - mainchan *mc = container_of(chan, mainchan, chan); - struct ssh2_connection_state *s = mc->connlayer; - s->mainchan = NULL; - conf_free(mc->conf); - sfree(mc); -} - -static void mainchan_try_fallback_command(mainchan *mc); -static void mainchan_ready(mainchan *mc); - -static void mainchan_open_confirmation(Channel *chan) -{ - mainchan *mc = container_of(chan, mainchan, chan); - struct ssh2_connection_state *s = mc->connlayer; - PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */ - - seat_update_specials_menu(s->ppl.seat); - ppl_logevent(("Opened main channel")); - - if (s->ssh_is_simple) - sshfwd_hint_channel_is_simple(mc->sc); - - if (mc->type == MAINCHAN_SESSION) { - /* - * Send the CHANNEL_REQUESTS for the main session channel. - */ - char *key, *val, *cmd; - struct X11Display *x11disp; - struct X11FakeAuth *x11auth; - int retry_cmd_now = FALSE; - - if (conf_get_int(mc->conf, CONF_x11_forward)) {; - char *x11_setup_err; - if ((x11disp = x11_setup_display( - conf_get_str(mc->conf, CONF_x11_display), - mc->conf, &x11_setup_err)) == NULL) { - ppl_logevent(("X11 forwarding not enabled: unable to" - " initialise X display: %s", x11_setup_err)); - sfree(x11_setup_err); - } else { - x11auth = x11_invent_fake_auth( - s->x11authtree, conf_get_int(mc->conf, CONF_x11_auth)); - x11auth->disp = x11disp; - - sshfwd_request_x11_forwarding( - mc->sc, TRUE, x11auth->protoname, x11auth->datastring, - x11disp->screennum, FALSE); - mc->req_x11 = TRUE; - } - } - - if (ssh_agent_forwarding_permitted(&s->cl)) { - sshfwd_request_agent_forwarding(mc->sc, TRUE); - mc->req_agent = TRUE; - } - - if (!conf_get_int(mc->conf, CONF_nopty)) { - sshfwd_request_pty( - mc->sc, TRUE, mc->conf, s->term_width, s->term_height); - /* Record the initial width/height we requested, so we - * know whether we need to send a change later once - * everything is set up (if the window is resized in - * between) */ - s->term_width_orig = s->term_width; - s->term_height_orig = s->term_height; - mc->req_pty = TRUE; - } - - for (val = conf_get_str_strs(mc->conf, CONF_environmt, NULL, &key); - val != NULL; - val = conf_get_str_strs(mc->conf, CONF_environmt, key, &key)) { - sshfwd_send_env_var(mc->sc, TRUE, key, val); - mc->n_req_env++; - } - if (mc->n_req_env) - ppl_logevent(("Sent %d environment variables", mc->n_req_env)); - - cmd = conf_get_str(s->conf, CONF_remote_cmd); - if (conf_get_int(s->conf, CONF_ssh_subsys)) { - retry_cmd_now = !sshfwd_start_subsystem(mc->sc, TRUE, cmd); - } else if (*cmd) { - sshfwd_start_command(mc->sc, TRUE, cmd); - } else { - sshfwd_start_shell(mc->sc, TRUE); - } - - if (retry_cmd_now) - mainchan_try_fallback_command(mc); - else - mc->req_cmd_primary = TRUE; - - } else { - s->echoedit = TRUE; - mainchan_ready(mc); - } -} - -static void mainchan_try_fallback_command(mainchan *mc) -{ - const char *cmd = conf_get_str(mc->conf, CONF_remote_cmd2); - if (conf_get_int(mc->conf, CONF_ssh_subsys2)) { - sshfwd_start_subsystem(mc->sc, TRUE, cmd); - } else { - sshfwd_start_command(mc->sc, TRUE, cmd); - } - mc->req_cmd_fallback = TRUE; -} - -static void mainchan_request_response(Channel *chan, int success) -{ - assert(chan->vt == &mainchan_channelvt); - mainchan *mc = container_of(chan, mainchan, chan); - struct ssh2_connection_state *s = mc->connlayer; - PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */ - - if (mc->req_x11) { - mc->req_x11 = FALSE; - - if (success) { - ppl_logevent(("X11 forwarding enabled")); - s->X11_fwd_enabled = TRUE; - } else { - ppl_logevent(("X11 forwarding refused")); - } - return; - } - - if (mc->req_agent) { - mc->req_agent = FALSE; - - if (success) { - ppl_logevent(("Agent forwarding enabled")); - } else { - ppl_logevent(("Agent forwarding refused")); - } - return; - } - - if (mc->req_pty) { - mc->req_pty = FALSE; - - if (success) { - ppl_logevent(("Allocated pty")); - s->agent_fwd_enabled = TRUE; - } else { - ppl_logevent(("Server refused to allocate pty")); - ppl_printf(("Server refused to allocate pty\r\n")); - s->echoedit = TRUE; - } - return; - } - - if (mc->n_env_replies < mc->n_req_env) { - int j = mc->n_env_replies++; - if (!success) { - ppl_logevent(("Server refused to set environment variable %s", - conf_get_str_nthstrkey(mc->conf, - CONF_environmt, j))); - mc->n_env_fails++; - } - - if (mc->n_env_replies == mc->n_req_env) { - if (mc->n_env_fails == 0) { - ppl_logevent(("All environment variables successfully set")); - } else if (mc->n_env_fails == mc->n_req_env) { - ppl_logevent(("All environment variables refused")); - ppl_printf(("Server refused to set environment " - "variables\r\n")); - } else { - ppl_printf(("Server refused to set all environment " - "variables\r\n")); - } - } - return; - } - - if (mc->req_cmd_primary) { - mc->req_cmd_primary = FALSE; - - if (success) { - ppl_logevent(("Started a shell/command")); - mainchan_ready(mc); - queue_idempotent_callback(&s->ppl.ic_process_queue); - } else if (*conf_get_str(mc->conf, CONF_remote_cmd2)) { - ppl_logevent(("Primary command failed; attempting fallback")); - mainchan_try_fallback_command(mc); - } else { - /* - * If there's no remote_cmd2 configured, then we have no - * fallback command, so we've run out of options. - */ - ssh_sw_abort(s->ppl.ssh, - "Server refused to start a shell/command"); - } - return; - } - - if (mc->req_cmd_fallback) { - mc->req_cmd_fallback = FALSE; - - if (success) { - ppl_logevent(("Started a shell/command")); - ssh_got_fallback_cmd(s->ppl.ssh); - mainchan_ready(mc); - queue_idempotent_callback(&s->ppl.ic_process_queue); - } else { - ssh_sw_abort(s->ppl.ssh, - "Server refused to start a shell/command"); - } - return; - } -} - -static void mainchan_ready(mainchan *mc) -{ - struct ssh2_connection_state *s = mc->connlayer; - - s->mainchan_ready = TRUE; - s->want_user_input = TRUE; - ssh_ppl_got_user_input(&s->ppl); /* in case any is already queued */ - - /* If an EOF or a window-size change arrived before we were ready - * to handle either one, handle them now. */ - if (s->mainchan_eof_pending) - ssh_ppl_special_cmd(&s->ppl, SS_EOF, 0); - if (s->term_width_orig != s->term_width || - s->term_height_orig != s->term_height) - ssh_terminal_size(&s->cl, s->term_width, s->term_height); - - ssh_ldisc_update(s->ppl.ssh); -} - -static void mainchan_open_failure(Channel *chan, const char *errtext) -{ - assert(chan->vt == &mainchan_channelvt); - mainchan *mc = container_of(chan, mainchan, chan); - struct ssh2_connection_state *s = mc->connlayer; - - ssh_sw_abort( - s->ppl.ssh, "Server refused to open main channel: %s", errtext); -} - -static int mainchan_send(Channel *chan, int is_stderr, - const void *data, int length) -{ - assert(chan->vt == &mainchan_channelvt); - mainchan *mc = container_of(chan, mainchan, chan); - struct ssh2_connection_state *s = mc->connlayer; - return seat_output(s->ppl.seat, is_stderr, data, length); -} - -static void mainchan_send_eof(Channel *chan) -{ - assert(chan->vt == &mainchan_channelvt); - mainchan *mc = container_of(chan, mainchan, chan); - struct ssh2_connection_state *s = mc->connlayer; - PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */ - - if (!s->mainchan_eof_sent && (seat_eof(s->ppl.seat) || s->got_pty)) { - /* - * Either seat_eof told us that the front end wants us to - * close the outgoing side of the connection as soon as we see - * EOF from the far end, or else we've unilaterally decided to - * do that because we've allocated a remote pty and hence EOF - * isn't a particularly meaningful concept. - */ - sshfwd_write_eof(mc->sc); - ppl_logevent(("Sent EOF message")); - s->mainchan_eof_sent = TRUE; - s->want_user_input = FALSE; /* now stop reading from stdin */ - } -} - -static void mainchan_set_input_wanted(Channel *chan, int wanted) -{ - assert(chan->vt == &mainchan_channelvt); - mainchan *mc = container_of(chan, mainchan, chan); - struct ssh2_connection_state *s = mc->connlayer; - - /* - * This is the main channel of the SSH session, i.e. the one tied - * to the standard input (or GUI) of the primary SSH client user - * interface. So ssh->send_ok is how we control whether we're - * reading from that input. - */ - s->want_user_input = wanted; -} - -static char *mainchan_log_close_msg(Channel *chan) -{ - return dupstr("Main session channel closed"); -} - -static int mainchan_rcvd_exit_status(Channel *chan, int status) -{ - assert(chan->vt == &mainchan_channelvt); - mainchan *mc = container_of(chan, mainchan, chan); - struct ssh2_connection_state *s = mc->connlayer; - PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */ - - ssh_got_exitcode(s->ppl.ssh, status); - ppl_logevent(("Session sent command exit status %d", status)); - return TRUE; -} - -static void ssh2_log_exit_signal_common( - struct ssh2_connection_state *s, const char *sigdesc, - int core_dumped, ptrlen msg) -{ - PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */ - - const char *core_msg = core_dumped ? " (core dumped)" : ""; - const char *msg_pre = (msg.len ? " (" : ""); - const char *msg_post = (msg.len ? ")" : ""); - ppl_logevent(("Session exited on %s%s%s%.*s%s", - sigdesc, core_msg, msg_pre, PTRLEN_PRINTF(msg), msg_post)); -} - -static int mainchan_rcvd_exit_signal( - Channel *chan, ptrlen signame, int core_dumped, ptrlen msg) -{ - assert(chan->vt == &mainchan_channelvt); - mainchan *mc = container_of(chan, mainchan, chan); - struct ssh2_connection_state *s = mc->connlayer; - int exitcode; - char *signame_str; - - /* - * Translate the signal description back into a locally - * meaningful number. - */ - - if (0) - ; -#define TRANSLATE_SIGNAL(s) \ - else if (ptrlen_eq_string(signame, #s)) \ - exitcode = 128 + SIG ## s -#ifdef SIGABRT - TRANSLATE_SIGNAL(ABRT); -#endif -#ifdef SIGALRM - TRANSLATE_SIGNAL(ALRM); -#endif -#ifdef SIGFPE - TRANSLATE_SIGNAL(FPE); -#endif -#ifdef SIGHUP - TRANSLATE_SIGNAL(HUP); -#endif -#ifdef SIGILL - TRANSLATE_SIGNAL(ILL); -#endif -#ifdef SIGINT - TRANSLATE_SIGNAL(INT); -#endif -#ifdef SIGKILL - TRANSLATE_SIGNAL(KILL); -#endif -#ifdef SIGPIPE - TRANSLATE_SIGNAL(PIPE); -#endif -#ifdef SIGQUIT - TRANSLATE_SIGNAL(QUIT); -#endif -#ifdef SIGSEGV - TRANSLATE_SIGNAL(SEGV); -#endif -#ifdef SIGTERM - TRANSLATE_SIGNAL(TERM); -#endif -#ifdef SIGUSR1 - TRANSLATE_SIGNAL(USR1); -#endif -#ifdef SIGUSR2 - TRANSLATE_SIGNAL(USR2); -#endif -#undef TRANSLATE_SIGNAL - else - exitcode = 128; - - ssh_got_exitcode(s->ppl.ssh, exitcode); - if (exitcode == 128) - signame_str = dupprintf("unrecognised signal \"%.*s\"", - PTRLEN_PRINTF(signame)); - else - signame_str = dupprintf("signal SIG%.*s", PTRLEN_PRINTF(signame)); - ssh2_log_exit_signal_common(s, signame_str, core_dumped, msg); - sfree(signame_str); - return TRUE; -} - -static int mainchan_rcvd_exit_signal_numeric( - Channel *chan, int signum, int core_dumped, ptrlen msg) -{ - assert(chan->vt == &mainchan_channelvt); - mainchan *mc = container_of(chan, mainchan, chan); - struct ssh2_connection_state *s = mc->connlayer; - char *signum_str; - - ssh_got_exitcode(s->ppl.ssh, 128 + signum); - signum_str = dupprintf("signal %d", signum); - ssh2_log_exit_signal_common(s, signum_str, core_dumped, msg); - sfree(signum_str); - return TRUE; -} - static char *chan_open_x11( struct ssh2_connection_state *s, Channel **ch, SshChannel *sc, ptrlen peeraddr, int peerport) @@ -2456,31 +2011,6 @@ static char *chan_open_auth_agent( return NULL; } -/* - * List of signal names defined by RFC 4254. These include all the ISO - * C signals, but are a subset of the POSIX required signals. - * - * The list macro takes parameters MAIN and SUB, which is an arbitrary - * UI decision to expose the signals we think users are most likely to - * want, with extra descriptive text, and relegate the less probable - * ones to a submenu for people who know what they're doing. - */ -#define SIGNAL_LIST(MAIN, SUB) \ - MAIN(INT, "Interrupt") \ - MAIN(TERM, "Terminate") \ - MAIN(KILL, "Kill") \ - MAIN(QUIT, "Quit") \ - MAIN(HUP, "Hangup") \ - SUB(ABRT) \ - SUB(ALRM) \ - SUB(FPE) \ - SUB(ILL) \ - SUB(PIPE) \ - SUB(SEGV) \ - SUB(USR1) \ - SUB(USR2) \ - /* end of list */ - static int ssh2_connection_get_specials( PacketProtocolLayer *ppl, add_special_fn_t add_special, void *ctx) { @@ -2489,26 +2019,7 @@ static int ssh2_connection_get_specials( int toret = FALSE; if (s->mainchan) { - add_special(ctx, "Break", SS_BRK, 0); - - #define ADD_MAIN(name, desc) \ - add_special(ctx, "SIG" #name " (" desc ")", SS_SIG ## name, 0); - #define ADD_SUB(name) \ - add_special(ctx, "SIG" #name, SS_SIG ## name, 0); - - #define NO_ADD_SUB(name) - #define NO_ADD_MAIN(name, desc) - - SIGNAL_LIST(ADD_MAIN, NO_ADD_SUB); - add_special(ctx, "More signals", SS_SUBMENU, 0); - SIGNAL_LIST(NO_ADD_MAIN, ADD_SUB); - add_special(ctx, NULL, SS_EXITMENU, 0); - - #undef ADD_MAIN - #undef ADD_SUB - #undef NO_ADD_MAIN - #undef NO_ADD_SUB - + mainchan_get_specials(s->mainchan, add_special, ctx); toret = TRUE; } @@ -2528,26 +2039,12 @@ static int ssh2_connection_get_specials( return toret; } -static const char *ssh_signal_lookup(SessionSpecialCode code) -{ - #define CHECK_SUB(name) \ - if (code == SS_SIG ## name) return #name; - #define CHECK_MAIN(name, desc) CHECK_SUB(name) - - SIGNAL_LIST(CHECK_MAIN, CHECK_SUB); - return NULL; - - #undef CHECK_MAIN - #undef CHECK_SUB -} - static void ssh2_connection_special_cmd(PacketProtocolLayer *ppl, SessionSpecialCode code, int arg) { struct ssh2_connection_state *s = container_of(ppl, struct ssh2_connection_state, ppl); PktOut *pktout; - const char *signame; if (code == SS_PING || code == SS_NOP) { if (!(s->ppl.remote_bugs & BUG_CHOKES_ON_SSH2_IGNORE)) { @@ -2555,30 +2052,8 @@ static void ssh2_connection_special_cmd(PacketProtocolLayer *ppl, put_stringz(pktout, ""); pq_push(s->ppl.out_pq, pktout); } - } else if (code == SS_EOF) { - if (!s->mainchan_ready) { - /* - * Buffer the EOF to send as soon as the main channel is - * fully set up. - */ - s->mainchan_eof_pending = TRUE; - } else if (s->mainchan && !s->mainchan_eof_sent) { - sshfwd_write_eof(&s->mainchan->sc); - } - } else if (code == SS_BRK) { - if (s->mainchan) { - pktout = ssh2_chanreq_init(s->mainchan, "break", NULL, NULL); - put_uint32(pktout, 0); /* default break length */ - pq_push(s->ppl.out_pq, pktout); - } - } else if ((signame = ssh_signal_lookup(code)) != NULL) { - /* It's a signal. */ - if (s->mainchan) { - pktout = ssh2_chanreq_init(s->mainchan, "signal", NULL, NULL); - put_stringz(pktout, signame); - pq_push(s->ppl.out_pq, pktout); - ppl_logevent(("Sent signal SIG%s", signame)); - } + } else if (s->mainchan) { + mainchan_special_cmd(s->mainchan, code, arg); } } @@ -2589,16 +2064,8 @@ static void ssh2_terminal_size(ConnectionLayer *cl, int width, int height) s->term_width = width; s->term_height = height; - - if (s->mainchan_ready) { - PktOut *pktout = ssh2_chanreq_init( - s->mainchan, "window-change", NULL, NULL); - put_uint32(pktout, s->term_width); - put_uint32(pktout, s->term_height); - put_uint32(pktout, 0); - put_uint32(pktout, 0); - pq_push(s->ppl.out_pq, pktout); - } + if (s->mainchan) + mainchan_terminal_size(s->mainchan, width, height); } static void ssh2_stdout_unthrottle(ConnectionLayer *cl, int bufsize) @@ -2607,15 +2074,19 @@ static void ssh2_stdout_unthrottle(ConnectionLayer *cl, int bufsize) container_of(cl, struct ssh2_connection_state, cl); if (s->mainchan) - ssh2channel_unthrottle(&s->mainchan->sc, bufsize); + sshfwd_unthrottle(s->mainchan_sc, bufsize); } static int ssh2_stdin_backlog(ConnectionLayer *cl) { struct ssh2_connection_state *s = container_of(cl, struct ssh2_connection_state, cl); + struct ssh2_channel *c; - return s->mainchan ? bufchain_size(&s->mainchan->outbuffer) : 0; + if (!s->mainchan) + return 0; + c = container_of(s->mainchan_sc, struct ssh2_channel, sc); + return s->mainchan ? bufchain_size(&c->outbuffer) : 0; } static void ssh2_throttle_all_channels(ConnectionLayer *cl, int throttled) @@ -2636,15 +2107,46 @@ static int ssh2_ldisc_option(ConnectionLayer *cl, int option) struct ssh2_connection_state *s = container_of(cl, struct ssh2_connection_state, cl); - /* We always return the same value for LD_ECHO and LD_EDIT */ - return s->echoedit; + return s->ldisc_opts[option]; +} + +static void ssh2_set_ldisc_option(ConnectionLayer *cl, int option, int value) +{ + struct ssh2_connection_state *s = + container_of(cl, struct ssh2_connection_state, cl); + + s->ldisc_opts[option] = value; +} + +static void ssh2_enable_x_fwd(ConnectionLayer *cl) +{ + struct ssh2_connection_state *s = + container_of(cl, struct ssh2_connection_state, cl); + + s->X11_fwd_enabled = TRUE; +} + +static void ssh2_enable_agent_fwd(ConnectionLayer *cl) +{ + struct ssh2_connection_state *s = + container_of(cl, struct ssh2_connection_state, cl); + + s->agent_fwd_enabled = TRUE; +} + +static void ssh2_set_wants_user_input(ConnectionLayer *cl, int wanted) +{ + struct ssh2_connection_state *s = + container_of(cl, struct ssh2_connection_state, cl); + + s->want_user_input = wanted; } static int ssh2_connection_want_user_input(PacketProtocolLayer *ppl) { struct ssh2_connection_state *s = container_of(ppl, struct ssh2_connection_state, ppl); - return s->mainchan_ready && s->want_user_input; + return s->want_user_input; } static void ssh2_connection_got_user_input(PacketProtocolLayer *ppl) @@ -2659,7 +2161,7 @@ static void ssh2_connection_got_user_input(PacketProtocolLayer *ppl) void *data; int len; bufchain_prefix(s->ppl.user_input, &data, &len); - sshfwd_write(&s->mainchan->sc, data, len); + sshfwd_write(s->mainchan_sc, data, len); bufchain_consume(s->ppl.user_input, len); } } diff --git a/sshchan.h b/sshchan.h index e29e00d0..7f1be259 100644 --- a/sshchan.h +++ b/sshchan.h @@ -191,4 +191,19 @@ struct SshChannel { #define sshfwd_hint_channel_is_simple(c) \ ((c)->vt->hint_channel_is_simple(c)) +/* ---------------------------------------------------------------------- + * The 'main' or primary channel of the SSH connection is special, + * because it's the one that's connected directly to parts of the + * frontend such as the terminal and the specials menu. So it exposes + * a richer API. + */ + +mainchan *mainchan_new( + PacketProtocolLayer *ppl, ConnectionLayer *cl, Conf *conf, + int term_width, int term_height, int is_simple, SshChannel **sc_out); +void mainchan_get_specials( + mainchan *mc, add_special_fn_t add_special, void *ctx); +void mainchan_special_cmd(mainchan *mc, SessionSpecialCode code, int arg); +void mainchan_terminal_size(mainchan *mc, int width, int height); + #endif /* PUTTY_SSHCHAN_H */ diff --git a/sshppl.h b/sshppl.h index 2536c0ec..e1d4c7c3 100644 --- a/sshppl.h +++ b/sshppl.h @@ -8,8 +8,6 @@ #define PUTTY_SSHPPL_H typedef void (*packet_handler_fn_t)(PacketProtocolLayer *ppl, PktIn *pktin); -typedef void (*add_special_fn_t)( - void *ctx, const char *text, SessionSpecialCode code, int arg); struct PacketProtocolLayerVtable { void (*free)(PacketProtocolLayer *); From dead35dd0f0ed3ad111e74bbaa5bf03b3b5c63bd Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Fri, 12 Oct 2018 19:25:59 +0100 Subject: [PATCH 532/607] New system for handling SSH terminal modes. I've introduced a new POD struct type 'ssh_ttymodes' which stores an encoding of everything you can specify in the "pty-req" packet or the SSH-1 equivalent. This allows me to split up write_ttymodes_to_packet_from_conf() into two separate functions, one to parse all the ttymode data out of a Conf (and a Seat for fallback) and return one of those structures, and the other to write it into an SSH packet. While I'm at it, I've moved the special case of terminal speeds into the same mechanism, simplifying the call sites in both versions of the SSH protocol. The new master definition of all terminal modes lives in a header file, with an ifdef around each item, so that later on I'll be able to include it in a context that only enumerates the modes supported by the particular target Unix platform. --- ssh.h | 43 ++++++++++-- ssh1connection.c | 15 ++-- ssh2connection.c | 11 +-- sshcommon.c | 172 ++++++++++++++++++--------------------------- sshttymodes.h | 179 +++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 292 insertions(+), 128 deletions(-) create mode 100644 sshttymodes.h diff --git a/ssh.h b/ssh.h index 9c198109..670fdb68 100644 --- a/ssh.h +++ b/ssh.h @@ -1393,6 +1393,44 @@ enum { #define SSH2_EXTENDED_DATA_STDERR 1 /* 0x1 */ +enum { + /* TTY modes with opcodes defined consistently in the SSH specs. */ + #define TTYMODE_CHAR(name, val, index) SSH_TTYMODE_##name = val, + #define TTYMODE_FLAG(name, val, field, mask) SSH_TTYMODE_##name = val, + #include "sshttymodes.h" + #undef TTYMODE_CHAR + #undef TTYMODE_FLAG + + /* Modes encoded differently between SSH-1 and SSH-2, for which we + * make up our own dummy opcodes to avoid confusion. */ + TTYMODE_dummy = 255, + TTYMODE_ISPEED, TTYMODE_OSPEED, + + /* Limiting value that we can use as an array bound below */ + TTYMODE_LIMIT, + + /* The real opcodes for terminal speeds. */ + TTYMODE_ISPEED_SSH1 = 192, + TTYMODE_OSPEED_SSH1 = 193, + TTYMODE_ISPEED_SSH2 = 128, + TTYMODE_OSPEED_SSH2 = 129, + + /* And the opcode that ends a list. */ + TTYMODE_END_OF_LIST = 0 +}; + +struct ssh_ttymodes { + /* A boolean per mode, indicating whether it's set. */ + int have_mode[TTYMODE_LIMIT]; + + /* The actual value for each mode. */ + unsigned mode_val[TTYMODE_LIMIT]; +}; + +struct ssh_ttymodes get_ttymodes_from_conf(Seat *seat, Conf *conf); +void write_ttymodes_to_packet(BinarySink *bs, int ssh_version, + struct ssh_ttymodes modes); + const char *ssh1_pkt_type(int type); const char *ssh2_pkt_type(Pkt_KCtx pkt_kctx, Pkt_ACtx pkt_actx, int type); int ssh2_pkt_type_code_valid(unsigned type); @@ -1429,11 +1467,6 @@ enum { SSH_IMPL_BUG_LIST(TMP_DECLARE_LOG2_ENUM) }; enum { SSH_IMPL_BUG_LIST(TMP_DECLARE_REAL_ENUM) }; #undef TMP_DECLARE_REAL_ENUM -/* Shared function that writes tty modes into a pty request */ -void write_ttymodes_to_packet_from_conf( - BinarySink *bs, Seat *seat, Conf *conf, - int ssh_version, int ospeed, int ispeed); - /* Shared system for allocating local SSH channel ids. Expects to be * passed a tree full of structs that have a field called 'localid' of * type unsigned, and will check that! */ diff --git a/ssh1connection.c b/ssh1connection.c index 34ba5bff..c7e284b6 100644 --- a/ssh1connection.c +++ b/ssh1connection.c @@ -28,7 +28,6 @@ struct ssh1_connection_state { int got_pty; int echoedit; - int ospeed, ispeed; int stdout_throttling; int session_ready; int session_eof_pending, session_eof_sent, session_terminated; @@ -709,11 +708,6 @@ static void ssh1_connection_process_queue(PacketProtocolLayer *ppl) s->portfwdmgr_configured = TRUE; if (!conf_get_int(s->conf, CONF_nopty)) { - /* Unpick the terminal-speed string. */ - /* XXX perhaps we should allow no speeds to be sent. */ - s->ospeed = 38400; s->ispeed = 38400; /* last-resort defaults */ - sscanf(conf_get_str(s->conf, CONF_termspeed), "%d,%d", - &s->ospeed, &s->ispeed); /* Send the pty request. */ pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_REQUEST_PTY); put_stringz(pktout, conf_get_str(s->conf, CONF_termtype)); @@ -723,14 +717,13 @@ static void ssh1_connection_process_queue(PacketProtocolLayer *ppl) s->term_height_orig = s->term_height; put_uint32(pktout, 0); /* width in pixels */ put_uint32(pktout, 0); /* height in pixels */ - write_ttymodes_to_packet_from_conf( - BinarySink_UPCAST(pktout), s->ppl.seat, s->conf, - 1, s->ospeed, s->ispeed); + write_ttymodes_to_packet( + BinarySink_UPCAST(pktout), 1, + get_ttymodes_from_conf(s->ppl.seat, s->conf)); pq_push(s->ppl.out_pq, pktout); crMaybeWaitUntilV((pktin = ssh1_connection_pop(s)) != NULL); if (pktin->type == SSH1_SMSG_SUCCESS) { - ppl_logevent(("Allocated pty (ospeed %dbps, ispeed %dbps)", - s->ospeed, s->ispeed)); + ppl_logevent(("Allocated pty")); s->got_pty = TRUE; } else if (pktin->type == SSH1_SMSG_FAILURE) { ppl_printf(("Server refused to allocate pty\r\n")); diff --git a/ssh2connection.c b/ssh2connection.c index 1307a6b1..c0b3e365 100644 --- a/ssh2connection.c +++ b/ssh2connection.c @@ -1593,13 +1593,8 @@ static void ssh2channel_request_pty( { struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc); struct ssh2_connection_state *s = c->connlayer; - int ospeed, ispeed; strbuf *modebuf; - ospeed = ispeed = 38400; /* last-resort defaults */ - sscanf(conf_get_str(conf, CONF_termspeed), "%d,%d", - &ospeed, &ispeed); - PktOut *pktout = ssh2_chanreq_init( c, "pty-req", want_reply ? ssh2_channel_response : NULL, NULL); put_stringz(pktout, conf_get_str(conf, CONF_termtype)); @@ -1608,9 +1603,9 @@ static void ssh2channel_request_pty( put_uint32(pktout, 0); /* pixel width */ put_uint32(pktout, 0); /* pixel height */ modebuf = strbuf_new(); - write_ttymodes_to_packet_from_conf( - BinarySink_UPCAST(modebuf), s->ppl.seat, conf, - 2, ospeed, ispeed); + write_ttymodes_to_packet( + BinarySink_UPCAST(modebuf), 2, + get_ttymodes_from_conf(s->ppl.seat, conf)); put_stringsb(pktout, modebuf); pq_push(s->ppl.out_pq, pktout); } diff --git a/sshcommon.c b/sshcommon.c index bd718dee..51595de5 100644 --- a/sshcommon.c +++ b/sshcommon.c @@ -367,101 +367,47 @@ void chan_no_request_response(Channel *chan, int success) } /* ---------------------------------------------------------------------- - * Common routine to marshal tty modes into an SSH packet. + * Common routines for handling SSH tty modes. */ -void write_ttymodes_to_packet_from_conf( - BinarySink *bs, Seat *seat, Conf *conf, - int ssh_version, int ospeed, int ispeed) +static unsigned real_ttymode_opcode(unsigned our_opcode, int ssh_version) { - int i; + switch (our_opcode) { + case TTYMODE_ISPEED: + return ssh_version == 1 ? TTYMODE_ISPEED_SSH1 : TTYMODE_ISPEED_SSH2; + case TTYMODE_OSPEED: + return ssh_version == 1 ? TTYMODE_OSPEED_SSH1 : TTYMODE_OSPEED_SSH2; + default: + return our_opcode; + } +} - /* - * Codes for terminal modes. - * Most of these are the same in SSH-1 and SSH-2. - * This list is derived from RFC 4254 and - * SSH-1 RFC-1.2.31. - */ - static const struct ssh_ttymode { +struct ssh_ttymodes get_ttymodes_from_conf(Seat *seat, Conf *conf) +{ + struct ssh_ttymodes modes; + size_t i; + + static const struct mode_name_type { const char *mode; int opcode; - enum { TTY_OP_CHAR, TTY_OP_BOOL } type; - } ssh_ttymodes[] = { - /* "V" prefix discarded for special characters relative to SSH specs */ - { "INTR", 1, TTY_OP_CHAR }, - { "QUIT", 2, TTY_OP_CHAR }, - { "ERASE", 3, TTY_OP_CHAR }, - { "KILL", 4, TTY_OP_CHAR }, - { "EOF", 5, TTY_OP_CHAR }, - { "EOL", 6, TTY_OP_CHAR }, - { "EOL2", 7, TTY_OP_CHAR }, - { "START", 8, TTY_OP_CHAR }, - { "STOP", 9, TTY_OP_CHAR }, - { "SUSP", 10, TTY_OP_CHAR }, - { "DSUSP", 11, TTY_OP_CHAR }, - { "REPRINT", 12, TTY_OP_CHAR }, - { "WERASE", 13, TTY_OP_CHAR }, - { "LNEXT", 14, TTY_OP_CHAR }, - { "FLUSH", 15, TTY_OP_CHAR }, - { "SWTCH", 16, TTY_OP_CHAR }, - { "STATUS", 17, TTY_OP_CHAR }, - { "DISCARD", 18, TTY_OP_CHAR }, - { "IGNPAR", 30, TTY_OP_BOOL }, - { "PARMRK", 31, TTY_OP_BOOL }, - { "INPCK", 32, TTY_OP_BOOL }, - { "ISTRIP", 33, TTY_OP_BOOL }, - { "INLCR", 34, TTY_OP_BOOL }, - { "IGNCR", 35, TTY_OP_BOOL }, - { "ICRNL", 36, TTY_OP_BOOL }, - { "IUCLC", 37, TTY_OP_BOOL }, - { "IXON", 38, TTY_OP_BOOL }, - { "IXANY", 39, TTY_OP_BOOL }, - { "IXOFF", 40, TTY_OP_BOOL }, - { "IMAXBEL", 41, TTY_OP_BOOL }, - { "IUTF8", 42, TTY_OP_BOOL }, - { "ISIG", 50, TTY_OP_BOOL }, - { "ICANON", 51, TTY_OP_BOOL }, - { "XCASE", 52, TTY_OP_BOOL }, - { "ECHO", 53, TTY_OP_BOOL }, - { "ECHOE", 54, TTY_OP_BOOL }, - { "ECHOK", 55, TTY_OP_BOOL }, - { "ECHONL", 56, TTY_OP_BOOL }, - { "NOFLSH", 57, TTY_OP_BOOL }, - { "TOSTOP", 58, TTY_OP_BOOL }, - { "IEXTEN", 59, TTY_OP_BOOL }, - { "ECHOCTL", 60, TTY_OP_BOOL }, - { "ECHOKE", 61, TTY_OP_BOOL }, - { "PENDIN", 62, TTY_OP_BOOL }, /* XXX is this a real mode? */ - { "OPOST", 70, TTY_OP_BOOL }, - { "OLCUC", 71, TTY_OP_BOOL }, - { "ONLCR", 72, TTY_OP_BOOL }, - { "OCRNL", 73, TTY_OP_BOOL }, - { "ONOCR", 74, TTY_OP_BOOL }, - { "ONLRET", 75, TTY_OP_BOOL }, - { "CS7", 90, TTY_OP_BOOL }, - { "CS8", 91, TTY_OP_BOOL }, - { "PARENB", 92, TTY_OP_BOOL }, - { "PARODD", 93, TTY_OP_BOOL } + enum { TYPE_CHAR, TYPE_BOOL } type; + } modes_names_types[] = { + #define TTYMODE_CHAR(name, val, index) { #name, val, TYPE_CHAR }, + #define TTYMODE_FLAG(name, val, field, mask) { #name, val, TYPE_BOOL }, + #include "sshttymodes.h" + #undef TTYMODE_CHAR + #undef TTYMODE_FLAG }; - /* Miscellaneous other tty-related constants. */ - enum { - /* The opcodes for ISPEED/OSPEED differ between SSH-1 and SSH-2. */ - SSH1_TTY_OP_ISPEED = 192, - SSH1_TTY_OP_OSPEED = 193, - SSH2_TTY_OP_ISPEED = 128, - SSH2_TTY_OP_OSPEED = 129, + memset(&modes, 0, sizeof(modes)); - SSH_TTY_OP_END = 0 - }; - - for (i = 0; i < lenof(ssh_ttymodes); i++) { - const struct ssh_ttymode *mode = ssh_ttymodes + i; + for (i = 0; i < lenof(modes_names_types); i++) { + const struct mode_name_type *mode = &modes_names_types[i]; const char *sval = conf_get_str_str(conf, CONF_ttymodes, mode->mode); char *to_free = NULL; - /* Every mode known to the current version of the code should be - * mentioned; this was ensured when settings were loaded. */ + if (!sval) + sval = "N"; /* just in case */ /* * sval[0] can be @@ -488,7 +434,7 @@ void write_ttymodes_to_packet_from_conf( unsigned ival = 0; switch (mode->type) { - case TTY_OP_CHAR: + case TYPE_CHAR: if (*sval) { char *next = NULL; /* We know ctrlparse won't write to the string, so @@ -500,7 +446,7 @@ void write_ttymodes_to_packet_from_conf( ival = 255; /* special value meaning "don't set" */ } break; - case TTY_OP_BOOL: + case TYPE_BOOL: if (stricmp(sval, "yes") == 0 || stricmp(sval, "on") == 0 || stricmp(sval, "true") == 0 || @@ -518,30 +464,48 @@ void write_ttymodes_to_packet_from_conf( assert(0 && "Bad mode->type"); } - /* - * And write it into the output packet. The parameter - * value is formatted as a byte in SSH-1, but a uint32 - * in SSH-2. - */ - put_byte(bs, mode->opcode); - if (ssh_version == 1) - put_byte(bs, ival); - else - put_uint32(bs, ival); + modes.have_mode[mode->opcode] = TRUE; + modes.mode_val[mode->opcode] = ival; } sfree(to_free); } - /* - * Finish off with the terminal speeds (which are formatted as - * uint32 in both protocol versions) and the end marker. - */ - put_byte(bs, ssh_version == 1 ? SSH1_TTY_OP_ISPEED : SSH2_TTY_OP_ISPEED); - put_uint32(bs, ispeed); - put_byte(bs, ssh_version == 1 ? SSH1_TTY_OP_OSPEED : SSH2_TTY_OP_OSPEED); - put_uint32(bs, ospeed); - put_byte(bs, SSH_TTY_OP_END); + { + unsigned ospeed, ispeed; + + /* Unpick the terminal-speed config string. */ + ospeed = ispeed = 38400; /* last-resort defaults */ + sscanf(conf_get_str(conf, CONF_termspeed), "%u,%u", &ospeed, &ispeed); + /* Currently we unconditionally set these */ + modes.have_mode[TTYMODE_ISPEED] = TRUE; + modes.mode_val[TTYMODE_ISPEED] = ispeed; + modes.have_mode[TTYMODE_OSPEED] = TRUE; + modes.mode_val[TTYMODE_OSPEED] = ospeed; + } + + return modes; +} + +void write_ttymodes_to_packet(BinarySink *bs, int ssh_version, + struct ssh_ttymodes modes) +{ + unsigned i; + + for (i = 0; i < TTYMODE_LIMIT; i++) { + if (modes.have_mode[i]) { + unsigned val = modes.mode_val[i]; + unsigned opcode = real_ttymode_opcode(i, ssh_version); + + put_byte(bs, opcode); + if (ssh_version == 1 && opcode >= 1 && opcode <= 127) + put_byte(bs, val); + else + put_uint32(bs, val); + } + } + + put_byte(bs, TTYMODE_END_OF_LIST); } /* ---------------------------------------------------------------------- diff --git a/sshttymodes.h b/sshttymodes.h new file mode 100644 index 00000000..8fffe1c5 --- /dev/null +++ b/sshttymodes.h @@ -0,0 +1,179 @@ +/* + * List of SSH terminal modes, indicating whether SSH types them as + * char or boolean, and if they're boolean, which POSIX flags field of + * a termios structure they appear in, and what bit mask removes them + * (e.g. CS7 and CS8 aren't single bits). + * + * Sources: RFC 4254, SSH-1 RFC-1.2.31, POSIX 2017, and the Linux + * termios manpage for flags not specified by POSIX. + * + * This is a separate header file rather than my usual style of a + * parametric list macro, because in this case I need to be able to + * #ifdef out each mode in case it's not defined on a particular + * target system. + * + * If you want only the locally defined modes, #define + * TTYMODES_LOCAL_ONLY before including this header. + */ +#if !defined TTYMODES_LOCAL_ONLY || defined VINTR +TTYMODE_CHAR(INTR, 1, VINTR) +#endif +#if !defined TTYMODES_LOCAL_ONLY || defined VQUIT +TTYMODE_CHAR(QUIT, 2, VQUIT) +#endif +#if !defined TTYMODES_LOCAL_ONLY || defined VERASE +TTYMODE_CHAR(ERASE, 3, VERASE) +#endif +#if !defined TTYMODES_LOCAL_ONLY || defined VKILL +TTYMODE_CHAR(KILL, 4, VKILL) +#endif +#if !defined TTYMODES_LOCAL_ONLY || defined VEOF +TTYMODE_CHAR(EOF, 5, VEOF) +#endif +#if !defined TTYMODES_LOCAL_ONLY || defined VEOL +TTYMODE_CHAR(EOL, 6, VEOL) +#endif +#if !defined TTYMODES_LOCAL_ONLY || defined VEOL2 +TTYMODE_CHAR(EOL2, 7, VEOL2) +#endif +#if !defined TTYMODES_LOCAL_ONLY || defined VSTART +TTYMODE_CHAR(START, 8, VSTART) +#endif +#if !defined TTYMODES_LOCAL_ONLY || defined VSTOP +TTYMODE_CHAR(STOP, 9, VSTOP) +#endif +#if !defined TTYMODES_LOCAL_ONLY || defined VSUSP +TTYMODE_CHAR(SUSP, 10, VSUSP) +#endif +#if !defined TTYMODES_LOCAL_ONLY || defined VDSUSP +TTYMODE_CHAR(DSUSP, 11, VDSUSP) +#endif +#if !defined TTYMODES_LOCAL_ONLY || defined VREPRINT +TTYMODE_CHAR(REPRINT, 12, VREPRINT) +#endif +#if !defined TTYMODES_LOCAL_ONLY || defined VWERASE +TTYMODE_CHAR(WERASE, 13, VWERASE) +#endif +#if !defined TTYMODES_LOCAL_ONLY || defined VLNEXT +TTYMODE_CHAR(LNEXT, 14, VLNEXT) +#endif +#if !defined TTYMODES_LOCAL_ONLY || defined VFLUSH +TTYMODE_CHAR(FLUSH, 15, VFLUSH) +#endif +#if !defined TTYMODES_LOCAL_ONLY || defined VSWTCH +TTYMODE_CHAR(SWTCH, 16, VSWTCH) +#endif +#if !defined TTYMODES_LOCAL_ONLY || defined VSTATUS +TTYMODE_CHAR(STATUS, 17, VSTATUS) +#endif +#if !defined TTYMODES_LOCAL_ONLY || defined VDISCARD +TTYMODE_CHAR(DISCARD, 18, VDISCARD) +#endif +#if !defined TTYMODES_LOCAL_ONLY || defined IGNPAR +TTYMODE_FLAG(IGNPAR, 30, i, IGNPAR) +#endif +#if !defined TTYMODES_LOCAL_ONLY || defined PARMRK +TTYMODE_FLAG(PARMRK, 31, i, PARMRK) +#endif +#if !defined TTYMODES_LOCAL_ONLY || defined INPCK +TTYMODE_FLAG(INPCK, 32, i, INPCK) +#endif +#if !defined TTYMODES_LOCAL_ONLY || defined ISTRIP +TTYMODE_FLAG(ISTRIP, 33, i, ISTRIP) +#endif +#if !defined TTYMODES_LOCAL_ONLY || defined INLCR +TTYMODE_FLAG(INLCR, 34, i, INLCR) +#endif +#if !defined TTYMODES_LOCAL_ONLY || defined IGNCR +TTYMODE_FLAG(IGNCR, 35, i, IGNCR) +#endif +#if !defined TTYMODES_LOCAL_ONLY || defined ICRNL +TTYMODE_FLAG(ICRNL, 36, i, ICRNL) +#endif +#if !defined TTYMODES_LOCAL_ONLY || defined IUCLC +TTYMODE_FLAG(IUCLC, 37, i, IUCLC) +#endif +#if !defined TTYMODES_LOCAL_ONLY || defined IXON +TTYMODE_FLAG(IXON, 38, i, IXON) +#endif +#if !defined TTYMODES_LOCAL_ONLY || defined IXANY +TTYMODE_FLAG(IXANY, 39, i, IXANY) +#endif +#if !defined TTYMODES_LOCAL_ONLY || defined IXOFF +TTYMODE_FLAG(IXOFF, 40, i, IXOFF) +#endif +#if !defined TTYMODES_LOCAL_ONLY || defined IMAXBEL +TTYMODE_FLAG(IMAXBEL, 41, i, IMAXBEL) +#endif +#if !defined TTYMODES_LOCAL_ONLY || defined IUTF8 +TTYMODE_FLAG(IUTF8, 42, i, IUTF8) +#endif +#if !defined TTYMODES_LOCAL_ONLY || defined ISIG +TTYMODE_FLAG(ISIG, 50, l, ISIG) +#endif +#if !defined TTYMODES_LOCAL_ONLY || defined ICANON +TTYMODE_FLAG(ICANON, 51, l, ICANON) +#endif +#if !defined TTYMODES_LOCAL_ONLY || defined XCASE +TTYMODE_FLAG(XCASE, 52, l, XCASE) +#endif +#if !defined TTYMODES_LOCAL_ONLY || defined ECHO +TTYMODE_FLAG(ECHO, 53, l, ECHO) +#endif +#if !defined TTYMODES_LOCAL_ONLY || defined ECHOE +TTYMODE_FLAG(ECHOE, 54, l, ECHOE) +#endif +#if !defined TTYMODES_LOCAL_ONLY || defined ECHOK +TTYMODE_FLAG(ECHOK, 55, l, ECHOK) +#endif +#if !defined TTYMODES_LOCAL_ONLY || defined ECHONL +TTYMODE_FLAG(ECHONL, 56, l, ECHONL) +#endif +#if !defined TTYMODES_LOCAL_ONLY || defined NOFLSH +TTYMODE_FLAG(NOFLSH, 57, l, NOFLSH) +#endif +#if !defined TTYMODES_LOCAL_ONLY || defined TOSTOP +TTYMODE_FLAG(TOSTOP, 58, l, TOSTOP) +#endif +#if !defined TTYMODES_LOCAL_ONLY || defined IEXTEN +TTYMODE_FLAG(IEXTEN, 59, l, IEXTEN) +#endif +#if !defined TTYMODES_LOCAL_ONLY || defined ECHOCTL +TTYMODE_FLAG(ECHOCTL, 60, l, ECHOCTL) +#endif +#if !defined TTYMODES_LOCAL_ONLY || defined ECHOKE +TTYMODE_FLAG(ECHOKE, 61, l, ECHOKE) +#endif +#if !defined TTYMODES_LOCAL_ONLY || defined PENDIN +TTYMODE_FLAG(PENDIN, 62, l, PENDIN) +#endif +#if !defined TTYMODES_LOCAL_ONLY || defined OPOST +TTYMODE_FLAG(OPOST, 70, o, OPOST) +#endif +#if !defined TTYMODES_LOCAL_ONLY || defined OLCUC +TTYMODE_FLAG(OLCUC, 71, o, OLCUC) +#endif +#if !defined TTYMODES_LOCAL_ONLY || defined ONLCR +TTYMODE_FLAG(ONLCR, 72, o, ONLCR) +#endif +#if !defined TTYMODES_LOCAL_ONLY || defined OCRNL +TTYMODE_FLAG(OCRNL, 73, o, OCRNL) +#endif +#if !defined TTYMODES_LOCAL_ONLY || defined ONOCR +TTYMODE_FLAG(ONOCR, 74, o, ONOCR) +#endif +#if !defined TTYMODES_LOCAL_ONLY || defined ONLRET +TTYMODE_FLAG(ONLRET, 75, o, ONLRET) +#endif +#if !defined TTYMODES_LOCAL_ONLY || defined CS7 +TTYMODE_FLAG(CS7, 90, c, CSIZE) +#endif +#if !defined TTYMODES_LOCAL_ONLY || defined CS8 +TTYMODE_FLAG(CS8, 91, c, CSIZE) +#endif +#if !defined TTYMODES_LOCAL_ONLY || defined PARENB +TTYMODE_FLAG(PARENB, 92, c, PARENB) +#endif +#if !defined TTYMODES_LOCAL_ONLY || defined PARODD +TTYMODE_FLAG(PARODD, 93, c, PARODD) +#endif From 72eca76d20674c4d8018c5e945f45a4f1a340943 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 14 Oct 2018 10:05:23 +0100 Subject: [PATCH 533/607] New system for handling SSH signals. This is in much the same style as the ttymodes revamp, using a header file which can be included in different ways to either iterate over _all_ the signals in the known list or just the ones for which a definition exists on the target OS. So this doesn't actually _remove_ the horrid pile of ifdefs in mainchan_rcvd_exit_signal, but at least it puts it somewhere less intrusive and more reusable. --- mainchan.c | 126 +++++++++++++-------------------------------------- putty.h | 13 ++++-- sshsignals.h | 53 ++++++++++++++++++++++ 3 files changed, 94 insertions(+), 98 deletions(-) create mode 100644 sshsignals.h diff --git a/mainchan.c b/mainchan.c index e1b75eb6..f70b7936 100644 --- a/mainchan.c +++ b/mainchan.c @@ -432,57 +432,20 @@ static int mainchan_rcvd_exit_signal( char *signame_str; /* - * Translate the signal description back into a locally - * meaningful number. + * Translate the signal description back into a locally meaningful + * number, or 128 if the string didn't match any we recognise. */ - - if (0) - ; -#define TRANSLATE_SIGNAL(s) \ - else if (ptrlen_eq_string(signame, #s)) \ - exitcode = 128 + SIG ## s -#ifdef SIGABRT - TRANSLATE_SIGNAL(ABRT); -#endif -#ifdef SIGALRM - TRANSLATE_SIGNAL(ALRM); -#endif -#ifdef SIGFPE - TRANSLATE_SIGNAL(FPE); -#endif -#ifdef SIGHUP - TRANSLATE_SIGNAL(HUP); -#endif -#ifdef SIGILL - TRANSLATE_SIGNAL(ILL); -#endif -#ifdef SIGINT - TRANSLATE_SIGNAL(INT); -#endif -#ifdef SIGKILL - TRANSLATE_SIGNAL(KILL); -#endif -#ifdef SIGPIPE - TRANSLATE_SIGNAL(PIPE); -#endif -#ifdef SIGQUIT - TRANSLATE_SIGNAL(QUIT); -#endif -#ifdef SIGSEGV - TRANSLATE_SIGNAL(SEGV); -#endif -#ifdef SIGTERM - TRANSLATE_SIGNAL(TERM); -#endif -#ifdef SIGUSR1 - TRANSLATE_SIGNAL(USR1); -#endif -#ifdef SIGUSR2 - TRANSLATE_SIGNAL(USR2); -#endif -#undef TRANSLATE_SIGNAL - else - exitcode = 128; + exitcode = 128; + + #define SIGNAL_SUB(s) \ + if (ptrlen_eq_string(signame, #s)) \ + exitcode = 128 + SIG ## s; + #define SIGNAL_MAIN(s, text) SIGNAL_SUB(s) + #define SIGNALS_LOCAL_ONLY + #include "sshsignals.h" + #undef SIGNAL_SUB + #undef SIGNAL_MAIN + #undef SIGNALS_LOCAL_ONLY ssh_got_exitcode(mc->ppl->ssh, exitcode); if (exitcode == 128) @@ -509,31 +472,6 @@ static int mainchan_rcvd_exit_signal_numeric( return TRUE; } -/* - * List of signal names defined by RFC 4254. These include all the ISO - * C signals, but are a subset of the POSIX required signals. - * - * The list macro takes parameters MAIN and SUB, which is an arbitrary - * UI decision to expose the signals we think users are most likely to - * want, with extra descriptive text, and relegate the less probable - * ones to a submenu for people who know what they're doing. - */ -#define SIGNAL_LIST(MAIN, SUB) \ - MAIN(INT, "Interrupt") \ - MAIN(TERM, "Terminate") \ - MAIN(KILL, "Kill") \ - MAIN(QUIT, "Quit") \ - MAIN(HUP, "Hangup") \ - SUB(ABRT) \ - SUB(ALRM) \ - SUB(FPE) \ - SUB(ILL) \ - SUB(PIPE) \ - SUB(SEGV) \ - SUB(USR1) \ - SUB(USR2) \ - /* end of list */ - void mainchan_get_specials( mainchan *mc, add_special_fn_t add_special, void *ctx) { @@ -541,36 +479,36 @@ void mainchan_get_specials( add_special(ctx, "Break", SS_BRK, 0); - #define ADD_MAIN(name, desc) \ + #define SIGNAL_MAIN(name, desc) \ add_special(ctx, "SIG" #name " (" desc ")", SS_SIG ## name, 0); - #define ADD_SUB(name) \ - add_special(ctx, "SIG" #name, SS_SIG ## name, 0); + #define SIGNAL_SUB(name) + #include "sshsignals.h" + #undef SIGNAL_MAIN + #undef SIGNAL_SUB - #define NO_ADD_SUB(name) - #define NO_ADD_MAIN(name, desc) - - SIGNAL_LIST(ADD_MAIN, NO_ADD_SUB); add_special(ctx, "More signals", SS_SUBMENU, 0); - SIGNAL_LIST(NO_ADD_MAIN, ADD_SUB); - add_special(ctx, NULL, SS_EXITMENU, 0); - #undef ADD_MAIN - #undef ADD_SUB - #undef NO_ADD_MAIN - #undef NO_ADD_SUB + #define SIGNAL_MAIN(name, desc) + #define SIGNAL_SUB(name) \ + add_special(ctx, "SIG" #name, SS_SIG ## name, 0); + #include "sshsignals.h" + #undef SIGNAL_MAIN + #undef SIGNAL_SUB + + add_special(ctx, NULL, SS_EXITMENU, 0); } static const char *ssh_signal_lookup(SessionSpecialCode code) { - #define CHECK_SUB(name) \ + #define SIGNAL_SUB(name) \ if (code == SS_SIG ## name) return #name; - #define CHECK_MAIN(name, desc) CHECK_SUB(name) + #define SIGNAL_MAIN(name, desc) SIGNAL_SUB(name) + #include "sshsignals.h" + #undef SIGNAL_MAIN + #undef SIGNAL_SUB - SIGNAL_LIST(CHECK_MAIN, CHECK_SUB); + /* If none of those clauses matched, fail lookup. */ return NULL; - - #undef CHECK_MAIN - #undef CHECK_SUB } void mainchan_special_cmd(mainchan *mc, SessionSpecialCode code, int arg) diff --git a/putty.h b/putty.h index dcf37286..6c380360 100644 --- a/putty.h +++ b/putty.h @@ -211,11 +211,16 @@ typedef enum { /* * Send a POSIX-style signal. (Useful in SSH and also pterm.) + * + * We use the master list in sshsignals.h to define these enum + * values, which will come out looking like names of the form + * SS_SIGABRT, SS_SIGINT etc. */ - SS_SIGABRT, SS_SIGALRM, SS_SIGFPE, SS_SIGHUP, SS_SIGILL, - SS_SIGINT, SS_SIGKILL, SS_SIGPIPE, SS_SIGQUIT, SS_SIGSEGV, - SS_SIGTERM, SS_SIGUSR1, SS_SIGUSR2, - + #define SIGNAL_MAIN(name, text) SS_SIG ## name, + #define SIGNAL_SUB(name) SS_SIG ## name, + #include "sshsignals.h" + #undef SIGNAL_MAIN + #undef SIGNAL_SUB /* * These aren't really special commands, but they appear in the diff --git a/sshsignals.h b/sshsignals.h new file mode 100644 index 00000000..b213c34f --- /dev/null +++ b/sshsignals.h @@ -0,0 +1,53 @@ +/* + * List of signal names known to SSH, indicating whether PuTTY's UI + * for special session commands likes to put them in the main specials + * menu or in a submenu (and if the former, what title they have). + * + * This is a separate header file rather than my usual style of a + * parametric list macro, because in this case I need to be able to + * #ifdef out each mode in case it's not defined on a particular + * target system. + * + * If you want only the locally defined signals, #define + * SIGNALS_LOCAL_ONLY before including this header. + */ + +#if !defined SIGNALS_LOCAL_ONLY || defined SIGINT +SIGNAL_MAIN(INT, "Interrupt") +#endif +#if !defined SIGNALS_LOCAL_ONLY || defined SIGTERM +SIGNAL_MAIN(TERM, "Terminate") +#endif +#if !defined SIGNALS_LOCAL_ONLY || defined SIGKILL +SIGNAL_MAIN(KILL, "Kill") +#endif +#if !defined SIGNALS_LOCAL_ONLY || defined SIGQUIT +SIGNAL_MAIN(QUIT, "Quit") +#endif +#if !defined SIGNALS_LOCAL_ONLY || defined SIGHUP +SIGNAL_MAIN(HUP, "Hangup") +#endif +#if !defined SIGNALS_LOCAL_ONLY || defined SIGABRT +SIGNAL_SUB(ABRT) +#endif +#if !defined SIGNALS_LOCAL_ONLY || defined SIGALRM +SIGNAL_SUB(ALRM) +#endif +#if !defined SIGNALS_LOCAL_ONLY || defined SIGFPE +SIGNAL_SUB(FPE) +#endif +#if !defined SIGNALS_LOCAL_ONLY || defined SIGILL +SIGNAL_SUB(ILL) +#endif +#if !defined SIGNALS_LOCAL_ONLY || defined SIGPIPE +SIGNAL_SUB(PIPE) +#endif +#if !defined SIGNALS_LOCAL_ONLY || defined SIGSEGV +SIGNAL_SUB(SEGV) +#endif +#if !defined SIGNALS_LOCAL_ONLY || defined SIGUSR1 +SIGNAL_SUB(USR1) +#endif +#if !defined SIGNALS_LOCAL_ONLY || defined SIGUSR2 +SIGNAL_SUB(USR2) +#endif From 79c4d3f3ee5e81ad743a0df02e8b1ff5d870581e Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 30 Sep 2018 11:22:01 +0100 Subject: [PATCH 534/607] Rewrite the SSH-1 main shell session using mainchan. In SSH-1, the channel system isn't rich enough to represent the complicated main shell session, so it's all done with a separate set of custom message types. But PuTTY now abstracts away that difference, by representing both as different implementations of the SshChannel class: ssh1channel is for things that the protocol thinks are 'really' channels, and ssh1mainchan is for the shell session. All the same methods are implemented, but generate different wire messages. This means that the logic to decide _when_ to enable X forwarding, agent forwarding etc is all centralised into mainchan.c, where it doesn't have to be repeated for both protocol versions. It also simplifies the final loop in the connection protocol, which no longer has to contain the code to move data from the user input bufchain to the channel's output; that's now done by the mainchan write method, the same as it is in SSH-2 where mainchan is just like other channels. --- mainchan.c | 2 +- ssh1connection.c | 558 +++++++++++++++++++++++++++++++---------------- 2 files changed, 371 insertions(+), 189 deletions(-) diff --git a/mainchan.c b/mainchan.c index f70b7936..c8963883 100644 --- a/mainchan.c +++ b/mainchan.c @@ -95,7 +95,7 @@ mainchan *mainchan_new( mc->type = MAINCHAN_SESSION; } - *sc_out = mc->sc; + if (sc_out) *sc_out = mc->sc; return mc; } diff --git a/ssh1connection.c b/ssh1connection.c index c7e284b6..d406ea33 100644 --- a/ssh1connection.c +++ b/ssh1connection.c @@ -26,11 +26,20 @@ struct ssh1_connection_state { tree234 *channels; /* indexed by local id */ + /* In SSH-1, the main session doesn't take the form of a 'channel' + * according to the wire protocol. But we want to use the same API + * for it, so we define an SshChannel here - but one that uses a + * separate vtable from the usual one, so it doesn't map to a + * struct ssh1_channel as all the others do. */ + SshChannel mainchan_sc; + Channel *mainchan_chan; /* the other end of mainchan_sc */ + mainchan *mainchan; /* and its subtype */ + int got_pty; - int echoedit; + int ldisc_opts[LD_N_OPTIONS]; int stdout_throttling; - int session_ready; - int session_eof_pending, session_eof_sent, session_terminated; + int want_user_input; + int session_terminated; int term_width, term_height, term_width_orig, term_height_orig; int X11_fwd_enabled; @@ -101,19 +110,26 @@ static void ssh1_rportfwd_remove( static SshChannel *ssh1_lportfwd_open( ConnectionLayer *cl, const char *hostname, int port, const char *org, Channel *chan); +static SshChannel *ssh1_session_open(ConnectionLayer *cl, Channel *chan); +static struct X11FakeAuth *ssh1_add_x11_display( + ConnectionLayer *cl, int authtype, struct X11Display *disp); static int ssh1_agent_forwarding_permitted(ConnectionLayer *cl); static void ssh1_terminal_size(ConnectionLayer *cl, int width, int height); static void ssh1_stdout_unthrottle(ConnectionLayer *cl, int bufsize); static int ssh1_stdin_backlog(ConnectionLayer *cl); static void ssh1_throttle_all_channels(ConnectionLayer *cl, int throttled); static int ssh1_ldisc_option(ConnectionLayer *cl, int option); +static void ssh1_set_ldisc_option(ConnectionLayer *cl, int option, int value); +static void ssh1_enable_x_fwd(ConnectionLayer *cl); +static void ssh1_enable_agent_fwd(ConnectionLayer *cl); +static void ssh1_set_wants_user_input(ConnectionLayer *cl, int wanted); static const struct ConnectionLayerVtable ssh1_connlayer_vtable = { ssh1_rportfwd_alloc, ssh1_rportfwd_remove, ssh1_lportfwd_open, - NULL /* session_open */, - NULL /* add_x11_display */, + ssh1_session_open, + ssh1_add_x11_display, NULL /* add_sharing_x11_display */, NULL /* remove_sharing_x11_display */, NULL /* send_packet_from_downstream */, @@ -127,10 +143,10 @@ static const struct ConnectionLayerVtable ssh1_connlayer_vtable = { ssh1_stdin_backlog, ssh1_throttle_all_channels, ssh1_ldisc_option, - NULL /* set_ldisc_option */, - NULL /* enable_x_fwd */, - NULL /* enable_agent_fwd */, - NULL /* set_wants_user_input */, + ssh1_set_ldisc_option, + ssh1_enable_x_fwd, + ssh1_enable_agent_fwd, + ssh1_set_wants_user_input, }; struct ssh1_channel { @@ -205,6 +221,54 @@ static const struct SshChannelVtable ssh1channel_vtable = { NULL /* hint_channel_is_simple */, }; +static void ssh1mainchan_request_x11_forwarding( + SshChannel *c, int want_reply, const char *authproto, + const char *authdata, int screen_number, int oneshot); +static void ssh1mainchan_request_agent_forwarding( + SshChannel *c, int want_reply); +static void ssh1mainchan_request_pty( + SshChannel *c, int want_reply, Conf *conf, int w, int h); +static int ssh1mainchan_send_env_var( + SshChannel *c, int want_reply, const char *var, const char *value); +static void ssh1mainchan_start_shell( + SshChannel *c, int want_reply); +static void ssh1mainchan_start_command( + SshChannel *c, int want_reply, const char *command); +static int ssh1mainchan_start_subsystem( + SshChannel *c, int want_reply, const char *subsystem); +static int ssh1mainchan_send_env_var( + SshChannel *c, int want_reply, const char *var, const char *value); +static int ssh1mainchan_send_serial_break( + SshChannel *c, int want_reply, int length); +static int ssh1mainchan_send_signal( + SshChannel *c, int want_reply, const char *signame); +static void ssh1mainchan_send_terminal_size_change( + SshChannel *c, int w, int h); +static void ssh1mainchan_hint_channel_is_simple(SshChannel *c); +static int ssh1mainchan_write(SshChannel *sc, const void *data, int len); +static void ssh1mainchan_write_eof(SshChannel *sc); + +static const struct SshChannelVtable ssh1mainchan_vtable = { + ssh1mainchan_write, + ssh1mainchan_write_eof, + NULL /* unclean_close */, + NULL /* unthrottle */, + NULL /* get_conf */, + NULL /* window_override_removed is only used by SSH-2 sharing */, + NULL /* x11_sharing_handover, likewise */, + ssh1mainchan_request_x11_forwarding, + ssh1mainchan_request_agent_forwarding, + ssh1mainchan_request_pty, + ssh1mainchan_send_env_var, + ssh1mainchan_start_shell, + ssh1mainchan_start_command, + ssh1mainchan_start_subsystem, + ssh1mainchan_send_serial_break, + ssh1mainchan_send_signal, + ssh1mainchan_send_terminal_size_change, + ssh1mainchan_hint_channel_is_simple, +}; + static void ssh1_channel_init(struct ssh1_channel *c); static void ssh1_channel_try_eof(struct ssh1_channel *c); static void ssh1_channel_close_local(struct ssh1_channel *c, @@ -215,24 +279,60 @@ static void ssh1_channel_check_close(struct ssh1_channel *c); static int ssh1_check_termination(struct ssh1_connection_state *s); typedef void (*sf_handler_fn_t)(struct ssh1_connection_state *s, - PktIn *pktin, void *ctx); + int success, void *ctx); struct outstanding_succfail { sf_handler_fn_t handler; void *ctx; struct outstanding_succfail *next; + + /* + * The 'trivial' flag is set if this handler is in response to a + * request for which the SSH-1 protocol doesn't actually specify a + * response packet. The client of this system (mainchan.c) will + * expect to get an acknowledgment regardless, so we arrange to + * send that ack immediately after the rest of the queue empties. + */ + int trivial; }; + +static void ssh1_connection_process_trivial_succfails(void *vs); + static void ssh1_queue_succfail_handler( - struct ssh1_connection_state *s, sf_handler_fn_t handler, void *ctx) + struct ssh1_connection_state *s, sf_handler_fn_t handler, void *ctx, + int trivial) { struct outstanding_succfail *osf = snew(struct outstanding_succfail); osf->handler = handler; osf->ctx = ctx; + osf->trivial = trivial; if (s->succfail_tail) s->succfail_tail->next = osf; else s->succfail_head = osf; s->succfail_tail = osf; + + /* In case this one was trivial and the queue was already empty, + * we should make sure we run the handler promptly, and the + * easiest way is to queue it anyway and then run a trivials pass + * by callback. */ + queue_toplevel_callback(ssh1_connection_process_trivial_succfails, s); +} + +static void ssh1_connection_process_succfail( + struct ssh1_connection_state *s, int success) +{ + struct outstanding_succfail *prevhead = s->succfail_head; + s->succfail_head = s->succfail_head->next; + prevhead->handler(s, success, prevhead->ctx); + sfree(prevhead); +} + +static void ssh1_connection_process_trivial_succfails(void *vs) +{ + struct ssh1_connection_state *s = (struct ssh1_connection_state *)vs; + while (s->succfail_head && s->succfail_head->trivial) + ssh1_connection_process_succfail(s, TRUE); } static int ssh1_channelcmp(void *av, void *bv) @@ -315,6 +415,8 @@ static void ssh1_connection_free(PacketProtocolLayer *ppl) freetree234(s->rportfwds); portfwdmgr_free(s->portfwdmgr); + delete_callbacks_for_context(s); + sfree(s); } @@ -363,12 +465,10 @@ static int ssh1_connection_filter_queue(struct ssh1_connection_state *s) return TRUE; } - s->succfail_head->handler(s, pktin, s->succfail_head->ctx); - { - struct outstanding_succfail *tmp = s->succfail_head; - s->succfail_head = s->succfail_head->next; - sfree(tmp); - } + ssh1_connection_process_succfail( + s, pktin->type == SSH1_SMSG_SUCCESS); + queue_toplevel_callback( + ssh1_connection_process_trivial_succfails, s); pq_pop(s->ppl.in_pq); break; @@ -638,147 +738,23 @@ static void ssh1_connection_process_queue(PacketProtocolLayer *ppl) struct ssh1_connection_state *s = container_of(ppl, struct ssh1_connection_state, ppl); PktIn *pktin; - PktOut *pktout; if (ssh1_connection_filter_queue(s)) /* no matter why we were called */ return; crBegin(s->crState); - if (ssh_agent_forwarding_permitted(&s->cl)) { - ppl_logevent(("Requesting agent forwarding")); - pktout = ssh_bpp_new_pktout(s->ppl.bpp, - SSH1_CMSG_AGENT_REQUEST_FORWARDING); - pq_push(s->ppl.out_pq, pktout); - crMaybeWaitUntilV((pktin = ssh1_connection_pop(s)) != NULL); - if (pktin->type == SSH1_SMSG_SUCCESS) { - ppl_logevent(("Agent forwarding enabled")); - s->agent_fwd_enabled = TRUE; - } else if (pktin->type == SSH1_SMSG_FAILURE) { - ppl_logevent(("Agent forwarding refused")); - } else { - ssh_proto_error(s->ppl.ssh, "Unexpected packet received" - " in response to agent forwarding request, " - "type %d (%s)", pktin->type, - ssh1_pkt_type(pktin->type)); - return; - } - } - - if (conf_get_int(s->conf, CONF_x11_forward)) { - char *x11_setup_err; - - s->x11disp = - x11_setup_display(conf_get_str(s->conf, CONF_x11_display), - s->conf, &x11_setup_err); - if (!s->x11disp) { - ppl_logevent(("X11 forwarding not enabled: unable to" - " initialise X display: %s", x11_setup_err)); - sfree(x11_setup_err); - } else { - s->x11auth = x11_invent_fake_auth - (s->x11authtree, conf_get_int(s->conf, CONF_x11_auth)); - s->x11auth->disp = s->x11disp; - - ppl_logevent(("Requesting X11 forwarding")); - pktout = ssh_bpp_new_pktout( - s->ppl.bpp, SSH1_CMSG_X11_REQUEST_FORWARDING); - put_stringz(pktout, s->x11auth->protoname); - put_stringz(pktout, s->x11auth->datastring); - if (s->local_protoflags & SSH1_PROTOFLAG_SCREEN_NUMBER) - put_uint32(pktout, s->x11disp->screennum); - pq_push(s->ppl.out_pq, pktout); - crMaybeWaitUntilV((pktin = ssh1_connection_pop(s)) != NULL); - if (pktin->type == SSH1_SMSG_SUCCESS) { - ppl_logevent(("X11 forwarding enabled")); - s->X11_fwd_enabled = TRUE; - } else if (pktin->type == SSH1_SMSG_FAILURE) { - ppl_logevent(("X11 forwarding refused")); - } else { - ssh_proto_error(s->ppl.ssh, "Unexpected packet received" - " in response to X11 forwarding request, " - "type %d (%s)", pktin->type, - ssh1_pkt_type(pktin->type)); - return; - } - } - } - portfwdmgr_config(s->portfwdmgr, s->conf); s->portfwdmgr_configured = TRUE; - if (!conf_get_int(s->conf, CONF_nopty)) { - /* Send the pty request. */ - pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_REQUEST_PTY); - put_stringz(pktout, conf_get_str(s->conf, CONF_termtype)); - put_uint32(pktout, s->term_height); - put_uint32(pktout, s->term_width); - s->term_width_orig = s->term_width; - s->term_height_orig = s->term_height; - put_uint32(pktout, 0); /* width in pixels */ - put_uint32(pktout, 0); /* height in pixels */ - write_ttymodes_to_packet( - BinarySink_UPCAST(pktout), 1, - get_ttymodes_from_conf(s->ppl.seat, s->conf)); - pq_push(s->ppl.out_pq, pktout); - crMaybeWaitUntilV((pktin = ssh1_connection_pop(s)) != NULL); - if (pktin->type == SSH1_SMSG_SUCCESS) { - ppl_logevent(("Allocated pty")); - s->got_pty = TRUE; - } else if (pktin->type == SSH1_SMSG_FAILURE) { - ppl_printf(("Server refused to allocate pty\r\n")); - s->echoedit = TRUE; - } else { - ssh_proto_error(s->ppl.ssh, "Unexpected packet received" - " in response to pty request, " - "type %d (%s)", pktin->type, - ssh1_pkt_type(pktin->type)); - crStopV; - } - } else { - s->echoedit = TRUE; - } - /* - * Start the shell or command. - * - * Special case: if the first-choice command is an SSH-2 - * subsystem (hence not usable here) and the second choice - * exists, we fall straight back to that. + * Start up the main session, by telling mainchan.c to do it all + * just as it would in SSH-2, and translating those concepts to + * SSH-1's non-channel-shaped idea of the main session. */ - { - char *cmd = conf_get_str(s->conf, CONF_remote_cmd); - - if (conf_get_int(s->conf, CONF_ssh_subsys) && - conf_get_str(s->conf, CONF_remote_cmd2)) { - cmd = conf_get_str(s->conf, CONF_remote_cmd2); - ssh_got_fallback_cmd(s->ppl.ssh); - } - if (*cmd) { - pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_EXEC_CMD); - put_stringz(pktout, cmd); - } else { - pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_EXEC_SHELL); - } - pq_push(s->ppl.out_pq, pktout); - ppl_logevent(("Started session")); - } - - s->session_ready = TRUE; - ssh_ppl_got_user_input(&s->ppl); /* in case any input is already queued */ - - /* If an EOF or a window-size change arrived before we were ready - * to handle either one, handle them now. */ - if (s->session_eof_pending) { - ssh_ppl_special_cmd(&s->ppl, SS_EOF, 0); - s->session_eof_pending = FALSE; - } - if (s->term_width_orig != s->term_width || - s->term_height_orig != s->term_height) - ssh_terminal_size(&s->cl, s->term_width, s->term_height); - - ssh_ldisc_update(s->ppl.ssh); - s->finished_setup = TRUE; + s->mainchan = mainchan_new( + &s->ppl, &s->cl, s->conf, s->term_width, s->term_height, + FALSE /* is_simple */, NULL); while (1) { @@ -794,17 +770,6 @@ static void ssh1_connection_process_queue(PacketProtocolLayer *ppl) ssh1_pkt_type(pktin->type)); return; } - while (bufchain_size(s->ppl.user_input) > 0) { - void *data; - int len; - bufchain_prefix(s->ppl.user_input, &data, &len); - if (len > 512) - len = 512; - pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_STDIN_DATA); - put_string(pktout, data, len); - pq_push(s->ppl.out_pq, pktout); - bufchain_consume(s->ppl.user_input, len); - } crReturnV; } @@ -1018,6 +983,197 @@ static int ssh1channel_write(SshChannel *sc, const void *buf, int len) return 0; } +static struct X11FakeAuth *ssh1_add_x11_display( + ConnectionLayer *cl, int authtype, struct X11Display *disp) +{ + struct ssh1_connection_state *s = + container_of(cl, struct ssh1_connection_state, cl); + struct X11FakeAuth *auth = x11_invent_fake_auth(s->x11authtree, authtype); + auth->disp = disp; + return auth; +} + +static void ssh1mainchan_succfail_wantreply(struct ssh1_connection_state *s, + int success, void *ctx) +{ + chan_request_response(s->mainchan_chan, success); +} + +static void ssh1mainchan_succfail_nowantreply(struct ssh1_connection_state *s, + int success, void *ctx) +{ +} + +static void ssh1mainchan_queue_response(struct ssh1_connection_state *s, + int want_reply, int trivial) +{ + sf_handler_fn_t handler = (want_reply ? ssh1mainchan_succfail_wantreply : + ssh1mainchan_succfail_nowantreply); + ssh1_queue_succfail_handler(s, handler, NULL, trivial); +} + +static void ssh1mainchan_request_x11_forwarding( + SshChannel *sc, int want_reply, const char *authproto, + const char *authdata, int screen_number, int oneshot) +{ + struct ssh1_connection_state *s = + container_of(sc, struct ssh1_connection_state, mainchan_sc); + PktOut *pktout; + + pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_X11_REQUEST_FORWARDING); + put_stringz(pktout, authproto); + put_stringz(pktout, authdata); + if (s->local_protoflags & SSH1_PROTOFLAG_SCREEN_NUMBER) + put_uint32(pktout, screen_number); + pq_push(s->ppl.out_pq, pktout); + + ssh1mainchan_queue_response(s, want_reply, FALSE); +} + +static void ssh1mainchan_request_agent_forwarding( + SshChannel *sc, int want_reply) +{ + struct ssh1_connection_state *s = + container_of(sc, struct ssh1_connection_state, mainchan_sc); + PktOut *pktout; + + pktout = ssh_bpp_new_pktout( + s->ppl.bpp, SSH1_CMSG_AGENT_REQUEST_FORWARDING); + pq_push(s->ppl.out_pq, pktout); + + ssh1mainchan_queue_response(s, want_reply, FALSE); +} + +static void ssh1mainchan_request_pty( + SshChannel *sc, int want_reply, Conf *conf, int w, int h) +{ + struct ssh1_connection_state *s = + container_of(sc, struct ssh1_connection_state, mainchan_sc); + PktOut *pktout; + + pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_REQUEST_PTY); + put_stringz(pktout, conf_get_str(s->conf, CONF_termtype)); + put_uint32(pktout, h); + put_uint32(pktout, w); + put_uint32(pktout, 0); /* width in pixels */ + put_uint32(pktout, 0); /* height in pixels */ + write_ttymodes_to_packet( + BinarySink_UPCAST(pktout), 1, + get_ttymodes_from_conf(s->ppl.seat, conf)); + pq_push(s->ppl.out_pq, pktout); + + ssh1mainchan_queue_response(s, want_reply, FALSE); +} + +static int ssh1mainchan_send_env_var( + SshChannel *sc, int want_reply, const char *var, const char *value) +{ + return FALSE; /* SSH-1 doesn't support this at all */ +} + +static void ssh1mainchan_start_shell( + SshChannel *sc, int want_reply) +{ + struct ssh1_connection_state *s = + container_of(sc, struct ssh1_connection_state, mainchan_sc); + PktOut *pktout; + + pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_EXEC_SHELL); + pq_push(s->ppl.out_pq, pktout); + + ssh1mainchan_queue_response(s, want_reply, TRUE); +} + +static void ssh1mainchan_start_command( + SshChannel *sc, int want_reply, const char *command) +{ + struct ssh1_connection_state *s = + container_of(sc, struct ssh1_connection_state, mainchan_sc); + PktOut *pktout; + + pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_EXEC_CMD); + put_stringz(pktout, command); + pq_push(s->ppl.out_pq, pktout); + + ssh1mainchan_queue_response(s, want_reply, TRUE); +} + +static int ssh1mainchan_start_subsystem( + SshChannel *sc, int want_reply, const char *subsystem) +{ + return FALSE; /* SSH-1 doesn't support this at all */ +} + +static int ssh1mainchan_send_serial_break( + SshChannel *sc, int want_reply, int length) +{ + return FALSE; /* SSH-1 doesn't support this at all */ +} + +static int ssh1mainchan_send_signal( + SshChannel *sc, int want_reply, const char *signame) +{ + return FALSE; /* SSH-1 doesn't support this at all */ +} + +static void ssh1mainchan_send_terminal_size_change(SshChannel *sc, int w, int h) +{ + struct ssh1_connection_state *s = + container_of(sc, struct ssh1_connection_state, mainchan_sc); + PktOut *pktout; + + pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_WINDOW_SIZE); + put_uint32(pktout, h); + put_uint32(pktout, w); + put_uint32(pktout, 0); /* width in pixels */ + put_uint32(pktout, 0); /* height in pixels */ + pq_push(s->ppl.out_pq, pktout); +} + +static void ssh1mainchan_hint_channel_is_simple(SshChannel *c) +{ +} + +static int ssh1mainchan_write(SshChannel *sc, const void *data, int len) +{ + struct ssh1_connection_state *s = + container_of(sc, struct ssh1_connection_state, mainchan_sc); + PktOut *pktout; + + pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_STDIN_DATA); + put_string(pktout, data, len); + pq_push(s->ppl.out_pq, pktout); + + return 0; +} + +static void ssh1mainchan_write_eof(SshChannel *sc) +{ + struct ssh1_connection_state *s = + container_of(sc, struct ssh1_connection_state, mainchan_sc); + PktOut *pktout; + + pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_EOF); + pq_push(s->ppl.out_pq, pktout); +} + +static void ssh1_session_confirm_callback(void *vctx) +{ + struct ssh1_connection_state *s = (struct ssh1_connection_state *)vctx; + chan_open_confirmation(s->mainchan_chan); +} + +static SshChannel *ssh1_session_open(ConnectionLayer *cl, Channel *chan) +{ + struct ssh1_connection_state *s = + container_of(cl, struct ssh1_connection_state, cl); + s->mainchan_sc.cl = &s->cl; + s->mainchan_sc.vt = &ssh1mainchan_vtable; + s->mainchan_chan = chan; + queue_toplevel_callback(ssh1_session_confirm_callback, s); + return &s->mainchan_sc; +} + static SshChannel *ssh1_lportfwd_open( ConnectionLayer *cl, const char *hostname, int port, const char *org, Channel *chan) @@ -1047,12 +1203,12 @@ static SshChannel *ssh1_lportfwd_open( } static void ssh1_rportfwd_response(struct ssh1_connection_state *s, - PktIn *pktin, void *ctx) + int success, void *ctx) { PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */ struct ssh_rportfwd *rpf = (struct ssh_rportfwd *)ctx; - if (pktin->type == SSH1_SMSG_SUCCESS) { + if (success) { ppl_logevent(("Remote port forwarding from %s enabled", rpf->log_description)); } else { @@ -1096,7 +1252,7 @@ static struct ssh_rportfwd *ssh1_rportfwd_alloc( put_uint32(pktout, rpf->dport); pq_push(s->ppl.out_pq, pktout); - ssh1_queue_succfail_handler(s, ssh1_rportfwd_response, rpf); + ssh1_queue_succfail_handler(s, ssh1_rportfwd_response, rpf, FALSE); return rpf; } @@ -1129,19 +1285,8 @@ static void ssh1_connection_special_cmd(PacketProtocolLayer *ppl, put_stringz(pktout, ""); pq_push(s->ppl.out_pq, pktout); } - } else if (code == SS_EOF) { - if (!s->session_ready) { - /* - * Buffer the EOF to send as soon as the main session is - * fully set up. - */ - s->session_eof_pending = TRUE; - } else if (!s->session_eof_sent) { - pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_EOF); - pq_push(s->ppl.out_pq, pktout); - ppl_logevent(("Sent EOF message")); - s->session_eof_sent = TRUE; - } + } else if (s->mainchan) { + mainchan_special_cmd(s->mainchan, code, arg); } } @@ -1152,15 +1297,8 @@ static void ssh1_terminal_size(ConnectionLayer *cl, int width, int height) s->term_width = width; s->term_height = height; - - if (s->session_ready) { - PktOut *pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_WINDOW_SIZE); - put_uint32(pktout, s->term_height); - put_uint32(pktout, s->term_width); - put_uint32(pktout, 0); - put_uint32(pktout, 0); - pq_push(s->ppl.out_pq, pktout); - } + if (s->mainchan) + mainchan_terminal_size(s->mainchan, width, height); } static void ssh1_stdout_unthrottle(ConnectionLayer *cl, int bufsize) @@ -1195,23 +1333,67 @@ static int ssh1_ldisc_option(ConnectionLayer *cl, int option) struct ssh1_connection_state *s = container_of(cl, struct ssh1_connection_state, cl); - /* We always return the same value for LD_ECHO and LD_EDIT */ - return s->echoedit; + return s->ldisc_opts[option]; +} + +static void ssh1_set_ldisc_option(ConnectionLayer *cl, int option, int value) +{ + struct ssh1_connection_state *s = + container_of(cl, struct ssh1_connection_state, cl); + + s->ldisc_opts[option] = value; +} + +static void ssh1_enable_x_fwd(ConnectionLayer *cl) +{ + struct ssh1_connection_state *s = + container_of(cl, struct ssh1_connection_state, cl); + + s->X11_fwd_enabled = TRUE; +} + +static void ssh1_enable_agent_fwd(ConnectionLayer *cl) +{ + struct ssh1_connection_state *s = + container_of(cl, struct ssh1_connection_state, cl); + + s->agent_fwd_enabled = TRUE; +} + +static void ssh1_set_wants_user_input(ConnectionLayer *cl, int wanted) +{ + struct ssh1_connection_state *s = + container_of(cl, struct ssh1_connection_state, cl); + + s->want_user_input = wanted; + s->finished_setup = TRUE; } static int ssh1_connection_want_user_input(PacketProtocolLayer *ppl) { struct ssh1_connection_state *s = container_of(ppl, struct ssh1_connection_state, ppl); - return s->session_ready && !s->session_eof_sent; + + return s->want_user_input; } static void ssh1_connection_got_user_input(PacketProtocolLayer *ppl) { struct ssh1_connection_state *s = container_of(ppl, struct ssh1_connection_state, ppl); - if (s->session_ready && !s->session_eof_sent) - queue_idempotent_callback(&s->ppl.ic_process_queue); + + while (s->mainchan && bufchain_size(s->ppl.user_input) > 0) { + /* + * Add user input to the main channel's buffer. + */ + void *data; + int len; + bufchain_prefix(s->ppl.user_input, &data, &len); + if (len > 512) + len = 512; + sshfwd_write(&s->mainchan_sc, data, len); + bufchain_consume(s->ppl.user_input, len); + } } static void ssh1_connection_reconfigure(PacketProtocolLayer *ppl, Conf *conf) From fe26ddb1d9432fafe841d823991c05942b02a339 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 6 Oct 2018 13:32:17 +0100 Subject: [PATCH 535/607] Move transient host key cache into its own file. This is a nice standalone piece of code which doesn't really have to appear in the middle of ssh2transport. --- Recipe | 2 +- ssh.h | 11 ++++ ssh2transhk.c | 124 ++++++++++++++++++++++++++++++++++++++++ ssh2transport.c | 149 ++++-------------------------------------------- 4 files changed, 146 insertions(+), 140 deletions(-) create mode 100644 ssh2transhk.c diff --git a/Recipe b/Recipe index 4aff0ab8..a18445e3 100644 --- a/Recipe +++ b/Recipe @@ -256,7 +256,7 @@ SSH = ssh sshcommon ssh1bpp ssh2bpp ssh2bpp-bare ssh1censor ssh2censor + sshdh sshcrcda sshpubk sshzlib sshdss x11fwd portfwd + sshaes sshccp sshsh256 sshsh512 sshbn wildcard pinger ssharcf + sshgssc pgssapi sshshare sshecc aqsync marshal nullplug agentf - + sshmac mainchan + + sshmac mainchan ssh2transhk WINSSH = SSH winnoise wincapi winpgntc wingss winshare winnps winnpc + winhsock errsock UXSSH = SSH uxnoise uxagentc uxgss uxshare diff --git a/ssh.h b/ssh.h index 670fdb68..180d8456 100644 --- a/ssh.h +++ b/ssh.h @@ -1482,3 +1482,14 @@ void add_to_commasep(strbuf *buf, const char *data); int verify_ssh_manual_host_key( Conf *conf, const char *fingerprint, ssh_key *key); + +typedef struct ssh_transient_hostkey_cache ssh_transient_hostkey_cache; +ssh_transient_hostkey_cache *ssh_transient_hostkey_cache_new(void); +void ssh_transient_hostkey_cache_free(ssh_transient_hostkey_cache *thc); +void ssh_transient_hostkey_cache_add( + ssh_transient_hostkey_cache *thc, ssh_key *key); +int ssh_transient_hostkey_cache_verify( + ssh_transient_hostkey_cache *thc, ssh_key *key); +int ssh_transient_hostkey_cache_has( + ssh_transient_hostkey_cache *thc, const ssh_keyalg *alg); +int ssh_transient_hostkey_cache_non_empty(ssh_transient_hostkey_cache *thc); diff --git a/ssh2transhk.c b/ssh2transhk.c new file mode 100644 index 00000000..6551f73f --- /dev/null +++ b/ssh2transhk.c @@ -0,0 +1,124 @@ +/* + * Data structure managing host keys in sessions based on GSSAPI KEX. + * + * In a session we started with a GSSAPI key exchange, the concept of + * 'host key' has completely different lifetime and security semantics + * from the usual ones. Per RFC 4462 section 2.1, we assume that any + * host key delivered to us in the course of a GSSAPI key exchange is + * _solely_ there to use as a transient fallback within the same + * session, if at the time of a subsequent rekey the GSS credentials + * are temporarily invalid and so a non-GSS KEX method has to be used. + * + * In particular, in a GSS-based SSH deployment, host keys may not + * even _be_ persistent identities for the server; it would be + * legitimate for a server to generate a fresh one routinely if it + * wanted to, like SSH-1 server keys. + * + * So, in this mode, we never touch the persistent host key cache at + * all, either to check keys against it _or_ to store keys in it. + * Instead, we maintain an in-memory cache of host keys that have been + * mentioned in GSS key exchanges within this particular session, and + * we permit precisely those host keys in non-GSS rekeys. + */ + +#include + +#include "putty.h" +#include "ssh.h" + +struct ssh_transient_hostkey_cache { + tree234 *cache; +}; + +struct ssh_transient_hostkey_cache_entry { + const ssh_keyalg *alg; + strbuf *pub_blob; +}; + +static int ssh_transient_hostkey_cache_cmp(void *av, void *bv) +{ + const struct ssh_transient_hostkey_cache_entry + *a = (const struct ssh_transient_hostkey_cache_entry *)av, + *b = (const struct ssh_transient_hostkey_cache_entry *)bv; + return strcmp(a->alg->ssh_id, b->alg->ssh_id); +} + +static int ssh_transient_hostkey_cache_find(void *av, void *bv) +{ + const ssh_keyalg *aalg = (const ssh_keyalg *)av; + const struct ssh_transient_hostkey_cache_entry + *b = (const struct ssh_transient_hostkey_cache_entry *)bv; + return strcmp(aalg->ssh_id, b->alg->ssh_id); +} + +ssh_transient_hostkey_cache *ssh_transient_hostkey_cache_new(void) +{ + ssh_transient_hostkey_cache *thc = snew(ssh_transient_hostkey_cache); + thc->cache = newtree234(ssh_transient_hostkey_cache_cmp); + return thc; +} + +void ssh_transient_hostkey_cache_free(ssh_transient_hostkey_cache *thc) +{ + struct ssh_transient_hostkey_cache_entry *ent; + while ((ent = delpos234(thc->cache, 0)) != NULL) { + strbuf_free(ent->pub_blob); + sfree(ent); + } + freetree234(thc->cache); +} + +void ssh_transient_hostkey_cache_add( + ssh_transient_hostkey_cache *thc, ssh_key *key) +{ + struct ssh_transient_hostkey_cache_entry *ent, *retd; + + if ((ent = find234(thc->cache, (void *)ssh_key_alg(key), + ssh_transient_hostkey_cache_find)) != NULL) { + strbuf_free(ent->pub_blob); + sfree(ent); + } + + ent = snew(struct ssh_transient_hostkey_cache_entry); + ent->alg = ssh_key_alg(key); + ent->pub_blob = strbuf_new(); + ssh_key_public_blob(key, BinarySink_UPCAST(ent->pub_blob)); + retd = add234(thc->cache, ent); + assert(retd == ent); +} + +int ssh_transient_hostkey_cache_verify( + ssh_transient_hostkey_cache *thc, ssh_key *key) +{ + struct ssh_transient_hostkey_cache_entry *ent; + int toret = FALSE; + + if ((ent = find234(thc->cache, (void *)ssh_key_alg(key), + ssh_transient_hostkey_cache_find)) != NULL) { + strbuf *this_blob = strbuf_new(); + ssh_key_public_blob(key, BinarySink_UPCAST(this_blob)); + + if (this_blob->len == ent->pub_blob->len && + !memcmp(this_blob->s, ent->pub_blob->s, + this_blob->len)) + toret = TRUE; + + strbuf_free(this_blob); + } + + return toret; +} + +int ssh_transient_hostkey_cache_has( + ssh_transient_hostkey_cache *thc, const ssh_keyalg *alg) +{ + struct ssh_transient_hostkey_cache_entry *ent = + find234(thc->cache, (void *)alg, + ssh_transient_hostkey_cache_find); + return ent != NULL; +} + +int ssh_transient_hostkey_cache_non_empty(ssh_transient_hostkey_cache *thc) +{ + return count234(thc->cache) > 0; +} diff --git a/ssh2transport.c b/ssh2transport.c index 7f316ec0..aaf2d028 100644 --- a/ssh2transport.c +++ b/ssh2transport.c @@ -192,8 +192,8 @@ struct ssh2_transport_state { int gss_status; time_t gss_cred_expiry; /* Re-delegate if newer */ unsigned long gss_ctxt_lifetime; /* Re-delegate when short */ - tree234 *transient_hostkey_cache; #endif + ssh_transient_hostkey_cache *thc; int gss_kex_used; @@ -287,16 +287,6 @@ static const struct PacketProtocolLayerVtable ssh2_transport_vtable = { #ifndef NO_GSSAPI static void ssh2_transport_gss_update(struct ssh2_transport_state *s, int definitely_rekeying); -static void ssh_init_transient_hostkey_store(struct ssh2_transport_state *); -static void ssh_cleanup_transient_hostkey_store(struct ssh2_transport_state *); -static void ssh_store_transient_hostkey( - struct ssh2_transport_state *s, ssh_key *key); -static int ssh_verify_transient_hostkey( - struct ssh2_transport_state *s, ssh_key *key); -static int ssh_have_transient_hostkey( - struct ssh2_transport_state *s, const ssh_keyalg *alg); -static int ssh_have_any_transient_hostkey( - struct ssh2_transport_state *s); #endif static int ssh2_transport_timer_update(struct ssh2_transport_state *s, @@ -347,8 +337,8 @@ PacketProtocolLayer *ssh2_transport_new( s->gss_cred_expiry = GSS_NO_EXPIRATION; s->shgss->srv_name = GSS_C_NO_NAME; s->shgss->ctx = NULL; - ssh_init_transient_hostkey_store(s); #endif + s->thc = ssh_transient_hostkey_cache_new(); s->gss_kex_used = FALSE; ssh2_transport_set_max_data_size(s); @@ -407,9 +397,7 @@ static void ssh2_transport_free(PacketProtocolLayer *ppl) ssh_ecdhkex_freekey(s->ecdh_key); if (s->exhash) ssh_hash_free(s->exhash); -#ifndef NO_GSSAPI - ssh_cleanup_transient_hostkey_store(s); -#endif + ssh_transient_hostkey_cache_free(s->thc); sfree(s); } @@ -860,7 +848,8 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) for (j = 0; j < lenof(hostkey_algs); j++) { if (hostkey_algs[j].id != s->preferred_hk[i]) continue; - if (ssh_have_transient_hostkey(s, hostkey_algs[j].alg)) { + if (ssh_transient_hostkey_cache_has( + s->thc, hostkey_algs[j].alg)) { alg = ssh2_kexinit_addalg(s->kexlists[KEXLIST_HOSTKEY], hostkey_algs[j].alg->ssh_id); alg->u.hk.hostkey = hostkey_algs[j].alg; @@ -1884,8 +1873,7 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) if (s->gss_kex_used) { /* * In a GSS-based session, check the host key (if any) against - * the transient host key cache. See comment above, at the - * definition of ssh_transient_hostkey_cache_entry. + * the transient host key cache. */ if (s->kex_alg->main_type == KEXTYPE_GSS) { @@ -1899,8 +1887,8 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) ppl_logevent(("%s", s->fingerprint)); sfree(s->fingerprint); s->fingerprint = NULL; - ssh_store_transient_hostkey(s, s->hkey); - } else if (!ssh_have_any_transient_hostkey(s)) { + ssh_transient_hostkey_cache_add(s->thc, s->hkey); + } else if (!ssh_transient_hostkey_cache_non_empty(s->thc)) { /* * But if it didn't, then we currently have no * fallback host key to use in subsequent non-GSS @@ -1957,9 +1945,9 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) if (s->need_gss_transient_hostkey) { ppl_logevent(("Post-GSS rekey provided fallback host key:")); ppl_logevent(("%s", s->fingerprint)); - ssh_store_transient_hostkey(s, s->hkey); + ssh_transient_hostkey_cache_add(s->thc, s->hkey); s->need_gss_transient_hostkey = FALSE; - } else if (!ssh_verify_transient_hostkey(s, s->hkey)) { + } else if (!ssh_transient_hostkey_cache_verify(s->thc, s->hkey)) { ppl_logevent(("Non-GSS rekey after initial GSS kex " "used host key:")); ppl_logevent(("%s", s->fingerprint)); @@ -2584,123 +2572,6 @@ static void ssh2_transport_gss_update(struct ssh2_transport_state *s, s->gss_status |= GSS_CTXT_EXPIRES; } -/* - * Data structure managing host keys in sessions based on GSSAPI KEX. - * - * In a session we started with a GSSAPI key exchange, the concept of - * 'host key' has completely different lifetime and security semantics - * from the usual ones. Per RFC 4462 section 2.1, we assume that any - * host key delivered to us in the course of a GSSAPI key exchange is - * _solely_ there to use as a transient fallback within the same - * session, if at the time of a subsequent rekey the GSS credentials - * are temporarily invalid and so a non-GSS KEX method has to be used. - * - * In particular, in a GSS-based SSH deployment, host keys may not - * even _be_ persistent identities for the server; it would be - * legitimate for a server to generate a fresh one routinely if it - * wanted to, like SSH-1 server keys. - * - * So, in this mode, we never touch the persistent host key cache at - * all, either to check keys against it _or_ to store keys in it. - * Instead, we maintain an in-memory cache of host keys that have been - * mentioned in GSS key exchanges within this particular session, and - * we permit precisely those host keys in non-GSS rekeys. - */ -struct ssh_transient_hostkey_cache_entry { - const ssh_keyalg *alg; - strbuf *pub_blob; -}; - -static int ssh_transient_hostkey_cache_cmp(void *av, void *bv) -{ - const struct ssh_transient_hostkey_cache_entry - *a = (const struct ssh_transient_hostkey_cache_entry *)av, - *b = (const struct ssh_transient_hostkey_cache_entry *)bv; - return strcmp(a->alg->ssh_id, b->alg->ssh_id); -} - -static int ssh_transient_hostkey_cache_find(void *av, void *bv) -{ - const ssh_keyalg *aalg = (const ssh_keyalg *)av; - const struct ssh_transient_hostkey_cache_entry - *b = (const struct ssh_transient_hostkey_cache_entry *)bv; - return strcmp(aalg->ssh_id, b->alg->ssh_id); -} - -static void ssh_init_transient_hostkey_store( - struct ssh2_transport_state *s) -{ - s->transient_hostkey_cache = - newtree234(ssh_transient_hostkey_cache_cmp); -} - -static void ssh_cleanup_transient_hostkey_store( - struct ssh2_transport_state *s) -{ - struct ssh_transient_hostkey_cache_entry *ent; - while ((ent = delpos234(s->transient_hostkey_cache, 0)) != NULL) { - strbuf_free(ent->pub_blob); - sfree(ent); - } - freetree234(s->transient_hostkey_cache); -} - -static void ssh_store_transient_hostkey( - struct ssh2_transport_state *s, ssh_key *key) -{ - struct ssh_transient_hostkey_cache_entry *ent, *retd; - - if ((ent = find234(s->transient_hostkey_cache, (void *)ssh_key_alg(key), - ssh_transient_hostkey_cache_find)) != NULL) { - strbuf_free(ent->pub_blob); - sfree(ent); - } - - ent = snew(struct ssh_transient_hostkey_cache_entry); - ent->alg = ssh_key_alg(key); - ent->pub_blob = strbuf_new(); - ssh_key_public_blob(key, BinarySink_UPCAST(ent->pub_blob)); - retd = add234(s->transient_hostkey_cache, ent); - assert(retd == ent); -} - -static int ssh_verify_transient_hostkey( - struct ssh2_transport_state *s, ssh_key *key) -{ - struct ssh_transient_hostkey_cache_entry *ent; - int toret = FALSE; - - if ((ent = find234(s->transient_hostkey_cache, (void *)ssh_key_alg(key), - ssh_transient_hostkey_cache_find)) != NULL) { - strbuf *this_blob = strbuf_new(); - ssh_key_public_blob(key, BinarySink_UPCAST(this_blob)); - - if (this_blob->len == ent->pub_blob->len && - !memcmp(this_blob->s, ent->pub_blob->s, - this_blob->len)) - toret = TRUE; - - strbuf_free(this_blob); - } - - return toret; -} - -static int ssh_have_transient_hostkey( - struct ssh2_transport_state *s, const ssh_keyalg *alg) -{ - struct ssh_transient_hostkey_cache_entry *ent = - find234(s->transient_hostkey_cache, (void *)alg, - ssh_transient_hostkey_cache_find); - return ent != NULL; -} - -static int ssh_have_any_transient_hostkey( - struct ssh2_transport_state *s) -{ - return count234(s->transient_hostkey_cache) > 0; -} - ptrlen ssh2_transport_get_session_id(PacketProtocolLayer *ppl) { struct ssh2_transport_state *s; From 3df80af868b5550ed891ea8fe58365bb20313a6f Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 6 Oct 2018 13:46:13 +0100 Subject: [PATCH 536/607] Factor KEXINIT construction out into its own function. This has nice effects on code tidiness (quite a few variables now become local to the new function instead of living permanently in the transport layer), but mostly, the idea is to add flexibility by introducing a convenient place to change the policy for how we write the negotiation lists in our KEXINIT. --- ssh2transport.c | 708 +++++++++++++++++++++++++----------------------- 1 file changed, 373 insertions(+), 335 deletions(-) diff --git a/ssh2transport.c b/ssh2transport.c index aaf2d028..7648c303 100644 --- a/ssh2transport.c +++ b/ssh2transport.c @@ -199,11 +199,8 @@ struct ssh2_transport_state { int nbits, pbits, warn_kex, warn_hk, warn_cscipher, warn_sccipher; Bignum p, g, e, f, K; - void *our_kexinit; - int our_kexinitlen; + strbuf *client_kexinit, *server_kexinit; int kex_init_value, kex_reply_value; - const struct ssh2_macalg *const *maclist; - int nmacs; struct { const struct ssh2_cipheralg *cipher; const struct ssh2_macalg *mac; @@ -217,16 +214,9 @@ struct ssh2_transport_state { struct RSAKey *rsa_kex_key; /* for RSA kex */ struct ec_key *ecdh_key; /* for ECDH kex */ unsigned char exchange_hash[SSH2_KEX_MAX_HASH_LEN]; - int n_preferred_kex; int can_gssapi_keyex; int need_gss_transient_hostkey; int warned_about_no_gss_transient_hostkey; - const struct ssh_kexes *preferred_kex[KEX_MAX + 1]; /* +1 for GSSAPI */ - int n_preferred_hk; - int preferred_hk[HK_MAX]; - int n_preferred_ciphers; - const struct ssh2_ciphers *preferred_ciphers[CIPHER_MAX]; - const struct ssh_compression_alg *preferred_comp; int got_session_id; int dlgret; int guessok; @@ -341,6 +331,9 @@ PacketProtocolLayer *ssh2_transport_new( s->thc = ssh_transient_hostkey_cache_new(); s->gss_kex_used = FALSE; + s->client_kexinit = strbuf_new(); + s->server_kexinit = strbuf_new(); + ssh2_transport_set_max_data_size(s); return &s->ppl; @@ -397,6 +390,8 @@ static void ssh2_transport_free(PacketProtocolLayer *ppl) ssh_ecdhkex_freekey(s->ecdh_key); if (s->exhash) ssh_hash_free(s->exhash); + strbuf_free(s->client_kexinit); + strbuf_free(s->server_kexinit); ssh_transient_hostkey_cache_free(s->thc); sfree(s); } @@ -583,6 +578,329 @@ static PktIn *ssh2_transport_pop(struct ssh2_transport_state *s) return pq_pop(s->ppl.in_pq); } +static void ssh2_write_kexinit_lists( + BinarySink *pktout, + struct kexinit_algorithm kexlists[NKEXLIST][MAXKEXLIST], + Conf *conf, int remote_bugs, + const char *hk_host, int hk_port, const ssh_keyalg *hk_prev, + ssh_transient_hostkey_cache *thc, + int first_time, int can_gssapi_keyex, int transient_hostkey_mode) +{ + int i, j, k, warn; + + int n_preferred_kex; + const struct ssh_kexes *preferred_kex[KEX_MAX + 1]; /* +1 for GSSAPI */ + int n_preferred_hk; + int preferred_hk[HK_MAX]; + int n_preferred_ciphers; + const struct ssh2_ciphers *preferred_ciphers[CIPHER_MAX]; + const struct ssh_compression_alg *preferred_comp; + const struct ssh2_macalg *const *maclist; + int nmacs; + + struct kexinit_algorithm *alg; + + /* + * Set up the preferred key exchange. (NULL => warn below here) + */ + n_preferred_kex = 0; + if (can_gssapi_keyex) + preferred_kex[n_preferred_kex++] = &ssh_gssk5_sha1_kex; + for (i = 0; i < KEX_MAX; i++) { + switch (conf_get_int_int(conf, CONF_ssh_kexlist, i)) { + case KEX_DHGEX: + preferred_kex[n_preferred_kex++] = + &ssh_diffiehellman_gex; + break; + case KEX_DHGROUP14: + preferred_kex[n_preferred_kex++] = + &ssh_diffiehellman_group14; + break; + case KEX_DHGROUP1: + preferred_kex[n_preferred_kex++] = + &ssh_diffiehellman_group1; + break; + case KEX_RSA: + preferred_kex[n_preferred_kex++] = + &ssh_rsa_kex; + break; + case KEX_ECDH: + preferred_kex[n_preferred_kex++] = + &ssh_ecdh_kex; + break; + case KEX_WARN: + /* Flag for later. Don't bother if it's the last in + * the list. */ + if (i < KEX_MAX - 1) { + preferred_kex[n_preferred_kex++] = NULL; + } + break; + } + } + + /* + * Set up the preferred host key types. These are just the ids + * in the enum in putty.h, so 'warn below here' is indicated + * by HK_WARN. + */ + n_preferred_hk = 0; + for (i = 0; i < HK_MAX; i++) { + int id = conf_get_int_int(conf, CONF_ssh_hklist, i); + /* As above, don't bother with HK_WARN if it's last in the + * list */ + if (id != HK_WARN || i < HK_MAX - 1) + preferred_hk[n_preferred_hk++] = id; + } + + /* + * Set up the preferred ciphers. (NULL => warn below here) + */ + n_preferred_ciphers = 0; + for (i = 0; i < CIPHER_MAX; i++) { + switch (conf_get_int_int(conf, CONF_ssh_cipherlist, i)) { + case CIPHER_BLOWFISH: + preferred_ciphers[n_preferred_ciphers++] = &ssh2_blowfish; + break; + case CIPHER_DES: + if (conf_get_int(conf, CONF_ssh2_des_cbc)) + preferred_ciphers[n_preferred_ciphers++] = &ssh2_des; + break; + case CIPHER_3DES: + preferred_ciphers[n_preferred_ciphers++] = &ssh2_3des; + break; + case CIPHER_AES: + preferred_ciphers[n_preferred_ciphers++] = &ssh2_aes; + break; + case CIPHER_ARCFOUR: + preferred_ciphers[n_preferred_ciphers++] = &ssh2_arcfour; + break; + case CIPHER_CHACHA20: + preferred_ciphers[n_preferred_ciphers++] = &ssh2_ccp; + break; + case CIPHER_WARN: + /* Flag for later. Don't bother if it's the last in + * the list. */ + if (i < CIPHER_MAX - 1) { + preferred_ciphers[n_preferred_ciphers++] = NULL; + } + break; + } + } + + /* + * Set up preferred compression. + */ + if (conf_get_int(conf, CONF_compression)) + preferred_comp = &ssh_zlib; + else + preferred_comp = &ssh_comp_none; + + for (i = 0; i < NKEXLIST; i++) + for (j = 0; j < MAXKEXLIST; j++) + kexlists[i][j].name = NULL; + /* List key exchange algorithms. */ + warn = FALSE; + for (i = 0; i < n_preferred_kex; i++) { + const struct ssh_kexes *k = preferred_kex[i]; + if (!k) warn = TRUE; + else for (j = 0; j < k->nkexes; j++) { + alg = ssh2_kexinit_addalg(kexlists[KEXLIST_KEX], + k->list[j]->name); + alg->u.kex.kex = k->list[j]; + alg->u.kex.warn = warn; + } + } + /* List server host key algorithms. */ + if (first_time) { + /* + * In the first key exchange, we list all the algorithms + * we're prepared to cope with, but prefer those algorithms + * for which we have a host key for this host. + * + * If the host key algorithm is below the warning + * threshold, we warn even if we did already have a key + * for it, on the basis that if the user has just + * reconfigured that host key type to be warned about, + * they surely _do_ want to be alerted that a server + * they're actually connecting to is using it. + */ + warn = FALSE; + for (i = 0; i < n_preferred_hk; i++) { + if (preferred_hk[i] == HK_WARN) + warn = TRUE; + for (j = 0; j < lenof(hostkey_algs); j++) { + if (hostkey_algs[j].id != preferred_hk[i]) + continue; + if (have_ssh_host_key(hk_host, hk_port, + hostkey_algs[j].alg->cache_id)) { + alg = ssh2_kexinit_addalg(kexlists[KEXLIST_HOSTKEY], + hostkey_algs[j].alg->ssh_id); + alg->u.hk.hostkey = hostkey_algs[j].alg; + alg->u.hk.warn = warn; + } + } + } + warn = FALSE; + for (i = 0; i < n_preferred_hk; i++) { + if (preferred_hk[i] == HK_WARN) + warn = TRUE; + for (j = 0; j < lenof(hostkey_algs); j++) { + if (hostkey_algs[j].id != preferred_hk[i]) + continue; + alg = ssh2_kexinit_addalg(kexlists[KEXLIST_HOSTKEY], + hostkey_algs[j].alg->ssh_id); + alg->u.hk.hostkey = hostkey_algs[j].alg; + alg->u.hk.warn = warn; + } + } +#ifndef NO_GSSAPI + } else if (transient_hostkey_mode) { + /* + * If we've previously done a GSSAPI KEX, then we list + * precisely the algorithms for which a previous GSS key + * exchange has delivered us a host key, because we expect + * one of exactly those keys to be used in any subsequent + * non-GSS-based rekey. + * + * An exception is if this is the key exchange we + * triggered for the purposes of populating that cache - + * in which case the cache will currently be empty, which + * isn't helpful! + */ + warn = FALSE; + for (i = 0; i < n_preferred_hk; i++) { + if (preferred_hk[i] == HK_WARN) + warn = TRUE; + for (j = 0; j < lenof(hostkey_algs); j++) { + if (hostkey_algs[j].id != preferred_hk[i]) + continue; + if (ssh_transient_hostkey_cache_has( + thc, hostkey_algs[j].alg)) { + alg = ssh2_kexinit_addalg(kexlists[KEXLIST_HOSTKEY], + hostkey_algs[j].alg->ssh_id); + alg->u.hk.hostkey = hostkey_algs[j].alg; + alg->u.hk.warn = warn; + } + } + } +#endif + } else { + /* + * In subsequent key exchanges, we list only the host key + * algorithm that was selected in the first key exchange, + * so that we keep getting the same host key and hence + * don't have to interrupt the user's session to ask for + * reverification. + */ + assert(hk_prev); + alg = ssh2_kexinit_addalg(kexlists[KEXLIST_HOSTKEY], hk_prev->ssh_id); + alg->u.hk.hostkey = hk_prev; + alg->u.hk.warn = FALSE; + } + if (can_gssapi_keyex) { + alg = ssh2_kexinit_addalg(kexlists[KEXLIST_HOSTKEY], "null"); + alg->u.hk.hostkey = NULL; + } + /* List encryption algorithms (client->server then server->client). */ + for (k = KEXLIST_CSCIPHER; k <= KEXLIST_SCCIPHER; k++) { + warn = FALSE; +#ifdef FUZZING + alg = ssh2_kexinit_addalg(kexlists[k], "none"); + alg->u.cipher.cipher = NULL; + alg->u.cipher.warn = warn; +#endif /* FUZZING */ + for (i = 0; i < n_preferred_ciphers; i++) { + const struct ssh2_ciphers *c = preferred_ciphers[i]; + if (!c) warn = TRUE; + else for (j = 0; j < c->nciphers; j++) { + alg = ssh2_kexinit_addalg(kexlists[k], + c->list[j]->name); + alg->u.cipher.cipher = c->list[j]; + alg->u.cipher.warn = warn; + } + } + } + + /* + * Be prepared to work around the buggy MAC problem. + */ + if (remote_bugs & BUG_SSH2_HMAC) { + maclist = buggymacs; + nmacs = lenof(buggymacs); + } else { + maclist = macs; + nmacs = lenof(macs); + } + + /* List MAC algorithms (client->server then server->client). */ + for (j = KEXLIST_CSMAC; j <= KEXLIST_SCMAC; j++) { +#ifdef FUZZING + alg = ssh2_kexinit_addalg(kexlists[j], "none"); + alg->u.mac.mac = NULL; + alg->u.mac.etm = FALSE; +#endif /* FUZZING */ + for (i = 0; i < nmacs; i++) { + alg = ssh2_kexinit_addalg(kexlists[j], maclist[i]->name); + alg->u.mac.mac = maclist[i]; + alg->u.mac.etm = FALSE; + } + for (i = 0; i < nmacs; i++) { + /* For each MAC, there may also be an ETM version, + * which we list second. */ + if (maclist[i]->etm_name) { + alg = ssh2_kexinit_addalg(kexlists[j], maclist[i]->etm_name); + alg->u.mac.mac = maclist[i]; + alg->u.mac.etm = TRUE; + } + } + } + + /* List client->server compression algorithms, + * then server->client compression algorithms. (We use the + * same set twice.) */ + for (j = KEXLIST_CSCOMP; j <= KEXLIST_SCCOMP; j++) { + assert(lenof(compressions) > 1); + /* Prefer non-delayed versions */ + alg = ssh2_kexinit_addalg(kexlists[j], preferred_comp->name); + alg->u.comp.comp = preferred_comp; + alg->u.comp.delayed = FALSE; + if (preferred_comp->delayed_name) { + alg = ssh2_kexinit_addalg(kexlists[j], + preferred_comp->delayed_name); + alg->u.comp.comp = preferred_comp; + alg->u.comp.delayed = TRUE; + } + for (i = 0; i < lenof(compressions); i++) { + const struct ssh_compression_alg *c = compressions[i]; + alg = ssh2_kexinit_addalg(kexlists[j], c->name); + alg->u.comp.comp = c; + alg->u.comp.delayed = FALSE; + if (c->delayed_name) { + alg = ssh2_kexinit_addalg(kexlists[j], c->delayed_name); + alg->u.comp.comp = c; + alg->u.comp.delayed = TRUE; + } + } + } + + /* + * Finally, format the lists into text and write them into the + * outgoing KEXINIT packet. + */ + for (i = 0; i < NKEXLIST; i++) { + strbuf *list = strbuf_new(); + for (j = 0; j < MAXKEXLIST; j++) { + if (kexlists[i][j].name == NULL) break; + add_to_commasep(list, kexlists[i][j].name); + } + put_stringsb(pktout, list); + } + /* List client->server languages. Empty list. */ + put_stringz(pktout, ""); + /* List server->client languages. Empty list. */ + put_stringz(pktout, ""); +} + static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) { struct ssh2_transport_state *s = @@ -607,14 +925,6 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) s->need_gss_transient_hostkey = FALSE; s->warned_about_no_gss_transient_hostkey = FALSE; - /* - * Be prepared to work around the buggy MAC problem. - */ - if (s->ppl.remote_bugs & BUG_SSH2_HMAC) - s->maclist = buggymacs, s->nmacs = lenof(buggymacs); - else - s->maclist = macs, s->nmacs = lenof(macs); - begin_key_exchange: #ifndef NO_GSSAPI @@ -665,316 +975,55 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) #endif s->ppl.bpp->pls->kctx = SSH2_PKTCTX_NOKEX; - { - int i, j, k, warn; - struct kexinit_algorithm *alg; - - /* - * Set up the preferred key exchange. (NULL => warn below here) - */ - s->n_preferred_kex = 0; - if (s->can_gssapi_keyex) - s->preferred_kex[s->n_preferred_kex++] = &ssh_gssk5_sha1_kex; - for (i = 0; i < KEX_MAX; i++) { - switch (conf_get_int_int(s->conf, CONF_ssh_kexlist, i)) { - case KEX_DHGEX: - s->preferred_kex[s->n_preferred_kex++] = - &ssh_diffiehellman_gex; - break; - case KEX_DHGROUP14: - s->preferred_kex[s->n_preferred_kex++] = - &ssh_diffiehellman_group14; - break; - case KEX_DHGROUP1: - s->preferred_kex[s->n_preferred_kex++] = - &ssh_diffiehellman_group1; - break; - case KEX_RSA: - s->preferred_kex[s->n_preferred_kex++] = - &ssh_rsa_kex; - break; - case KEX_ECDH: - s->preferred_kex[s->n_preferred_kex++] = - &ssh_ecdh_kex; - break; - case KEX_WARN: - /* Flag for later. Don't bother if it's the last in - * the list. */ - if (i < KEX_MAX - 1) { - s->preferred_kex[s->n_preferred_kex++] = NULL; - } - break; - } - } - - /* - * Set up the preferred host key types. These are just the ids - * in the enum in putty.h, so 'warn below here' is indicated - * by HK_WARN. - */ - s->n_preferred_hk = 0; - for (i = 0; i < HK_MAX; i++) { - int id = conf_get_int_int(s->conf, CONF_ssh_hklist, i); - /* As above, don't bother with HK_WARN if it's last in the - * list */ - if (id != HK_WARN || i < HK_MAX - 1) - s->preferred_hk[s->n_preferred_hk++] = id; - } - - /* - * Set up the preferred ciphers. (NULL => warn below here) - */ - s->n_preferred_ciphers = 0; - for (i = 0; i < CIPHER_MAX; i++) { - switch (conf_get_int_int(s->conf, CONF_ssh_cipherlist, i)) { - case CIPHER_BLOWFISH: - s->preferred_ciphers[s->n_preferred_ciphers++] = &ssh2_blowfish; - break; - case CIPHER_DES: - if (conf_get_int(s->conf, CONF_ssh2_des_cbc)) - s->preferred_ciphers[s->n_preferred_ciphers++] = &ssh2_des; - break; - case CIPHER_3DES: - s->preferred_ciphers[s->n_preferred_ciphers++] = &ssh2_3des; - break; - case CIPHER_AES: - s->preferred_ciphers[s->n_preferred_ciphers++] = &ssh2_aes; - break; - case CIPHER_ARCFOUR: - s->preferred_ciphers[s->n_preferred_ciphers++] = &ssh2_arcfour; - break; - case CIPHER_CHACHA20: - s->preferred_ciphers[s->n_preferred_ciphers++] = &ssh2_ccp; - break; - case CIPHER_WARN: - /* Flag for later. Don't bother if it's the last in - * the list. */ - if (i < CIPHER_MAX - 1) { - s->preferred_ciphers[s->n_preferred_ciphers++] = NULL; - } - break; - } - } - - /* - * Set up preferred compression. - */ - if (conf_get_int(s->conf, CONF_compression)) - s->preferred_comp = &ssh_zlib; - else - s->preferred_comp = &ssh_comp_none; - - /* - * Flag that KEX is in progress. - */ - s->kex_in_progress = TRUE; - for (i = 0; i < NKEXLIST; i++) - for (j = 0; j < MAXKEXLIST; j++) - s->kexlists[i][j].name = NULL; - /* List key exchange algorithms. */ - warn = FALSE; - for (i = 0; i < s->n_preferred_kex; i++) { - const struct ssh_kexes *k = s->preferred_kex[i]; - if (!k) warn = TRUE; - else for (j = 0; j < k->nkexes; j++) { - alg = ssh2_kexinit_addalg(s->kexlists[KEXLIST_KEX], - k->list[j]->name); - alg->u.kex.kex = k->list[j]; - alg->u.kex.warn = warn; - } - } - /* List server host key algorithms. */ - if (!s->got_session_id) { - /* - * In the first key exchange, we list all the algorithms - * we're prepared to cope with, but prefer those algorithms - * for which we have a host key for this host. - * - * If the host key algorithm is below the warning - * threshold, we warn even if we did already have a key - * for it, on the basis that if the user has just - * reconfigured that host key type to be warned about, - * they surely _do_ want to be alerted that a server - * they're actually connecting to is using it. - */ - warn = FALSE; - for (i = 0; i < s->n_preferred_hk; i++) { - if (s->preferred_hk[i] == HK_WARN) - warn = TRUE; - for (j = 0; j < lenof(hostkey_algs); j++) { - if (hostkey_algs[j].id != s->preferred_hk[i]) - continue; - if (have_ssh_host_key(s->savedhost, s->savedport, - hostkey_algs[j].alg->cache_id)) { - alg = ssh2_kexinit_addalg(s->kexlists[KEXLIST_HOSTKEY], - hostkey_algs[j].alg->ssh_id); - alg->u.hk.hostkey = hostkey_algs[j].alg; - alg->u.hk.warn = warn; - } - } - } - warn = FALSE; - for (i = 0; i < s->n_preferred_hk; i++) { - if (s->preferred_hk[i] == HK_WARN) - warn = TRUE; - for (j = 0; j < lenof(hostkey_algs); j++) { - if (hostkey_algs[j].id != s->preferred_hk[i]) - continue; - alg = ssh2_kexinit_addalg(s->kexlists[KEXLIST_HOSTKEY], - hostkey_algs[j].alg->ssh_id); - alg->u.hk.hostkey = hostkey_algs[j].alg; - alg->u.hk.warn = warn; - } - } -#ifndef NO_GSSAPI - } else if (s->gss_kex_used && !s->need_gss_transient_hostkey) { - /* - * If we've previously done a GSSAPI KEX, then we list - * precisely the algorithms for which a previous GSS key - * exchange has delivered us a host key, because we expect - * one of exactly those keys to be used in any subsequent - * non-GSS-based rekey. - * - * An exception is if this is the key exchange we - * triggered for the purposes of populating that cache - - * in which case the cache will currently be empty, which - * isn't helpful! - */ - warn = FALSE; - for (i = 0; i < s->n_preferred_hk; i++) { - if (s->preferred_hk[i] == HK_WARN) - warn = TRUE; - for (j = 0; j < lenof(hostkey_algs); j++) { - if (hostkey_algs[j].id != s->preferred_hk[i]) - continue; - if (ssh_transient_hostkey_cache_has( - s->thc, hostkey_algs[j].alg)) { - alg = ssh2_kexinit_addalg(s->kexlists[KEXLIST_HOSTKEY], - hostkey_algs[j].alg->ssh_id); - alg->u.hk.hostkey = hostkey_algs[j].alg; - alg->u.hk.warn = warn; - } - } - } -#endif - } else { - /* - * In subsequent key exchanges, we list only the kex - * algorithm that was selected in the first key exchange, - * so that we keep getting the same host key and hence - * don't have to interrupt the user's session to ask for - * reverification. - */ - assert(s->kex_alg); - alg = ssh2_kexinit_addalg(s->kexlists[KEXLIST_HOSTKEY], - s->hostkey_alg->ssh_id); - alg->u.hk.hostkey = s->hostkey_alg; - alg->u.hk.warn = FALSE; - } - if (s->can_gssapi_keyex) { - alg = ssh2_kexinit_addalg(s->kexlists[KEXLIST_HOSTKEY], "null"); - alg->u.hk.hostkey = NULL; - } - /* List encryption algorithms (client->server then server->client). */ - for (k = KEXLIST_CSCIPHER; k <= KEXLIST_SCCIPHER; k++) { - warn = FALSE; -#ifdef FUZZING - alg = ssh2_kexinit_addalg(s->kexlists[k], "none"); - alg->u.cipher.cipher = NULL; - alg->u.cipher.warn = warn; -#endif /* FUZZING */ - for (i = 0; i < s->n_preferred_ciphers; i++) { - const struct ssh2_ciphers *c = s->preferred_ciphers[i]; - if (!c) warn = TRUE; - else for (j = 0; j < c->nciphers; j++) { - alg = ssh2_kexinit_addalg(s->kexlists[k], - c->list[j]->name); - alg->u.cipher.cipher = c->list[j]; - alg->u.cipher.warn = warn; - } - } - } - /* List MAC algorithms (client->server then server->client). */ - for (j = KEXLIST_CSMAC; j <= KEXLIST_SCMAC; j++) { -#ifdef FUZZING - alg = ssh2_kexinit_addalg(s->kexlists[j], "none"); - alg->u.mac.mac = NULL; - alg->u.mac.etm = FALSE; -#endif /* FUZZING */ - for (i = 0; i < s->nmacs; i++) { - alg = ssh2_kexinit_addalg(s->kexlists[j], s->maclist[i]->name); - alg->u.mac.mac = s->maclist[i]; - alg->u.mac.etm = FALSE; - } - for (i = 0; i < s->nmacs; i++) - /* For each MAC, there may also be an ETM version, - * which we list second. */ - if (s->maclist[i]->etm_name) { - alg = ssh2_kexinit_addalg(s->kexlists[j], - s->maclist[i]->etm_name); - alg->u.mac.mac = s->maclist[i]; - alg->u.mac.etm = TRUE; - } - } - /* List client->server compression algorithms, - * then server->client compression algorithms. (We use the - * same set twice.) */ - for (j = KEXLIST_CSCOMP; j <= KEXLIST_SCCOMP; j++) { - assert(lenof(compressions) > 1); - /* Prefer non-delayed versions */ - alg = ssh2_kexinit_addalg(s->kexlists[j], s->preferred_comp->name); - alg->u.comp.comp = s->preferred_comp; - alg->u.comp.delayed = FALSE; - if (s->preferred_comp->delayed_name) { - alg = ssh2_kexinit_addalg(s->kexlists[j], - s->preferred_comp->delayed_name); - alg->u.comp.comp = s->preferred_comp; - alg->u.comp.delayed = TRUE; - } - for (i = 0; i < lenof(compressions); i++) { - const struct ssh_compression_alg *c = compressions[i]; - alg = ssh2_kexinit_addalg(s->kexlists[j], c->name); - alg->u.comp.comp = c; - alg->u.comp.delayed = FALSE; - if (c->delayed_name) { - alg = ssh2_kexinit_addalg(s->kexlists[j], c->delayed_name); - alg->u.comp.comp = c; - alg->u.comp.delayed = TRUE; - } - } - } - /* - * Construct and send our key exchange packet. - */ - pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH2_MSG_KEXINIT); + /* + * Construct our KEXINIT packet, in a strbuf so we can refer to it + * later. + */ + s->client_kexinit->len = 0; + put_byte(s->client_kexinit, SSH2_MSG_KEXINIT); + { + int i; for (i = 0; i < 16; i++) - put_byte(pktout, (unsigned char) random_byte()); - for (i = 0; i < NKEXLIST; i++) { - strbuf *list = strbuf_new(); - for (j = 0; j < MAXKEXLIST; j++) { - if (s->kexlists[i][j].name == NULL) break; - add_to_commasep(list, s->kexlists[i][j].name); - } - put_stringsb(pktout, list); - } - /* List client->server languages. Empty list. */ - put_stringz(pktout, ""); - /* List server->client languages. Empty list. */ - put_stringz(pktout, ""); - /* First KEX packet does _not_ follow, because we're not that brave. */ - put_bool(pktout, FALSE); - /* Reserved. */ - put_uint32(pktout, 0); + put_byte(s->client_kexinit, (unsigned char) random_byte()); } + ssh2_write_kexinit_lists( + BinarySink_UPCAST(s->client_kexinit), s->kexlists, + s->conf, s->ppl.remote_bugs, + s->savedhost, s->savedport, s->hostkey_alg, s->thc, + !s->got_session_id, s->can_gssapi_keyex, + s->gss_kex_used && !s->need_gss_transient_hostkey); + /* First KEX packet does _not_ follow, because we're not that brave. */ + put_bool(s->client_kexinit, FALSE); + put_uint32(s->client_kexinit, 0); /* reserved */ - s->our_kexinitlen = pktout->length - 5; - s->our_kexinit = snewn(s->our_kexinitlen, unsigned char); - memcpy(s->our_kexinit, pktout->data + 5, s->our_kexinitlen); - + /* + * Send our KEXINIT. + */ + pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH2_MSG_KEXINIT); + put_data(pktout, s->client_kexinit->u + 1, + s->client_kexinit->len - 1); /* omit initial packet type byte */ pq_push(s->ppl.out_pq, pktout); + /* + * Flag that KEX is in progress. + */ + s->kex_in_progress = TRUE; + + /* + * Wait for the other side's KEXINIT, and save it. + */ crMaybeWaitUntilV((pktin = ssh2_transport_pop(s)) != NULL); + if (pktin->type != SSH2_MSG_KEXINIT) { + ssh_proto_error(s->ppl.ssh, "Received unexpected packet when " + "expecting KEXINIT, type %d (%s)", pktin->type, + ssh2_pkt_type(s->ppl.bpp->pls->kctx, + s->ppl.bpp->pls->actx, pktin->type)); + return; + } + s->server_kexinit->len = 0; + put_byte(s->server_kexinit, SSH2_MSG_KEXINIT); + put_data(s->server_kexinit, get_ptr(pktin), get_avail(pktin)); /* * Now examine the other side's KEXINIT to see what we're up @@ -984,13 +1033,6 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) ptrlen str; int i, j; - if (pktin->type != SSH2_MSG_KEXINIT) { - ssh_proto_error(s->ppl.ssh, "Received unexpected packet when " - "expecting KEXINIT, type %d (%s)", pktin->type, - ssh2_pkt_type(s->ppl.bpp->pls->kctx, - s->ppl.bpp->pls->actx, pktin->type)); - return; - } s->kex_alg = NULL; s->hostkey_alg = NULL; s->in.cipher = s->out.cipher = NULL; @@ -1118,12 +1160,8 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) s->exhash = ssh_hash_new(s->kex_alg->hash); put_stringz(s->exhash, s->client_greeting); put_stringz(s->exhash, s->server_greeting); - put_string(s->exhash, s->our_kexinit, s->our_kexinitlen); - sfree(s->our_kexinit); - /* Include the type byte in the hash of server's KEXINIT */ - put_string(s->exhash, - (const char *)BinarySource_UPCAST(pktin)->data - 1, - BinarySource_UPCAST(pktin)->len + 1); + put_string(s->exhash, s->client_kexinit->u, s->client_kexinit->len); + put_string(s->exhash, s->server_kexinit->u, s->server_kexinit->len); if (s->warn_kex) { s->dlgret = seat_confirm_weak_crypto_primitive( From 7de8801e73d797705f5b1904fa7663d66475b615 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 7 Oct 2018 13:51:04 +0100 Subject: [PATCH 537/607] Factor KEXINIT analysis out into its own function. The function takes the two KEXINIT packets in their string form, together with a list of mappings from names to known algorithm implementations, and returns the selected one of each kind, along with all the other necessary auxiliary stuff. --- ssh.h | 1 + ssh2transport.c | 539 +++++++++++++++++++++++++++++------------------- sshcommon.c | 32 +++ 3 files changed, 363 insertions(+), 209 deletions(-) diff --git a/ssh.h b/ssh.h index 180d8456..583ab61b 100644 --- a/ssh.h +++ b/ssh.h @@ -1479,6 +1479,7 @@ int first_in_commasep_string(char const *needle, char const *haystack, int haylen); int in_commasep_string(char const *needle, char const *haystack, int haylen); void add_to_commasep(strbuf *buf, const char *data); +int get_commasep_word(ptrlen *list, ptrlen *word); int verify_ssh_manual_host_key( Conf *conf, const char *fingerprint, ssh_key *key); diff --git a/ssh2transport.c b/ssh2transport.c index 7648c303..ac1caf8a 100644 --- a/ssh2transport.c +++ b/ssh2transport.c @@ -146,6 +146,14 @@ typedef enum RekeyClass { RK_GSS_UPDATE } RekeyClass; +typedef struct transport_direction { + const struct ssh2_cipheralg *cipher; + const struct ssh2_macalg *mac; + int etm_mode; + const struct ssh_compression_alg *comp; + int comp_delayed; +} transport_direction; + struct ssh2_transport_state { int crState; @@ -201,13 +209,7 @@ struct ssh2_transport_state { Bignum p, g, e, f, K; strbuf *client_kexinit, *server_kexinit; int kex_init_value, kex_reply_value; - struct { - const struct ssh2_cipheralg *cipher; - const struct ssh2_macalg *mac; - int etm_mode; - const struct ssh_compression_alg *comp; - int comp_delayed; - } in, out; + transport_direction in, out; ptrlen hostkeydata, sigdata; char *keystr, *fingerprint; ssh_key *hkey; /* actual host key */ @@ -901,6 +903,217 @@ static void ssh2_write_kexinit_lists( put_stringz(pktout, ""); } +static int ssh2_scan_kexinits( + ptrlen client_kexinit, ptrlen server_kexinit, + struct kexinit_algorithm kexlists[NKEXLIST][MAXKEXLIST], + const struct ssh_kex **kex_alg, const ssh_keyalg **hostkey_alg, + transport_direction *cs, transport_direction *sc, + int *warn_kex, int *warn_hk, int *warn_cscipher, int *warn_sccipher, + Ssh *ssh, int *ignore_guess_cs_packet, int *ignore_guess_sc_packet, + int *n_server_hostkeys, int server_hostkeys[MAXKEXLIST]) +{ + BinarySource client[1], server[1]; + int i; + int guess_correct; + ptrlen clists[NKEXLIST], slists[NKEXLIST]; + const struct kexinit_algorithm *selected[NKEXLIST]; + + BinarySource_BARE_INIT(client, client_kexinit.ptr, client_kexinit.len); + BinarySource_BARE_INIT(server, server_kexinit.ptr, server_kexinit.len); + + /* Skip packet type bytes and random cookies. */ + get_data(client, 1 + 16); + get_data(server, 1 + 16); + + guess_correct = TRUE; + + /* Find the matching string in each list, and map it to its + * kexinit_algorithm structure. */ + for (i = 0; i < NKEXLIST; i++) { + ptrlen clist, slist, cword, sword, found; + int cfirst, sfirst, j; + + clists[i] = get_string(client); + slists[i] = get_string(server); + if (get_err(client) || get_err(server)) { + /* Report a better error than the spurious "Couldn't + * agree" that we'd generate if we pressed on regardless + * and treated the empty get_string() result as genuine */ + ssh_proto_error(ssh, "KEXINIT packet was incomplete"); + return FALSE; + } + + for (cfirst = TRUE, clist = clists[i]; + get_commasep_word(&clist, &cword); cfirst = FALSE) + for (sfirst = TRUE, slist = slists[i]; + get_commasep_word(&slist, &sword); sfirst = FALSE) + if (ptrlen_eq_ptrlen(cword, sword)) { + found = cword; + goto found_match; + } + + /* No matching string found in the two lists. Delay reporting + * a fatal error until below, because sometimes it turns out + * not to be fatal. */ + selected[i] = NULL; + + /* + * However, even if a failure to agree on any algorithm at all + * is not completely fatal (e.g. because it's the MAC + * negotiation for a cipher that comes with a built-in MAC), + * it still invalidates the guessed key exchange packet. (RFC + * 4253 section 7, not contradicted by OpenSSH's + * PROTOCOL.chacha20poly1305 or as far as I can see by their + * code.) + */ + guess_correct = FALSE; + + continue; + + found_match: + + selected[i] = NULL; + for (j = 0; j < MAXKEXLIST; j++) { + if (ptrlen_eq_string(found, kexlists[i][j].name)) { + selected[i] = &kexlists[i][j]; + break; + } + } + assert(selected[i]); /* kexlists[] must cover one of the inputs */ + + /* + * If the kex or host key algorithm is not the first one in + * both sides' lists, that means the guessed key exchange + * packet (if any) is officially wrong. + */ + if ((i == KEXLIST_KEX || i == KEXLIST_HOSTKEY) && !(cfirst || sfirst)) + guess_correct = FALSE; + } + + /* + * Skip language strings in both KEXINITs, and read the flags + * saying whether a guessed KEX packet follows. + */ + get_string(client); + get_string(client); + get_string(server); + get_string(server); + if (ignore_guess_cs_packet) + *ignore_guess_cs_packet = get_bool(client) && !guess_correct; + if (ignore_guess_sc_packet) + *ignore_guess_sc_packet = get_bool(server) && !guess_correct; + + /* + * Now transcribe the selected algorithm set into the output data. + */ + for (i = 0; i < NKEXLIST; i++) { + const struct kexinit_algorithm *alg; + + /* + * If we've already selected a cipher which requires a + * particular MAC, then just select that. This is the case in + * which it's not a fatal error if the actual MAC string lists + * didn't include any matching error. + */ + if (i == KEXLIST_CSMAC && cs->cipher && + cs->cipher->required_mac) { + cs->mac = cs->cipher->required_mac; + cs->etm_mode = !!(cs->mac->etm_name); + continue; + } + if (i == KEXLIST_SCMAC && sc->cipher && + sc->cipher->required_mac) { + sc->mac = sc->cipher->required_mac; + sc->etm_mode = !!(sc->mac->etm_name); + continue; + } + + alg = selected[i]; + if (!alg) { + /* + * Otherwise, any match failure _is_ a fatal error. + */ + ssh_sw_abort(ssh, "Couldn't agree a %s (available: %.*s)", + kexlist_descr[i], PTRLEN_PRINTF(slists[i])); + return FALSE; + } + + switch (i) { + case KEXLIST_KEX: + *kex_alg = alg->u.kex.kex; + *warn_kex = alg->u.kex.warn; + break; + + case KEXLIST_HOSTKEY: + /* + * Ignore an unexpected/inappropriate offer of "null", + * we offer "null" when we're willing to use GSS KEX, + * but it is only acceptable when GSSKEX is actually + * selected. + */ + if (alg->u.hk.hostkey == NULL && + (*kex_alg)->main_type != KEXTYPE_GSS) + continue; + + *hostkey_alg = alg->u.hk.hostkey; + *warn_hk = alg->u.hk.warn; + break; + + case KEXLIST_CSCIPHER: + cs->cipher = alg->u.cipher.cipher; + *warn_cscipher = alg->u.cipher.warn; + break; + + case KEXLIST_SCCIPHER: + sc->cipher = alg->u.cipher.cipher; + *warn_sccipher = alg->u.cipher.warn; + break; + + case KEXLIST_CSMAC: + cs->mac = alg->u.mac.mac; + cs->etm_mode = alg->u.mac.etm; + break; + + case KEXLIST_SCMAC: + sc->mac = alg->u.mac.mac; + sc->etm_mode = alg->u.mac.etm; + break; + + case KEXLIST_CSCOMP: + cs->comp = alg->u.comp.comp; + cs->comp_delayed = alg->u.comp.delayed; + break; + + case KEXLIST_SCCOMP: + sc->comp = alg->u.comp.comp; + sc->comp_delayed = alg->u.comp.delayed; + break; + + default: + assert(FALSE && "Bad list index in scan_kexinits"); + } + } + + if (server_hostkeys) { + /* + * Finally, make an auxiliary pass over the server's host key + * list to find all the host key algorithms offered by the + * server which we know about at all, whether we selected each + * one or not. We return these as a list of indices into the + * constant hostkey_algs[] array. + */ + *n_server_hostkeys = 0; + + for (i = 0; i < lenof(hostkey_algs); i++) + if (in_commasep_string(hostkey_algs[i].alg->ssh_id, + slists[KEXLIST_HOSTKEY].ptr, + slists[KEXLIST_HOSTKEY].len)) + server_hostkeys[(*n_server_hostkeys)++] = i; + } + + return TRUE; +} + static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) { struct ssh2_transport_state *s = @@ -1026,238 +1239,146 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) put_data(s->server_kexinit, get_ptr(pktin), get_avail(pktin)); /* - * Now examine the other side's KEXINIT to see what we're up - * to. + * Work through the two KEXINIT packets in parallel to find the + * selected algorithm identifiers. */ { - ptrlen str; - int i, j; - - s->kex_alg = NULL; - s->hostkey_alg = NULL; - s->in.cipher = s->out.cipher = NULL; - s->in.mac = s->out.mac = NULL; - s->in.comp = s->out.comp = NULL; - s->in.comp_delayed = s->out.comp_delayed = FALSE; - s->warn_kex = s->warn_hk = FALSE; - s->warn_cscipher = s->warn_sccipher = FALSE; - - get_data(pktin, 16); /* skip garbage cookie */ - - s->guessok = FALSE; - for (i = 0; i < NKEXLIST; i++) { - str = get_string(pktin); - if (get_err(pktin)) { - ssh_proto_error(s->ppl.ssh, "KEXINIT packet was incomplete"); - return; - } - - /* If we've already selected a cipher which requires a - * particular MAC, then just select that, and don't even - * bother looking through the server's KEXINIT string for - * MACs. */ - if (i == KEXLIST_CSMAC && s->out.cipher && - s->out.cipher->required_mac) { - s->out.mac = s->out.cipher->required_mac; - s->out.etm_mode = !!(s->out.mac->etm_name); - goto matched; - } - if (i == KEXLIST_SCMAC && s->in.cipher && - s->in.cipher->required_mac) { - s->in.mac = s->in.cipher->required_mac; - s->in.etm_mode = !!(s->in.mac->etm_name); - goto matched; - } - - for (j = 0; j < MAXKEXLIST; j++) { - struct kexinit_algorithm *alg = &s->kexlists[i][j]; - if (alg->name == NULL) break; - if (in_commasep_string(alg->name, str.ptr, str.len)) { - /* We've found a matching algorithm. */ - if (i == KEXLIST_KEX || i == KEXLIST_HOSTKEY) { - /* Check if we might need to ignore first kex pkt */ - if (j != 0 || - !first_in_commasep_string(alg->name, - str.ptr, str.len)) - s->guessok = FALSE; - } - if (i == KEXLIST_KEX) { - s->kex_alg = alg->u.kex.kex; - s->warn_kex = alg->u.kex.warn; - } else if (i == KEXLIST_HOSTKEY) { - /* - * Ignore an unexpected/inappropriate offer of "null", - * we offer "null" when we're willing to use GSS KEX, - * but it is only acceptable when GSSKEX is actually - * selected. - */ - if (alg->u.hk.hostkey == NULL && - s->kex_alg->main_type != KEXTYPE_GSS) - continue; - s->hostkey_alg = alg->u.hk.hostkey; - s->warn_hk = alg->u.hk.warn; - } else if (i == KEXLIST_CSCIPHER) { - s->out.cipher = alg->u.cipher.cipher; - s->warn_cscipher = alg->u.cipher.warn; - } else if (i == KEXLIST_SCCIPHER) { - s->in.cipher = alg->u.cipher.cipher; - s->warn_sccipher = alg->u.cipher.warn; - } else if (i == KEXLIST_CSMAC) { - s->out.mac = alg->u.mac.mac; - s->out.etm_mode = alg->u.mac.etm; - } else if (i == KEXLIST_SCMAC) { - s->in.mac = alg->u.mac.mac; - s->in.etm_mode = alg->u.mac.etm; - } else if (i == KEXLIST_CSCOMP) { - s->out.comp = alg->u.comp.comp; - s->out.comp_delayed = alg->u.comp.delayed; - } else if (i == KEXLIST_SCCOMP) { - s->in.comp = alg->u.comp.comp; - s->in.comp_delayed = alg->u.comp.delayed; - } - goto matched; - } - } - ssh_sw_abort(s->ppl.ssh, "Couldn't agree a %s (available: %.*s)", - kexlist_descr[i], PTRLEN_PRINTF(str)); - return; - matched:; + int nhk, hks[MAXKEXLIST], i, j; - if (i == KEXLIST_HOSTKEY && - !s->gss_kex_used && - s->kex_alg->main_type != KEXTYPE_GSS) { - int j; + if (!ssh2_scan_kexinits( + ptrlen_from_strbuf(s->client_kexinit), + ptrlen_from_strbuf(s->server_kexinit), + s->kexlists, &s->kex_alg, &s->hostkey_alg, &s->out, &s->in, + &s->warn_kex, &s->warn_hk, &s->warn_cscipher, + &s->warn_sccipher, s->ppl.ssh, NULL, &s->ignorepkt, &nhk, hks)) + return; /* FALSE means a fatal error function was called */ - /* - * In addition to deciding which host key we're - * actually going to use, we should make a list of the - * host keys offered by the server which we _don't_ - * have cached. These will be offered as cross- - * certification options by ssh_get_specials. - * - * We also count the key we're currently using for KEX - * as one we've already got, because by the time this - * menu becomes visible, it will be. - */ - s->n_uncert_hostkeys = 0; - - for (j = 0; j < lenof(hostkey_algs); j++) { - if (hostkey_algs[j].alg != s->hostkey_alg && - in_commasep_string(hostkey_algs[j].alg->ssh_id, - str.ptr, str.len) && - !have_ssh_host_key(s->savedhost, s->savedport, - hostkey_algs[j].alg->cache_id)) { - s->uncert_hostkeys[s->n_uncert_hostkeys++] = j; - } - } + /* + * In addition to deciding which host key we're actually going + * to use, we should make a list of the host keys offered by + * the server which we _don't_ have cached. These will be + * offered as cross-certification options by ssh_get_specials. + * + * We also count the key we're currently using for KEX as one + * we've already got, because by the time this menu becomes + * visible, it will be. + */ + s->n_uncert_hostkeys = 0; + + for (i = 0; i < nhk; i++) { + j = hks[i]; + if (hostkey_algs[j].alg != s->hostkey_alg && + !have_ssh_host_key(s->savedhost, s->savedport, + hostkey_algs[j].alg->cache_id)) { + s->uncert_hostkeys[s->n_uncert_hostkeys++] = j; } } + } - get_string(pktin); /* client->server language */ - get_string(pktin); /* server->client language */ - s->ignorepkt = get_bool(pktin) && !s->guessok; - - s->exhash = ssh_hash_new(s->kex_alg->hash); - put_stringz(s->exhash, s->client_greeting); - put_stringz(s->exhash, s->server_greeting); - put_string(s->exhash, s->client_kexinit->u, s->client_kexinit->len); - put_string(s->exhash, s->server_kexinit->u, s->server_kexinit->len); - - if (s->warn_kex) { - s->dlgret = seat_confirm_weak_crypto_primitive( - s->ppl.seat, "key-exchange algorithm", s->kex_alg->name, - ssh2_transport_dialog_callback, s); - crMaybeWaitUntilV(s->dlgret >= 0); - if (s->dlgret == 0) { - ssh_user_close(s->ppl.ssh, "User aborted at kex warning"); - return; - } + s->exhash = ssh_hash_new(s->kex_alg->hash); + put_stringz(s->exhash, s->client_greeting); + put_stringz(s->exhash, s->server_greeting); + put_string(s->exhash, s->client_kexinit->u, s->client_kexinit->len); + put_string(s->exhash, s->server_kexinit->u, s->server_kexinit->len); + + if (s->warn_kex) { + s->dlgret = seat_confirm_weak_crypto_primitive( + s->ppl.seat, "key-exchange algorithm", s->kex_alg->name, + ssh2_transport_dialog_callback, s); + crMaybeWaitUntilV(s->dlgret >= 0); + if (s->dlgret == 0) { + ssh_user_close(s->ppl.ssh, "User aborted at kex warning"); + return; } + } - if (s->warn_hk) { - int j, k; - char *betteralgs; + if (s->warn_hk) { + int j, k; + char *betteralgs; - /* - * Change warning box wording depending on why we chose a - * warning-level host key algorithm. If it's because - * that's all we have *cached*, list the host keys we - * could usefully cross-certify. Otherwise, use the same - * standard wording as any other weak crypto primitive. - */ - betteralgs = NULL; - for (j = 0; j < s->n_uncert_hostkeys; j++) { - const struct ssh_signkey_with_user_pref_id *hktype = - &hostkey_algs[s->uncert_hostkeys[j]]; - int better = FALSE; - for (k = 0; k < HK_MAX; k++) { - int id = conf_get_int_int(s->conf, CONF_ssh_hklist, k); - if (id == HK_WARN) { - break; - } else if (id == hktype->id) { - better = TRUE; - break; - } + /* + * Change warning box wording depending on why we chose a + * warning-level host key algorithm. If it's because + * that's all we have *cached*, list the host keys we + * could usefully cross-certify. Otherwise, use the same + * standard wording as any other weak crypto primitive. + */ + betteralgs = NULL; + for (j = 0; j < s->n_uncert_hostkeys; j++) { + const struct ssh_signkey_with_user_pref_id *hktype = + &hostkey_algs[s->uncert_hostkeys[j]]; + int better = FALSE; + for (k = 0; k < HK_MAX; k++) { + int id = conf_get_int_int(s->conf, CONF_ssh_hklist, k); + if (id == HK_WARN) { + break; + } else if (id == hktype->id) { + better = TRUE; + break; } - if (better) { - if (betteralgs) { - char *old_ba = betteralgs; - betteralgs = dupcat(betteralgs, ",", - hktype->alg->ssh_id, - (const char *)NULL); - sfree(old_ba); - } else { - betteralgs = dupstr(hktype->alg->ssh_id); - } + } + if (better) { + if (betteralgs) { + char *old_ba = betteralgs; + betteralgs = dupcat(betteralgs, ",", + hktype->alg->ssh_id, + (const char *)NULL); + sfree(old_ba); + } else { + betteralgs = dupstr(hktype->alg->ssh_id); } } - if (betteralgs) { + } + if (betteralgs) { /* Use the special warning prompt that lets us provide * a list of better algorithms */ s->dlgret = seat_confirm_weak_cached_hostkey( s->ppl.seat, s->hostkey_alg->ssh_id, betteralgs, ssh2_transport_dialog_callback, s); - sfree(betteralgs); - } else { + sfree(betteralgs); + } else { /* If none exist, use the more general 'weak crypto' * warning prompt */ s->dlgret = seat_confirm_weak_crypto_primitive( s->ppl.seat, "host key type", s->hostkey_alg->ssh_id, ssh2_transport_dialog_callback, s); - } - crMaybeWaitUntilV(s->dlgret >= 0); - if (s->dlgret == 0) { - ssh_user_close(s->ppl.ssh, "User aborted at host key warning"); - return; - } } - - if (s->warn_cscipher) { - s->dlgret = seat_confirm_weak_crypto_primitive( - s->ppl.seat, "client-to-server cipher", s->out.cipher->name, - ssh2_transport_dialog_callback, s); - crMaybeWaitUntilV(s->dlgret >= 0); - if (s->dlgret == 0) { - ssh_user_close(s->ppl.ssh, "User aborted at cipher warning"); - return; - } + crMaybeWaitUntilV(s->dlgret >= 0); + if (s->dlgret == 0) { + ssh_user_close(s->ppl.ssh, "User aborted at host key warning"); + return; } + } - if (s->warn_sccipher) { - s->dlgret = seat_confirm_weak_crypto_primitive( - s->ppl.seat, "server-to-client cipher", s->in.cipher->name, - ssh2_transport_dialog_callback, s); - crMaybeWaitUntilV(s->dlgret >= 0); - if (s->dlgret == 0) { - ssh_user_close(s->ppl.ssh, "User aborted at cipher warning"); - return; - } + if (s->warn_cscipher) { + s->dlgret = seat_confirm_weak_crypto_primitive( + s->ppl.seat, "client-to-server cipher", s->out.cipher->name, + ssh2_transport_dialog_callback, s); + crMaybeWaitUntilV(s->dlgret >= 0); + if (s->dlgret == 0) { + ssh_user_close(s->ppl.ssh, "User aborted at cipher warning"); + return; } + } - if (s->ignorepkt) /* first_kex_packet_follows */ - crMaybeWaitUntilV((pktin = ssh2_transport_pop(s)) != NULL); + if (s->warn_sccipher) { + s->dlgret = seat_confirm_weak_crypto_primitive( + s->ppl.seat, "server-to-client cipher", s->in.cipher->name, + ssh2_transport_dialog_callback, s); + crMaybeWaitUntilV(s->dlgret >= 0); + if (s->dlgret == 0) { + ssh_user_close(s->ppl.ssh, "User aborted at cipher warning"); + return; + } } + /* + * If the other side has sent an initial key exchange packet that + * we must treat as a wrong guess, wait for it, and discard it. + */ + if (s->ignorepkt) + crMaybeWaitUntilV((pktin = ssh2_transport_pop(s)) != NULL); + if (s->kex_alg->main_type == KEXTYPE_DH) { /* * Work out the number of bits of key we will need from the diff --git a/sshcommon.c b/sshcommon.c index 51595de5..ec206c60 100644 --- a/sshcommon.c +++ b/sshcommon.c @@ -596,6 +596,38 @@ void add_to_commasep(strbuf *buf, const char *data) put_data(buf, data, strlen(data)); } +int get_commasep_word(ptrlen *list, ptrlen *word) +{ + const char *comma; + + /* + * Discard empty list elements, should there be any, because we + * never want to return one as if it was a real string. (This + * introduces a mild tolerance of badly formatted data in lists we + * receive, but I think that's acceptable.) + */ + while (list->len > 0 && *(const char *)list->ptr == ',') { + list->ptr = (const char *)list->ptr + 1; + list->len--; + } + + if (!list->len) + return FALSE; + + comma = memchr(list->ptr, ',', list->len); + if (!comma) { + *word = *list; + list->len = 0; + } else { + size_t wordlen = comma - (const char *)list->ptr; + word->ptr = list->ptr; + word->len = wordlen; + list->ptr = (const char *)list->ptr + wordlen + 1; + list->len -= wordlen + 1; + } + return TRUE; +} + /* ---------------------------------------------------------------------- * Functions for translating SSH packet type codes into their symbolic * string names. From c95b277798ae1c6830ab2b8c03576c1c28822490 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 7 Oct 2018 14:55:32 +0100 Subject: [PATCH 538/607] Unix: turn LocalProxySocket into a general FdSocket. The new FdSocket just takes an arbitrary pair of file descriptors to read and write, optionally with an extra input fd providing the standard error output from a command. uxproxy.c now just does the forking and pipe setup, and once it's got all its fds, it hands off to FdSocket to actually do the reading and writing. This is very like the reorganisation I did on the Windows side in commit 98a6a3553 (back in 2013, in preparation for named-pipe sockets and connection sharing). The idea is that it should enable me to make a thing that the PuTTY code base sees as a Socket, but which actually connects to the standard I/O handles of the process it lives in. --- Recipe | 3 +- unix/unix.h | 5 + unix/uxfdsock.c | 364 +++++++++++++++++++++++++++++++++++++++++++++++ unix/uxproxy.c | 367 +++--------------------------------------------- 4 files changed, 389 insertions(+), 350 deletions(-) create mode 100644 unix/uxfdsock.c diff --git a/Recipe b/Recipe index a18445e3..347e1e4f 100644 --- a/Recipe +++ b/Recipe @@ -270,7 +270,8 @@ MISC = misc marshal MISCNET = timing callback MISC version settings tree234 proxy CONF be_misc WINMISC = MISCNET winstore winnet winhandl cmdline windefs winmisc winproxy + wintime winhsock errsock winsecur winucs miscucs -UXMISC = MISCNET uxstore uxsel uxnet uxpeer uxmisc uxproxy errsock time +UXMISC = MISCNET uxstore uxsel uxnet uxpeer uxmisc time + + uxproxy uxfdsock errsock # import.c and dependencies, for PuTTYgen-like utilities that have to # load foreign key files. diff --git a/unix/unix.h b/unix/unix.h index f222928e..71dfc953 100644 --- a/unix/unix.h +++ b/unix/unix.h @@ -344,6 +344,11 @@ extern const struct BackendVtable serial_backend; */ int so_peercred(int fd, int *pid, int *uid, int *gid); +/* + * uxfdsock.c. + */ +Socket *make_fd_socket(int infd, int outfd, int inerrfd, Plug *plug); + /* * Default font setting, which can vary depending on NOT_X_WINDOWS. */ diff --git a/unix/uxfdsock.c b/unix/uxfdsock.c new file mode 100644 index 00000000..41aaf232 --- /dev/null +++ b/unix/uxfdsock.c @@ -0,0 +1,364 @@ +/* + * uxfdsick.c: implementation of Socket that just talks to two + * existing input and output file descriptors. + */ + +#include +#include +#include +#include +#include + +#include "tree234.h" +#include "putty.h" +#include "network.h" + +typedef struct FdSocket { + int outfd, infd, inerrfd; + + bufchain pending_output_data; + bufchain pending_input_data; + bufchain pending_input_error_data; + enum { EOF_NO, EOF_PENDING, EOF_SENT } outgoingeof; + + int pending_error; + + Plug *plug; + + Socket sock; +} FdSocket; + +static void fdsocket_select_result_input(int fd, int event); +static void fdsocket_select_result_output(int fd, int event); +static void fdsocket_select_result_input_error(int fd, int event); + +/* + * Trees to look up the fds in. + */ +static tree234 *fdsocket_by_outfd; +static tree234 *fdsocket_by_infd; +static tree234 *fdsocket_by_inerrfd; + +static int fdsocket_infd_cmp(void *av, void *bv) +{ + FdSocket *a = (FdSocket *)av; + FdSocket *b = (FdSocket *)bv; + if (a->infd < b->infd) + return -1; + if (a->infd > b->infd) + return +1; + return 0; +} +static int fdsocket_infd_find(void *av, void *bv) +{ + int a = *(int *)av; + FdSocket *b = (FdSocket *)bv; + if (a < b->infd) + return -1; + if (a > b->infd) + return +1; + return 0; +} +static int fdsocket_inerrfd_cmp(void *av, void *bv) +{ + FdSocket *a = (FdSocket *)av; + FdSocket *b = (FdSocket *)bv; + if (a->inerrfd < b->inerrfd) + return -1; + if (a->inerrfd > b->inerrfd) + return +1; + return 0; +} +static int fdsocket_inerrfd_find(void *av, void *bv) +{ + int a = *(int *)av; + FdSocket *b = (FdSocket *)bv; + if (a < b->inerrfd) + return -1; + if (a > b->inerrfd) + return +1; + return 0; +} +static int fdsocket_outfd_cmp(void *av, void *bv) +{ + FdSocket *a = (FdSocket *)av; + FdSocket *b = (FdSocket *)bv; + if (a->outfd < b->outfd) + return -1; + if (a->outfd > b->outfd) + return +1; + return 0; +} +static int fdsocket_outfd_find(void *av, void *bv) +{ + int a = *(int *)av; + FdSocket *b = (FdSocket *)bv; + if (a < b->outfd) + return -1; + if (a > b->outfd) + return +1; + return 0; +} + +static Plug *fdsocket_plug(Socket *s, Plug *p) +{ + FdSocket *fds = container_of(s, FdSocket, sock); + Plug *ret = fds->plug; + if (p) + fds->plug = p; + return ret; +} + +static void fdsocket_close(Socket *s) +{ + FdSocket *fds = container_of(s, FdSocket, sock); + + if (fds->outfd >= 0) { + del234(fdsocket_by_outfd, fds); + uxsel_del(fds->outfd); + close(fds->outfd); + } + + if (fds->infd >= 0) { + del234(fdsocket_by_infd, fds); + uxsel_del(fds->infd); + close(fds->infd); + } + + if (fds->inerrfd >= 0) { + del234(fdsocket_by_inerrfd, fds); + uxsel_del(fds->inerrfd); + close(fds->inerrfd); + } + + bufchain_clear(&fds->pending_input_data); + bufchain_clear(&fds->pending_output_data); + + delete_callbacks_for_context(fds); + + sfree(fds); +} + +static void fdsocket_error_callback(void *vs) +{ + FdSocket *fds = (FdSocket *)vs; + + /* + * Just in case other socket work has caused this socket to vanish + * or become somehow non-erroneous before this callback arrived... + */ + if (!fds->pending_error) + return; + + /* + * An error has occurred on this socket. Pass it to the plug. + */ + plug_closing(fds->plug, strerror(fds->pending_error), + fds->pending_error, 0); +} + +static int fdsocket_try_send(FdSocket *fds) +{ + int sent = 0; + + while (bufchain_size(&fds->pending_output_data) > 0) { + void *data; + int len, ret; + + bufchain_prefix(&fds->pending_output_data, &data, &len); + ret = write(fds->outfd, data, len); + if (ret < 0 && errno != EWOULDBLOCK) { + if (!fds->pending_error) { + fds->pending_error = errno; + queue_toplevel_callback(fdsocket_error_callback, fds); + } + return 0; + } else if (ret <= 0) { + break; + } else { + bufchain_consume(&fds->pending_output_data, ret); + sent += ret; + } + } + + if (fds->outgoingeof == EOF_PENDING) { + del234(fdsocket_by_outfd, fds); + close(fds->outfd); + uxsel_del(fds->outfd); + fds->outfd = -1; + fds->outgoingeof = EOF_SENT; + } + + if (bufchain_size(&fds->pending_output_data) == 0) + uxsel_del(fds->outfd); + else + uxsel_set(fds->outfd, 2, fdsocket_select_result_output); + + return sent; +} + +static int fdsocket_write(Socket *s, const void *data, int len) +{ + FdSocket *fds = container_of(s, FdSocket, sock); + + assert(fds->outgoingeof == EOF_NO); + + bufchain_add(&fds->pending_output_data, data, len); + + fdsocket_try_send(fds); + + return bufchain_size(&fds->pending_output_data); +} + +static int fdsocket_write_oob(Socket *s, const void *data, int len) +{ + /* + * oob data is treated as inband; nasty, but nothing really + * better we can do + */ + return fdsocket_write(s, data, len); +} + +static void fdsocket_write_eof(Socket *s) +{ + FdSocket *fds = container_of(s, FdSocket, sock); + + assert(fds->outgoingeof == EOF_NO); + fds->outgoingeof = EOF_PENDING; + + fdsocket_try_send(fds); +} + +static void fdsocket_flush(Socket *s) +{ + /* FdSocket *fds = container_of(s, FdSocket, sock); */ + /* do nothing */ +} + +static void fdsocket_set_frozen(Socket *s, int is_frozen) +{ + FdSocket *fds = container_of(s, FdSocket, sock); + + if (fds->infd < 0) + return; + + if (is_frozen) + uxsel_del(fds->infd); + else + uxsel_set(fds->infd, 1, fdsocket_select_result_input); +} + +static const char *fdsocket_socket_error(Socket *s) +{ + return NULL; +} + +static void fdsocket_select_result_input(int fd, int event) +{ + FdSocket *fds; + char buf[20480]; + int retd; + + if (!(fds = find234(fdsocket_by_infd, &fd, fdsocket_infd_find))) + return; + + retd = read(fds->infd, buf, sizeof(buf)); + if (retd > 0) { + plug_receive(fds->plug, 0, buf, retd); + } else { + if (retd < 0) { + plug_closing(fds->plug, strerror(errno), errno, 0); + } else { + plug_closing(fds->plug, NULL, 0, 0); + } + del234(fdsocket_by_infd, fds); + uxsel_del(fds->infd); + close(fds->infd); + fds->infd = -1; + } +} + +static void fdsocket_select_result_output(int fd, int event) +{ + FdSocket *fds; + + if (!(fds = find234(fdsocket_by_outfd, &fd, fdsocket_outfd_find))) + return; + + if (fdsocket_try_send(fds)) + plug_sent(fds->plug, bufchain_size(&fds->pending_output_data)); +} + +static void fdsocket_select_result_input_error(int fd, int event) +{ + FdSocket *fds; + char buf[20480]; + int retd; + + if (!(fds = find234(fdsocket_by_inerrfd, &fd, fdsocket_inerrfd_find))) + return; + + retd = read(fd, buf, sizeof(buf)); + if (retd > 0) { + log_proxy_stderr(fds->plug, &fds->pending_input_error_data, buf, retd); + } else { + del234(fdsocket_by_inerrfd, fds); + uxsel_del(fds->inerrfd); + close(fds->inerrfd); + fds->inerrfd = -1; + } +} + +static const SocketVtable FdSocket_sockvt = { + fdsocket_plug, + fdsocket_close, + fdsocket_write, + fdsocket_write_oob, + fdsocket_write_eof, + fdsocket_flush, + fdsocket_set_frozen, + fdsocket_socket_error, + NULL, /* peer_info */ +}; + +Socket *make_fd_socket(int infd, int outfd, int inerrfd, Plug *plug) +{ + FdSocket *fds; + + fds = snew(FdSocket); + fds->sock.vt = &FdSocket_sockvt; + fds->plug = plug; + fds->outgoingeof = EOF_NO; + fds->pending_error = 0; + + fds->infd = infd; + fds->outfd = outfd; + fds->inerrfd = inerrfd; + + bufchain_init(&fds->pending_input_data); + bufchain_init(&fds->pending_output_data); + bufchain_init(&fds->pending_input_error_data); + + if (fds->outfd >= 0) { + if (!fdsocket_by_outfd) + fdsocket_by_outfd = newtree234(fdsocket_outfd_cmp); + add234(fdsocket_by_outfd, fds); + } + + if (fds->infd >= 0) { + if (!fdsocket_by_infd) + fdsocket_by_infd = newtree234(fdsocket_infd_cmp); + add234(fdsocket_by_infd, fds); + uxsel_set(fds->infd, 1, fdsocket_select_result_input); + } + + if (fds->inerrfd >= 0) { + assert(fds->inerrfd != fds->infd); + if (!fdsocket_by_inerrfd) + fdsocket_by_inerrfd = newtree234(fdsocket_inerrfd_cmp); + add234(fdsocket_by_inerrfd, fds); + uxsel_set(fds->inerrfd, 1, fdsocket_select_result_input_error); + } + + return &fds->sock; +} diff --git a/unix/uxproxy.c b/unix/uxproxy.c index 9e727ef8..c8d40d86 100644 --- a/unix/uxproxy.c +++ b/unix/uxproxy.c @@ -14,306 +14,6 @@ #include "network.h" #include "proxy.h" -typedef struct LocalProxySocket { - int to_cmd, from_cmd, cmd_err; /* fds */ - - char *error; - - Plug *plug; - - bufchain pending_output_data; - bufchain pending_input_data; - bufchain pending_error_data; - enum { EOF_NO, EOF_PENDING, EOF_SENT } outgoingeof; - - int pending_error; - - Socket sock; -} LocalProxySocket; - -static void localproxy_select_result(int fd, int event); - -/* - * Trees to look up the pipe fds in. - */ -static tree234 *localproxy_by_fromfd; -static tree234 *localproxy_by_tofd; -static tree234 *localproxy_by_errfd; -static int localproxy_fromfd_cmp(void *av, void *bv) -{ - LocalProxySocket *a = (LocalProxySocket *)av; - LocalProxySocket *b = (LocalProxySocket *)bv; - if (a->from_cmd < b->from_cmd) - return -1; - if (a->from_cmd > b->from_cmd) - return +1; - return 0; -} -static int localproxy_fromfd_find(void *av, void *bv) -{ - int a = *(int *)av; - LocalProxySocket *b = (LocalProxySocket *)bv; - if (a < b->from_cmd) - return -1; - if (a > b->from_cmd) - return +1; - return 0; -} -static int localproxy_tofd_cmp(void *av, void *bv) -{ - LocalProxySocket *a = (LocalProxySocket *)av; - LocalProxySocket *b = (LocalProxySocket *)bv; - if (a->to_cmd < b->to_cmd) - return -1; - if (a->to_cmd > b->to_cmd) - return +1; - return 0; -} -static int localproxy_tofd_find(void *av, void *bv) -{ - int a = *(int *)av; - LocalProxySocket *b = (LocalProxySocket *)bv; - if (a < b->to_cmd) - return -1; - if (a > b->to_cmd) - return +1; - return 0; -} -static int localproxy_errfd_cmp(void *av, void *bv) -{ - LocalProxySocket *a = (LocalProxySocket *)av; - LocalProxySocket *b = (LocalProxySocket *)bv; - if (a->cmd_err < b->cmd_err) - return -1; - if (a->cmd_err > b->cmd_err) - return +1; - return 0; -} -static int localproxy_errfd_find(void *av, void *bv) -{ - int a = *(int *)av; - LocalProxySocket *b = (LocalProxySocket *)bv; - if (a < b->cmd_err) - return -1; - if (a > b->cmd_err) - return +1; - return 0; -} - -/* basic proxy socket functions */ - -static Plug *sk_localproxy_plug (Socket *s, Plug *p) -{ - LocalProxySocket *ps = container_of(s, LocalProxySocket, sock); - Plug *ret = ps->plug; - if (p) - ps->plug = p; - return ret; -} - -static void sk_localproxy_close (Socket *s) -{ - LocalProxySocket *ps = container_of(s, LocalProxySocket, sock); - - if (ps->to_cmd >= 0) { - del234(localproxy_by_tofd, ps); - uxsel_del(ps->to_cmd); - close(ps->to_cmd); - } - - if (ps->from_cmd >= 0) { - del234(localproxy_by_fromfd, ps); - uxsel_del(ps->from_cmd); - close(ps->from_cmd); - } - - if (ps->cmd_err >= 0) { - del234(localproxy_by_errfd, ps); - uxsel_del(ps->cmd_err); - close(ps->cmd_err); - } - - bufchain_clear(&ps->pending_input_data); - bufchain_clear(&ps->pending_output_data); - bufchain_clear(&ps->pending_error_data); - - delete_callbacks_for_context(ps); - - sfree(ps); -} - -static void localproxy_error_callback(void *vs) -{ - LocalProxySocket *ps = (LocalProxySocket *)vs; - - /* - * Just in case other socket work has caused this socket to vanish - * or become somehow non-erroneous before this callback arrived... - */ - if (!ps->pending_error) - return; - - /* - * An error has occurred on this socket. Pass it to the plug. - */ - plug_closing(ps->plug, strerror(ps->pending_error), ps->pending_error, 0); -} - -static int localproxy_try_send(LocalProxySocket *ps) -{ - int sent = 0; - - while (bufchain_size(&ps->pending_output_data) > 0) { - void *data; - int len, ret; - - bufchain_prefix(&ps->pending_output_data, &data, &len); - ret = write(ps->to_cmd, data, len); - if (ret < 0 && errno != EWOULDBLOCK) { - if (!ps->pending_error) { - ps->pending_error = errno; - queue_toplevel_callback(localproxy_error_callback, ps); - } - return 0; - } else if (ret <= 0) { - break; - } else { - bufchain_consume(&ps->pending_output_data, ret); - sent += ret; - } - } - - if (ps->outgoingeof == EOF_PENDING) { - del234(localproxy_by_tofd, ps); - close(ps->to_cmd); - uxsel_del(ps->to_cmd); - ps->to_cmd = -1; - ps->outgoingeof = EOF_SENT; - } - - if (bufchain_size(&ps->pending_output_data) == 0) - uxsel_del(ps->to_cmd); - else - uxsel_set(ps->to_cmd, 2, localproxy_select_result); - - return sent; -} - -static int sk_localproxy_write (Socket *s, const void *data, int len) -{ - LocalProxySocket *ps = container_of(s, LocalProxySocket, sock); - - assert(ps->outgoingeof == EOF_NO); - - bufchain_add(&ps->pending_output_data, data, len); - - localproxy_try_send(ps); - - return bufchain_size(&ps->pending_output_data); -} - -static int sk_localproxy_write_oob (Socket *s, const void *data, int len) -{ - /* - * oob data is treated as inband; nasty, but nothing really - * better we can do - */ - return sk_localproxy_write(s, data, len); -} - -static void sk_localproxy_write_eof (Socket *s) -{ - LocalProxySocket *ps = container_of(s, LocalProxySocket, sock); - - assert(ps->outgoingeof == EOF_NO); - ps->outgoingeof = EOF_PENDING; - - localproxy_try_send(ps); -} - -static void sk_localproxy_flush (Socket *s) -{ - /* LocalProxySocket *ps = container_of(s, LocalProxySocket, sock); */ - /* do nothing */ -} - -static void sk_localproxy_set_frozen (Socket *s, int is_frozen) -{ - LocalProxySocket *ps = container_of(s, LocalProxySocket, sock); - - if (ps->from_cmd < 0) - return; - - if (is_frozen) - uxsel_del(ps->from_cmd); - else - uxsel_set(ps->from_cmd, 1, localproxy_select_result); -} - -static const char * sk_localproxy_socket_error (Socket *s) -{ - LocalProxySocket *ps = container_of(s, LocalProxySocket, sock); - return ps->error; -} - -static void localproxy_select_result(int fd, int event) -{ - LocalProxySocket *s; - char buf[20480]; - int ret; - - if (!(s = find234(localproxy_by_fromfd, &fd, localproxy_fromfd_find)) && - !(s = find234(localproxy_by_errfd, &fd, localproxy_errfd_find)) && - !(s = find234(localproxy_by_tofd, &fd, localproxy_tofd_find)) ) - return; /* boggle */ - - if (event == 1) { - if (fd == s->cmd_err) { - ret = read(fd, buf, sizeof(buf)); - if (ret > 0) { - log_proxy_stderr(s->plug, &s->pending_error_data, buf, ret); - } else { - del234(localproxy_by_errfd, s); - uxsel_del(s->cmd_err); - close(s->cmd_err); - s->cmd_err = -1; - } - } else { - assert(fd == s->from_cmd); - ret = read(fd, buf, sizeof(buf)); - if (ret > 0) { - plug_receive(s->plug, 0, buf, ret); - } else { - if (ret < 0) { - plug_closing(s->plug, strerror(errno), errno, 0); - } else { - plug_closing(s->plug, NULL, 0, 0); - } - del234(localproxy_by_fromfd, s); - uxsel_del(s->from_cmd); - close(s->from_cmd); - s->from_cmd = -1; - } - } - } else if (event == 2) { - assert(fd == s->to_cmd); - if (localproxy_try_send(s)) - plug_sent(s->plug, bufchain_size(&s->pending_output_data)); - } -} - -static const SocketVtable LocalProxySocket_sockvt = { - sk_localproxy_plug, - sk_localproxy_close, - sk_localproxy_write, - sk_localproxy_write_oob, - sk_localproxy_write_eof, - sk_localproxy_flush, - sk_localproxy_set_frozen, - sk_localproxy_socket_error, - NULL, /* peer_info */ -}; - Socket *platform_new_connection(SockAddr *addr, const char *hostname, int port, int privport, int oobinline, int nodelay, int keepalive, @@ -321,24 +21,13 @@ Socket *platform_new_connection(SockAddr *addr, const char *hostname, { char *cmd; - LocalProxySocket *ret; int to_cmd_pipe[2], from_cmd_pipe[2], cmd_err_pipe[2], pid, proxytype; + int infd, outfd, inerrfd; proxytype = conf_get_int(conf, CONF_proxy_type); if (proxytype != PROXY_CMD && proxytype != PROXY_FUZZ) return NULL; - ret = snew(LocalProxySocket); - ret->sock.vt = &LocalProxySocket_sockvt; - ret->plug = plug; - ret->error = NULL; - ret->outgoingeof = EOF_NO; - ret->pending_error = 0; - - bufchain_init(&ret->pending_input_data); - bufchain_init(&ret->pending_output_data); - bufchain_init(&ret->pending_error_data); - if (proxytype == PROXY_CMD) { cmd = format_telnet_command(addr, port, conf); @@ -355,21 +44,15 @@ Socket *platform_new_connection(SockAddr *addr, const char *hostname, if (pipe(to_cmd_pipe) < 0 || pipe(from_cmd_pipe) < 0 || pipe(cmd_err_pipe) < 0) { - ret->error = dupprintf("pipe: %s", strerror(errno)); sfree(cmd); - return &ret->sock; + return new_error_socket_fmt(plug, "pipe: %s", strerror(errno)); } cloexec(to_cmd_pipe[1]); cloexec(from_cmd_pipe[0]); cloexec(cmd_err_pipe[0]); pid = fork(); - - if (pid < 0) { - ret->error = dupprintf("fork: %s", strerror(errno)); - sfree(cmd); - return &ret->sock; - } else if (pid == 0) { + if (pid == 0) { close(0); close(1); dup2(to_cmd_pipe[0], 0); @@ -385,49 +68,35 @@ Socket *platform_new_connection(SockAddr *addr, const char *hostname, sfree(cmd); + if (pid < 0) + return new_error_socket_fmt(plug, "fork: %s", strerror(errno)); + close(to_cmd_pipe[0]); close(from_cmd_pipe[1]); close(cmd_err_pipe[1]); - ret->to_cmd = to_cmd_pipe[1]; - ret->from_cmd = from_cmd_pipe[0]; - ret->cmd_err = cmd_err_pipe[0]; + outfd = to_cmd_pipe[1]; + infd = from_cmd_pipe[0]; + inerrfd = cmd_err_pipe[0]; } else { cmd = format_telnet_command(addr, port, conf); - ret->to_cmd = open("/dev/null", O_WRONLY); - if (ret->to_cmd == -1) { - ret->error = dupprintf("/dev/null: %s", strerror(errno)); + outfd = open("/dev/null", O_WRONLY); + if (outfd == -1) { sfree(cmd); - return &ret->sock; + return new_error_socket_fmt( + plug, "/dev/null: %s", strerror(errno)); } - ret->from_cmd = open(cmd, O_RDONLY); - if (ret->from_cmd == -1) { - ret->error = dupprintf("%s: %s", cmd, strerror(errno)); + infd = open(cmd, O_RDONLY); + if (infd == -1) { sfree(cmd); - return &ret->sock; + return new_error_socket_fmt(plug, "%s: %s", cmd, strerror(errno)); } sfree(cmd); - ret->cmd_err = -1; + inerrfd = -1; } - if (!localproxy_by_fromfd) - localproxy_by_fromfd = newtree234(localproxy_fromfd_cmp); - if (!localproxy_by_tofd) - localproxy_by_tofd = newtree234(localproxy_tofd_cmp); - if (!localproxy_by_errfd) - localproxy_by_errfd = newtree234(localproxy_errfd_cmp); - - add234(localproxy_by_fromfd, ret); - add234(localproxy_by_tofd, ret); - if (ret->cmd_err >= 0) - add234(localproxy_by_errfd, ret); - - uxsel_set(ret->from_cmd, 1, localproxy_select_result); - if (ret->cmd_err >= 0) - uxsel_set(ret->cmd_err, 1, localproxy_select_result); - /* We are responsible for this and don't need it any more */ sk_addr_free(addr); - return &ret->sock; + return make_fd_socket(infd, outfd, inerrfd, plug); } From 99c215e761b01b99244bf4649ddfd71c246712fc Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 13 Oct 2018 07:37:24 +0100 Subject: [PATCH 539/607] Change Seat's get_char_cell_size to get_window_pixel_size. That's more directly useful in uxpty.c (which is currently the only actual client of the function), and also matches the data that SSH clients send in "pty-req". Also, it makes that method behave more like the GUI query function get_window_pixels used by terminal.c (with the sole exception that unlike g_w_p it's allowed to return failure), so it becomes even more trivial to implement in the GUI front ends. --- misc.c | 2 +- pscp.c | 2 +- psftp.c | 2 +- putty.h | 10 +++++----- unix/gtkwin.c | 7 +++---- unix/uxplink.c | 2 +- unix/uxpty.c | 6 +++--- windows/window.c | 7 +++---- windows/winplink.c | 2 +- 9 files changed, 19 insertions(+), 21 deletions(-) diff --git a/misc.c b/misc.c index 274f8aa8..c84a2096 100644 --- a/misc.c +++ b/misc.c @@ -1414,5 +1414,5 @@ int nullseat_is_always_utf8(Seat *seat) { return TRUE; } void nullseat_echoedit_update(Seat *seat, int echoing, int editing) {} const char *nullseat_get_x_display(Seat *seat) { return NULL; } int nullseat_get_windowid(Seat *seat, long *id_out) { return FALSE; } -int nullseat_get_char_cell_size( +int nullseat_get_window_pixel_size( Seat *seat, int *width, int *height) { return FALSE; } diff --git a/pscp.c b/pscp.c index 9fc0c3e0..d7efd147 100644 --- a/pscp.c +++ b/pscp.c @@ -80,7 +80,7 @@ static const SeatVtable pscp_seat_vt = { nullseat_echoedit_update, nullseat_get_x_display, nullseat_get_windowid, - nullseat_get_char_cell_size, + nullseat_get_window_pixel_size, }; static Seat pscp_seat[1] = {{ &pscp_seat_vt }}; diff --git a/psftp.c b/psftp.c index 08f5d5bd..bee62b7d 100644 --- a/psftp.c +++ b/psftp.c @@ -61,7 +61,7 @@ static const SeatVtable psftp_seat_vt = { nullseat_echoedit_update, nullseat_get_x_display, nullseat_get_windowid, - nullseat_get_char_cell_size, + nullseat_get_window_pixel_size, }; static Seat psftp_seat[1] = {{ &psftp_seat_vt }}; diff --git a/putty.h b/putty.h index 6c380360..81fbfc0f 100644 --- a/putty.h +++ b/putty.h @@ -903,12 +903,12 @@ struct SeatVtable { int (*get_windowid)(Seat *seat, long *id_out); /* - * Return the pixel size of a terminal character cell. If the + * Return the size of the terminal window in pixels. If the * concept is meaningless or the information is unavailable, * return FALSE; otherwise fill in the output pointers and return * TRUE. */ - int (*get_char_cell_size)(Seat *seat, int *width, int *height); + int (*get_window_pixel_size)(Seat *seat, int *width, int *height); }; #define seat_output(seat, is_stderr, data, len) \ @@ -939,8 +939,8 @@ struct SeatVtable { ((seat)->vt->get_x_display(seat)) #define seat_get_windowid(seat, out) \ ((seat)->vt->get_windowid(seat, out)) -#define seat_get_char_cell_size(seat, width, height) \ - ((seat)->vt->get_char_cell_size(seat, width, height)) +#define seat_get_window_pixel_size(seat, width, height) \ + ((seat)->vt->get_window_pixel_size(seat, width, height)) /* Unlike the seat's actual method, the public entry point * seat_connection_fatal is a wrapper function with a printf-like API, @@ -983,7 +983,7 @@ int nullseat_is_always_utf8(Seat *seat); void nullseat_echoedit_update(Seat *seat, int echoing, int editing); const char *nullseat_get_x_display(Seat *seat); int nullseat_get_windowid(Seat *seat, long *id_out); -int nullseat_get_char_cell_size(Seat *seat, int *width, int *height); +int nullseat_get_window_pixel_size(Seat *seat, int *width, int *height); /* * Seat functions provided by the platform's console-application diff --git a/unix/gtkwin.c b/unix/gtkwin.c index 63ae311c..c364afe2 100644 --- a/unix/gtkwin.c +++ b/unix/gtkwin.c @@ -340,11 +340,10 @@ static int gtk_seat_is_utf8(Seat *seat) return frontend_is_utf8(inst); } -static int gtk_seat_get_char_cell_size(Seat *seat, int *w, int *h) +static int gtk_seat_get_window_pixel_size(Seat *seat, int *w, int *h) { Frontend *inst = container_of(seat, Frontend, seat); - *w = inst->font_width; - *h = inst->font_height; + get_window_pixels(inst, w, h); return TRUE; } @@ -376,7 +375,7 @@ static const SeatVtable gtk_seat_vt = { #else gtk_seat_get_windowid, #endif - gtk_seat_get_char_cell_size, + gtk_seat_get_window_pixel_size, }; static void gtk_eventlog(LogPolicy *lp, const char *string) diff --git a/unix/uxplink.c b/unix/uxplink.c index 6f3e7bea..6b7da66c 100644 --- a/unix/uxplink.c +++ b/unix/uxplink.c @@ -394,7 +394,7 @@ static const SeatVtable plink_seat_vt = { plink_echoedit_update, nullseat_get_x_display, nullseat_get_windowid, - nullseat_get_char_cell_size, + nullseat_get_window_pixel_size, }; static Seat plink_seat[1] = {{ &plink_seat_vt }}; diff --git a/unix/uxpty.c b/unix/uxpty.c index c80dde6b..5ae1acca 100644 --- a/unix/uxpty.c +++ b/unix/uxpty.c @@ -1155,12 +1155,12 @@ static void pty_size(Backend *be, int width, int height) pty->term_width = width; pty->term_height = height; - seat_get_char_cell_size(pty->seat, &xpixel, &ypixel); + seat_get_window_pixel_size(pty->seat, &xpixel, &ypixel); size.ws_row = (unsigned short)pty->term_height; size.ws_col = (unsigned short)pty->term_width; - size.ws_xpixel = (unsigned short)pty->term_width * xpixel; - size.ws_ypixel = (unsigned short)pty->term_height * ypixel; + size.ws_xpixel = (unsigned short)xpixel; + size.ws_ypixel = (unsigned short)ypixel; ioctl(pty->master_fd, TIOCSWINSZ, (void *)&size); return; } diff --git a/windows/window.c b/windows/window.c index d0320433..d3047b25 100644 --- a/windows/window.c +++ b/windows/window.c @@ -245,10 +245,9 @@ char *win_seat_get_ttymode(Seat *seat, const char *mode) return term_get_ttymode(term, mode); } -int win_seat_get_char_cell_size(Seat *seat, int *x, int *y) +int win_seat_get_window_pixel_size(Seat *seat, int *x, int *y) { - *x = font_width; - *y = font_height; + get_window_pixels(NULL, x, y); return TRUE; } @@ -277,7 +276,7 @@ static const SeatVtable win_seat_vt = { nullseat_echoedit_update, nullseat_get_x_display, nullseat_get_windowid, - win_seat_get_char_cell_size, + win_seat_get_window_pixel_size, }; Seat win_seat[1] = {{ &win_seat_vt }}; diff --git a/windows/winplink.c b/windows/winplink.c index 4c173182..d2a7b80e 100644 --- a/windows/winplink.c +++ b/windows/winplink.c @@ -103,7 +103,7 @@ static const SeatVtable plink_seat_vt = { plink_echoedit_update, nullseat_get_x_display, nullseat_get_windowid, - nullseat_get_char_cell_size, + nullseat_get_window_pixel_size, }; static Seat plink_seat[1] = {{ &plink_seat_vt }}; From 1bde686945326644a4ed8a9da3d6dd7edfe66f1e Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 13 Oct 2018 10:30:03 +0100 Subject: [PATCH 540/607] Rename sshfwd_unclean_close to sshfwd_initiate_close. Turns out that initiation of a CHANNEL_CLOSE message before both sides have sent EOF is not only for _unclean_ closures or emergencies; it's actually a perfectly normal thing that some channel types want to do. (For example, a channel with a pty at the server end of it has no real concept of sending EOF independently in both directions: when the pty master sends EIO, the pty is no longer functioning, and you can no longer send to it any more than you can receive.) --- portfwd.c | 4 ++-- ssh1connection.c | 8 ++++---- ssh2connection.c | 8 ++++---- sshchan.h | 4 ++-- x11fwd.c | 2 +- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/portfwd.c b/portfwd.c index 03c30dc2..656acf86 100644 --- a/portfwd.c +++ b/portfwd.c @@ -120,12 +120,12 @@ static void pfd_closing(Plug *plug, const char *error_msg, int error_code, * Socket error. Slam the connection instantly shut. */ if (pf->c) { - sshfwd_unclean_close(pf->c, error_msg); + sshfwd_initiate_close(pf->c, error_msg); } else { /* * We might not have an SSH channel, if a socket error * occurred during SOCKS negotiation. If not, we must - * clean ourself up without sshfwd_unclean_close's call + * clean ourself up without sshfwd_initiate_close's call * back to pfd_close. */ pfd_close(pf); diff --git a/ssh1connection.c b/ssh1connection.c index d406ea33..77bd01f7 100644 --- a/ssh1connection.c +++ b/ssh1connection.c @@ -195,7 +195,7 @@ struct ssh1_channel { static int ssh1channel_write(SshChannel *c, const void *buf, int len); static void ssh1channel_write_eof(SshChannel *c); -static void ssh1channel_unclean_close(SshChannel *c, const char *err); +static void ssh1channel_initiate_close(SshChannel *c, const char *err); static void ssh1channel_unthrottle(SshChannel *c, int bufsize); static Conf *ssh1channel_get_conf(SshChannel *c); static void ssh1channel_window_override_removed(SshChannel *c) { /* ignore */ } @@ -203,7 +203,7 @@ static void ssh1channel_window_override_removed(SshChannel *c) { /* ignore */ } static const struct SshChannelVtable ssh1channel_vtable = { ssh1channel_write, ssh1channel_write_eof, - ssh1channel_unclean_close, + ssh1channel_initiate_close, ssh1channel_unthrottle, ssh1channel_get_conf, ssh1channel_window_override_removed, @@ -937,12 +937,12 @@ static void ssh1channel_write_eof(SshChannel *sc) ssh1_channel_try_eof(c); } -static void ssh1channel_unclean_close(SshChannel *sc, const char *err) +static void ssh1channel_initiate_close(SshChannel *sc, const char *err) { struct ssh1_channel *c = container_of(sc, struct ssh1_channel, sc); char *reason; - reason = dupprintf("due to local error: %s", err); + reason = err ? dupprintf("due to local error: %s", err) : NULL; ssh1_channel_close_local(c, reason); sfree(reason); c->pending_eof = FALSE; /* this will confuse a zombie channel */ diff --git a/ssh2connection.c b/ssh2connection.c index c0b3e365..03857ea1 100644 --- a/ssh2connection.c +++ b/ssh2connection.c @@ -258,7 +258,7 @@ struct ssh2_channel { static int ssh2channel_write(SshChannel *c, const void *buf, int len); static void ssh2channel_write_eof(SshChannel *c); -static void ssh2channel_unclean_close(SshChannel *c, const char *err); +static void ssh2channel_initiate_close(SshChannel *c, const char *err); static void ssh2channel_unthrottle(SshChannel *c, int bufsize); static Conf *ssh2channel_get_conf(SshChannel *c); static void ssh2channel_window_override_removed(SshChannel *c); @@ -294,7 +294,7 @@ static void ssh2channel_hint_channel_is_simple(SshChannel *c); static const struct SshChannelVtable ssh2channel_vtable = { ssh2channel_write, ssh2channel_write_eof, - ssh2channel_unclean_close, + ssh2channel_initiate_close, ssh2channel_unthrottle, ssh2channel_get_conf, ssh2channel_window_override_removed, @@ -1442,12 +1442,12 @@ static void ssh2channel_write_eof(SshChannel *sc) ssh2_channel_try_eof(c); } -static void ssh2channel_unclean_close(SshChannel *sc, const char *err) +static void ssh2channel_initiate_close(SshChannel *sc, const char *err) { struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc); char *reason; - reason = dupprintf("due to local error: %s", err); + reason = err ? dupprintf("due to local error: %s", err) : NULL; ssh2_channel_close_local(c, reason); sfree(reason); c->pending_eof = FALSE; /* this will confuse a zombie channel */ diff --git a/sshchan.h b/sshchan.h index 7f1be259..3b221481 100644 --- a/sshchan.h +++ b/sshchan.h @@ -106,7 +106,7 @@ Channel *zombiechan_new(void); struct SshChannelVtable { int (*write)(SshChannel *c, const void *, int); void (*write_eof)(SshChannel *c); - void (*unclean_close)(SshChannel *c, const char *err); + void (*initiate_close)(SshChannel *c, const char *err); void (*unthrottle)(SshChannel *c, int bufsize); Conf *(*get_conf)(SshChannel *c); void (*window_override_removed)(SshChannel *c); @@ -162,7 +162,7 @@ struct SshChannel { #define sshfwd_write(c, buf, len) ((c)->vt->write(c, buf, len)) #define sshfwd_write_eof(c) ((c)->vt->write_eof(c)) -#define sshfwd_unclean_close(c, err) ((c)->vt->unclean_close(c, err)) +#define sshfwd_initiate_close(c, err) ((c)->vt->initiate_close(c, err)) #define sshfwd_unthrottle(c, bufsize) ((c)->vt->unthrottle(c, bufsize)) #define sshfwd_get_conf(c) ((c)->vt->get_conf(c)) #define sshfwd_window_override_removed(c) ((c)->vt->window_override_removed(c)) diff --git a/x11fwd.c b/x11fwd.c index 708f8d0e..44c9df1e 100644 --- a/x11fwd.c +++ b/x11fwd.c @@ -662,7 +662,7 @@ static void x11_closing(Plug *plug, const char *error_msg, int error_code, * Whether we did that or not, now we slam the connection * shut. */ - sshfwd_unclean_close(xconn->c, error_msg); + sshfwd_initiate_close(xconn->c, error_msg); } else { /* * Ordinary EOF received on socket. Send an EOF on the SSH From 82c83c1894b34b28c44e78d6b52eb0c91a022560 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Thu, 18 Oct 2018 20:06:42 +0100 Subject: [PATCH 541/607] Improve sk_peer_info. Previously, it returned a human-readable string suitable for log files, which tried to say something useful about the remote end of a socket. Now it returns a whole SocketPeerInfo structure, of which that human-friendly log string is just one field, but also some of the same information - remote IP address and port, in particular - is provided in machine-readable form where it's available. --- defs.h | 1 + errsock.c | 2 +- mainchan.c | 3 ++- misc.c | 9 +++++++++ network.h | 48 ++++++++++++++++++++++++++++++++++++++++---- pageant.c | 7 ++++--- portfwd.c | 14 ++++++------- putty.h | 6 +++++- ssh.h | 7 ++++--- ssh1connection.c | 7 ++++--- ssh2connection.c | 7 ++++--- sshshare.c | 8 ++++---- unix/uxnet.c | 50 +++++++++++++++++++++++++++++++--------------- windows/winhsock.c | 12 ++++++++--- windows/winnet.c | 39 ++++++++++++++++++++++++++---------- windows/winnps.c | 2 +- 16 files changed, 161 insertions(+), 61 deletions(-) diff --git a/defs.h b/defs.h index 84df209a..ed934a13 100644 --- a/defs.h +++ b/defs.h @@ -44,6 +44,7 @@ typedef struct SockAddr SockAddr; typedef struct Socket Socket; typedef struct Plug Plug; +typedef struct SocketPeerInfo SocketPeerInfo; typedef struct Backend Backend; typedef struct BackendVtable BackendVtable; diff --git a/errsock.c b/errsock.c index 7e5f97be..9ab7c3db 100644 --- a/errsock.c +++ b/errsock.c @@ -39,7 +39,7 @@ static const char *sk_error_socket_error(Socket *s) return es->error; } -static char *sk_error_peer_info(Socket *s) +static SocketPeerInfo *sk_error_peer_info(Socket *s) { return NULL; } diff --git a/mainchan.c b/mainchan.c index c8963883..524a0fc8 100644 --- a/mainchan.c +++ b/mainchan.c @@ -88,7 +88,8 @@ mainchan *mainchan_new( const char *host = conf_get_str(mc->conf, CONF_ssh_nc_host); int port = conf_get_int(mc->conf, CONF_ssh_nc_port); - mc->sc = ssh_lportfwd_open(cl, host, port, "main channel", &mc->chan); + mc->sc = ssh_lportfwd_open(cl, host, port, "main channel", + NULL, &mc->chan); mc->type = MAINCHAN_DIRECT_TCPIP; } else { mc->sc = ssh_session_open(cl, &mc->chan); diff --git a/misc.c b/misc.c index c84a2096..39e77f76 100644 --- a/misc.c +++ b/misc.c @@ -1416,3 +1416,12 @@ const char *nullseat_get_x_display(Seat *seat) { return NULL; } int nullseat_get_windowid(Seat *seat, long *id_out) { return FALSE; } int nullseat_get_window_pixel_size( Seat *seat, int *width, int *height) { return FALSE; } + +void sk_free_peer_info(SocketPeerInfo *pi) +{ + if (pi) { + sfree((char *)pi->addr_text); + sfree((char *)pi->log_text); + sfree(pi); + } +} diff --git a/network.h b/network.h index 4799a337..62f3afe3 100644 --- a/network.h +++ b/network.h @@ -35,7 +35,7 @@ struct SocketVtable { void (*set_frozen) (Socket *s, int is_frozen); /* ignored by tcp, but vital for ssl */ const char *(*socket_error) (Socket *s); - char *(*peer_info) (Socket *s); + SocketPeerInfo *(*peer_info) (Socket *s); }; typedef union { void *p; int i; } accept_ctx_t; @@ -194,12 +194,52 @@ const char *sk_addr_error(SockAddr *addr); #define sk_set_frozen(s, is_frozen) (((s)->vt->set_frozen) (s, is_frozen)) /* - * Return a (dynamically allocated) string giving some information - * about the other end of the socket, suitable for putting in log - * files. May be NULL if nothing is available at all. + * Return a structure giving some information about the other end of + * the socket. May be NULL, if nothing is available at all. If it is + * not NULL, then it is dynamically allocated, and should be freed by + * a call to sk_free_peer_info(). See below for the definition. */ #define sk_peer_info(s) (((s)->vt->peer_info) (s)) +/* + * The structure returned from sk_peer_info, and a function to free + * one (in misc.c). + */ +struct SocketPeerInfo { + int addressfamily; + + /* + * Text form of the IPv4 or IPv6 address of the other end of the + * socket, if available, in the standard text representation. + */ + const char *addr_text; + + /* + * Binary form of the same address. Filled in if and only if + * addr_text is not NULL. You can tell which branch of the union + * is used by examining 'addressfamily'. + */ + union { + unsigned char ipv6[16]; + unsigned char ipv4[4]; + } addr_bin; + + /* + * Remote port number, or -1 if not available. + */ + int port; + + /* + * Free-form text suitable for putting in log messages. For IP + * sockets, repeats the address and port information from above. + * But it can be completely different, e.g. for Unix-domain + * sockets it gives information about the uid, gid and pid of the + * connecting process. + */ + const char *log_text; +}; +void sk_free_peer_info(SocketPeerInfo *pi); + /* * Simple wrapper on getservbyname(), needed by ssh.c. Returns the * port number, in host byte order (suitable for printf and so on). diff --git a/pageant.c b/pageant.c index 5f22127e..bde0f66e 100644 --- a/pageant.c +++ b/pageant.c @@ -830,7 +830,7 @@ static int pageant_listen_accepting(Plug *plug, plug, struct pageant_listen_state, plug); struct pageant_conn_state *pc; const char *err; - char *peerinfo; + SocketPeerInfo *peerinfo; pc = snew(struct pageant_conn_state); pc->plug.vt = &pageant_connection_plugvt; @@ -848,12 +848,13 @@ static int pageant_listen_accepting(Plug *plug, sk_set_frozen(pc->connsock, 0); peerinfo = sk_peer_info(pc->connsock); - if (peerinfo) { + if (peerinfo && peerinfo->log_text) { plog(pl->logctx, pl->logfn, "%p: new connection from %s", - pc, peerinfo); + pc, peerinfo->log_text); } else { plog(pl->logctx, pl->logfn, "%p: new connection", pc); } + sk_free_peer_info(peerinfo); return 0; } diff --git a/portfwd.c b/portfwd.c index 656acf86..dbba3889 100644 --- a/portfwd.c +++ b/portfwd.c @@ -153,18 +153,18 @@ static SshChannel *wrap_lportfwd_open( ConnectionLayer *cl, const char *hostname, int port, Socket *s, Channel *chan) { - char *peerinfo, *description; + SocketPeerInfo *pi; + char *description; SshChannel *toret; - peerinfo = sk_peer_info(s); - if (peerinfo) { - description = dupprintf("forwarding from %s", peerinfo); - sfree(peerinfo); + pi = sk_peer_info(s); + if (pi && pi->log_text) { + description = dupprintf("forwarding from %s", pi->log_text); } else { description = dupstr("forwarding"); } - - toret = ssh_lportfwd_open(cl, hostname, port, description, chan); + toret = ssh_lportfwd_open(cl, hostname, port, description, pi, chan); + sk_free_peer_info(pi); sfree(description); return toret; diff --git a/putty.h b/putty.h index 81fbfc0f..aaf8d78c 100644 --- a/putty.h +++ b/putty.h @@ -483,7 +483,11 @@ enum { * host name has already been resolved or will be resolved at * the proxy end. */ - ADDRTYPE_UNSPEC, ADDRTYPE_IPV4, ADDRTYPE_IPV6, ADDRTYPE_NAME + ADDRTYPE_UNSPEC, + ADDRTYPE_IPV4, + ADDRTYPE_IPV6, + ADDRTYPE_LOCAL, /* e.g. Unix domain socket, or Windows named pipe */ + ADDRTYPE_NAME /* SockAddr storing an unresolved host name */ }; struct Backend { diff --git a/ssh.h b/ssh.h index 583ab61b..bf7eda97 100644 --- a/ssh.h +++ b/ssh.h @@ -216,7 +216,8 @@ struct ConnectionLayerVtable { * PortFwdManager */ SshChannel *(*lportfwd_open)( ConnectionLayer *cl, const char *hostname, int port, - const char *org, Channel *chan); + const char *description, const SocketPeerInfo *peerinfo, + Channel *chan); /* Initiate opening of a 'session'-type channel */ SshChannel *(*session_open)(ConnectionLayer *cl, Channel *chan); @@ -297,8 +298,8 @@ struct ConnectionLayer { #define ssh_rportfwd_alloc(cl, sh, sp, dh, dp, af, ld, pfr, share) \ ((cl)->vt->rportfwd_alloc(cl, sh, sp, dh, dp, af, ld, pfr, share)) #define ssh_rportfwd_remove(cl, rpf) ((cl)->vt->rportfwd_remove(cl, rpf)) -#define ssh_lportfwd_open(cl, h, p, org, chan) \ - ((cl)->vt->lportfwd_open(cl, h, p, org, chan)) +#define ssh_lportfwd_open(cl, h, p, desc, pi, chan) \ + ((cl)->vt->lportfwd_open(cl, h, p, desc, pi, chan)) #define ssh_session_open(cl, chan) \ ((cl)->vt->session_open(cl, chan)) #define ssh_add_x11_display(cl, auth, disp) \ diff --git a/ssh1connection.c b/ssh1connection.c index 77bd01f7..fda57299 100644 --- a/ssh1connection.c +++ b/ssh1connection.c @@ -109,7 +109,7 @@ static void ssh1_rportfwd_remove( ConnectionLayer *cl, struct ssh_rportfwd *rpf); static SshChannel *ssh1_lportfwd_open( ConnectionLayer *cl, const char *hostname, int port, - const char *org, Channel *chan); + const char *description, const SocketPeerInfo *pi, Channel *chan); static SshChannel *ssh1_session_open(ConnectionLayer *cl, Channel *chan); static struct X11FakeAuth *ssh1_add_x11_display( ConnectionLayer *cl, int authtype, struct X11Display *disp); @@ -1176,7 +1176,7 @@ static SshChannel *ssh1_session_open(ConnectionLayer *cl, Channel *chan) static SshChannel *ssh1_lportfwd_open( ConnectionLayer *cl, const char *hostname, int port, - const char *org, Channel *chan) + const char *description, const SocketPeerInfo *pi, Channel *chan) { struct ssh1_connection_state *s = container_of(cl, struct ssh1_connection_state, cl); @@ -1189,7 +1189,8 @@ static SshChannel *ssh1_lportfwd_open( c->halfopen = TRUE; c->chan = chan; - ppl_logevent(("Opening connection to %s:%d for %s", hostname, port, org)); + ppl_logevent(("Opening connection to %s:%d for %s", + hostname, port, description)); pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_MSG_PORT_OPEN); put_uint32(pktout, c->localid); diff --git a/ssh2connection.c b/ssh2connection.c index 03857ea1..52b8e0f8 100644 --- a/ssh2connection.c +++ b/ssh2connection.c @@ -104,7 +104,7 @@ static void ssh2_rportfwd_remove( ConnectionLayer *cl, struct ssh_rportfwd *rpf); static SshChannel *ssh2_lportfwd_open( ConnectionLayer *cl, const char *hostname, int port, - const char *org, Channel *chan); + const char *description, const SocketPeerInfo *pi, Channel *chan); static SshChannel *ssh2_session_open(ConnectionLayer *cl, Channel *chan); static struct X11FakeAuth *ssh2_add_x11_display( ConnectionLayer *cl, int authtype, struct X11Display *x11disp); @@ -1678,7 +1678,7 @@ static void ssh2channel_hint_channel_is_simple(SshChannel *sc) static SshChannel *ssh2_lportfwd_open( ConnectionLayer *cl, const char *hostname, int port, - const char *org, Channel *chan) + const char *description, const SocketPeerInfo *pi, Channel *chan) { struct ssh2_connection_state *s = container_of(cl, struct ssh2_connection_state, cl); @@ -1691,7 +1691,8 @@ static SshChannel *ssh2_lportfwd_open( c->halfopen = TRUE; c->chan = chan; - ppl_logevent(("Opening connection to %s:%d for %s", hostname, port, org)); + ppl_logevent(("Opening connection to %s:%d for %s", + hostname, port, description)); pktout = ssh2_chanopen_init(c, "direct-tcpip"); { diff --git a/sshshare.c b/sshshare.c index b3e5b65d..c964de13 100644 --- a/sshshare.c +++ b/sshshare.c @@ -1914,7 +1914,7 @@ static int share_listen_accepting(Plug *plug, plug, struct ssh_sharing_state, plug); struct ssh_sharing_connstate *cs; const char *err; - char *peerinfo; + SocketPeerInfo *peerinfo; /* * A new downstream has connected to us. @@ -1959,9 +1959,9 @@ static int share_listen_accepting(Plug *plug, peerinfo = sk_peer_info(cs->sock); log_downstream(cs, "connected%s%s", - peerinfo ? " from " : "", peerinfo ? peerinfo : ""); - - sfree(peerinfo); + (peerinfo && peerinfo->log_text ? " from " : ""), + (peerinfo && peerinfo->log_text ? peerinfo->log_text : "")); + sk_free_peer_info(peerinfo); return 0; } diff --git a/unix/uxnet.c b/unix/uxnet.c index dddaee9a..92311fc9 100644 --- a/unix/uxnet.c +++ b/unix/uxnet.c @@ -503,7 +503,7 @@ static int sk_net_write(Socket *s, const void *data, int len); static int sk_net_write_oob(Socket *s, const void *data, int len); static void sk_net_write_eof(Socket *s); static void sk_net_set_frozen(Socket *s, int is_frozen); -static char *sk_net_peer_info(Socket *s); +static SocketPeerInfo *sk_net_peer_info(Socket *s); static const char *sk_net_socket_error(Socket *s); static struct SocketVtable NetSocket_sockvt = { @@ -1480,7 +1480,7 @@ static void sk_net_set_frozen(Socket *sock, int is_frozen) uxsel_tell(s); } -static char *sk_net_peer_info(Socket *sock) +static SocketPeerInfo *sk_net_peer_info(Socket *sock) { NetSocket *s = container_of(sock, NetSocket, sock); union sockaddr_union addr; @@ -1488,26 +1488,42 @@ static char *sk_net_peer_info(Socket *sock) #ifndef NO_IPV6 char buf[INET6_ADDRSTRLEN]; #endif + SocketPeerInfo *pi; if (getpeername(s->s, &addr.sa, &addrlen) < 0) return NULL; + + pi = snew(SocketPeerInfo); + pi->addressfamily = ADDRTYPE_UNSPEC; + pi->addr_text = NULL; + pi->port = -1; + pi->log_text = NULL; + if (addr.storage.ss_family == AF_INET) { - return dupprintf - ("%s:%d", - inet_ntoa(addr.sin.sin_addr), - (int)ntohs(addr.sin.sin_port)); + pi->addressfamily = ADDRTYPE_IPV4; + memcpy(pi->addr_bin.ipv4, &addr.sin.sin_addr, 4); + pi->port = ntohs(addr.sin.sin_port); + pi->addr_text = dupstr(inet_ntoa(addr.sin.sin_addr)); + pi->log_text = dupprintf("%s:%d", pi->addr_text, pi->port); + #ifndef NO_IPV6 } else if (addr.storage.ss_family == AF_INET6) { - return dupprintf - ("[%s]:%d", - inet_ntop(AF_INET6, &addr.sin6.sin6_addr, buf, sizeof(buf)), - (int)ntohs(addr.sin6.sin6_port)); + pi->addressfamily = ADDRTYPE_IPV6; + memcpy(pi->addr_bin.ipv6, &addr.sin6.sin6_addr, 16); + pi->port = ntohs(addr.sin6.sin6_port); + pi->addr_text = dupstr( + inet_ntop(AF_INET6, &addr.sin6.sin6_addr, buf, sizeof(buf))); + pi->log_text = dupprintf("[%s]:%d", pi->addr_text, pi->port); #endif + } else if (addr.storage.ss_family == AF_UNIX) { + pi->addressfamily = ADDRTYPE_LOCAL; + /* * For Unix sockets, the source address is unlikely to be - * helpful. Instead, we try SO_PEERCRED and try to get the - * source pid. + * helpful, so we leave addr_txt NULL (and we certainly can't + * fill in port, obviously). Instead, we try SO_PEERCRED and + * try to get the source pid, and put that in the log text. */ int pid, uid, gid; if (so_peercred(s->s, &pid, &uid, &gid)) { @@ -1516,14 +1532,16 @@ static char *sk_net_peer_info(Socket *sock) sprintf(gidbuf, "%d", gid); struct passwd *pw = getpwuid(uid); struct group *gr = getgrgid(gid); - return dupprintf("pid %d (%s:%s)", pid, - pw ? pw->pw_name : uidbuf, - gr ? gr->gr_name : gidbuf); + pi->log_text = dupprintf("pid %d (%s:%s)", pid, + pw ? pw->pw_name : uidbuf, + gr ? gr->gr_name : gidbuf); } - return NULL; } else { + sfree(pi); return NULL; } + + return pi; } static void uxsel_tell(NetSocket *s) diff --git a/windows/winhsock.c b/windows/winhsock.c index f4d0d916..27e1e0c5 100644 --- a/windows/winhsock.c +++ b/windows/winhsock.c @@ -270,7 +270,7 @@ static const char *sk_handle_socket_error(Socket *s) return hs->error; } -static char *sk_handle_peer_info(Socket *s) +static SocketPeerInfo *sk_handle_peer_info(Socket *s) { HandleSocket *hs = container_of(s, HandleSocket, sock); ULONG pid; @@ -299,8 +299,14 @@ static char *sk_handle_peer_info(Socket *s) * to log what we can find out about the client end. */ if (p_GetNamedPipeClientProcessId && - p_GetNamedPipeClientProcessId(hs->send_H, &pid)) - return dupprintf("process id %lu", (unsigned long)pid); + p_GetNamedPipeClientProcessId(hs->send_H, &pid)) { + SocketPeerInfo *pi = snew(SocketPeerInfo); + pi->addressfamily = ADDRTYPE_LOCAL; + pi->addr_text = NULL; + pi->port = -1; + pi->log_text = dupprintf("process id %lu", (unsigned long)pid); + return pi; + } return NULL; } diff --git a/windows/winnet.c b/windows/winnet.c index 0ddb62d4..e320397d 100644 --- a/windows/winnet.c +++ b/windows/winnet.c @@ -904,7 +904,7 @@ static int sk_net_write_oob(Socket *s, const void *data, int len); static void sk_net_write_eof(Socket *s); static void sk_net_set_frozen(Socket *s, int is_frozen); static const char *sk_net_socket_error(Socket *s); -static char *sk_net_peer_info(Socket *s); +static SocketPeerInfo *sk_net_peer_info(Socket *s); extern char *do_select(SOCKET skt, int startup); @@ -1763,7 +1763,7 @@ static const char *sk_net_socket_error(Socket *sock) return s->error; } -static char *sk_net_peer_info(Socket *sock) +static SocketPeerInfo *sk_net_peer_info(Socket *sock) { NetSocket *s = container_of(sock, NetSocket, sock); #ifdef NO_IPV6 @@ -1773,26 +1773,43 @@ static char *sk_net_peer_info(Socket *sock) char buf[INET6_ADDRSTRLEN]; #endif int addrlen = sizeof(addr); + SocketPeerInfo *pi; if (p_getpeername(s->s, (struct sockaddr *)&addr, &addrlen) < 0) return NULL; + pi = snew(SocketPeerInfo); + pi->addressfamily = ADDRTYPE_UNSPEC; + pi->addr_text = NULL; + pi->port = -1; + pi->log_text = NULL; + if (((struct sockaddr *)&addr)->sa_family == AF_INET) { - return dupprintf - ("%s:%d", - p_inet_ntoa(((struct sockaddr_in *)&addr)->sin_addr), - (int)p_ntohs(((struct sockaddr_in *)&addr)->sin_port)); + pi->addressfamily = ADDRTYPE_IPV4; + memcpy(pi->addr_bin.ipv4, &((struct sockaddr_in *)&addr)->sin_addr, 4); + pi->port = p_ntohs(((struct sockaddr_in *)&addr)->sin_port); + pi->addr_text = dupstr( + p_inet_ntoa(((struct sockaddr_in *)&addr)->sin_addr)); + pi->log_text = dupprintf("%s:%d", pi->addr_text, pi->port); + #ifndef NO_IPV6 } else if (((struct sockaddr *)&addr)->sa_family == AF_INET6) { - return dupprintf - ("[%s]:%d", - p_inet_ntop(AF_INET6, &((struct sockaddr_in6 *)&addr)->sin6_addr, - buf, sizeof(buf)), - (int)p_ntohs(((struct sockaddr_in6 *)&addr)->sin6_port)); + pi->addressfamily = ADDRTYPE_IPV6; + memcpy(pi->addr_bin.ipv6, + &((struct sockaddr_in6 *)&addr)->sin6_addr, 16); + pi->port = p_ntohs(((struct sockaddr_in6 *)&addr)->sin6_port); + pi->addr_text = dupstr( + p_inet_ntop(AF_INET6, &((struct sockaddr_in6 *)&addr)->sin6_addr, + buf, sizeof(buf))); + pi->log_text = dupprintf("[%s]:%d", pi->addr_text, pi->port); + #endif } else { + sfree(pi); return NULL; } + + return pi; } static void sk_net_set_frozen(Socket *sock, int is_frozen) diff --git a/windows/winnps.c b/windows/winnps.c index d76d5dae..3e6904f3 100644 --- a/windows/winnps.c +++ b/windows/winnps.c @@ -68,7 +68,7 @@ static const char *sk_namedpipeserver_socket_error(Socket *s) return ps->error; } -static char *sk_namedpipeserver_peer_info(Socket *s) +static SocketPeerInfo *sk_namedpipeserver_peer_info(Socket *s) { return NULL; } From d3a9142dac74d01a96a93fec7d556641df25755d Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Thu, 18 Oct 2018 18:02:59 +0100 Subject: [PATCH 542/607] Allow channels not to close immediately after two EOFs. Some kinds of channel, even after they've sent EOF in both directions, still have something to do before they initiate the CLOSE mechanism and wind up the channel completely. For example, a session channel with a subprocess running inside it will want to be sure to send the "exit-status" or "exit-signal" notification, even if that happens after bidirectional EOF of the data channels. Previously, the SSH-2 connection layer had the standard policy that once EOF had been both sent and received, it would start the final close procedure. There's a method chan_want_close() by which a Channel could vary this policy in one direction, by indicating that it wanted the close procedure to commence after EOF was sent in only one direction. Its parameters are a pair of booleans saying whether EOF has been sent, and whether it's been received. Now chan_want_close can vary the policy in the other direction as well: if it returns FALSE even when _both_ parameters are true, the connection layer will honour that, and not send CHANNEL_CLOSE. If it does that, the Channel is responsible for indicating when it _does_ want close later, by calling sshfwd_initiate_close. --- agentf.c | 2 +- mainchan.c | 2 +- portfwd.c | 2 +- ssh2connection.c | 5 ++--- sshchan.h | 2 +- sshcommon.c | 9 +++++++-- unix/uxpgnt.c | 2 +- x11fwd.c | 2 +- 8 files changed, 15 insertions(+), 11 deletions(-) diff --git a/agentf.c b/agentf.c index 69ede15e..3fab01a9 100644 --- a/agentf.c +++ b/agentf.c @@ -155,7 +155,7 @@ static const struct ChannelVtable agentf_channelvt = { agentf_send_eof, agentf_set_input_wanted, agentf_log_close_msg, - chan_no_eager_close, + chan_default_want_close, chan_no_exit_status, chan_no_exit_signal, chan_no_exit_signal_numeric, diff --git a/mainchan.c b/mainchan.c index 524a0fc8..1ee731a6 100644 --- a/mainchan.c +++ b/mainchan.c @@ -33,7 +33,7 @@ static const struct ChannelVtable mainchan_channelvt = { mainchan_send_eof, mainchan_set_input_wanted, mainchan_log_close_msg, - chan_no_eager_close, + chan_default_want_close, mainchan_rcvd_exit_status, mainchan_rcvd_exit_signal, mainchan_rcvd_exit_signal_numeric, diff --git a/portfwd.c b/portfwd.c index dbba3889..6d8d1153 100644 --- a/portfwd.c +++ b/portfwd.c @@ -450,7 +450,7 @@ static const struct ChannelVtable PortForwarding_channelvt = { pfd_send_eof, pfd_set_input_wanted, pfd_log_close_msg, - chan_no_eager_close, + chan_default_want_close, chan_no_exit_status, chan_no_exit_signal, chan_no_exit_signal_numeric, diff --git a/ssh2connection.c b/ssh2connection.c index 52b8e0f8..e6e2fd14 100644 --- a/ssh2connection.c +++ b/ssh2connection.c @@ -1153,9 +1153,8 @@ static void ssh2_channel_check_close(struct ssh2_channel *c) return; } - if ((!((CLOSES_SENT_EOF | CLOSES_RCVD_EOF) & ~c->closes) || - chan_want_close(c->chan, (c->closes & CLOSES_SENT_EOF), - (c->closes & CLOSES_RCVD_EOF))) && + if (chan_want_close(c->chan, (c->closes & CLOSES_SENT_EOF), + (c->closes & CLOSES_RCVD_EOF)) && !c->chanreq_head && !(c->closes & CLOSES_SENT_CLOSE)) { /* diff --git a/sshchan.h b/sshchan.h index 3b221481..63f13136 100644 --- a/sshchan.h +++ b/sshchan.h @@ -75,7 +75,7 @@ void chan_remotely_opened_failure(Channel *chan, const char *errtext); /* want_close for any channel that wants the default behaviour of not * closing until both directions have had an EOF */ -int chan_no_eager_close(Channel *, int, int); +int chan_default_want_close(Channel *, int, int); /* default implementations that refuse all the channel requests */ int chan_no_exit_status(Channel *, int); diff --git a/sshcommon.c b/sshcommon.c index ec206c60..48eeff1b 100644 --- a/sshcommon.c +++ b/sshcommon.c @@ -339,9 +339,14 @@ void chan_remotely_opened_failure(Channel *chan, const char *errtext) assert(0 && "this channel type should never receive OPEN_FAILURE"); } -int chan_no_eager_close(Channel *chan, int sent_local_eof, int rcvd_remote_eof) +int chan_default_want_close( + Channel *chan, int sent_local_eof, int rcvd_remote_eof) { - return FALSE; /* default: never proactively ask for a close */ + /* + * Default close policy: we start initiating the CHANNEL_CLOSE + * procedure as soon as both sides of the channel have seen EOF. + */ + return sent_local_eof && rcvd_remote_eof; } int chan_no_exit_status(Channel *chan, int status) diff --git a/unix/uxpgnt.c b/unix/uxpgnt.c index 55e7981a..a0c48ca3 100644 --- a/unix/uxpgnt.c +++ b/unix/uxpgnt.c @@ -124,7 +124,7 @@ static int time_to_die = FALSE; * forwarding too. */ void chan_remotely_opened_confirmation(Channel *chan) { } void chan_remotely_opened_failure(Channel *chan, const char *err) { } -int chan_no_eager_close(Channel *chan, int s, int r) { return FALSE; } +int chan_default_want_close(Channel *chan, int s, int r) { return FALSE; } int chan_no_exit_status(Channel *ch, int s) { return FALSE; } int chan_no_exit_signal(Channel *ch, ptrlen s, int c, ptrlen m) { return FALSE; } diff --git a/x11fwd.c b/x11fwd.c index 44c9df1e..8e306f42 100644 --- a/x11fwd.c +++ b/x11fwd.c @@ -730,7 +730,7 @@ static const struct ChannelVtable X11Connection_channelvt = { x11_send_eof, x11_set_input_wanted, x11_log_close_msg, - chan_no_eager_close, + chan_default_want_close, chan_no_exit_status, chan_no_exit_signal, chan_no_exit_signal_numeric, From b94c6a7e38d71b4a37e109d861e57859b5462d17 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 20 Oct 2018 17:57:37 +0100 Subject: [PATCH 543/607] Move client-specific SSH code into new files. This is a major code reorganisation in preparation for making this code base into one that can build an SSH server as well as a client. (Mostly for purposes of using the server as a regression test suite for the client, though I have some other possible uses in mind too. However, it's currently no part of my plan to harden the server to the point where it can sensibly be deployed in a hostile environment.) In this preparatory commit, I've broken up the SSH-2 transport and connection layers, and the SSH-1 connection layer, into multiple source files, with each layer having its own header file containing the shared type definitions. In each case, the new source file contains code that's specific to the client side of the protocol, so that a new file can be swapped in in its place when building the server. Mostly this is just a straightforward moving of code without changing it very much, but there are a couple of actual changes in the process: The parsing of SSH-2 global-request and channel open-messages is now done by a new pair of functions in the client module. For channel opens, I've invented a new union data type to be the return value from that function, representing either failure (plus error message), success (plus Channel instance to manage the new channel), or an instruction to hand the channel over to a sharing downstream (plus a pointer to the downstream in question). Also, the tree234 of remote port forwardings in ssh2connection is now initialised on first use by the client-specific code, so that's where its compare function lives. The shared ssh2connection_free() still takes responsibility for freeing it, but now has to check if it's non-null first. The outer shell of the ssh2_lportfwd_open method, for making a local-to-remote port forwarding, is still centralised in ssh2connection.c, but the part of it that actually constructs the outgoing channel-open message has moved into the client code, because that will have to change depending on whether the channel-open has to have type direct-tcpip or forwarded-tcpip. In the SSH-1 connection layer, half the filter_queue method has moved out into the new client-specific code, but not all of it - bidirectional channel maintenance messages are still handled centrally. One exception is SSH_MSG_PORT_OPEN, which can be sent in both directions, but with subtly different semantics - from server to client, it's referring to a previously established remote forwarding (and must be rejected if there isn't one that matches it), but from client to server it's just a "direct-tcpip" request with no prior context. So that one is in the client-specific module, and when I add the server code it will have its own different handler. --- Recipe | 3 +- ssh1connection-client.c | 514 ++++++++++++++++++ ssh1connection.c | 648 +--------------------- ssh1connection.h | 114 ++++ ssh1login.c | 47 +- ssh2connection-client.c | 448 ++++++++++++++++ ssh2connection.c | 622 ++------------------- ssh2connection.h | 222 ++++++++ ssh2kex-client.c | 870 ++++++++++++++++++++++++++++++ ssh2transport.c | 1129 ++------------------------------------- ssh2transport.h | 219 ++++++++ sshcommon.c | 52 +- sshppl.h | 6 + 13 files changed, 2550 insertions(+), 2344 deletions(-) create mode 100644 ssh1connection-client.c create mode 100644 ssh1connection.h create mode 100644 ssh2connection-client.c create mode 100644 ssh2connection.h create mode 100644 ssh2kex-client.c create mode 100644 ssh2transport.h diff --git a/Recipe b/Recipe index 347e1e4f..f276b86f 100644 --- a/Recipe +++ b/Recipe @@ -256,7 +256,8 @@ SSH = ssh sshcommon ssh1bpp ssh2bpp ssh2bpp-bare ssh1censor ssh2censor + sshdh sshcrcda sshpubk sshzlib sshdss x11fwd portfwd + sshaes sshccp sshsh256 sshsh512 sshbn wildcard pinger ssharcf + sshgssc pgssapi sshshare sshecc aqsync marshal nullplug agentf - + sshmac mainchan ssh2transhk + + sshmac mainchan ssh2transhk ssh2kex-client ssh2connection-client + + ssh1connection-client WINSSH = SSH winnoise wincapi winpgntc wingss winshare winnps winnpc + winhsock errsock UXSSH = SSH uxnoise uxagentc uxgss uxshare diff --git a/ssh1connection-client.c b/ssh1connection-client.c new file mode 100644 index 00000000..4098bb22 --- /dev/null +++ b/ssh1connection-client.c @@ -0,0 +1,514 @@ +/* + * Client-specific parts of the SSH-1 connection layer. + */ + +#include + +#include "putty.h" +#include "ssh.h" +#include "sshbpp.h" +#include "sshppl.h" +#include "sshchan.h" +#include "sshcr.h" +#include "ssh1connection.h" + +void ssh1_connection_direction_specific_setup( + struct ssh1_connection_state *s) +{ + if (!s->mainchan) { + /* + * Start up the main session, by telling mainchan.c to do it + * all just as it would in SSH-2, and translating those + * concepts to SSH-1's non-channel-shaped idea of the main + * session. + */ + s->mainchan = mainchan_new( + &s->ppl, &s->cl, s->conf, s->term_width, s->term_height, + FALSE /* is_simple */, NULL); + } +} + +typedef void (*sf_handler_fn_t)(struct ssh1_connection_state *s, + int success, void *ctx); + +struct outstanding_succfail { + sf_handler_fn_t handler; + void *ctx; + struct outstanding_succfail *next; + + /* + * The 'trivial' flag is set if this handler is in response to a + * request for which the SSH-1 protocol doesn't actually specify a + * response packet. The client of this system (mainchan.c) will + * expect to get an acknowledgment regardless, so we arrange to + * send that ack immediately after the rest of the queue empties. + */ + int trivial; +}; + +static void ssh1_connection_process_trivial_succfails(void *vs); + +static void ssh1_queue_succfail_handler( + struct ssh1_connection_state *s, sf_handler_fn_t handler, void *ctx, + int trivial) +{ + struct outstanding_succfail *osf = snew(struct outstanding_succfail); + osf->handler = handler; + osf->ctx = ctx; + osf->trivial = trivial; + osf->next = NULL; + if (s->succfail_tail) + s->succfail_tail->next = osf; + else + s->succfail_head = osf; + s->succfail_tail = osf; + + /* In case this one was trivial and the queue was already empty, + * we should make sure we run the handler promptly, and the + * easiest way is to queue it anyway and then run a trivials pass + * by callback. */ + queue_toplevel_callback(ssh1_connection_process_trivial_succfails, s); +} + +static void ssh1_connection_process_succfail( + struct ssh1_connection_state *s, int success) +{ + struct outstanding_succfail *prevhead = s->succfail_head; + s->succfail_head = s->succfail_head->next; + if (!s->succfail_head) + s->succfail_tail = NULL; + prevhead->handler(s, success, prevhead->ctx); + sfree(prevhead); +} + +static void ssh1_connection_process_trivial_succfails(void *vs) +{ + struct ssh1_connection_state *s = (struct ssh1_connection_state *)vs; + while (s->succfail_head && s->succfail_head->trivial) + ssh1_connection_process_succfail(s, TRUE); +} + +int ssh1_handle_direction_specific_packet( + struct ssh1_connection_state *s, PktIn *pktin) +{ + PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */ + + PktOut *pktout; + struct ssh1_channel *c; + unsigned remid; + struct ssh_rportfwd pf, *pfp; + ptrlen host, data; + int port; + + switch (pktin->type) { + case SSH1_SMSG_SUCCESS: + case SSH1_SMSG_FAILURE: + if (!s->succfail_head) { + ssh_remote_error(s->ppl.ssh, + "Received %s with no outstanding request", + ssh1_pkt_type(pktin->type)); + return TRUE; + } + + ssh1_connection_process_succfail( + s, pktin->type == SSH1_SMSG_SUCCESS); + queue_toplevel_callback( + ssh1_connection_process_trivial_succfails, s); + + return TRUE; + + case SSH1_SMSG_X11_OPEN: + remid = get_uint32(pktin); + + /* Refuse if X11 forwarding is disabled. */ + if (!s->X11_fwd_enabled) { + pktout = ssh_bpp_new_pktout( + s->ppl.bpp, SSH1_MSG_CHANNEL_OPEN_FAILURE); + put_uint32(pktout, remid); + pq_push(s->ppl.out_pq, pktout); + ppl_logevent(("Rejected X11 connect request")); + } else { + c = snew(struct ssh1_channel); + c->connlayer = s; + ssh1_channel_init(c); + c->remoteid = remid; + c->chan = x11_new_channel(s->x11authtree, &c->sc, + NULL, -1, FALSE); + c->remoteid = remid; + c->halfopen = FALSE; + + pktout = ssh_bpp_new_pktout( + s->ppl.bpp, SSH1_MSG_CHANNEL_OPEN_CONFIRMATION); + put_uint32(pktout, c->remoteid); + put_uint32(pktout, c->localid); + pq_push(s->ppl.out_pq, pktout); + ppl_logevent(("Opened X11 forward channel")); + } + + return TRUE; + + case SSH1_SMSG_AGENT_OPEN: + remid = get_uint32(pktin); + + /* Refuse if agent forwarding is disabled. */ + if (!s->agent_fwd_enabled) { + pktout = ssh_bpp_new_pktout( + s->ppl.bpp, SSH1_MSG_CHANNEL_OPEN_FAILURE); + put_uint32(pktout, remid); + pq_push(s->ppl.out_pq, pktout); + } else { + c = snew(struct ssh1_channel); + c->connlayer = s; + ssh1_channel_init(c); + c->remoteid = remid; + c->chan = agentf_new(&c->sc); + c->halfopen = FALSE; + + pktout = ssh_bpp_new_pktout( + s->ppl.bpp, SSH1_MSG_CHANNEL_OPEN_CONFIRMATION); + put_uint32(pktout, c->remoteid); + put_uint32(pktout, c->localid); + pq_push(s->ppl.out_pq, pktout); + } + + return TRUE; + + case SSH1_MSG_PORT_OPEN: + remid = get_uint32(pktin); + host = get_string(pktin); + port = toint(get_uint32(pktin)); + + pf.dhost = mkstr(host); + pf.dport = port; + pfp = find234(s->rportfwds, &pf, NULL); + + if (!pfp) { + ppl_logevent(("Rejected remote port open request for %s:%d", + pf.dhost, port)); + pktout = ssh_bpp_new_pktout( + s->ppl.bpp, SSH1_MSG_CHANNEL_OPEN_FAILURE); + put_uint32(pktout, remid); + pq_push(s->ppl.out_pq, pktout); + } else { + char *err; + + c = snew(struct ssh1_channel); + c->connlayer = s; + ppl_logevent(("Received remote port open request for %s:%d", + pf.dhost, port)); + err = portfwdmgr_connect( + s->portfwdmgr, &c->chan, pf.dhost, port, + &c->sc, pfp->addressfamily); + + if (err) { + ppl_logevent(("Port open failed: %s", err)); + sfree(err); + ssh1_channel_free(c); + pktout = ssh_bpp_new_pktout( + s->ppl.bpp, SSH1_MSG_CHANNEL_OPEN_FAILURE); + put_uint32(pktout, remid); + pq_push(s->ppl.out_pq, pktout); + } else { + ssh1_channel_init(c); + c->remoteid = remid; + c->halfopen = FALSE; + pktout = ssh_bpp_new_pktout( + s->ppl.bpp, SSH1_MSG_CHANNEL_OPEN_CONFIRMATION); + put_uint32(pktout, c->remoteid); + put_uint32(pktout, c->localid); + pq_push(s->ppl.out_pq, pktout); + ppl_logevent(("Forwarded port opened successfully")); + } + } + + sfree(pf.dhost); + + return TRUE; + + case SSH1_SMSG_STDOUT_DATA: + case SSH1_SMSG_STDERR_DATA: + data = get_string(pktin); + if (!get_err(pktin)) { + int bufsize = seat_output( + s->ppl.seat, pktin->type == SSH1_SMSG_STDERR_DATA, + data.ptr, data.len); + if (!s->stdout_throttling && bufsize > SSH1_BUFFER_LIMIT) { + s->stdout_throttling = 1; + ssh_throttle_conn(s->ppl.ssh, +1); + } + } + + return TRUE; + + case SSH1_SMSG_EXIT_STATUS: + { + int exitcode = get_uint32(pktin); + ppl_logevent(("Server sent command exit status %d", exitcode)); + ssh_got_exitcode(s->ppl.ssh, exitcode); + + s->session_terminated = TRUE; + } + return TRUE; + + default: + return FALSE; + } +} + +static void ssh1mainchan_succfail_wantreply(struct ssh1_connection_state *s, + int success, void *ctx) +{ + chan_request_response(s->mainchan_chan, success); +} + +static void ssh1mainchan_succfail_nowantreply(struct ssh1_connection_state *s, + int success, void *ctx) +{ +} + +static void ssh1mainchan_queue_response(struct ssh1_connection_state *s, + int want_reply, int trivial) +{ + sf_handler_fn_t handler = (want_reply ? ssh1mainchan_succfail_wantreply : + ssh1mainchan_succfail_nowantreply); + ssh1_queue_succfail_handler(s, handler, NULL, trivial); +} + +static void ssh1mainchan_request_x11_forwarding( + SshChannel *sc, int want_reply, const char *authproto, + const char *authdata, int screen_number, int oneshot) +{ + struct ssh1_connection_state *s = + container_of(sc, struct ssh1_connection_state, mainchan_sc); + PktOut *pktout; + + pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_X11_REQUEST_FORWARDING); + put_stringz(pktout, authproto); + put_stringz(pktout, authdata); + if (s->local_protoflags & SSH1_PROTOFLAG_SCREEN_NUMBER) + put_uint32(pktout, screen_number); + pq_push(s->ppl.out_pq, pktout); + + ssh1mainchan_queue_response(s, want_reply, FALSE); +} + +static void ssh1mainchan_request_agent_forwarding( + SshChannel *sc, int want_reply) +{ + struct ssh1_connection_state *s = + container_of(sc, struct ssh1_connection_state, mainchan_sc); + PktOut *pktout; + + pktout = ssh_bpp_new_pktout( + s->ppl.bpp, SSH1_CMSG_AGENT_REQUEST_FORWARDING); + pq_push(s->ppl.out_pq, pktout); + + ssh1mainchan_queue_response(s, want_reply, FALSE); +} + +static void ssh1mainchan_request_pty( + SshChannel *sc, int want_reply, Conf *conf, int w, int h) +{ + struct ssh1_connection_state *s = + container_of(sc, struct ssh1_connection_state, mainchan_sc); + PktOut *pktout; + + pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_REQUEST_PTY); + put_stringz(pktout, conf_get_str(s->conf, CONF_termtype)); + put_uint32(pktout, h); + put_uint32(pktout, w); + put_uint32(pktout, 0); /* width in pixels */ + put_uint32(pktout, 0); /* height in pixels */ + write_ttymodes_to_packet( + BinarySink_UPCAST(pktout), 1, + get_ttymodes_from_conf(s->ppl.seat, conf)); + pq_push(s->ppl.out_pq, pktout); + + ssh1mainchan_queue_response(s, want_reply, FALSE); +} + +static int ssh1mainchan_send_env_var( + SshChannel *sc, int want_reply, const char *var, const char *value) +{ + return FALSE; /* SSH-1 doesn't support this at all */ +} + +static void ssh1mainchan_start_shell( + SshChannel *sc, int want_reply) +{ + struct ssh1_connection_state *s = + container_of(sc, struct ssh1_connection_state, mainchan_sc); + PktOut *pktout; + + pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_EXEC_SHELL); + pq_push(s->ppl.out_pq, pktout); + + ssh1mainchan_queue_response(s, want_reply, TRUE); +} + +static void ssh1mainchan_start_command( + SshChannel *sc, int want_reply, const char *command) +{ + struct ssh1_connection_state *s = + container_of(sc, struct ssh1_connection_state, mainchan_sc); + PktOut *pktout; + + pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_EXEC_CMD); + put_stringz(pktout, command); + pq_push(s->ppl.out_pq, pktout); + + ssh1mainchan_queue_response(s, want_reply, TRUE); +} + +static int ssh1mainchan_start_subsystem( + SshChannel *sc, int want_reply, const char *subsystem) +{ + return FALSE; /* SSH-1 doesn't support this at all */ +} + +static int ssh1mainchan_send_serial_break( + SshChannel *sc, int want_reply, int length) +{ + return FALSE; /* SSH-1 doesn't support this at all */ +} + +static int ssh1mainchan_send_signal( + SshChannel *sc, int want_reply, const char *signame) +{ + return FALSE; /* SSH-1 doesn't support this at all */ +} + +static void ssh1mainchan_send_terminal_size_change( + SshChannel *sc, int w, int h) +{ + struct ssh1_connection_state *s = + container_of(sc, struct ssh1_connection_state, mainchan_sc); + PktOut *pktout; + + pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_WINDOW_SIZE); + put_uint32(pktout, h); + put_uint32(pktout, w); + put_uint32(pktout, 0); /* width in pixels */ + put_uint32(pktout, 0); /* height in pixels */ + pq_push(s->ppl.out_pq, pktout); +} + +static void ssh1mainchan_hint_channel_is_simple(SshChannel *sc) +{ +} + +static int ssh1mainchan_write(SshChannel *sc, const void *data, int len) +{ + struct ssh1_connection_state *s = + container_of(sc, struct ssh1_connection_state, mainchan_sc); + PktOut *pktout; + + pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_STDIN_DATA); + put_string(pktout, data, len); + pq_push(s->ppl.out_pq, pktout); + + return 0; +} + +static void ssh1mainchan_write_eof(SshChannel *sc) +{ + struct ssh1_connection_state *s = + container_of(sc, struct ssh1_connection_state, mainchan_sc); + PktOut *pktout; + + pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_EOF); + pq_push(s->ppl.out_pq, pktout); +} + +static const struct SshChannelVtable ssh1mainchan_vtable = { + ssh1mainchan_write, + ssh1mainchan_write_eof, + NULL /* unclean_close */, + NULL /* unthrottle */, + NULL /* get_conf */, + NULL /* window_override_removed is only used by SSH-2 sharing */, + NULL /* x11_sharing_handover, likewise */, + ssh1mainchan_request_x11_forwarding, + ssh1mainchan_request_agent_forwarding, + ssh1mainchan_request_pty, + ssh1mainchan_send_env_var, + ssh1mainchan_start_shell, + ssh1mainchan_start_command, + ssh1mainchan_start_subsystem, + ssh1mainchan_send_serial_break, + ssh1mainchan_send_signal, + ssh1mainchan_send_terminal_size_change, + ssh1mainchan_hint_channel_is_simple, +}; + +static void ssh1_session_confirm_callback(void *vctx) +{ + struct ssh1_connection_state *s = (struct ssh1_connection_state *)vctx; + chan_open_confirmation(s->mainchan_chan); +} + +SshChannel *ssh1_session_open(ConnectionLayer *cl, Channel *chan) +{ + struct ssh1_connection_state *s = + container_of(cl, struct ssh1_connection_state, cl); + s->mainchan_sc.vt = &ssh1mainchan_vtable; + s->mainchan_sc.cl = &s->cl; + s->mainchan_chan = chan; + queue_toplevel_callback(ssh1_session_confirm_callback, s); + return &s->mainchan_sc; +} + +static void ssh1_rportfwd_response(struct ssh1_connection_state *s, + int success, void *ctx) +{ + PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */ + struct ssh_rportfwd *rpf = (struct ssh_rportfwd *)ctx; + + if (success) { + ppl_logevent(("Remote port forwarding from %s enabled", + rpf->log_description)); + } else { + ppl_logevent(("Remote port forwarding from %s refused", + rpf->log_description)); + + struct ssh_rportfwd *realpf = del234(s->rportfwds, rpf); + assert(realpf == rpf); + portfwdmgr_close(s->portfwdmgr, rpf->pfr); + free_rportfwd(rpf); + } +} + +struct ssh_rportfwd *ssh1_rportfwd_alloc( + ConnectionLayer *cl, + const char *shost, int sport, const char *dhost, int dport, + int addressfamily, const char *log_description, PortFwdRecord *pfr, + ssh_sharing_connstate *share_ctx) +{ + struct ssh1_connection_state *s = + container_of(cl, struct ssh1_connection_state, cl); + struct ssh_rportfwd *rpf = snew(struct ssh_rportfwd); + + rpf->shost = dupstr(shost); + rpf->sport = sport; + rpf->dhost = dupstr(dhost); + rpf->dport = dport; + rpf->addressfamily = addressfamily; + rpf->log_description = dupstr(log_description); + rpf->pfr = pfr; + + if (add234(s->rportfwds, rpf) != rpf) { + free_rportfwd(rpf); + return NULL; + } + + PktOut *pktout = ssh_bpp_new_pktout( + s->ppl.bpp, SSH1_CMSG_PORT_FORWARD_REQUEST); + put_uint32(pktout, rpf->sport); + put_stringz(pktout, rpf->dhost); + put_uint32(pktout, rpf->dport); + pq_push(s->ppl.out_pq, pktout); + + ssh1_queue_succfail_handler(s, ssh1_rportfwd_response, rpf, FALSE); + + return rpf; +} diff --git a/ssh1connection.c b/ssh1connection.c index fda57299..d44a21f0 100644 --- a/ssh1connection.c +++ b/ssh1connection.c @@ -11,61 +11,7 @@ #include "sshppl.h" #include "sshchan.h" #include "sshcr.h" - -struct ssh1_channel; - -struct outstanding_succfail; - -struct ssh1_connection_state { - int crState; - - Ssh *ssh; - - Conf *conf; - int local_protoflags; - - tree234 *channels; /* indexed by local id */ - - /* In SSH-1, the main session doesn't take the form of a 'channel' - * according to the wire protocol. But we want to use the same API - * for it, so we define an SshChannel here - but one that uses a - * separate vtable from the usual one, so it doesn't map to a - * struct ssh1_channel as all the others do. */ - SshChannel mainchan_sc; - Channel *mainchan_chan; /* the other end of mainchan_sc */ - mainchan *mainchan; /* and its subtype */ - - int got_pty; - int ldisc_opts[LD_N_OPTIONS]; - int stdout_throttling; - int want_user_input; - int session_terminated; - int term_width, term_height, term_width_orig, term_height_orig; - - int X11_fwd_enabled; - struct X11Display *x11disp; - struct X11FakeAuth *x11auth; - tree234 *x11authtree; - - int agent_fwd_enabled; - - tree234 *rportfwds; - PortFwdManager *portfwdmgr; - int portfwdmgr_configured; - - int finished_setup; - - /* - * These store the list of requests that we're waiting for - * SSH_SMSG_{SUCCESS,FAILURE} replies to. (Those messages don't - * come with any indication of what they're in response to, so we - * have to keep track of the queue ourselves.) - */ - struct outstanding_succfail *succfail_head, *succfail_tail; - - ConnectionLayer cl; - PacketProtocolLayer ppl; -}; +#include "ssh1connection.h" static int ssh1_rportfwd_cmp(void *av, void *bv) { @@ -100,17 +46,11 @@ static const struct PacketProtocolLayerVtable ssh1_connection_vtable = { NULL /* no layer names in SSH-1 */, }; -static struct ssh_rportfwd *ssh1_rportfwd_alloc( - ConnectionLayer *cl, - const char *shost, int sport, const char *dhost, int dport, - int addressfamily, const char *log_description, PortFwdRecord *pfr, - ssh_sharing_connstate *share_ctx); static void ssh1_rportfwd_remove( ConnectionLayer *cl, struct ssh_rportfwd *rpf); static SshChannel *ssh1_lportfwd_open( ConnectionLayer *cl, const char *hostname, int port, const char *description, const SocketPeerInfo *pi, Channel *chan); -static SshChannel *ssh1_session_open(ConnectionLayer *cl, Channel *chan); static struct X11FakeAuth *ssh1_add_x11_display( ConnectionLayer *cl, int authtype, struct X11Display *disp); static int ssh1_agent_forwarding_permitted(ConnectionLayer *cl); @@ -149,50 +89,6 @@ static const struct ConnectionLayerVtable ssh1_connlayer_vtable = { ssh1_set_wants_user_input, }; -struct ssh1_channel { - struct ssh1_connection_state *connlayer; - - unsigned remoteid, localid; - int type; - /* True if we opened this channel but server hasn't confirmed. */ - int halfopen; - - /* Bitmap of whether we've sent/received CHANNEL_CLOSE and - * CHANNEL_CLOSE_CONFIRMATION. */ -#define CLOSES_SENT_CLOSE 1 -#define CLOSES_SENT_CLOSECONF 2 -#define CLOSES_RCVD_CLOSE 4 -#define CLOSES_RCVD_CLOSECONF 8 - int closes; - - /* - * This flag indicates that an EOF is pending on the outgoing side - * of the channel: that is, wherever we're getting the data for - * this channel has sent us some data followed by EOF. We can't - * actually send the EOF until we've finished sending the data, so - * we set this flag instead to remind us to do so once our buffer - * is clear. - */ - int pending_eof; - - /* - * True if this channel is causing the underlying connection to be - * throttled. - */ - int throttling_conn; - - /* - * True if we currently have backed-up data on the direction of - * this channel pointing out of the SSH connection, and therefore - * would prefer the 'Channel' implementation not to read further - * local input if possible. - */ - int throttled_by_backlog; - - Channel *chan; /* handle the client side of this channel, if not */ - SshChannel sc; /* entry point for chan to talk back to */ -}; - static int ssh1channel_write(SshChannel *c, const void *buf, int len); static void ssh1channel_write_eof(SshChannel *c); static void ssh1channel_initiate_close(SshChannel *c, const char *err); @@ -221,120 +117,12 @@ static const struct SshChannelVtable ssh1channel_vtable = { NULL /* hint_channel_is_simple */, }; -static void ssh1mainchan_request_x11_forwarding( - SshChannel *c, int want_reply, const char *authproto, - const char *authdata, int screen_number, int oneshot); -static void ssh1mainchan_request_agent_forwarding( - SshChannel *c, int want_reply); -static void ssh1mainchan_request_pty( - SshChannel *c, int want_reply, Conf *conf, int w, int h); -static int ssh1mainchan_send_env_var( - SshChannel *c, int want_reply, const char *var, const char *value); -static void ssh1mainchan_start_shell( - SshChannel *c, int want_reply); -static void ssh1mainchan_start_command( - SshChannel *c, int want_reply, const char *command); -static int ssh1mainchan_start_subsystem( - SshChannel *c, int want_reply, const char *subsystem); -static int ssh1mainchan_send_env_var( - SshChannel *c, int want_reply, const char *var, const char *value); -static int ssh1mainchan_send_serial_break( - SshChannel *c, int want_reply, int length); -static int ssh1mainchan_send_signal( - SshChannel *c, int want_reply, const char *signame); -static void ssh1mainchan_send_terminal_size_change( - SshChannel *c, int w, int h); -static void ssh1mainchan_hint_channel_is_simple(SshChannel *c); -static int ssh1mainchan_write(SshChannel *sc, const void *data, int len); -static void ssh1mainchan_write_eof(SshChannel *sc); - -static const struct SshChannelVtable ssh1mainchan_vtable = { - ssh1mainchan_write, - ssh1mainchan_write_eof, - NULL /* unclean_close */, - NULL /* unthrottle */, - NULL /* get_conf */, - NULL /* window_override_removed is only used by SSH-2 sharing */, - NULL /* x11_sharing_handover, likewise */, - ssh1mainchan_request_x11_forwarding, - ssh1mainchan_request_agent_forwarding, - ssh1mainchan_request_pty, - ssh1mainchan_send_env_var, - ssh1mainchan_start_shell, - ssh1mainchan_start_command, - ssh1mainchan_start_subsystem, - ssh1mainchan_send_serial_break, - ssh1mainchan_send_signal, - ssh1mainchan_send_terminal_size_change, - ssh1mainchan_hint_channel_is_simple, -}; - -static void ssh1_channel_init(struct ssh1_channel *c); static void ssh1_channel_try_eof(struct ssh1_channel *c); static void ssh1_channel_close_local(struct ssh1_channel *c, const char *reason); static void ssh1_channel_destroy(struct ssh1_channel *c); static void ssh1_channel_check_close(struct ssh1_channel *c); -static int ssh1_check_termination(struct ssh1_connection_state *s); - -typedef void (*sf_handler_fn_t)(struct ssh1_connection_state *s, - int success, void *ctx); -struct outstanding_succfail { - sf_handler_fn_t handler; - void *ctx; - struct outstanding_succfail *next; - - /* - * The 'trivial' flag is set if this handler is in response to a - * request for which the SSH-1 protocol doesn't actually specify a - * response packet. The client of this system (mainchan.c) will - * expect to get an acknowledgment regardless, so we arrange to - * send that ack immediately after the rest of the queue empties. - */ - int trivial; -}; - -static void ssh1_connection_process_trivial_succfails(void *vs); - -static void ssh1_queue_succfail_handler( - struct ssh1_connection_state *s, sf_handler_fn_t handler, void *ctx, - int trivial) -{ - struct outstanding_succfail *osf = - snew(struct outstanding_succfail); - osf->handler = handler; - osf->ctx = ctx; - osf->trivial = trivial; - if (s->succfail_tail) - s->succfail_tail->next = osf; - else - s->succfail_head = osf; - s->succfail_tail = osf; - - /* In case this one was trivial and the queue was already empty, - * we should make sure we run the handler promptly, and the - * easiest way is to queue it anyway and then run a trivials pass - * by callback. */ - queue_toplevel_callback(ssh1_connection_process_trivial_succfails, s); -} - -static void ssh1_connection_process_succfail( - struct ssh1_connection_state *s, int success) -{ - struct outstanding_succfail *prevhead = s->succfail_head; - s->succfail_head = s->succfail_head->next; - prevhead->handler(s, success, prevhead->ctx); - sfree(prevhead); -} - -static void ssh1_connection_process_trivial_succfails(void *vs) -{ - struct ssh1_connection_state *s = (struct ssh1_connection_state *)vs; - while (s->succfail_head && s->succfail_head->trivial) - ssh1_connection_process_succfail(s, TRUE); -} - static int ssh1_channelcmp(void *av, void *bv) { const struct ssh1_channel *a = (const struct ssh1_channel *) av; @@ -357,7 +145,7 @@ static int ssh1_channelfind(void *av, void *bv) return 0; } -static void ssh1_channel_free(struct ssh1_channel *c) +void ssh1_channel_free(struct ssh1_channel *c) { if (c->chan) chan_free(c->chan); @@ -431,17 +219,10 @@ void ssh1_connection_set_local_protoflags(PacketProtocolLayer *ppl, int flags) static int ssh1_connection_filter_queue(struct ssh1_connection_state *s) { PktIn *pktin; - PktOut *pktout; - ptrlen data, host; + ptrlen data; struct ssh1_channel *c; - unsigned localid, remid; - int port, expect_halfopen; - struct ssh_rportfwd pf, *pfp; - PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */ - - /* Cross-reference to ssh1login.c to handle the common packets - * between login and connection: DISCONNECT, DEBUG and IGNORE. */ - extern int ssh1_common_filter_queue(PacketProtocolLayer *ppl); + unsigned localid; + int expect_halfopen; while (1) { if (ssh1_common_filter_queue(&s->ppl)) @@ -450,140 +231,6 @@ static int ssh1_connection_filter_queue(struct ssh1_connection_state *s) return FALSE; switch (pktin->type) { - case SSH1_SMSG_SUCCESS: - case SSH1_SMSG_FAILURE: - if (!s->finished_setup) { - /* During initial setup, these messages are not - * filtered out, but go back to the main coroutine. */ - return FALSE; - } - - if (!s->succfail_head) { - ssh_remote_error(s->ppl.ssh, - "Received %s with no outstanding request", - ssh1_pkt_type(pktin->type)); - return TRUE; - } - - ssh1_connection_process_succfail( - s, pktin->type == SSH1_SMSG_SUCCESS); - queue_toplevel_callback( - ssh1_connection_process_trivial_succfails, s); - - pq_pop(s->ppl.in_pq); - break; - - case SSH1_SMSG_X11_OPEN: - remid = get_uint32(pktin); - - /* Refuse if X11 forwarding is disabled. */ - if (!s->X11_fwd_enabled) { - pktout = ssh_bpp_new_pktout( - s->ppl.bpp, SSH1_MSG_CHANNEL_OPEN_FAILURE); - put_uint32(pktout, remid); - pq_push(s->ppl.out_pq, pktout); - ppl_logevent(("Rejected X11 connect request")); - } else { - c = snew(struct ssh1_channel); - c->connlayer = s; - ssh1_channel_init(c); - c->remoteid = remid; - c->chan = x11_new_channel(s->x11authtree, &c->sc, - NULL, -1, FALSE); - c->remoteid = remid; - c->halfopen = FALSE; - - pktout = ssh_bpp_new_pktout( - s->ppl.bpp, SSH1_MSG_CHANNEL_OPEN_CONFIRMATION); - put_uint32(pktout, c->remoteid); - put_uint32(pktout, c->localid); - pq_push(s->ppl.out_pq, pktout); - ppl_logevent(("Opened X11 forward channel")); - } - - pq_pop(s->ppl.in_pq); - break; - - case SSH1_SMSG_AGENT_OPEN: - remid = get_uint32(pktin); - - /* Refuse if agent forwarding is disabled. */ - if (!s->agent_fwd_enabled) { - pktout = ssh_bpp_new_pktout( - s->ppl.bpp, SSH1_MSG_CHANNEL_OPEN_FAILURE); - put_uint32(pktout, remid); - pq_push(s->ppl.out_pq, pktout); - } else { - c = snew(struct ssh1_channel); - c->connlayer = s; - ssh1_channel_init(c); - c->remoteid = remid; - c->chan = agentf_new(&c->sc); - c->halfopen = FALSE; - - pktout = ssh_bpp_new_pktout( - s->ppl.bpp, SSH1_MSG_CHANNEL_OPEN_CONFIRMATION); - put_uint32(pktout, c->remoteid); - put_uint32(pktout, c->localid); - pq_push(s->ppl.out_pq, pktout); - } - - pq_pop(s->ppl.in_pq); - break; - - case SSH1_MSG_PORT_OPEN: - remid = get_uint32(pktin); - host = get_string(pktin); - port = toint(get_uint32(pktin)); - - pf.dhost = mkstr(host); - pf.dport = port; - pfp = find234(s->rportfwds, &pf, NULL); - - if (!pfp) { - ppl_logevent(("Rejected remote port open request for %s:%d", - pf.dhost, port)); - pktout = ssh_bpp_new_pktout( - s->ppl.bpp, SSH1_MSG_CHANNEL_OPEN_FAILURE); - put_uint32(pktout, remid); - pq_push(s->ppl.out_pq, pktout); - } else { - char *err; - - c = snew(struct ssh1_channel); - c->connlayer = s; - ppl_logevent(("Received remote port open request for %s:%d", - pf.dhost, port)); - err = portfwdmgr_connect( - s->portfwdmgr, &c->chan, pf.dhost, port, - &c->sc, pfp->addressfamily); - - if (err) { - ppl_logevent(("Port open failed: %s", err)); - sfree(err); - ssh1_channel_free(c); - pktout = ssh_bpp_new_pktout( - s->ppl.bpp, SSH1_MSG_CHANNEL_OPEN_FAILURE); - put_uint32(pktout, remid); - pq_push(s->ppl.out_pq, pktout); - } else { - ssh1_channel_init(c); - c->remoteid = remid; - c->halfopen = FALSE; - pktout = ssh_bpp_new_pktout( - s->ppl.bpp, SSH1_MSG_CHANNEL_OPEN_CONFIRMATION); - put_uint32(pktout, c->remoteid); - put_uint32(pktout, c->localid); - pq_push(s->ppl.out_pq, pktout); - ppl_logevent(("Forwarded port opened successfully")); - } - } - - sfree(pf.dhost); - - pq_pop(s->ppl.in_pq); - break; - case SSH1_MSG_CHANNEL_DATA: case SSH1_MSG_CHANNEL_OPEN_CONFIRMATION: case SSH1_MSG_CHANNEL_OPEN_FAILURE: @@ -692,37 +339,14 @@ static int ssh1_connection_filter_queue(struct ssh1_connection_state *s) pq_pop(s->ppl.in_pq); break; - case SSH1_SMSG_STDOUT_DATA: - case SSH1_SMSG_STDERR_DATA: - data = get_string(pktin); - if (!get_err(pktin)) { - int bufsize = seat_output( - s->ppl.seat, pktin->type == SSH1_SMSG_STDERR_DATA, - data.ptr, data.len); - if (!s->stdout_throttling && bufsize > SSH1_BUFFER_LIMIT) { - s->stdout_throttling = 1; - ssh_throttle_conn(s->ppl.ssh, +1); - } - } - - pq_pop(s->ppl.in_pq); - break; - - case SSH1_SMSG_EXIT_STATUS: - { - int exitcode = get_uint32(pktin); - ppl_logevent(("Server sent command exit status %d", exitcode)); - ssh_got_exitcode(s->ppl.ssh, exitcode); - - s->session_terminated = TRUE; + default: + if (ssh1_handle_direction_specific_packet(s, pktin)) { + pq_pop(s->ppl.in_pq); if (ssh1_check_termination(s)) return TRUE; + } else { + return FALSE; } - pq_pop(s->ppl.in_pq); - break; - - default: - return FALSE; } } } @@ -747,14 +371,10 @@ static void ssh1_connection_process_queue(PacketProtocolLayer *ppl) portfwdmgr_config(s->portfwdmgr, s->conf); s->portfwdmgr_configured = TRUE; - /* - * Start up the main session, by telling mainchan.c to do it all - * just as it would in SSH-2, and translating those concepts to - * SSH-1's non-channel-shaped idea of the main session. - */ - s->mainchan = mainchan_new( - &s->ppl, &s->cl, s->conf, s->term_width, s->term_height, - FALSE /* is_simple */, NULL); + while (!s->finished_setup) { + ssh1_connection_direction_specific_setup(s); + crReturnV; + } while (1) { @@ -883,7 +503,7 @@ static void ssh1_channel_destroy(struct ssh1_channel *c) queue_toplevel_callback(ssh1_check_termination_callback, s); } -static int ssh1_check_termination(struct ssh1_connection_state *s) +int ssh1_check_termination(struct ssh1_connection_state *s) { /* * Decide whether we should terminate the SSH connection now. @@ -907,7 +527,7 @@ static int ssh1_check_termination(struct ssh1_connection_state *s) * Set up most of a new ssh1_channel. Leaves chan untouched (since it * will sometimes have been filled in before calling this). */ -static void ssh1_channel_init(struct ssh1_channel *c) +void ssh1_channel_init(struct ssh1_channel *c) { struct ssh1_connection_state *s = c->connlayer; c->closes = 0; @@ -993,187 +613,6 @@ static struct X11FakeAuth *ssh1_add_x11_display( return auth; } -static void ssh1mainchan_succfail_wantreply(struct ssh1_connection_state *s, - int success, void *ctx) -{ - chan_request_response(s->mainchan_chan, success); -} - -static void ssh1mainchan_succfail_nowantreply(struct ssh1_connection_state *s, - int success, void *ctx) -{ -} - -static void ssh1mainchan_queue_response(struct ssh1_connection_state *s, - int want_reply, int trivial) -{ - sf_handler_fn_t handler = (want_reply ? ssh1mainchan_succfail_wantreply : - ssh1mainchan_succfail_nowantreply); - ssh1_queue_succfail_handler(s, handler, NULL, trivial); -} - -static void ssh1mainchan_request_x11_forwarding( - SshChannel *sc, int want_reply, const char *authproto, - const char *authdata, int screen_number, int oneshot) -{ - struct ssh1_connection_state *s = - container_of(sc, struct ssh1_connection_state, mainchan_sc); - PktOut *pktout; - - pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_X11_REQUEST_FORWARDING); - put_stringz(pktout, authproto); - put_stringz(pktout, authdata); - if (s->local_protoflags & SSH1_PROTOFLAG_SCREEN_NUMBER) - put_uint32(pktout, screen_number); - pq_push(s->ppl.out_pq, pktout); - - ssh1mainchan_queue_response(s, want_reply, FALSE); -} - -static void ssh1mainchan_request_agent_forwarding( - SshChannel *sc, int want_reply) -{ - struct ssh1_connection_state *s = - container_of(sc, struct ssh1_connection_state, mainchan_sc); - PktOut *pktout; - - pktout = ssh_bpp_new_pktout( - s->ppl.bpp, SSH1_CMSG_AGENT_REQUEST_FORWARDING); - pq_push(s->ppl.out_pq, pktout); - - ssh1mainchan_queue_response(s, want_reply, FALSE); -} - -static void ssh1mainchan_request_pty( - SshChannel *sc, int want_reply, Conf *conf, int w, int h) -{ - struct ssh1_connection_state *s = - container_of(sc, struct ssh1_connection_state, mainchan_sc); - PktOut *pktout; - - pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_REQUEST_PTY); - put_stringz(pktout, conf_get_str(s->conf, CONF_termtype)); - put_uint32(pktout, h); - put_uint32(pktout, w); - put_uint32(pktout, 0); /* width in pixels */ - put_uint32(pktout, 0); /* height in pixels */ - write_ttymodes_to_packet( - BinarySink_UPCAST(pktout), 1, - get_ttymodes_from_conf(s->ppl.seat, conf)); - pq_push(s->ppl.out_pq, pktout); - - ssh1mainchan_queue_response(s, want_reply, FALSE); -} - -static int ssh1mainchan_send_env_var( - SshChannel *sc, int want_reply, const char *var, const char *value) -{ - return FALSE; /* SSH-1 doesn't support this at all */ -} - -static void ssh1mainchan_start_shell( - SshChannel *sc, int want_reply) -{ - struct ssh1_connection_state *s = - container_of(sc, struct ssh1_connection_state, mainchan_sc); - PktOut *pktout; - - pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_EXEC_SHELL); - pq_push(s->ppl.out_pq, pktout); - - ssh1mainchan_queue_response(s, want_reply, TRUE); -} - -static void ssh1mainchan_start_command( - SshChannel *sc, int want_reply, const char *command) -{ - struct ssh1_connection_state *s = - container_of(sc, struct ssh1_connection_state, mainchan_sc); - PktOut *pktout; - - pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_EXEC_CMD); - put_stringz(pktout, command); - pq_push(s->ppl.out_pq, pktout); - - ssh1mainchan_queue_response(s, want_reply, TRUE); -} - -static int ssh1mainchan_start_subsystem( - SshChannel *sc, int want_reply, const char *subsystem) -{ - return FALSE; /* SSH-1 doesn't support this at all */ -} - -static int ssh1mainchan_send_serial_break( - SshChannel *sc, int want_reply, int length) -{ - return FALSE; /* SSH-1 doesn't support this at all */ -} - -static int ssh1mainchan_send_signal( - SshChannel *sc, int want_reply, const char *signame) -{ - return FALSE; /* SSH-1 doesn't support this at all */ -} - -static void ssh1mainchan_send_terminal_size_change(SshChannel *sc, int w, int h) -{ - struct ssh1_connection_state *s = - container_of(sc, struct ssh1_connection_state, mainchan_sc); - PktOut *pktout; - - pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_WINDOW_SIZE); - put_uint32(pktout, h); - put_uint32(pktout, w); - put_uint32(pktout, 0); /* width in pixels */ - put_uint32(pktout, 0); /* height in pixels */ - pq_push(s->ppl.out_pq, pktout); -} - -static void ssh1mainchan_hint_channel_is_simple(SshChannel *c) -{ -} - -static int ssh1mainchan_write(SshChannel *sc, const void *data, int len) -{ - struct ssh1_connection_state *s = - container_of(sc, struct ssh1_connection_state, mainchan_sc); - PktOut *pktout; - - pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_STDIN_DATA); - put_string(pktout, data, len); - pq_push(s->ppl.out_pq, pktout); - - return 0; -} - -static void ssh1mainchan_write_eof(SshChannel *sc) -{ - struct ssh1_connection_state *s = - container_of(sc, struct ssh1_connection_state, mainchan_sc); - PktOut *pktout; - - pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_EOF); - pq_push(s->ppl.out_pq, pktout); -} - -static void ssh1_session_confirm_callback(void *vctx) -{ - struct ssh1_connection_state *s = (struct ssh1_connection_state *)vctx; - chan_open_confirmation(s->mainchan_chan); -} - -static SshChannel *ssh1_session_open(ConnectionLayer *cl, Channel *chan) -{ - struct ssh1_connection_state *s = - container_of(cl, struct ssh1_connection_state, cl); - s->mainchan_sc.cl = &s->cl; - s->mainchan_sc.vt = &ssh1mainchan_vtable; - s->mainchan_chan = chan; - queue_toplevel_callback(ssh1_session_confirm_callback, s); - return &s->mainchan_sc; -} - static SshChannel *ssh1_lportfwd_open( ConnectionLayer *cl, const char *hostname, int port, const char *description, const SocketPeerInfo *pi, Channel *chan) @@ -1203,61 +642,6 @@ static SshChannel *ssh1_lportfwd_open( return &c->sc; } -static void ssh1_rportfwd_response(struct ssh1_connection_state *s, - int success, void *ctx) -{ - PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */ - struct ssh_rportfwd *rpf = (struct ssh_rportfwd *)ctx; - - if (success) { - ppl_logevent(("Remote port forwarding from %s enabled", - rpf->log_description)); - } else { - ppl_logevent(("Remote port forwarding from %s refused", - rpf->log_description)); - - struct ssh_rportfwd *realpf = del234(s->rportfwds, rpf); - assert(realpf == rpf); - portfwdmgr_close(s->portfwdmgr, rpf->pfr); - free_rportfwd(rpf); - } -} - -static struct ssh_rportfwd *ssh1_rportfwd_alloc( - ConnectionLayer *cl, - const char *shost, int sport, const char *dhost, int dport, - int addressfamily, const char *log_description, PortFwdRecord *pfr, - ssh_sharing_connstate *share_ctx) -{ - struct ssh1_connection_state *s = - container_of(cl, struct ssh1_connection_state, cl); - struct ssh_rportfwd *rpf = snew(struct ssh_rportfwd); - - rpf->shost = dupstr(shost); - rpf->sport = sport; - rpf->dhost = dupstr(dhost); - rpf->dport = dport; - rpf->addressfamily = addressfamily; - rpf->log_description = dupstr(log_description); - rpf->pfr = pfr; - - if (add234(s->rportfwds, rpf) != rpf) { - free_rportfwd(rpf); - return NULL; - } - - PktOut *pktout = ssh_bpp_new_pktout( - s->ppl.bpp, SSH1_CMSG_PORT_FORWARD_REQUEST); - put_uint32(pktout, rpf->sport); - put_stringz(pktout, rpf->dhost); - put_uint32(pktout, rpf->dport); - pq_push(s->ppl.out_pq, pktout); - - ssh1_queue_succfail_handler(s, ssh1_rportfwd_response, rpf, FALSE); - - return rpf; -} - static void ssh1_rportfwd_remove(ConnectionLayer *cl, struct ssh_rportfwd *rpf) { /* diff --git a/ssh1connection.h b/ssh1connection.h new file mode 100644 index 00000000..c55a002d --- /dev/null +++ b/ssh1connection.h @@ -0,0 +1,114 @@ +struct ssh1_channel; + +struct outstanding_succfail; + +struct ssh1_connection_state { + int crState; + + Ssh *ssh; + + Conf *conf; + int local_protoflags; + + tree234 *channels; /* indexed by local id */ + + /* In SSH-1, the main session doesn't take the form of a 'channel' + * according to the wire protocol. But we want to use the same API + * for it, so we define an SshChannel here - but one that uses a + * separate vtable from the usual one, so it doesn't map to a + * struct ssh1_channel as all the others do. */ + SshChannel mainchan_sc; + Channel *mainchan_chan; /* the other end of mainchan_sc */ + mainchan *mainchan; /* and its subtype */ + + int got_pty; + int ldisc_opts[LD_N_OPTIONS]; + int stdout_throttling; + int want_user_input; + int session_terminated; + int term_width, term_height, term_width_orig, term_height_orig; + + int X11_fwd_enabled; + struct X11Display *x11disp; + struct X11FakeAuth *x11auth; + tree234 *x11authtree; + + int agent_fwd_enabled; + + tree234 *rportfwds; + PortFwdManager *portfwdmgr; + int portfwdmgr_configured; + + int finished_setup; + + /* + * These store the list of requests that we're waiting for + * SSH_SMSG_{SUCCESS,FAILURE} replies to. (Those messages don't + * come with any indication of what they're in response to, so we + * have to keep track of the queue ourselves.) + */ + struct outstanding_succfail *succfail_head, *succfail_tail; + + ConnectionLayer cl; + PacketProtocolLayer ppl; +}; + +struct ssh1_channel { + struct ssh1_connection_state *connlayer; + + unsigned remoteid, localid; + int type; + /* True if we opened this channel but server hasn't confirmed. */ + int halfopen; + + /* Bitmap of whether we've sent/received CHANNEL_CLOSE and + * CHANNEL_CLOSE_CONFIRMATION. */ +#define CLOSES_SENT_CLOSE 1 +#define CLOSES_SENT_CLOSECONF 2 +#define CLOSES_RCVD_CLOSE 4 +#define CLOSES_RCVD_CLOSECONF 8 + int closes; + + /* + * This flag indicates that an EOF is pending on the outgoing side + * of the channel: that is, wherever we're getting the data for + * this channel has sent us some data followed by EOF. We can't + * actually send the EOF until we've finished sending the data, so + * we set this flag instead to remind us to do so once our buffer + * is clear. + */ + int pending_eof; + + /* + * True if this channel is causing the underlying connection to be + * throttled. + */ + int throttling_conn; + + /* + * True if we currently have backed-up data on the direction of + * this channel pointing out of the SSH connection, and therefore + * would prefer the 'Channel' implementation not to read further + * local input if possible. + */ + int throttled_by_backlog; + + Channel *chan; /* handle the client side of this channel, if not */ + SshChannel sc; /* entry point for chan to talk back to */ +}; + +SshChannel *ssh1_session_open(ConnectionLayer *cl, Channel *chan); +void ssh1_channel_init(struct ssh1_channel *c); +void ssh1_channel_free(struct ssh1_channel *c); +struct ssh_rportfwd *ssh1_rportfwd_alloc( + ConnectionLayer *cl, + const char *shost, int sport, const char *dhost, int dport, + int addressfamily, const char *log_description, PortFwdRecord *pfr, + ssh_sharing_connstate *share_ctx); + +void ssh1_connection_direction_specific_setup( + struct ssh1_connection_state *s); +int ssh1_handle_direction_specific_packet( + struct ssh1_connection_state *s, PktIn *pktin); + +int ssh1_check_termination(struct ssh1_connection_state *s); diff --git a/ssh1login.c b/ssh1login.c index 8b6f1d7b..0010b288 100644 --- a/ssh1login.c +++ b/ssh1login.c @@ -120,40 +120,6 @@ static void ssh1_login_free(PacketProtocolLayer *ppl) sfree(s); } -int ssh1_common_filter_queue(PacketProtocolLayer *ppl) -{ - PktIn *pktin; - ptrlen msg; - - while ((pktin = pq_peek(ppl->in_pq)) != NULL) { - switch (pktin->type) { - case SSH1_MSG_DISCONNECT: - msg = get_string(pktin); - ssh_remote_error(ppl->ssh, - "Server sent disconnect message:\n\"%.*s\"", - PTRLEN_PRINTF(msg)); - pq_pop(ppl->in_pq); - return TRUE; /* indicate that we've been freed */ - - case SSH1_MSG_DEBUG: - msg = get_string(pktin); - ppl_logevent(("Remote debug message: %.*s", PTRLEN_PRINTF(msg))); - pq_pop(ppl->in_pq); - break; - - case SSH1_MSG_IGNORE: - /* Do nothing, because we're ignoring it! Duhh. */ - pq_pop(ppl->in_pq); - break; - - default: - return FALSE; - } - } - - return FALSE; -} - static int ssh1_login_filter_queue(struct ssh1_login_state *s) { return ssh1_common_filter_queue(&s->ppl); @@ -229,17 +195,8 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl) s->remote_protoflags & SSH1_PROTOFLAGS_SUPPORTED; s->local_protoflags |= SSH1_PROTOFLAG_SCREEN_NUMBER; - { - struct MD5Context md5c; - - MD5Init(&md5c); - for (i = (bignum_bitcount(s->hostkey.modulus) + 7) / 8; i-- ;) - put_byte(&md5c, bignum_byte(s->hostkey.modulus, i)); - for (i = (bignum_bitcount(s->servkey.modulus) + 7) / 8; i-- ;) - put_byte(&md5c, bignum_byte(s->servkey.modulus, i)); - put_data(&md5c, s->cookie, 8); - MD5Final(s->session_id, &md5c); - } + ssh1_compute_session_id(s->session_id, s->cookie, + &s->hostkey, &s->servkey); for (i = 0; i < 32; i++) s->session_key[i] = random_byte(); diff --git a/ssh2connection-client.c b/ssh2connection-client.c new file mode 100644 index 00000000..8cef6aca --- /dev/null +++ b/ssh2connection-client.c @@ -0,0 +1,448 @@ +/* + * Client-specific parts of the SSH-2 connection layer. + */ + +#include + +#include "putty.h" +#include "ssh.h" +#include "sshbpp.h" +#include "sshppl.h" +#include "sshchan.h" +#include "sshcr.h" +#include "ssh2connection.h" + +static ChanopenResult chan_open_x11( + struct ssh2_connection_state *s, SshChannel *sc, + ptrlen peeraddr, int peerport) +{ + PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */ + char *peeraddr_str; + Channel *ch; + + ppl_logevent(("Received X11 connect request from %.*s:%d", + PTRLEN_PRINTF(peeraddr), peerport)); + + if (!s->X11_fwd_enabled && !s->connshare) { + CHANOPEN_RETURN_FAILURE( + SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED, + ("X11 forwarding is not enabled")); + } + + peeraddr_str = peeraddr.ptr ? mkstr(peeraddr) : NULL; + ch = x11_new_channel( + s->x11authtree, sc, peeraddr_str, peerport, s->connshare != NULL); + sfree(peeraddr_str); + ppl_logevent(("Opened X11 forward channel")); + CHANOPEN_RETURN_SUCCESS(ch); +} + +static ChanopenResult chan_open_forwarded_tcpip( + struct ssh2_connection_state *s, SshChannel *sc, + ptrlen fwdaddr, int fwdport, ptrlen peeraddr, int peerport) +{ + PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */ + struct ssh_rportfwd pf, *realpf; + Channel *ch; + char *err; + + ppl_logevent(("Received remote port %.*s:%d open request from %.*s:%d", + PTRLEN_PRINTF(fwdaddr), fwdport, + PTRLEN_PRINTF(peeraddr), peerport)); + + pf.shost = mkstr(fwdaddr); + pf.sport = fwdport; + realpf = find234(s->rportfwds, &pf, NULL); + sfree(pf.shost); + + if (realpf == NULL) { + CHANOPEN_RETURN_FAILURE( + SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED, + ("Remote port is not recognised")); + } + + if (realpf->share_ctx) { + /* + * This port forwarding is on behalf of a connection-sharing + * downstream. + */ + CHANOPEN_RETURN_DOWNSTREAM(realpf->share_ctx); + } + + err = portfwdmgr_connect( + s->portfwdmgr, &ch, realpf->dhost, realpf->dport, + sc, realpf->addressfamily); + ppl_logevent(("Attempting to forward remote port to %s:%d", + realpf->dhost, realpf->dport)); + if (err != NULL) { + ppl_logevent(("Port open failed: %s", err)); + sfree(err); + CHANOPEN_RETURN_FAILURE( + SSH2_OPEN_CONNECT_FAILED, + ("Port open failed")); + } + + ppl_logevent(("Forwarded port opened successfully")); + CHANOPEN_RETURN_SUCCESS(ch); +} + +static ChanopenResult chan_open_auth_agent( + struct ssh2_connection_state *s, SshChannel *sc) +{ + if (!s->agent_fwd_enabled) { + CHANOPEN_RETURN_FAILURE( + SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED, + ("Agent forwarding is not enabled")); + } + + CHANOPEN_RETURN_SUCCESS(agentf_new(sc)); +} + +ChanopenResult ssh2_connection_parse_channel_open( + struct ssh2_connection_state *s, ptrlen type, + PktIn *pktin, SshChannel *sc) +{ + if (ptrlen_eq_string(type, "x11")) { + ptrlen peeraddr = get_string(pktin); + int peerport = get_uint32(pktin); + + return chan_open_x11(s, sc, peeraddr, peerport); + } else if (ptrlen_eq_string(type, "forwarded-tcpip")) { + ptrlen fwdaddr = get_string(pktin); + int fwdport = toint(get_uint32(pktin)); + ptrlen peeraddr = get_string(pktin); + int peerport = toint(get_uint32(pktin)); + + return chan_open_forwarded_tcpip( + s, sc, fwdaddr, fwdport, peeraddr, peerport); + } else if (ptrlen_eq_string(type, "auth-agent@openssh.com")) { + return chan_open_auth_agent(s, sc); + } else { + CHANOPEN_RETURN_FAILURE( + SSH2_OPEN_UNKNOWN_CHANNEL_TYPE, + ("Unsupported channel type requested")); + } +} + +int ssh2_connection_parse_global_request( + struct ssh2_connection_state *s, ptrlen type, PktIn *pktin) +{ + /* + * We don't know of any global requests that an SSH client needs + * to honour. + */ + return FALSE; +} + +PktOut *ssh2_portfwd_chanopen( + struct ssh2_connection_state *s, struct ssh2_channel *c, + const char *hostname, int port, + const char *description, const SocketPeerInfo *peerinfo) +{ + PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */ + PktOut *pktout; + + /* + * In client mode, this function is called by portfwdmgr in + * response to PortListeners that were set up in + * portfwdmgr_config, which means that the hostname and port + * parameters will indicate the host we want to tell the server to + * connect _to_. + */ + + ppl_logevent(("Opening connection to %s:%d for %s", + hostname, port, description)); + + pktout = ssh2_chanopen_init(c, "direct-tcpip"); + { + char *trimmed_host = host_strduptrim(hostname); + put_stringz(pktout, trimmed_host); + sfree(trimmed_host); + } + put_uint32(pktout, port); + + /* + * We make up values for the originator data; partly it's too much + * hassle to keep track, and partly I'm not convinced the server + * should be told details like that about my local network + * configuration. The "originator IP address" is syntactically a + * numeric IP address, and some servers (e.g., Tectia) get upset + * if it doesn't match this syntax. + */ + put_stringz(pktout, "0.0.0.0"); + put_uint32(pktout, 0); + + return pktout; +} + +static int ssh2_rportfwd_cmp(void *av, void *bv) +{ + struct ssh_rportfwd *a = (struct ssh_rportfwd *) av; + struct ssh_rportfwd *b = (struct ssh_rportfwd *) bv; + int i; + if ( (i = strcmp(a->shost, b->shost)) != 0) + return i < 0 ? -1 : +1; + if (a->sport > b->sport) + return +1; + if (a->sport < b->sport) + return -1; + return 0; +} + +static void ssh2_rportfwd_globreq_response(struct ssh2_connection_state *s, + PktIn *pktin, void *ctx) +{ + PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */ + struct ssh_rportfwd *rpf = (struct ssh_rportfwd *)ctx; + + if (pktin->type == SSH2_MSG_REQUEST_SUCCESS) { + ppl_logevent(("Remote port forwarding from %s enabled", + rpf->log_description)); + } else { + ppl_logevent(("Remote port forwarding from %s refused", + rpf->log_description)); + + struct ssh_rportfwd *realpf = del234(s->rportfwds, rpf); + assert(realpf == rpf); + portfwdmgr_close(s->portfwdmgr, rpf->pfr); + free_rportfwd(rpf); + } +} + +struct ssh_rportfwd *ssh2_rportfwd_alloc( + ConnectionLayer *cl, + const char *shost, int sport, const char *dhost, int dport, + int addressfamily, const char *log_description, PortFwdRecord *pfr, + ssh_sharing_connstate *share_ctx) +{ + struct ssh2_connection_state *s = + container_of(cl, struct ssh2_connection_state, cl); + struct ssh_rportfwd *rpf = snew(struct ssh_rportfwd); + + if (!s->rportfwds) + s->rportfwds = newtree234(ssh2_rportfwd_cmp); + + rpf->shost = dupstr(shost); + rpf->sport = sport; + rpf->dhost = dupstr(dhost); + rpf->dport = dport; + rpf->addressfamily = addressfamily; + rpf->log_description = dupstr(log_description); + rpf->pfr = pfr; + rpf->share_ctx = share_ctx; + + if (add234(s->rportfwds, rpf) != rpf) { + free_rportfwd(rpf); + return NULL; + } + + if (!rpf->share_ctx) { + PktOut *pktout = ssh_bpp_new_pktout( + s->ppl.bpp, SSH2_MSG_GLOBAL_REQUEST); + put_stringz(pktout, "tcpip-forward"); + put_bool(pktout, 1); /* want reply */ + put_stringz(pktout, rpf->shost); + put_uint32(pktout, rpf->sport); + pq_push(s->ppl.out_pq, pktout); + + ssh2_queue_global_request_handler( + s, ssh2_rportfwd_globreq_response, rpf); + } + + return rpf; +} + +void ssh2_rportfwd_remove(ConnectionLayer *cl, struct ssh_rportfwd *rpf) +{ + struct ssh2_connection_state *s = + container_of(cl, struct ssh2_connection_state, cl); + + if (rpf->share_ctx) { + /* + * We don't manufacture a cancel-tcpip-forward message for + * remote port forwardings being removed on behalf of a + * downstream; we just pass through the one the downstream + * sent to us. + */ + } else { + PktOut *pktout = ssh_bpp_new_pktout( + s->ppl.bpp, SSH2_MSG_GLOBAL_REQUEST); + put_stringz(pktout, "cancel-tcpip-forward"); + put_bool(pktout, 0); /* _don't_ want reply */ + put_stringz(pktout, rpf->shost); + put_uint32(pktout, rpf->sport); + pq_push(s->ppl.out_pq, pktout); + } + + assert(s->rportfwds); + struct ssh_rportfwd *realpf = del234(s->rportfwds, rpf); + assert(realpf == rpf); + free_rportfwd(rpf); +} + +SshChannel *ssh2_session_open(ConnectionLayer *cl, Channel *chan) +{ + struct ssh2_connection_state *s = + container_of(cl, struct ssh2_connection_state, cl); + PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */ + struct ssh2_channel *c = snew(struct ssh2_channel); + PktOut *pktout; + + c->connlayer = s; + ssh2_channel_init(c); + c->halfopen = TRUE; + c->chan = chan; + + ppl_logevent(("Opening main session channel")); + + pktout = ssh2_chanopen_init(c, "session"); + pq_push(s->ppl.out_pq, pktout); + + return &c->sc; +} + +static void ssh2_channel_response( + struct ssh2_channel *c, PktIn *pkt, void *ctx) +{ + chan_request_response(c->chan, pkt->type == SSH2_MSG_CHANNEL_SUCCESS); +} + +void ssh2channel_start_shell(SshChannel *sc, int want_reply) +{ + struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc); + struct ssh2_connection_state *s = c->connlayer; + + PktOut *pktout = ssh2_chanreq_init( + c, "shell", want_reply ? ssh2_channel_response : NULL, NULL); + pq_push(s->ppl.out_pq, pktout); +} + +void ssh2channel_start_command( + SshChannel *sc, int want_reply, const char *command) +{ + struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc); + struct ssh2_connection_state *s = c->connlayer; + + PktOut *pktout = ssh2_chanreq_init( + c, "exec", want_reply ? ssh2_channel_response : NULL, NULL); + put_stringz(pktout, command); + pq_push(s->ppl.out_pq, pktout); +} + +int ssh2channel_start_subsystem( + SshChannel *sc, int want_reply, const char *subsystem) +{ + struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc); + struct ssh2_connection_state *s = c->connlayer; + + PktOut *pktout = ssh2_chanreq_init( + c, "subsystem", want_reply ? ssh2_channel_response : NULL, NULL); + put_stringz(pktout, subsystem); + pq_push(s->ppl.out_pq, pktout); + + return TRUE; +} + +void ssh2channel_request_x11_forwarding( + SshChannel *sc, int want_reply, const char *authproto, + const char *authdata, int screen_number, int oneshot) +{ + struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc); + struct ssh2_connection_state *s = c->connlayer; + + PktOut *pktout = ssh2_chanreq_init( + c, "x11-req", want_reply ? ssh2_channel_response : NULL, NULL); + put_bool(pktout, oneshot); + put_stringz(pktout, authproto); + put_stringz(pktout, authdata); + put_uint32(pktout, screen_number); + pq_push(s->ppl.out_pq, pktout); +} + +void ssh2channel_request_agent_forwarding(SshChannel *sc, int want_reply) +{ + struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc); + struct ssh2_connection_state *s = c->connlayer; + + PktOut *pktout = ssh2_chanreq_init( + c, "auth-agent-req@openssh.com", + want_reply ? ssh2_channel_response : NULL, NULL); + pq_push(s->ppl.out_pq, pktout); +} + +void ssh2channel_request_pty( + SshChannel *sc, int want_reply, Conf *conf, int w, int h) +{ + struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc); + struct ssh2_connection_state *s = c->connlayer; + strbuf *modebuf; + + PktOut *pktout = ssh2_chanreq_init( + c, "pty-req", want_reply ? ssh2_channel_response : NULL, NULL); + put_stringz(pktout, conf_get_str(conf, CONF_termtype)); + put_uint32(pktout, w); + put_uint32(pktout, h); + put_uint32(pktout, 0); /* pixel width */ + put_uint32(pktout, 0); /* pixel height */ + modebuf = strbuf_new(); + write_ttymodes_to_packet( + BinarySink_UPCAST(modebuf), 2, + get_ttymodes_from_conf(s->ppl.seat, conf)); + put_stringsb(pktout, modebuf); + pq_push(s->ppl.out_pq, pktout); +} + +int ssh2channel_send_env_var( + SshChannel *sc, int want_reply, const char *var, const char *value) +{ + struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc); + struct ssh2_connection_state *s = c->connlayer; + + PktOut *pktout = ssh2_chanreq_init( + c, "env", want_reply ? ssh2_channel_response : NULL, NULL); + put_stringz(pktout, var); + put_stringz(pktout, value); + pq_push(s->ppl.out_pq, pktout); + + return TRUE; +} + +int ssh2channel_send_serial_break(SshChannel *sc, int want_reply, int length) +{ + struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc); + struct ssh2_connection_state *s = c->connlayer; + + PktOut *pktout = ssh2_chanreq_init( + c, "break", want_reply ? ssh2_channel_response : NULL, NULL); + put_uint32(pktout, length); + pq_push(s->ppl.out_pq, pktout); + + return TRUE; +} + +int ssh2channel_send_signal( + SshChannel *sc, int want_reply, const char *signame) +{ + struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc); + struct ssh2_connection_state *s = c->connlayer; + + PktOut *pktout = ssh2_chanreq_init( + c, "signal", want_reply ? ssh2_channel_response : NULL, NULL); + put_stringz(pktout, signame); + pq_push(s->ppl.out_pq, pktout); + + return TRUE; +} + +void ssh2channel_send_terminal_size_change(SshChannel *sc, int w, int h) +{ + struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc); + struct ssh2_connection_state *s = c->connlayer; + + PktOut *pktout = ssh2_chanreq_init(c, "window-change", NULL, NULL); + put_uint32(pktout, w); + put_uint32(pktout, h); + put_uint32(pktout, 0); /* pixel width */ + put_uint32(pktout, 0); /* pixel height */ + pq_push(s->ppl.out_pq, pktout); +} diff --git a/ssh2connection.c b/ssh2connection.c index e6e2fd14..543e8496 100644 --- a/ssh2connection.c +++ b/ssh2connection.c @@ -10,69 +10,7 @@ #include "sshppl.h" #include "sshchan.h" #include "sshcr.h" - -struct ssh2_channel; - -struct outstanding_global_request; - -struct ssh2_connection_state { - int crState; - - Ssh *ssh; - - ssh_sharing_state *connshare; - char *peer_verstring; - - mainchan *mainchan; - SshChannel *mainchan_sc; - int ldisc_opts[LD_N_OPTIONS]; - int session_attempt, session_status; - int term_width, term_height; - int want_user_input; - - int ssh_is_simple; - int persistent; - - Conf *conf; - - tree234 *channels; /* indexed by local id */ - int all_channels_throttled; - - int X11_fwd_enabled; - tree234 *x11authtree; - - int got_pty; - int agent_fwd_enabled; - - tree234 *rportfwds; - PortFwdManager *portfwdmgr; - int portfwdmgr_configured; - - /* - * These store the list of global requests that we're waiting for - * replies to. (REQUEST_FAILURE doesn't come with any indication - * of what message caused it, so we have to keep track of the - * queue ourselves.) - */ - struct outstanding_global_request *globreq_head, *globreq_tail; - - ConnectionLayer cl; - PacketProtocolLayer ppl; -}; - -static int ssh2_rportfwd_cmp(void *av, void *bv) -{ - struct ssh_rportfwd *a = (struct ssh_rportfwd *) av; - struct ssh_rportfwd *b = (struct ssh_rportfwd *) bv; - int i; - if ( (i = strcmp(a->shost, b->shost)) != 0) - return i < 0 ? -1 : +1; - if (a->sport > b->sport) - return +1; - if (a->sport < b->sport) - return -1; - return 0; -} +#include "ssh2connection.h" static void ssh2_connection_free(PacketProtocolLayer *); static void ssh2_connection_process_queue(PacketProtocolLayer *); @@ -95,17 +33,9 @@ static const struct PacketProtocolLayerVtable ssh2_connection_vtable = { "ssh-connection", }; -static struct ssh_rportfwd *ssh2_rportfwd_alloc( - ConnectionLayer *cl, - const char *shost, int sport, const char *dhost, int dport, - int addressfamily, const char *log_description, PortFwdRecord *pfr, - ssh_sharing_connstate *share_ctx); -static void ssh2_rportfwd_remove( - ConnectionLayer *cl, struct ssh_rportfwd *rpf); static SshChannel *ssh2_lportfwd_open( ConnectionLayer *cl, const char *hostname, int port, const char *description, const SocketPeerInfo *pi, Channel *chan); -static SshChannel *ssh2_session_open(ConnectionLayer *cl, Channel *chan); static struct X11FakeAuth *ssh2_add_x11_display( ConnectionLayer *cl, int authtype, struct X11Display *x11disp); static struct X11FakeAuth *ssh2_add_sharing_x11_display( @@ -186,76 +116,6 @@ static char *ssh2_channel_open_failure_error_text(PktIn *pktin) return dupprintf("%s [%.*s]", reason_code_string, PTRLEN_PRINTF(reason)); } -struct outstanding_channel_request; -struct outstanding_global_request; - -struct ssh2_channel { - struct ssh2_connection_state *connlayer; - - unsigned remoteid, localid; - int type; - /* True if we opened this channel but server hasn't confirmed. */ - int halfopen; - - /* Bitmap of whether we've sent/received CHANNEL_EOF and - * CHANNEL_CLOSE. */ -#define CLOSES_SENT_EOF 1 -#define CLOSES_SENT_CLOSE 2 -#define CLOSES_RCVD_EOF 4 -#define CLOSES_RCVD_CLOSE 8 - int closes; - - /* - * This flag indicates that an EOF is pending on the outgoing side - * of the channel: that is, wherever we're getting the data for - * this channel has sent us some data followed by EOF. We can't - * actually send the EOF until we've finished sending the data, so - * we set this flag instead to remind us to do so once our buffer - * is clear. - */ - int pending_eof; - - /* - * True if this channel is causing the underlying connection to be - * throttled. - */ - int throttling_conn; - - /* - * True if we currently have backed-up data on the direction of - * this channel pointing out of the SSH connection, and therefore - * would prefer the 'Channel' implementation not to read further - * local input if possible. - */ - int throttled_by_backlog; - - bufchain outbuffer; - unsigned remwindow, remmaxpkt; - /* locwindow is signed so we can cope with excess data. */ - int locwindow, locmaxwin; - /* - * remlocwin is the amount of local window that we think - * the remote end had available to it after it sent the - * last data packet or window adjust ack. - */ - int remlocwin; - - /* - * These store the list of channel requests that we're waiting for - * replies to. (CHANNEL_FAILURE doesn't come with any indication - * of what message caused it, so we have to keep track of the - * queue ourselves.) - */ - struct outstanding_channel_request *chanreq_head, *chanreq_tail; - - enum { THROTTLED, UNTHROTTLING, UNTHROTTLED } throttle_state; - - ssh_sharing_connstate *sharectx; /* sharing context, if this is a - * downstream channel */ - Channel *chan; /* handle the client side of this channel, if not */ - SshChannel sc; /* entry point for chan to talk back to */ -}; - static int ssh2channel_write(SshChannel *c, const void *buf, int len); static void ssh2channel_write_eof(SshChannel *c); static void ssh2channel_initiate_close(SshChannel *c, const char *err); @@ -266,29 +126,6 @@ static void ssh2channel_x11_sharing_handover( SshChannel *c, ssh_sharing_connstate *share_cs, share_channel *share_chan, const char *peer_addr, int peer_port, int endian, int protomajor, int protominor, const void *initial_data, int initial_len); -static void ssh2channel_request_x11_forwarding( - SshChannel *c, int want_reply, const char *authproto, - const char *authdata, int screen_number, int oneshot); -static void ssh2channel_request_agent_forwarding( - SshChannel *c, int want_reply); -static void ssh2channel_request_pty( - SshChannel *c, int want_reply, Conf *conf, int w, int h); -static int ssh2channel_send_env_var( - SshChannel *c, int want_reply, const char *var, const char *value); -static void ssh2channel_start_shell( - SshChannel *c, int want_reply); -static void ssh2channel_start_command( - SshChannel *c, int want_reply, const char *command); -static int ssh2channel_start_subsystem( - SshChannel *c, int want_reply, const char *subsystem); -static int ssh2channel_send_env_var( - SshChannel *c, int want_reply, const char *var, const char *value); -static int ssh2channel_send_serial_break( - SshChannel *c, int want_reply, int length); -static int ssh2channel_send_signal( - SshChannel *c, int want_reply, const char *signame); -static void ssh2channel_send_terminal_size_change( - SshChannel *c, int w, int h); static void ssh2channel_hint_channel_is_simple(SshChannel *c); static const struct SshChannelVtable ssh2channel_vtable = { @@ -312,12 +149,6 @@ static const struct SshChannelVtable ssh2channel_vtable = { ssh2channel_hint_channel_is_simple, }; -typedef void (*cr_handler_fn_t)(struct ssh2_channel *, PktIn *, void *); - -static void ssh2_channel_init(struct ssh2_channel *c); -static PktOut *ssh2_chanopen_init(struct ssh2_channel *c, const char *type); -static PktOut *ssh2_chanreq_init(struct ssh2_channel *c, const char *type, - cr_handler_fn_t handler, void *ctx); static void ssh2_channel_check_close(struct ssh2_channel *c); static void ssh2_channel_try_eof(struct ssh2_channel *c); static void ssh2_set_window(struct ssh2_channel *c, int newwin); @@ -330,14 +161,12 @@ static void ssh2_channel_destroy(struct ssh2_channel *c); static void ssh2_check_termination(struct ssh2_connection_state *s); -typedef void (*gr_handler_fn_t)(struct ssh2_connection_state *s, - PktIn *pktin, void *ctx); struct outstanding_global_request { gr_handler_fn_t handler; void *ctx; struct outstanding_global_request *next; }; -static void ssh2_queue_global_request_handler( +void ssh2_queue_global_request_handler( struct ssh2_connection_state *s, gr_handler_fn_t handler, void *ctx) { struct outstanding_global_request *ogr = @@ -436,7 +265,6 @@ PacketProtocolLayer *ssh2_connection_new( s->cl.logctx = ssh_get_logctx(ssh); s->portfwdmgr = portfwdmgr_new(&s->cl); - s->rportfwds = newtree234(ssh2_rportfwd_cmp); *cl_out = &s->cl; if (s->connshare) @@ -468,35 +296,26 @@ static void ssh2_connection_free(PacketProtocolLayer *ppl) } freetree234(s->x11authtree); - while ((rpf = delpos234(s->rportfwds, 0)) != NULL) - free_rportfwd(rpf); - freetree234(s->rportfwds); + if (s->rportfwds) { + while ((rpf = delpos234(s->rportfwds, 0)) != NULL) + free_rportfwd(rpf); + freetree234(s->rportfwds); + } portfwdmgr_free(s->portfwdmgr); sfree(s); } -static char *chan_open_x11( - struct ssh2_connection_state *s, Channel **ch, SshChannel *sc, - ptrlen peeraddr, int peerport); -static char *chan_open_forwarded_tcpip( - struct ssh2_connection_state *s, Channel **ch, SshChannel *sc, - ssh_sharing_connstate **share_ctx, - ptrlen fwdaddr, int fwdport, ptrlen peeraddr, int peerport); -static char *chan_open_auth_agent( - struct ssh2_connection_state *s, Channel **ch, SshChannel *sc); - static int ssh2_connection_filter_queue(struct ssh2_connection_state *s) { PktIn *pktin; PktOut *pktout; ptrlen type, data; struct ssh2_channel *c; - ssh_sharing_connstate *share_ctx; struct outstanding_channel_request *ocr; unsigned localid, remid, winsize, pktsize, ext_type; int want_reply, reply_success, expect_halfopen; - char *error; + ChanopenResult chanopen_result; PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */ /* Cross-reference to ssh2transport.c to handle the common packets @@ -514,16 +333,11 @@ static int ssh2_connection_filter_queue(struct ssh2_connection_state *s) switch (pktin->type) { case SSH2_MSG_GLOBAL_REQUEST: - /* type = */ get_string(pktin); + type = get_string(pktin); want_reply = get_bool(pktin); - reply_success = FALSE; - - /* - * We currently don't support any incoming global requests - * at all. Here's where to insert some code to handle - * them, if and when we do. - */ + reply_success = ssh2_connection_parse_global_request( + s, type, pktin); if (want_reply) { int type = (reply_success ? SSH2_MSG_REQUEST_SUCCESS : @@ -556,69 +370,49 @@ static int ssh2_connection_filter_queue(struct ssh2_connection_state *s) break; case SSH2_MSG_CHANNEL_OPEN: - error = NULL; - type = get_string(pktin); c = snew(struct ssh2_channel); c->connlayer = s; + c->chan = NULL; remid = get_uint32(pktin); winsize = get_uint32(pktin); pktsize = get_uint32(pktin); - share_ctx = NULL; - - if (ptrlen_eq_string(type, "x11")) { - ptrlen peeraddr = get_string(pktin); - int peerport = get_uint32(pktin); - - error = chan_open_x11( - s, &c->chan, &c->sc, peeraddr, peerport); - } else if (ptrlen_eq_string(type, "forwarded-tcpip")) { - ptrlen fwdaddr = get_string(pktin); - int fwdport = toint(get_uint32(pktin)); - ptrlen peeraddr = get_string(pktin); - int peerport = toint(get_uint32(pktin)); - - error = chan_open_forwarded_tcpip( - s, &c->chan, &c->sc, &share_ctx, - fwdaddr, fwdport, peeraddr, peerport); - } else if (ptrlen_eq_string(type, "auth-agent@openssh.com")) { - error = chan_open_auth_agent(s, &c->chan, &c->sc); - } else { - error = dupstr("Unsupported channel type requested"); - c->chan = NULL; - } + chanopen_result = ssh2_connection_parse_channel_open( + s, type, pktin, &c->sc); - if (share_ctx) { + if (chanopen_result.outcome == CHANOPEN_RESULT_DOWNSTREAM) { /* * This channel-open request needs to go to a * connection-sharing downstream, so abandon our own * channel-open procedure and just pass the message on * to sshshare.c. */ - assert(!error); - share_got_pkt_from_server(share_ctx, pktin->type, - BinarySource_UPCAST(pktin)->data, - BinarySource_UPCAST(pktin)->len); + share_got_pkt_from_server( + chanopen_result.u.downstream.share_ctx, pktin->type, + BinarySource_UPCAST(pktin)->data, + BinarySource_UPCAST(pktin)->len); sfree(c); break; } c->remoteid = remid; c->halfopen = FALSE; - if (error) { + if (chanopen_result.outcome == CHANOPEN_RESULT_FAILURE) { pktout = ssh_bpp_new_pktout( s->ppl.bpp, SSH2_MSG_CHANNEL_OPEN_FAILURE); put_uint32(pktout, c->remoteid); - put_uint32(pktout, SSH2_OPEN_CONNECT_FAILED); - put_stringz(pktout, error); + put_uint32(pktout, chanopen_result.u.failure.reason_code); + put_stringz(pktout, chanopen_result.u.failure.wire_message); put_stringz(pktout, "en"); /* language tag */ pq_push(s->ppl.out_pq, pktout); - ppl_logevent(("Rejected channel open: %s", error)); - sfree(error); + ppl_logevent(("Rejected channel open: %s", + chanopen_result.u.failure.wire_message)); + sfree(chanopen_result.u.failure.wire_message); sfree(c); } else { + c->chan = chanopen_result.u.success.channel; ssh2_channel_init(c); c->remwindow = winsize; c->remmaxpkt = pktsize; @@ -1349,7 +1143,7 @@ static void ssh2_check_termination(struct ssh2_connection_state *s) * chan untouched (since it will sometimes have been filled in before * calling this). */ -static void ssh2_channel_init(struct ssh2_channel *c) +void ssh2_channel_init(struct ssh2_channel *c) { struct ssh2_connection_state *s = c->connlayer; c->closes = 0; @@ -1370,7 +1164,7 @@ static void ssh2_channel_init(struct ssh2_channel *c) /* * Construct the common parts of a CHANNEL_OPEN. */ -static PktOut *ssh2_chanopen_init(struct ssh2_channel *c, const char *type) +PktOut *ssh2_chanopen_init(struct ssh2_channel *c, const char *type) { struct ssh2_connection_state *s = c->connlayer; PktOut *pktout; @@ -1396,8 +1190,8 @@ static PktOut *ssh2_chanopen_init(struct ssh2_channel *c, const char *type) * the server initiated channel closure before we saw the response) * and the handler should free any storage it's holding. */ -static PktOut *ssh2_chanreq_init(struct ssh2_channel *c, const char *type, - cr_handler_fn_t handler, void *ctx) +PktOut *ssh2_chanreq_init(struct ssh2_channel *c, const char *type, + cr_handler_fn_t handler, void *ctx) { struct ssh2_connection_state *s = c->connlayer; PktOut *pktout; @@ -1516,155 +1310,6 @@ static void ssh2channel_window_override_removed(SshChannel *sc) ssh2_set_window(c, s->ssh_is_simple ? OUR_V2_BIGWIN : OUR_V2_WINSIZE); } -static void ssh2_channel_response( - struct ssh2_channel *c, PktIn *pkt, void *ctx) -{ - chan_request_response(c->chan, pkt->type == SSH2_MSG_CHANNEL_SUCCESS); -} - -static void ssh2channel_start_shell( - SshChannel *sc, int want_reply) -{ - struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc); - struct ssh2_connection_state *s = c->connlayer; - - PktOut *pktout = ssh2_chanreq_init( - c, "shell", want_reply ? ssh2_channel_response : NULL, NULL); - pq_push(s->ppl.out_pq, pktout); -} - -static void ssh2channel_start_command( - SshChannel *sc, int want_reply, const char *command) -{ - struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc); - struct ssh2_connection_state *s = c->connlayer; - - PktOut *pktout = ssh2_chanreq_init( - c, "exec", want_reply ? ssh2_channel_response : NULL, NULL); - put_stringz(pktout, command); - pq_push(s->ppl.out_pq, pktout); -} - -static int ssh2channel_start_subsystem( - SshChannel *sc, int want_reply, const char *subsystem) -{ - struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc); - struct ssh2_connection_state *s = c->connlayer; - - PktOut *pktout = ssh2_chanreq_init( - c, "subsystem", want_reply ? ssh2_channel_response : NULL, NULL); - put_stringz(pktout, subsystem); - pq_push(s->ppl.out_pq, pktout); - - return TRUE; -} - -static void ssh2channel_request_x11_forwarding( - SshChannel *sc, int want_reply, const char *authproto, - const char *authdata, int screen_number, int oneshot) -{ - struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc); - struct ssh2_connection_state *s = c->connlayer; - - PktOut *pktout = ssh2_chanreq_init( - c, "x11-req", want_reply ? ssh2_channel_response : NULL, NULL); - put_bool(pktout, oneshot); - put_stringz(pktout, authproto); - put_stringz(pktout, authdata); - put_uint32(pktout, screen_number); - pq_push(s->ppl.out_pq, pktout); -} - -static void ssh2channel_request_agent_forwarding( - SshChannel *sc, int want_reply) -{ - struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc); - struct ssh2_connection_state *s = c->connlayer; - - PktOut *pktout = ssh2_chanreq_init( - c, "auth-agent-req@openssh.com", - want_reply ? ssh2_channel_response : NULL, NULL); - pq_push(s->ppl.out_pq, pktout); -} - -static void ssh2channel_request_pty( - SshChannel *sc, int want_reply, Conf *conf, int w, int h) -{ - struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc); - struct ssh2_connection_state *s = c->connlayer; - strbuf *modebuf; - - PktOut *pktout = ssh2_chanreq_init( - c, "pty-req", want_reply ? ssh2_channel_response : NULL, NULL); - put_stringz(pktout, conf_get_str(conf, CONF_termtype)); - put_uint32(pktout, w); - put_uint32(pktout, h); - put_uint32(pktout, 0); /* pixel width */ - put_uint32(pktout, 0); /* pixel height */ - modebuf = strbuf_new(); - write_ttymodes_to_packet( - BinarySink_UPCAST(modebuf), 2, - get_ttymodes_from_conf(s->ppl.seat, conf)); - put_stringsb(pktout, modebuf); - pq_push(s->ppl.out_pq, pktout); -} - -static int ssh2channel_send_env_var( - SshChannel *sc, int want_reply, const char *var, const char *value) -{ - struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc); - struct ssh2_connection_state *s = c->connlayer; - - PktOut *pktout = ssh2_chanreq_init( - c, "env", want_reply ? ssh2_channel_response : NULL, NULL); - put_stringz(pktout, var); - put_stringz(pktout, value); - pq_push(s->ppl.out_pq, pktout); - - return TRUE; -} - -static int ssh2channel_send_serial_break( - SshChannel *sc, int want_reply, int length) -{ - struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc); - struct ssh2_connection_state *s = c->connlayer; - - PktOut *pktout = ssh2_chanreq_init( - c, "break", want_reply ? ssh2_channel_response : NULL, NULL); - put_uint32(pktout, length); - pq_push(s->ppl.out_pq, pktout); - - return TRUE; -} - -static int ssh2channel_send_signal( - SshChannel *sc, int want_reply, const char *signame) -{ - struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc); - struct ssh2_connection_state *s = c->connlayer; - - PktOut *pktout = ssh2_chanreq_init( - c, "signal", want_reply ? ssh2_channel_response : NULL, NULL); - put_stringz(pktout, signame); - pq_push(s->ppl.out_pq, pktout); - - return TRUE; -} - -static void ssh2channel_send_terminal_size_change(SshChannel *sc, int w, int h) -{ - struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc); - struct ssh2_connection_state *s = c->connlayer; - - PktOut *pktout = ssh2_chanreq_init(c, "window-change", NULL, NULL); - put_uint32(pktout, w); - put_uint32(pktout, h); - put_uint32(pktout, 0); /* pixel width */ - put_uint32(pktout, 0); /* pixel height */ - pq_push(s->ppl.out_pq, pktout); -} - static void ssh2channel_hint_channel_is_simple(SshChannel *sc) { struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc); @@ -1681,45 +1326,6 @@ static SshChannel *ssh2_lportfwd_open( { struct ssh2_connection_state *s = container_of(cl, struct ssh2_connection_state, cl); - PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */ - struct ssh2_channel *c = snew(struct ssh2_channel); - PktOut *pktout; - - c->connlayer = s; - ssh2_channel_init(c); - c->halfopen = TRUE; - c->chan = chan; - - ppl_logevent(("Opening connection to %s:%d for %s", - hostname, port, description)); - - pktout = ssh2_chanopen_init(c, "direct-tcpip"); - { - char *trimmed_host = host_strduptrim(hostname); - put_stringz(pktout, trimmed_host); - sfree(trimmed_host); - } - put_uint32(pktout, port); - /* - * We make up values for the originator data; partly it's too much - * hassle to keep track, and partly I'm not convinced the server - * should be told details like that about my local network - * configuration. The "originator IP address" is syntactically a - * numeric IP address, and some servers (e.g., Tectia) get upset - * if it doesn't match this syntax. - */ - put_stringz(pktout, "0.0.0.0"); - put_uint32(pktout, 0); - pq_push(s->ppl.out_pq, pktout); - - return &c->sc; -} - -static SshChannel *ssh2_session_open(ConnectionLayer *cl, Channel *chan) -{ - struct ssh2_connection_state *s = - container_of(cl, struct ssh2_connection_state, cl); - PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */ struct ssh2_channel *c = snew(struct ssh2_channel); PktOut *pktout; @@ -1728,101 +1334,12 @@ static SshChannel *ssh2_session_open(ConnectionLayer *cl, Channel *chan) c->halfopen = TRUE; c->chan = chan; - ppl_logevent(("Opening main session channel")); - - pktout = ssh2_chanopen_init(c, "session"); + pktout = ssh2_portfwd_chanopen(s, c, hostname, port, description, pi); pq_push(s->ppl.out_pq, pktout); return &c->sc; } -static void ssh2_rportfwd_globreq_response(struct ssh2_connection_state *s, - PktIn *pktin, void *ctx) -{ - PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */ - struct ssh_rportfwd *rpf = (struct ssh_rportfwd *)ctx; - - if (pktin->type == SSH2_MSG_REQUEST_SUCCESS) { - ppl_logevent(("Remote port forwarding from %s enabled", - rpf->log_description)); - } else { - ppl_logevent(("Remote port forwarding from %s refused", - rpf->log_description)); - - struct ssh_rportfwd *realpf = del234(s->rportfwds, rpf); - assert(realpf == rpf); - portfwdmgr_close(s->portfwdmgr, rpf->pfr); - free_rportfwd(rpf); - } -} - -static struct ssh_rportfwd *ssh2_rportfwd_alloc( - ConnectionLayer *cl, - const char *shost, int sport, const char *dhost, int dport, - int addressfamily, const char *log_description, PortFwdRecord *pfr, - ssh_sharing_connstate *share_ctx) -{ - struct ssh2_connection_state *s = - container_of(cl, struct ssh2_connection_state, cl); - struct ssh_rportfwd *rpf = snew(struct ssh_rportfwd); - - rpf->shost = dupstr(shost); - rpf->sport = sport; - rpf->dhost = dupstr(dhost); - rpf->dport = dport; - rpf->addressfamily = addressfamily; - rpf->log_description = dupstr(log_description); - rpf->pfr = pfr; - rpf->share_ctx = share_ctx; - - if (add234(s->rportfwds, rpf) != rpf) { - free_rportfwd(rpf); - return NULL; - } - - if (!rpf->share_ctx) { - PktOut *pktout = ssh_bpp_new_pktout( - s->ppl.bpp, SSH2_MSG_GLOBAL_REQUEST); - put_stringz(pktout, "tcpip-forward"); - put_bool(pktout, 1); /* want reply */ - put_stringz(pktout, rpf->shost); - put_uint32(pktout, rpf->sport); - pq_push(s->ppl.out_pq, pktout); - - ssh2_queue_global_request_handler( - s, ssh2_rportfwd_globreq_response, rpf); - } - - return rpf; -} - -static void ssh2_rportfwd_remove(ConnectionLayer *cl, struct ssh_rportfwd *rpf) -{ - struct ssh2_connection_state *s = - container_of(cl, struct ssh2_connection_state, cl); - - if (rpf->share_ctx) { - /* - * We don't manufacture a cancel-tcpip-forward message for - * remote port forwardings being removed on behalf of a - * downstream; we just pass through the one the downstream - * sent to us. - */ - } else { - PktOut *pktout = ssh_bpp_new_pktout( - s->ppl.bpp, SSH2_MSG_GLOBAL_REQUEST); - put_stringz(pktout, "cancel-tcpip-forward"); - put_bool(pktout, 0); /* _don't_ want reply */ - put_stringz(pktout, rpf->shost); - put_uint32(pktout, rpf->sport); - pq_push(s->ppl.out_pq, pktout); - } - - struct ssh_rportfwd *realpf = del234(s->rportfwds, rpf); - assert(realpf == rpf); - free_rportfwd(rpf); -} - static void ssh2_sharing_globreq_response( struct ssh2_connection_state *s, PktIn *pktin, void *ctx) { @@ -1929,83 +1446,6 @@ static int ssh2_agent_forwarding_permitted(ConnectionLayer *cl) return conf_get_int(s->conf, CONF_agentfwd) && agent_exists(); } -static char *chan_open_x11( - struct ssh2_connection_state *s, Channel **ch, SshChannel *sc, - ptrlen peeraddr, int peerport) -{ - PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */ - char *peeraddr_str; - - ppl_logevent(("Received X11 connect request from %.*s:%d", - PTRLEN_PRINTF(peeraddr), peerport)); - - if (!s->X11_fwd_enabled && !s->connshare) - return dupstr("X11 forwarding is not enabled"); - - peeraddr_str = peeraddr.ptr ? mkstr(peeraddr) : NULL; - *ch = x11_new_channel( - s->x11authtree, sc, peeraddr_str, peerport, s->connshare != NULL); - sfree(peeraddr_str); - ppl_logevent(("Opened X11 forward channel")); - - return NULL; -} - -static char *chan_open_forwarded_tcpip( - struct ssh2_connection_state *s, Channel **ch, SshChannel *sc, - ssh_sharing_connstate **share_ctx, - ptrlen fwdaddr, int fwdport, ptrlen peeraddr, int peerport) -{ - PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */ - struct ssh_rportfwd pf, *realpf; - char *err; - - ppl_logevent(("Received remote port %.*s:%d open request from %.*s:%d", - PTRLEN_PRINTF(fwdaddr), fwdport, - PTRLEN_PRINTF(peeraddr), peerport)); - - pf.shost = mkstr(fwdaddr); - pf.sport = fwdport; - realpf = find234(s->rportfwds, &pf, NULL); - sfree(pf.shost); - - if (realpf == NULL) - return dupstr("Remote port is not recognised"); - - if (realpf->share_ctx) { - /* - * This port forwarding is on behalf of a connection-sharing - * downstream. - */ - *share_ctx = realpf->share_ctx; - return NULL; - } - - err = portfwdmgr_connect( - s->portfwdmgr, ch, realpf->dhost, realpf->dport, - sc, realpf->addressfamily); - ppl_logevent(("Attempting to forward remote port to %s:%d", - realpf->dhost, realpf->dport)); - if (err != NULL) { - ppl_logevent(("Port open failed: %s", err)); - sfree(err); - return dupstr("Port open failed"); - } - - ppl_logevent(("Forwarded port opened successfully")); - return NULL; -} - -static char *chan_open_auth_agent( - struct ssh2_connection_state *s, Channel **ch, SshChannel *sc) -{ - if (!s->agent_fwd_enabled) - return dupstr("Agent forwarding is not enabled"); - - *ch = agentf_new(sc); - return NULL; -} - static int ssh2_connection_get_specials( PacketProtocolLayer *ppl, add_special_fn_t add_special, void *ctx) { diff --git a/ssh2connection.h b/ssh2connection.h new file mode 100644 index 00000000..eb958bf1 --- /dev/null +++ b/ssh2connection.h @@ -0,0 +1,222 @@ +#ifndef PUTTY_SSH2CONNECTION_H +#define PUTTY_SSH2CONNECTION_H + +struct outstanding_channel_request; +struct outstanding_global_request; + +struct ssh2_connection_state { + int crState; + + Ssh *ssh; + + ssh_sharing_state *connshare; + char *peer_verstring; + + mainchan *mainchan; + SshChannel *mainchan_sc; + int ldisc_opts[LD_N_OPTIONS]; + int session_attempt, session_status; + int term_width, term_height; + int want_user_input; + + int ssh_is_simple; + int persistent; + + Conf *conf; + + tree234 *channels; /* indexed by local id */ + int all_channels_throttled; + + int X11_fwd_enabled; + tree234 *x11authtree; + + int got_pty; + int agent_fwd_enabled; + + tree234 *rportfwds; + PortFwdManager *portfwdmgr; + int portfwdmgr_configured; + + /* + * These store the list of global requests that we're waiting for + * replies to. (REQUEST_FAILURE doesn't come with any indication + * of what message caused it, so we have to keep track of the + * queue ourselves.) + */ + struct outstanding_global_request *globreq_head, *globreq_tail; + + ConnectionLayer cl; + PacketProtocolLayer ppl; +}; + +typedef void (*gr_handler_fn_t)(struct ssh2_connection_state *s, + PktIn *pktin, void *ctx); +void ssh2_queue_global_request_handler( + struct ssh2_connection_state *s, gr_handler_fn_t handler, void *ctx); + +struct ssh2_channel { + struct ssh2_connection_state *connlayer; + + unsigned remoteid, localid; + int type; + /* True if we opened this channel but server hasn't confirmed. */ + int halfopen; + + /* Bitmap of whether we've sent/received CHANNEL_EOF and + * CHANNEL_CLOSE. */ +#define CLOSES_SENT_EOF 1 +#define CLOSES_SENT_CLOSE 2 +#define CLOSES_RCVD_EOF 4 +#define CLOSES_RCVD_CLOSE 8 + int closes; + + /* + * This flag indicates that an EOF is pending on the outgoing side + * of the channel: that is, wherever we're getting the data for + * this channel has sent us some data followed by EOF. We can't + * actually send the EOF until we've finished sending the data, so + * we set this flag instead to remind us to do so once our buffer + * is clear. + */ + int pending_eof; + + /* + * True if this channel is causing the underlying connection to be + * throttled. + */ + int throttling_conn; + + /* + * True if we currently have backed-up data on the direction of + * this channel pointing out of the SSH connection, and therefore + * would prefer the 'Channel' implementation not to read further + * local input if possible. + */ + int throttled_by_backlog; + + bufchain outbuffer; + unsigned remwindow, remmaxpkt; + /* locwindow is signed so we can cope with excess data. */ + int locwindow, locmaxwin; + /* + * remlocwin is the amount of local window that we think + * the remote end had available to it after it sent the + * last data packet or window adjust ack. + */ + int remlocwin; + + /* + * These store the list of channel requests that we're waiting for + * replies to. (CHANNEL_FAILURE doesn't come with any indication + * of what message caused it, so we have to keep track of the + * queue ourselves.) + */ + struct outstanding_channel_request *chanreq_head, *chanreq_tail; + + enum { THROTTLED, UNTHROTTLING, UNTHROTTLED } throttle_state; + + ssh_sharing_connstate *sharectx; /* sharing context, if this is a + * downstream channel */ + Channel *chan; /* handle the client side of this channel, if not */ + SshChannel sc; /* entry point for chan to talk back to */ +}; + +typedef void (*cr_handler_fn_t)(struct ssh2_channel *, PktIn *, void *); + +void ssh2_channel_init(struct ssh2_channel *c); +PktOut *ssh2_chanreq_init(struct ssh2_channel *c, const char *type, + cr_handler_fn_t handler, void *ctx); + +typedef enum ChanopenOutcome { + CHANOPEN_RESULT_FAILURE, + CHANOPEN_RESULT_SUCCESS, + CHANOPEN_RESULT_DOWNSTREAM, +} ChanopenOutcome; + +typedef struct ChanopenResult { + ChanopenOutcome outcome; + union { + struct { + char *wire_message; /* must be freed by recipient */ + unsigned reason_code; + } failure; + struct { + Channel *channel; + } success; + struct { + ssh_sharing_connstate *share_ctx; + } downstream; + } u; +} ChanopenResult; + +PktOut *ssh2_chanopen_init(struct ssh2_channel *c, const char *type); + +PktOut *ssh2_portfwd_chanopen( + struct ssh2_connection_state *s, struct ssh2_channel *c, + const char *hostname, int port, + const char *description, const SocketPeerInfo *peerinfo); + +struct ssh_rportfwd *ssh2_rportfwd_alloc( + ConnectionLayer *cl, + const char *shost, int sport, const char *dhost, int dport, + int addressfamily, const char *log_description, PortFwdRecord *pfr, + ssh_sharing_connstate *share_ctx); +void ssh2_rportfwd_remove( + ConnectionLayer *cl, struct ssh_rportfwd *rpf); + +SshChannel *ssh2_session_open(ConnectionLayer *cl, Channel *chan); + +void ssh2channel_request_x11_forwarding( + SshChannel *c, int want_reply, const char *authproto, + const char *authdata, int screen_number, int oneshot); +void ssh2channel_request_agent_forwarding(SshChannel *c, int want_reply); +void ssh2channel_request_pty( + SshChannel *c, int want_reply, Conf *conf, int w, int h); +int ssh2channel_send_env_var( + SshChannel *c, int want_reply, const char *var, const char *value); +void ssh2channel_start_shell(SshChannel *c, int want_reply); +void ssh2channel_start_command( + SshChannel *c, int want_reply, const char *command); +int ssh2channel_start_subsystem( + SshChannel *c, int want_reply, const char *subsystem); +int ssh2channel_send_env_var( + SshChannel *c, int want_reply, const char *var, const char *value); +int ssh2channel_send_serial_break( + SshChannel *c, int want_reply, int length); +int ssh2channel_send_signal( + SshChannel *c, int want_reply, const char *signame); +void ssh2channel_send_terminal_size_change(SshChannel *c, int w, int h); + +#define CHANOPEN_RETURN_FAILURE(code, msgparams) do \ + { \ + ChanopenResult toret; \ + toret.outcome = CHANOPEN_RESULT_FAILURE; \ + toret.u.failure.reason_code = code; \ + toret.u.failure.wire_message = dupprintf msgparams; \ + return toret; \ + } while (0) + +#define CHANOPEN_RETURN_SUCCESS(chan) do \ + { \ + ChanopenResult toret; \ + toret.outcome = CHANOPEN_RESULT_SUCCESS; \ + toret.u.success.channel = chan; \ + return toret; \ + } while (0) + +#define CHANOPEN_RETURN_DOWNSTREAM(shctx) do \ + { \ + ChanopenResult toret; \ + toret.outcome = CHANOPEN_RESULT_DOWNSTREAM; \ + toret.u.downstream.share_ctx = shctx; \ + return toret; \ + } while (0) + +ChanopenResult ssh2_connection_parse_channel_open( + struct ssh2_connection_state *s, ptrlen type, + PktIn *pktin, SshChannel *sc); + +int ssh2_connection_parse_global_request( + struct ssh2_connection_state *s, ptrlen type, PktIn *pktin); + +#endif /* PUTTY_SSH2CONNECTION_H */ diff --git a/ssh2kex-client.c b/ssh2kex-client.c new file mode 100644 index 00000000..ff09dcf7 --- /dev/null +++ b/ssh2kex-client.c @@ -0,0 +1,870 @@ +/* + * Client side of key exchange for the SSH-2 transport protocol (RFC 4253). + */ + +#include + +#include "putty.h" +#include "ssh.h" +#include "sshbpp.h" +#include "sshppl.h" +#include "sshcr.h" +#include "storage.h" +#include "ssh2transport.h" + +void ssh2kex_coroutine(struct ssh2_transport_state *s) +{ + PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */ + PktIn *pktin; + PktOut *pktout; + + crBegin(s->crStateKex); + + if (s->kex_alg->main_type == KEXTYPE_DH) { + /* + * Work out the number of bits of key we will need from the + * key exchange. We start with the maximum key length of + * either cipher... + */ + { + int csbits, scbits; + + csbits = s->out.cipher ? s->out.cipher->real_keybits : 0; + scbits = s->in.cipher ? s->in.cipher->real_keybits : 0; + s->nbits = (csbits > scbits ? csbits : scbits); + } + /* The keys only have hlen-bit entropy, since they're based on + * a hash. So cap the key size at hlen bits. */ + if (s->nbits > s->kex_alg->hash->hlen * 8) + s->nbits = s->kex_alg->hash->hlen * 8; + + /* + * If we're doing Diffie-Hellman group exchange, start by + * requesting a group. + */ + if (dh_is_gex(s->kex_alg)) { + ppl_logevent(("Doing Diffie-Hellman group exchange")); + s->ppl.bpp->pls->kctx = SSH2_PKTCTX_DHGEX; + /* + * Work out how big a DH group we will need to allow that + * much data. + */ + s->pbits = 512 << ((s->nbits - 1) / 64); + if (s->pbits < DH_MIN_SIZE) + s->pbits = DH_MIN_SIZE; + if (s->pbits > DH_MAX_SIZE) + s->pbits = DH_MAX_SIZE; + if ((s->ppl.remote_bugs & BUG_SSH2_OLDGEX)) { + pktout = ssh_bpp_new_pktout( + s->ppl.bpp, SSH2_MSG_KEX_DH_GEX_REQUEST_OLD); + put_uint32(pktout, s->pbits); + } else { + pktout = ssh_bpp_new_pktout( + s->ppl.bpp, SSH2_MSG_KEX_DH_GEX_REQUEST); + put_uint32(pktout, DH_MIN_SIZE); + put_uint32(pktout, s->pbits); + put_uint32(pktout, DH_MAX_SIZE); + } + pq_push(s->ppl.out_pq, pktout); + + crMaybeWaitUntilV((pktin = ssh2_transport_pop(s)) != NULL); + if (pktin->type != SSH2_MSG_KEX_DH_GEX_GROUP) { + ssh_proto_error(s->ppl.ssh, "Received unexpected packet when " + "expecting Diffie-Hellman group, type %d (%s)", + pktin->type, + ssh2_pkt_type(s->ppl.bpp->pls->kctx, + s->ppl.bpp->pls->actx, + pktin->type)); + return; + } + s->p = get_mp_ssh2(pktin); + s->g = get_mp_ssh2(pktin); + if (get_err(pktin)) { + ssh_proto_error(s->ppl.ssh, + "Unable to parse Diffie-Hellman group packet"); + return; + } + s->dh_ctx = dh_setup_gex(s->p, s->g); + s->kex_init_value = SSH2_MSG_KEX_DH_GEX_INIT; + s->kex_reply_value = SSH2_MSG_KEX_DH_GEX_REPLY; + } else { + s->ppl.bpp->pls->kctx = SSH2_PKTCTX_DHGROUP; + s->dh_ctx = dh_setup_group(s->kex_alg); + s->kex_init_value = SSH2_MSG_KEXDH_INIT; + s->kex_reply_value = SSH2_MSG_KEXDH_REPLY; + ppl_logevent(("Using Diffie-Hellman with standard group \"%s\"", + s->kex_alg->groupname)); + } + + ppl_logevent(("Doing Diffie-Hellman key exchange with hash %s", + s->kex_alg->hash->text_name)); + /* + * Now generate and send e for Diffie-Hellman. + */ + seat_set_busy_status(s->ppl.seat, BUSY_CPU); + s->e = dh_create_e(s->dh_ctx, s->nbits * 2); + pktout = ssh_bpp_new_pktout(s->ppl.bpp, s->kex_init_value); + put_mp_ssh2(pktout, s->e); + pq_push(s->ppl.out_pq, pktout); + + seat_set_busy_status(s->ppl.seat, BUSY_WAITING); + crMaybeWaitUntilV((pktin = ssh2_transport_pop(s)) != NULL); + if (pktin->type != s->kex_reply_value) { + ssh_proto_error(s->ppl.ssh, "Received unexpected packet when " + "expecting Diffie-Hellman reply, type %d (%s)", + pktin->type, + ssh2_pkt_type(s->ppl.bpp->pls->kctx, + s->ppl.bpp->pls->actx, + pktin->type)); + return; + } + seat_set_busy_status(s->ppl.seat, BUSY_CPU); + s->hostkeydata = get_string(pktin); + s->hkey = ssh_key_new_pub(s->hostkey_alg, s->hostkeydata); + s->f = get_mp_ssh2(pktin); + s->sigdata = get_string(pktin); + if (get_err(pktin)) { + ssh_proto_error(s->ppl.ssh, + "Unable to parse Diffie-Hellman reply packet"); + return; + } + + { + const char *err = dh_validate_f(s->dh_ctx, s->f); + if (err) { + ssh_proto_error(s->ppl.ssh, "Diffie-Hellman reply failed " + "validation: %s", err); + return; + } + } + s->K = dh_find_K(s->dh_ctx, s->f); + + /* We assume everything from now on will be quick, and it might + * involve user interaction. */ + seat_set_busy_status(s->ppl.seat, BUSY_NOT); + + put_stringpl(s->exhash, s->hostkeydata); + if (dh_is_gex(s->kex_alg)) { + if (!(s->ppl.remote_bugs & BUG_SSH2_OLDGEX)) + put_uint32(s->exhash, DH_MIN_SIZE); + put_uint32(s->exhash, s->pbits); + if (!(s->ppl.remote_bugs & BUG_SSH2_OLDGEX)) + put_uint32(s->exhash, DH_MAX_SIZE); + put_mp_ssh2(s->exhash, s->p); + put_mp_ssh2(s->exhash, s->g); + } + put_mp_ssh2(s->exhash, s->e); + put_mp_ssh2(s->exhash, s->f); + + dh_cleanup(s->dh_ctx); + s->dh_ctx = NULL; + freebn(s->f); s->f = NULL; + if (dh_is_gex(s->kex_alg)) { + freebn(s->g); s->g = NULL; + freebn(s->p); s->p = NULL; + } + } else if (s->kex_alg->main_type == KEXTYPE_ECDH) { + + ppl_logevent(("Doing ECDH key exchange with curve %s and hash %s", + ssh_ecdhkex_curve_textname(s->kex_alg), + s->kex_alg->hash->text_name)); + s->ppl.bpp->pls->kctx = SSH2_PKTCTX_ECDHKEX; + + s->ecdh_key = ssh_ecdhkex_newkey(s->kex_alg); + if (!s->ecdh_key) { + ssh_sw_abort(s->ppl.ssh, "Unable to generate key for ECDH"); + return; + } + + pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH2_MSG_KEX_ECDH_INIT); + { + strbuf *pubpoint = strbuf_new(); + ssh_ecdhkex_getpublic(s->ecdh_key, BinarySink_UPCAST(pubpoint)); + put_stringsb(pktout, pubpoint); + } + + pq_push(s->ppl.out_pq, pktout); + + crMaybeWaitUntilV((pktin = ssh2_transport_pop(s)) != NULL); + if (pktin->type != SSH2_MSG_KEX_ECDH_REPLY) { + ssh_proto_error(s->ppl.ssh, "Received unexpected packet when " + "expecting ECDH reply, type %d (%s)", pktin->type, + ssh2_pkt_type(s->ppl.bpp->pls->kctx, + s->ppl.bpp->pls->actx, + pktin->type)); + return; + } + + s->hostkeydata = get_string(pktin); + put_stringpl(s->exhash, s->hostkeydata); + s->hkey = ssh_key_new_pub(s->hostkey_alg, s->hostkeydata); + + { + strbuf *pubpoint = strbuf_new(); + ssh_ecdhkex_getpublic(s->ecdh_key, BinarySink_UPCAST(pubpoint)); + put_string(s->exhash, pubpoint->u, pubpoint->len); + strbuf_free(pubpoint); + } + + { + ptrlen keydata = get_string(pktin); + put_stringpl(s->exhash, keydata); + s->K = ssh_ecdhkex_getkey(s->ecdh_key, keydata.ptr, keydata.len); + if (!get_err(pktin) && !s->K) { + ssh_proto_error(s->ppl.ssh, "Received invalid elliptic curve " + "point in ECDH reply"); + return; + } + } + + s->sigdata = get_string(pktin); + if (get_err(pktin)) { + ssh_proto_error(s->ppl.ssh, "Unable to parse ECDH reply packet"); + return; + } + + ssh_ecdhkex_freekey(s->ecdh_key); + s->ecdh_key = NULL; +#ifndef NO_GSSAPI + } else if (s->kex_alg->main_type == KEXTYPE_GSS) { + ptrlen data; + + s->ppl.bpp->pls->kctx = SSH2_PKTCTX_GSSKEX; + s->init_token_sent = 0; + s->complete_rcvd = 0; + s->hkey = NULL; + s->fingerprint = NULL; + s->keystr = NULL; + + /* + * Work out the number of bits of key we will need from the + * key exchange. We start with the maximum key length of + * either cipher... + * + * This is rote from the KEXTYPE_DH section above. + */ + { + int csbits, scbits; + + csbits = s->out.cipher->real_keybits; + scbits = s->in.cipher->real_keybits; + s->nbits = (csbits > scbits ? csbits : scbits); + } + /* The keys only have hlen-bit entropy, since they're based on + * a hash. So cap the key size at hlen bits. */ + if (s->nbits > s->kex_alg->hash->hlen * 8) + s->nbits = s->kex_alg->hash->hlen * 8; + + if (dh_is_gex(s->kex_alg)) { + /* + * Work out how big a DH group we will need to allow that + * much data. + */ + s->pbits = 512 << ((s->nbits - 1) / 64); + ppl_logevent(("Doing GSSAPI (with Kerberos V5) Diffie-Hellman " + "group exchange, with minimum %d bits", s->pbits)); + pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH2_MSG_KEXGSS_GROUPREQ); + put_uint32(pktout, s->pbits); /* min */ + put_uint32(pktout, s->pbits); /* preferred */ + put_uint32(pktout, s->pbits * 2); /* max */ + pq_push(s->ppl.out_pq, pktout); + + crMaybeWaitUntilV( + (pktin = ssh2_transport_pop(s)) != NULL); + if (pktin->type != SSH2_MSG_KEXGSS_GROUP) { + ssh_proto_error(s->ppl.ssh, "Received unexpected packet when " + "expecting Diffie-Hellman group, type %d (%s)", + pktin->type, + ssh2_pkt_type(s->ppl.bpp->pls->kctx, + s->ppl.bpp->pls->actx, + pktin->type)); + return; + } + s->p = get_mp_ssh2(pktin); + s->g = get_mp_ssh2(pktin); + if (get_err(pktin)) { + ssh_proto_error(s->ppl.ssh, + "Unable to parse Diffie-Hellman group packet"); + return; + } + s->dh_ctx = dh_setup_gex(s->p, s->g); + } else { + s->dh_ctx = dh_setup_group(s->kex_alg); + ppl_logevent(("Using GSSAPI (with Kerberos V5) Diffie-Hellman with" + " standard group \"%s\"", s->kex_alg->groupname)); + } + + ppl_logevent(("Doing GSSAPI (with Kerberos V5) Diffie-Hellman key " + "exchange with hash %s", s->kex_alg->hash->text_name)); + /* Now generate e for Diffie-Hellman. */ + seat_set_busy_status(s->ppl.seat, BUSY_CPU); + s->e = dh_create_e(s->dh_ctx, s->nbits * 2); + + if (s->shgss->lib->gsslogmsg) + ppl_logevent(("%s", s->shgss->lib->gsslogmsg)); + + /* initial tokens are empty */ + SSH_GSS_CLEAR_BUF(&s->gss_rcvtok); + SSH_GSS_CLEAR_BUF(&s->gss_sndtok); + SSH_GSS_CLEAR_BUF(&s->mic); + s->gss_stat = s->shgss->lib->acquire_cred( + s->shgss->lib, &s->shgss->ctx, &s->gss_cred_expiry); + if (s->gss_stat != SSH_GSS_OK) { + ssh_sw_abort(s->ppl.ssh, + "GSSAPI key exchange failed to initialise"); + return; + } + + /* now enter the loop */ + assert(s->shgss->srv_name); + do { + /* + * When acquire_cred yields no useful expiration, go with the + * service ticket expiration. + */ + s->gss_stat = s->shgss->lib->init_sec_context( + s->shgss->lib, &s->shgss->ctx, s->shgss->srv_name, + s->gss_delegate, &s->gss_rcvtok, &s->gss_sndtok, + (s->gss_cred_expiry == GSS_NO_EXPIRATION ? + &s->gss_cred_expiry : NULL), NULL); + SSH_GSS_CLEAR_BUF(&s->gss_rcvtok); + + if (s->gss_stat == SSH_GSS_S_COMPLETE && s->complete_rcvd) + break; /* MIC is verified after the loop */ + + if (s->gss_stat != SSH_GSS_S_COMPLETE && + s->gss_stat != SSH_GSS_S_CONTINUE_NEEDED) { + if (s->shgss->lib->display_status( + s->shgss->lib, s->shgss->ctx, + &s->gss_buf) == SSH_GSS_OK) { + char *err = s->gss_buf.value; + ssh_sw_abort(s->ppl.ssh, + "GSSAPI key exchange failed to initialise " + "context: %s", err); + sfree(err); + return; + } + } + assert(s->gss_stat == SSH_GSS_S_COMPLETE || + s->gss_stat == SSH_GSS_S_CONTINUE_NEEDED); + + if (!s->init_token_sent) { + s->init_token_sent = 1; + pktout = ssh_bpp_new_pktout(s->ppl.bpp, + SSH2_MSG_KEXGSS_INIT); + if (s->gss_sndtok.length == 0) { + ssh_sw_abort(s->ppl.ssh, "GSSAPI key exchange failed: " + "no initial context token"); + return; + } + put_string(pktout, + s->gss_sndtok.value, s->gss_sndtok.length); + put_mp_ssh2(pktout, s->e); + pq_push(s->ppl.out_pq, pktout); + s->shgss->lib->free_tok(s->shgss->lib, &s->gss_sndtok); + ppl_logevent(("GSSAPI key exchange initialised")); + } else if (s->gss_sndtok.length != 0) { + pktout = ssh_bpp_new_pktout( + s->ppl.bpp, SSH2_MSG_KEXGSS_CONTINUE); + put_string(pktout, + s->gss_sndtok.value, s->gss_sndtok.length); + pq_push(s->ppl.out_pq, pktout); + s->shgss->lib->free_tok(s->shgss->lib, &s->gss_sndtok); + } + + if (s->gss_stat == SSH_GSS_S_COMPLETE && s->complete_rcvd) + break; + + wait_for_gss_token: + crMaybeWaitUntilV( + (pktin = ssh2_transport_pop(s)) != NULL); + switch (pktin->type) { + case SSH2_MSG_KEXGSS_CONTINUE: + data = get_string(pktin); + s->gss_rcvtok.value = (char *)data.ptr; + s->gss_rcvtok.length = data.len; + continue; + case SSH2_MSG_KEXGSS_COMPLETE: + s->complete_rcvd = 1; + s->f = get_mp_ssh2(pktin); + data = get_string(pktin); + s->mic.value = (char *)data.ptr; + s->mic.length = data.len; + /* Save expiration time of cred when delegating */ + if (s->gss_delegate && s->gss_cred_expiry != GSS_NO_EXPIRATION) + s->gss_cred_expiry = s->gss_cred_expiry; + /* If there's a final token we loop to consume it */ + if (get_bool(pktin)) { + data = get_string(pktin); + s->gss_rcvtok.value = (char *)data.ptr; + s->gss_rcvtok.length = data.len; + continue; + } + break; + case SSH2_MSG_KEXGSS_HOSTKEY: + s->hostkeydata = get_string(pktin); + if (s->hostkey_alg) { + s->hkey = ssh_key_new_pub(s->hostkey_alg, + s->hostkeydata); + put_string(s->exhash, + s->hostkeydata.ptr, s->hostkeydata.len); + } + /* + * Can't loop as we have no token to pass to + * init_sec_context. + */ + goto wait_for_gss_token; + case SSH2_MSG_KEXGSS_ERROR: + /* + * We have no use for the server's major and minor + * status. The minor status is really only + * meaningful to the server, and with luck the major + * status means something to us (but not really all + * that much). The string is more meaningful, and + * hopefully the server sends any error tokens, as + * that will produce the most useful information for + * us. + */ + get_uint32(pktin); /* server's major status */ + get_uint32(pktin); /* server's minor status */ + data = get_string(pktin); + ppl_logevent(("GSSAPI key exchange failed; " + "server's message: %.*s", PTRLEN_PRINTF(data))); + /* Language tag, but we have no use for it */ + get_string(pktin); + /* + * Wait for an error token, if there is one, or the + * server's disconnect. The error token, if there + * is one, must follow the SSH2_MSG_KEXGSS_ERROR + * message, per the RFC. + */ + goto wait_for_gss_token; + default: + ssh_proto_error(s->ppl.ssh, "Received unexpected packet " + "during GSSAPI key exchange, type %d (%s)", + pktin->type, + ssh2_pkt_type(s->ppl.bpp->pls->kctx, + s->ppl.bpp->pls->actx, + pktin->type)); + return; + } + } while (s->gss_rcvtok.length || + s->gss_stat == SSH_GSS_S_CONTINUE_NEEDED || + !s->complete_rcvd); + + s->K = dh_find_K(s->dh_ctx, s->f); + + /* We assume everything from now on will be quick, and it might + * involve user interaction. */ + seat_set_busy_status(s->ppl.seat, BUSY_NOT); + + if (!s->hkey) + put_stringz(s->exhash, ""); + if (dh_is_gex(s->kex_alg)) { + /* min, preferred, max */ + put_uint32(s->exhash, s->pbits); + put_uint32(s->exhash, s->pbits); + put_uint32(s->exhash, s->pbits * 2); + + put_mp_ssh2(s->exhash, s->p); + put_mp_ssh2(s->exhash, s->g); + } + put_mp_ssh2(s->exhash, s->e); + put_mp_ssh2(s->exhash, s->f); + + /* + * MIC verification is done below, after we compute the hash + * used as the MIC input. + */ + + dh_cleanup(s->dh_ctx); + s->dh_ctx = NULL; + freebn(s->f); s->f = NULL; + if (dh_is_gex(s->kex_alg)) { + freebn(s->g); s->g = NULL; + freebn(s->p); s->p = NULL; + } +#endif + } else { + ptrlen rsakeydata; + + assert(s->kex_alg->main_type == KEXTYPE_RSA); + ppl_logevent(("Doing RSA key exchange with hash %s", + s->kex_alg->hash->text_name)); + s->ppl.bpp->pls->kctx = SSH2_PKTCTX_RSAKEX; + /* + * RSA key exchange. First expect a KEXRSA_PUBKEY packet + * from the server. + */ + crMaybeWaitUntilV((pktin = ssh2_transport_pop(s)) != NULL); + if (pktin->type != SSH2_MSG_KEXRSA_PUBKEY) { + ssh_proto_error(s->ppl.ssh, "Received unexpected packet when " + "expecting RSA public key, type %d (%s)", + pktin->type, + ssh2_pkt_type(s->ppl.bpp->pls->kctx, + s->ppl.bpp->pls->actx, + pktin->type)); + return; + } + + s->hostkeydata = get_string(pktin); + put_stringpl(s->exhash, s->hostkeydata); + s->hkey = ssh_key_new_pub(s->hostkey_alg, s->hostkeydata); + + rsakeydata = get_string(pktin); + + s->rsa_kex_key = ssh_rsakex_newkey(rsakeydata.ptr, rsakeydata.len); + if (!s->rsa_kex_key) { + ssh_proto_error(s->ppl.ssh, + "Unable to parse RSA public key packet"); + return; + } + + put_stringpl(s->exhash, rsakeydata); + + /* + * Next, set up a shared secret K, of precisely KLEN - + * 2*HLEN - 49 bits, where KLEN is the bit length of the + * RSA key modulus and HLEN is the bit length of the hash + * we're using. + */ + { + int klen = ssh_rsakex_klen(s->rsa_kex_key); + int nbits = klen - (2*s->kex_alg->hash->hlen*8 + 49); + int i, byte = 0; + strbuf *buf; + unsigned char *outstr; + int outstrlen; + + s->K = bn_power_2(nbits - 1); + + for (i = 0; i < nbits; i++) { + if ((i & 7) == 0) { + byte = random_byte(); + } + bignum_set_bit(s->K, i, (byte >> (i & 7)) & 1); + } + + /* + * Encode this as an mpint. + */ + buf = strbuf_new(); + put_mp_ssh2(buf, s->K); + + /* + * Encrypt it with the given RSA key. + */ + outstrlen = (klen + 7) / 8; + outstr = snewn(outstrlen, unsigned char); + ssh_rsakex_encrypt(s->kex_alg->hash, buf->u, buf->len, + outstr, outstrlen, s->rsa_kex_key); + + /* + * And send it off in a return packet. + */ + pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH2_MSG_KEXRSA_SECRET); + put_string(pktout, outstr, outstrlen); + pq_push(s->ppl.out_pq, pktout); + + put_string(s->exhash, outstr, outstrlen); + + strbuf_free(buf); + sfree(outstr); + } + + ssh_rsakex_freekey(s->rsa_kex_key); + s->rsa_kex_key = NULL; + + crMaybeWaitUntilV((pktin = ssh2_transport_pop(s)) != NULL); + if (pktin->type != SSH2_MSG_KEXRSA_DONE) { + ssh_proto_error(s->ppl.ssh, "Received unexpected packet when " + "expecting RSA kex signature, type %d (%s)", + pktin->type, + ssh2_pkt_type(s->ppl.bpp->pls->kctx, + s->ppl.bpp->pls->actx, + pktin->type)); + return; + } + + s->sigdata = get_string(pktin); + if (get_err(pktin)) { + ssh_proto_error(s->ppl.ssh, "Unable to parse RSA kex signature"); + return; + } + } + + ssh2transport_finalise_exhash(s); + +#ifndef NO_GSSAPI + if (s->kex_alg->main_type == KEXTYPE_GSS) { + Ssh_gss_buf gss_buf; + SSH_GSS_CLEAR_BUF(&s->gss_buf); + + gss_buf.value = s->exchange_hash; + gss_buf.length = s->kex_alg->hash->hlen; + s->gss_stat = s->shgss->lib->verify_mic( + s->shgss->lib, s->shgss->ctx, &gss_buf, &s->mic); + if (s->gss_stat != SSH_GSS_OK) { + if (s->shgss->lib->display_status( + s->shgss->lib, s->shgss->ctx, &s->gss_buf) == SSH_GSS_OK) { + char *err = s->gss_buf.value; + ssh_sw_abort(s->ppl.ssh, "GSSAPI key exchange MIC was " + "not valid: %s", err); + sfree(err); + } else { + ssh_sw_abort(s->ppl.ssh, "GSSAPI key exchange MIC was " + "not valid"); + } + return; + } + + s->gss_kex_used = TRUE; + + /*- + * If this the first KEX, save the GSS context for "gssapi-keyex" + * authentication. + * + * http://tools.ietf.org/html/rfc4462#section-4 + * + * This method may be used only if the initial key exchange was + * performed using a GSS-API-based key exchange method defined in + * accordance with Section 2. The GSS-API context used with this + * method is always that established during an initial GSS-API-based + * key exchange. Any context established during key exchange for the + * purpose of rekeying MUST NOT be used with this method. + */ + if (s->got_session_id) { + s->shgss->lib->release_cred(s->shgss->lib, &s->shgss->ctx); + } + ppl_logevent(("GSSAPI Key Exchange complete!")); + } +#endif + + s->dh_ctx = NULL; + + /* In GSS keyex there's no hostkey signature to verify */ + if (s->kex_alg->main_type != KEXTYPE_GSS) { + if (!s->hkey) { + ssh_proto_error(s->ppl.ssh, "Server's host key is invalid"); + return; + } + + if (!ssh_key_verify( + s->hkey, s->sigdata, + make_ptrlen(s->exchange_hash, s->kex_alg->hash->hlen))) { +#ifndef FUZZING + ssh_proto_error(s->ppl.ssh, "Signature from server's host key " + "is invalid"); + return; +#endif + } + } + + s->keystr = (s->hkey ? ssh_key_cache_str(s->hkey) : NULL); +#ifndef NO_GSSAPI + if (s->gss_kex_used) { + /* + * In a GSS-based session, check the host key (if any) against + * the transient host key cache. + */ + if (s->kex_alg->main_type == KEXTYPE_GSS) { + + /* + * We've just done a GSS key exchange. If it gave us a + * host key, store it. + */ + if (s->hkey) { + s->fingerprint = ssh2_fingerprint(s->hkey); + ppl_logevent(("GSS kex provided fallback host key:")); + ppl_logevent(("%s", s->fingerprint)); + sfree(s->fingerprint); + s->fingerprint = NULL; + ssh_transient_hostkey_cache_add(s->thc, s->hkey); + } else if (!ssh_transient_hostkey_cache_non_empty(s->thc)) { + /* + * But if it didn't, then we currently have no + * fallback host key to use in subsequent non-GSS + * rekeys. So we should immediately trigger a non-GSS + * rekey of our own, to set one up, before the session + * keys have been used for anything else. + * + * This is similar to the cross-certification done at + * user request in the permanent host key cache, but + * here we do it automatically, once, at session + * startup, and only add the key to the transient + * cache. + */ + if (s->hostkey_alg) { + s->need_gss_transient_hostkey = TRUE; + } else { + /* + * If we negotiated the "null" host key algorithm + * in the key exchange, that's an indication that + * no host key at all is available from the server + * (both because we listed "null" last, and + * because RFC 4462 section 5 says that a server + * MUST NOT offer "null" as a host key algorithm + * unless that is the only algorithm it provides + * at all). + * + * In that case we actually _can't_ perform a + * non-GSSAPI key exchange, so it's pointless to + * attempt one proactively. This is also likely to + * cause trouble later if a rekey is required at a + * moment whne GSS credentials are not available, + * but someone setting up a server in this + * configuration presumably accepts that as a + * consequence. + */ + if (!s->warned_about_no_gss_transient_hostkey) { + ppl_logevent(("No fallback host key available")); + s->warned_about_no_gss_transient_hostkey = TRUE; + } + } + } + } else { + /* + * We've just done a fallback key exchange, so make + * sure the host key it used is in the cache of keys + * we previously received in GSS kexes. + * + * An exception is if this was the non-GSS key exchange we + * triggered on purpose to populate the transient cache. + */ + assert(s->hkey); /* only KEXTYPE_GSS lets this be null */ + s->fingerprint = ssh2_fingerprint(s->hkey); + + if (s->need_gss_transient_hostkey) { + ppl_logevent(("Post-GSS rekey provided fallback host key:")); + ppl_logevent(("%s", s->fingerprint)); + ssh_transient_hostkey_cache_add(s->thc, s->hkey); + s->need_gss_transient_hostkey = FALSE; + } else if (!ssh_transient_hostkey_cache_verify(s->thc, s->hkey)) { + ppl_logevent(("Non-GSS rekey after initial GSS kex " + "used host key:")); + ppl_logevent(("%s", s->fingerprint)); + ssh_sw_abort(s->ppl.ssh, "Server's host key did not match any " + "used in previous GSS kex"); + return; + } + + sfree(s->fingerprint); + s->fingerprint = NULL; + } + } else +#endif /* NO_GSSAPI */ + if (!s->got_session_id) { + /* + * Make a note of any other host key formats that are available. + */ + { + int i, j, nkeys = 0; + char *list = NULL; + for (i = 0; i < lenof(ssh2_hostkey_algs); i++) { + if (ssh2_hostkey_algs[i].alg == s->hostkey_alg) + continue; + + for (j = 0; j < s->n_uncert_hostkeys; j++) + if (s->uncert_hostkeys[j] == i) + break; + + if (j < s->n_uncert_hostkeys) { + char *newlist; + if (list) + newlist = dupprintf( + "%s/%s", list, + ssh2_hostkey_algs[i].alg->ssh_id); + else + newlist = dupprintf( + "%s", ssh2_hostkey_algs[i].alg->ssh_id); + sfree(list); + list = newlist; + nkeys++; + } + } + if (list) { + ppl_logevent(("Server also has %s host key%s, but we " + "don't know %s", list, + nkeys > 1 ? "s" : "", + nkeys > 1 ? "any of them" : "it")); + sfree(list); + } + } + + /* + * Authenticate remote host: verify host key. (We've already + * checked the signature of the exchange hash.) + */ + s->fingerprint = ssh2_fingerprint(s->hkey); + ppl_logevent(("Host key fingerprint is:")); + ppl_logevent(("%s", s->fingerprint)); + /* First check against manually configured host keys. */ + s->dlgret = verify_ssh_manual_host_key( + s->conf, s->fingerprint, s->hkey); + if (s->dlgret == 0) { /* did not match */ + ssh_sw_abort(s->ppl.ssh, "Host key did not appear in manually " + "configured list"); + return; + } else if (s->dlgret < 0) { /* none configured; use standard handling */ + s->dlgret = seat_verify_ssh_host_key( + s->ppl.seat, s->savedhost, s->savedport, + ssh_key_cache_id(s->hkey), s->keystr, s->fingerprint, + ssh2_transport_dialog_callback, s); +#ifdef FUZZING + s->dlgret = 1; +#endif + crMaybeWaitUntilV(s->dlgret >= 0); + if (s->dlgret == 0) { + ssh_user_close(s->ppl.ssh, + "User aborted at host key verification"); + return; + } + } + sfree(s->fingerprint); + s->fingerprint = NULL; + /* + * Save this host key, to check against the one presented in + * subsequent rekeys. + */ + s->hostkey_str = s->keystr; + s->keystr = NULL; + } else if (s->cross_certifying) { + s->fingerprint = ssh2_fingerprint(s->hkey); + ppl_logevent(("Storing additional host key for this host:")); + ppl_logevent(("%s", s->fingerprint)); + sfree(s->fingerprint); + s->fingerprint = NULL; + store_host_key(s->savedhost, s->savedport, + ssh_key_cache_id(s->hkey), s->keystr); + s->cross_certifying = FALSE; + /* + * Don't forget to store the new key as the one we'll be + * re-checking in future normal rekeys. + */ + s->hostkey_str = s->keystr; + s->keystr = NULL; + } else { + /* + * In a rekey, we never present an interactive host key + * verification request to the user. Instead, we simply + * enforce that the key we're seeing this time is identical to + * the one we saw before. + */ + if (strcmp(s->hostkey_str, s->keystr)) { +#ifndef FUZZING + ssh_sw_abort(s->ppl.ssh, + "Host key was different in repeat key exchange"); + return; +#endif + } + } + + sfree(s->keystr); + s->keystr = NULL; + if (s->hkey) { + ssh_key_free(s->hkey); + s->hkey = NULL; + } + + crFinishV; +} diff --git a/ssh2transport.c b/ssh2transport.c index ac1caf8a..24597ece 100644 --- a/ssh2transport.c +++ b/ssh2transport.c @@ -10,63 +10,11 @@ #include "sshppl.h" #include "sshcr.h" #include "storage.h" +#include "ssh2transport.h" -#ifndef NO_GSSAPI -#include "sshgssc.h" -#include "sshgss.h" -#define MIN_CTXT_LIFETIME 5 /* Avoid rekey with short lifetime (seconds) */ -#define GSS_KEX_CAPABLE (1<<0) /* Can do GSS KEX */ -#define GSS_CRED_UPDATED (1<<1) /* Cred updated since previous delegation */ -#define GSS_CTXT_EXPIRES (1<<2) /* Context expires before next timer */ -#define GSS_CTXT_MAYFAIL (1<<3) /* Context may expire during handshake */ -#endif - -#define DH_MIN_SIZE 1024 -#define DH_MAX_SIZE 8192 - -enum kexlist { - KEXLIST_KEX, KEXLIST_HOSTKEY, KEXLIST_CSCIPHER, KEXLIST_SCCIPHER, - KEXLIST_CSMAC, KEXLIST_SCMAC, KEXLIST_CSCOMP, KEXLIST_SCCOMP, - NKEXLIST -}; -#define MAXKEXLIST 16 -struct kexinit_algorithm { - const char *name; - union { - struct { - const struct ssh_kex *kex; - int warn; - } kex; - struct { - const ssh_keyalg *hostkey; - int warn; - } hk; - struct { - const struct ssh2_cipheralg *cipher; - int warn; - } cipher; - struct { - const struct ssh2_macalg *mac; - int etm; - } mac; - struct { - const struct ssh_compression_alg *comp; - int delayed; - } comp; - } u; -}; - -struct ssh_signkey_with_user_pref_id { - const ssh_keyalg *alg; - int id; -}; -const static struct ssh_signkey_with_user_pref_id hostkey_algs[] = { - { &ssh_ecdsa_ed25519, HK_ED25519 }, - { &ssh_ecdsa_nistp256, HK_ECDSA }, - { &ssh_ecdsa_nistp384, HK_ECDSA }, - { &ssh_ecdsa_nistp521, HK_ECDSA }, - { &ssh_dss, HK_DSA }, - { &ssh_rsa, HK_RSA }, +const struct ssh_signkey_with_user_pref_id ssh2_hostkey_algs[] = { + #define ARRAYENT_HOSTKEY_ALGORITHM(type, alg) { &alg, type }, + HOSTKEY_ALGORITHMS(ARRAYENT_HOSTKEY_ALGORITHM) }; const static struct ssh2_macalg *const macs[] = { @@ -112,144 +60,6 @@ const static struct ssh_compression_alg *const compressions[] = { &ssh_zlib, &ssh_comp_none }; -/* - * Enumeration of high-level classes of reason why we might need to do - * a repeat key exchange. A full detailed reason in human-readable - * string form for the Event Log is also provided, but this enum type - * is used to discriminate between classes of reason that the code - * needs to treat differently. - * - * RK_NONE == 0 is the value indicating that no rekey is currently - * needed at all. RK_INITIAL indicates that we haven't even done the - * _first_ key exchange yet. RK_SERVER indicates that we're rekeying - * because the server asked for it, not because we decided it - * ourselves. RK_NORMAL is the usual case. RK_GSS_UPDATE indicates - * that we're rekeying because we've just got new GSSAPI credentials - * (hence there's no point in doing a preliminary check for new GSS - * creds, because we already know the answer); RK_POST_USERAUTH - * indicates that _if_ we're going to need a post-userauth immediate - * rekey for any reason, this is the moment to do it. - * - * So RK_POST_USERAUTH only tells the transport layer to _consider_ - * rekeying, not to definitely do it. Also, that one enum value is - * special in that the user-readable reason text is passed in to the - * transport layer as NULL, whereas fills in the reason text after it - * decides whether it needs a rekey at all. In the other cases, - * rekey_reason is passed in to the at the same time as rekey_class. - */ -typedef enum RekeyClass { - RK_NONE = 0, - RK_INITIAL, - RK_SERVER, - RK_NORMAL, - RK_POST_USERAUTH, - RK_GSS_UPDATE -} RekeyClass; - -typedef struct transport_direction { - const struct ssh2_cipheralg *cipher; - const struct ssh2_macalg *mac; - int etm_mode; - const struct ssh_compression_alg *comp; - int comp_delayed; -} transport_direction; - -struct ssh2_transport_state { - int crState; - - PacketProtocolLayer *higher_layer; - PktInQueue pq_in_higher; - PktOutQueue pq_out_higher; - IdempotentCallback ic_pq_out_higher; - - Conf *conf; - char *savedhost; - int savedport; - const char *rekey_reason; - enum RekeyClass rekey_class; - - unsigned long max_data_size; - - const struct ssh_kex *kex_alg; - const ssh_keyalg *hostkey_alg; - char *hostkey_str; /* string representation, for easy checking in rekeys */ - unsigned char session_id[SSH2_KEX_MAX_HASH_LEN]; - int session_id_len; - struct dh_ctx *dh_ctx; - ssh_hash *exhash; - - struct DataTransferStats *stats; - - char *client_greeting, *server_greeting; - - int kex_in_progress; - unsigned long next_rekey, last_rekey; - const char *deferred_rekey_reason; - int higher_layer_ok; - - /* - * Fully qualified host name, which we need if doing GSSAPI. - */ - char *fullhostname; - - /* shgss is outside the ifdef on purpose to keep APIs simple. If - * NO_GSSAPI is not defined, then it's just an opaque structure - * tag and the pointer will be NULL. */ - struct ssh_connection_shared_gss_state *shgss; -#ifndef NO_GSSAPI - int gss_status; - time_t gss_cred_expiry; /* Re-delegate if newer */ - unsigned long gss_ctxt_lifetime; /* Re-delegate when short */ -#endif - ssh_transient_hostkey_cache *thc; - - int gss_kex_used; - - int nbits, pbits, warn_kex, warn_hk, warn_cscipher, warn_sccipher; - Bignum p, g, e, f, K; - strbuf *client_kexinit, *server_kexinit; - int kex_init_value, kex_reply_value; - transport_direction in, out; - ptrlen hostkeydata, sigdata; - char *keystr, *fingerprint; - ssh_key *hkey; /* actual host key */ - struct RSAKey *rsa_kex_key; /* for RSA kex */ - struct ec_key *ecdh_key; /* for ECDH kex */ - unsigned char exchange_hash[SSH2_KEX_MAX_HASH_LEN]; - int can_gssapi_keyex; - int need_gss_transient_hostkey; - int warned_about_no_gss_transient_hostkey; - int got_session_id; - int dlgret; - int guessok; - int ignorepkt; - struct kexinit_algorithm kexlists[NKEXLIST][MAXKEXLIST]; -#ifndef NO_GSSAPI - Ssh_gss_buf gss_buf; - Ssh_gss_buf gss_rcvtok, gss_sndtok; - Ssh_gss_stat gss_stat; - Ssh_gss_buf mic; - int init_token_sent; - int complete_rcvd; - int gss_delegate; -#endif - - /* - * List of host key algorithms for which we _don't_ have a stored - * host key. These are indices into the main hostkey_algs[] array - */ - int uncert_hostkeys[lenof(hostkey_algs)]; - int n_uncert_hostkeys; - - /* - * Flag indicating that the current rekey is intended to finish - * with a newly cross-certified host key. - */ - int cross_certifying; - - PacketProtocolLayer ppl; -}; - static void ssh2_transport_free(PacketProtocolLayer *); static void ssh2_transport_process_queue(PacketProtocolLayer *); static int ssh2_transport_get_specials( @@ -260,7 +70,6 @@ static int ssh2_transport_want_user_input(PacketProtocolLayer *ppl); static void ssh2_transport_got_user_input(PacketProtocolLayer *ppl); static void ssh2_transport_reconfigure(PacketProtocolLayer *ppl, Conf *conf); -static void ssh2_transport_dialog_callback(void *, int); static void ssh2_transport_set_max_data_size(struct ssh2_transport_state *s); static unsigned long sanitise_rekey_time(int rekey_time, unsigned long def); static void ssh2_transport_higher_layer_packet_callback(void *context); @@ -574,7 +383,7 @@ static int ssh2_transport_filter_queue(struct ssh2_transport_state *s) } } -static PktIn *ssh2_transport_pop(struct ssh2_transport_state *s) +PktIn *ssh2_transport_pop(struct ssh2_transport_state *s) { ssh2_transport_filter_queue(s); return pq_pop(s->ppl.in_pq); @@ -730,14 +539,14 @@ static void ssh2_write_kexinit_lists( for (i = 0; i < n_preferred_hk; i++) { if (preferred_hk[i] == HK_WARN) warn = TRUE; - for (j = 0; j < lenof(hostkey_algs); j++) { - if (hostkey_algs[j].id != preferred_hk[i]) + for (j = 0; j < lenof(ssh2_hostkey_algs); j++) { + if (ssh2_hostkey_algs[j].id != preferred_hk[i]) continue; if (have_ssh_host_key(hk_host, hk_port, - hostkey_algs[j].alg->cache_id)) { + ssh2_hostkey_algs[j].alg->cache_id)) { alg = ssh2_kexinit_addalg(kexlists[KEXLIST_HOSTKEY], - hostkey_algs[j].alg->ssh_id); - alg->u.hk.hostkey = hostkey_algs[j].alg; + ssh2_hostkey_algs[j].alg->ssh_id); + alg->u.hk.hostkey = ssh2_hostkey_algs[j].alg; alg->u.hk.warn = warn; } } @@ -746,12 +555,12 @@ static void ssh2_write_kexinit_lists( for (i = 0; i < n_preferred_hk; i++) { if (preferred_hk[i] == HK_WARN) warn = TRUE; - for (j = 0; j < lenof(hostkey_algs); j++) { - if (hostkey_algs[j].id != preferred_hk[i]) + for (j = 0; j < lenof(ssh2_hostkey_algs); j++) { + if (ssh2_hostkey_algs[j].id != preferred_hk[i]) continue; alg = ssh2_kexinit_addalg(kexlists[KEXLIST_HOSTKEY], - hostkey_algs[j].alg->ssh_id); - alg->u.hk.hostkey = hostkey_algs[j].alg; + ssh2_hostkey_algs[j].alg->ssh_id); + alg->u.hk.hostkey = ssh2_hostkey_algs[j].alg; alg->u.hk.warn = warn; } } @@ -773,14 +582,14 @@ static void ssh2_write_kexinit_lists( for (i = 0; i < n_preferred_hk; i++) { if (preferred_hk[i] == HK_WARN) warn = TRUE; - for (j = 0; j < lenof(hostkey_algs); j++) { - if (hostkey_algs[j].id != preferred_hk[i]) + for (j = 0; j < lenof(ssh2_hostkey_algs); j++) { + if (ssh2_hostkey_algs[j].id != preferred_hk[i]) continue; if (ssh_transient_hostkey_cache_has( - thc, hostkey_algs[j].alg)) { + thc, ssh2_hostkey_algs[j].alg)) { alg = ssh2_kexinit_addalg(kexlists[KEXLIST_HOSTKEY], - hostkey_algs[j].alg->ssh_id); - alg->u.hk.hostkey = hostkey_algs[j].alg; + ssh2_hostkey_algs[j].alg->ssh_id); + alg->u.hk.hostkey = ssh2_hostkey_algs[j].alg; alg->u.hk.warn = warn; } } @@ -1100,12 +909,12 @@ static int ssh2_scan_kexinits( * list to find all the host key algorithms offered by the * server which we know about at all, whether we selected each * one or not. We return these as a list of indices into the - * constant hostkey_algs[] array. + * constant ssh2_hostkey_algs[] array. */ *n_server_hostkeys = 0; - for (i = 0; i < lenof(hostkey_algs); i++) - if (in_commasep_string(hostkey_algs[i].alg->ssh_id, + for (i = 0; i < lenof(ssh2_hostkey_algs); i++) + if (in_commasep_string(ssh2_hostkey_algs[i].alg->ssh_id, slists[KEXLIST_HOSTKEY].ptr, slists[KEXLIST_HOSTKEY].len)) server_hostkeys[(*n_server_hostkeys)++] = i; @@ -1114,6 +923,19 @@ static int ssh2_scan_kexinits( return TRUE; } +void ssh2transport_finalise_exhash(struct ssh2_transport_state *s) +{ + put_mp_ssh2(s->exhash, s->K); + assert(ssh_hash_alg(s->exhash)->hlen <= sizeof(s->exchange_hash)); + ssh_hash_final(s->exhash, s->exchange_hash); + s->exhash = NULL; + +#if 0 + debug(("Exchange hash is:\n")); + dmemdump(s->exchange_hash, s->kex_alg->hash->hlen); +#endif +} + static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) { struct ssh2_transport_state *s = @@ -1267,20 +1089,14 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) for (i = 0; i < nhk; i++) { j = hks[i]; - if (hostkey_algs[j].alg != s->hostkey_alg && + if (ssh2_hostkey_algs[j].alg != s->hostkey_alg && !have_ssh_host_key(s->savedhost, s->savedport, - hostkey_algs[j].alg->cache_id)) { + ssh2_hostkey_algs[j].alg->cache_id)) { s->uncert_hostkeys[s->n_uncert_hostkeys++] = j; } } } - s->exhash = ssh_hash_new(s->kex_alg->hash); - put_stringz(s->exhash, s->client_greeting); - put_stringz(s->exhash, s->server_greeting); - put_string(s->exhash, s->client_kexinit->u, s->client_kexinit->len); - put_string(s->exhash, s->server_kexinit->u, s->server_kexinit->len); - if (s->warn_kex) { s->dlgret = seat_confirm_weak_crypto_primitive( s->ppl.seat, "key-exchange algorithm", s->kex_alg->name, @@ -1306,7 +1122,7 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) betteralgs = NULL; for (j = 0; j < s->n_uncert_hostkeys; j++) { const struct ssh_signkey_with_user_pref_id *hktype = - &hostkey_algs[s->uncert_hostkeys[j]]; + &ssh2_hostkey_algs[s->uncert_hostkeys[j]]; int better = FALSE; for (k = 0; k < HK_MAX; k++) { int id = conf_get_int_int(s->conf, CONF_ssh_hklist, k); @@ -1379,855 +1195,20 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) if (s->ignorepkt) crMaybeWaitUntilV((pktin = ssh2_transport_pop(s)) != NULL); - if (s->kex_alg->main_type == KEXTYPE_DH) { - /* - * Work out the number of bits of key we will need from the - * key exchange. We start with the maximum key length of - * either cipher... - */ - { - int csbits, scbits; - - csbits = s->out.cipher ? s->out.cipher->real_keybits : 0; - scbits = s->in.cipher ? s->in.cipher->real_keybits : 0; - s->nbits = (csbits > scbits ? csbits : scbits); - } - /* The keys only have hlen-bit entropy, since they're based on - * a hash. So cap the key size at hlen bits. */ - if (s->nbits > s->kex_alg->hash->hlen * 8) - s->nbits = s->kex_alg->hash->hlen * 8; - - /* - * If we're doing Diffie-Hellman group exchange, start by - * requesting a group. - */ - if (dh_is_gex(s->kex_alg)) { - ppl_logevent(("Doing Diffie-Hellman group exchange")); - s->ppl.bpp->pls->kctx = SSH2_PKTCTX_DHGEX; - /* - * Work out how big a DH group we will need to allow that - * much data. - */ - s->pbits = 512 << ((s->nbits - 1) / 64); - if (s->pbits < DH_MIN_SIZE) - s->pbits = DH_MIN_SIZE; - if (s->pbits > DH_MAX_SIZE) - s->pbits = DH_MAX_SIZE; - if ((s->ppl.remote_bugs & BUG_SSH2_OLDGEX)) { - pktout = ssh_bpp_new_pktout( - s->ppl.bpp, SSH2_MSG_KEX_DH_GEX_REQUEST_OLD); - put_uint32(pktout, s->pbits); - } else { - pktout = ssh_bpp_new_pktout( - s->ppl.bpp, SSH2_MSG_KEX_DH_GEX_REQUEST); - put_uint32(pktout, DH_MIN_SIZE); - put_uint32(pktout, s->pbits); - put_uint32(pktout, DH_MAX_SIZE); - } - pq_push(s->ppl.out_pq, pktout); - - crMaybeWaitUntilV((pktin = ssh2_transport_pop(s)) != NULL); - if (pktin->type != SSH2_MSG_KEX_DH_GEX_GROUP) { - ssh_proto_error(s->ppl.ssh, "Received unexpected packet when " - "expecting Diffie-Hellman group, type %d (%s)", - pktin->type, - ssh2_pkt_type(s->ppl.bpp->pls->kctx, - s->ppl.bpp->pls->actx, - pktin->type)); - return; - } - s->p = get_mp_ssh2(pktin); - s->g = get_mp_ssh2(pktin); - if (get_err(pktin)) { - ssh_proto_error(s->ppl.ssh, - "Unable to parse Diffie-Hellman group packet"); - return; - } - s->dh_ctx = dh_setup_gex(s->p, s->g); - s->kex_init_value = SSH2_MSG_KEX_DH_GEX_INIT; - s->kex_reply_value = SSH2_MSG_KEX_DH_GEX_REPLY; - } else { - s->ppl.bpp->pls->kctx = SSH2_PKTCTX_DHGROUP; - s->dh_ctx = dh_setup_group(s->kex_alg); - s->kex_init_value = SSH2_MSG_KEXDH_INIT; - s->kex_reply_value = SSH2_MSG_KEXDH_REPLY; - ppl_logevent(("Using Diffie-Hellman with standard group \"%s\"", - s->kex_alg->groupname)); - } - - ppl_logevent(("Doing Diffie-Hellman key exchange with hash %s", - s->kex_alg->hash->text_name)); - /* - * Now generate and send e for Diffie-Hellman. - */ - seat_set_busy_status(s->ppl.seat, BUSY_CPU); - s->e = dh_create_e(s->dh_ctx, s->nbits * 2); - pktout = ssh_bpp_new_pktout(s->ppl.bpp, s->kex_init_value); - put_mp_ssh2(pktout, s->e); - pq_push(s->ppl.out_pq, pktout); - - seat_set_busy_status(s->ppl.seat, BUSY_WAITING); - crMaybeWaitUntilV((pktin = ssh2_transport_pop(s)) != NULL); - if (pktin->type != s->kex_reply_value) { - ssh_proto_error(s->ppl.ssh, "Received unexpected packet when " - "expecting Diffie-Hellman reply, type %d (%s)", - pktin->type, - ssh2_pkt_type(s->ppl.bpp->pls->kctx, - s->ppl.bpp->pls->actx, - pktin->type)); - return; - } - seat_set_busy_status(s->ppl.seat, BUSY_CPU); - s->hostkeydata = get_string(pktin); - s->hkey = ssh_key_new_pub(s->hostkey_alg, s->hostkeydata); - s->f = get_mp_ssh2(pktin); - s->sigdata = get_string(pktin); - if (get_err(pktin)) { - ssh_proto_error(s->ppl.ssh, - "Unable to parse Diffie-Hellman reply packet"); - return; - } - - { - const char *err = dh_validate_f(s->dh_ctx, s->f); - if (err) { - ssh_proto_error(s->ppl.ssh, "Diffie-Hellman reply failed " - "validation: %s", err); - return; - } - } - s->K = dh_find_K(s->dh_ctx, s->f); - - /* We assume everything from now on will be quick, and it might - * involve user interaction. */ - seat_set_busy_status(s->ppl.seat, BUSY_NOT); - - put_stringpl(s->exhash, s->hostkeydata); - if (dh_is_gex(s->kex_alg)) { - if (!(s->ppl.remote_bugs & BUG_SSH2_OLDGEX)) - put_uint32(s->exhash, DH_MIN_SIZE); - put_uint32(s->exhash, s->pbits); - if (!(s->ppl.remote_bugs & BUG_SSH2_OLDGEX)) - put_uint32(s->exhash, DH_MAX_SIZE); - put_mp_ssh2(s->exhash, s->p); - put_mp_ssh2(s->exhash, s->g); - } - put_mp_ssh2(s->exhash, s->e); - put_mp_ssh2(s->exhash, s->f); - - dh_cleanup(s->dh_ctx); - s->dh_ctx = NULL; - freebn(s->f); s->f = NULL; - if (dh_is_gex(s->kex_alg)) { - freebn(s->g); s->g = NULL; - freebn(s->p); s->p = NULL; - } - } else if (s->kex_alg->main_type == KEXTYPE_ECDH) { - - ppl_logevent(("Doing ECDH key exchange with curve %s and hash %s", - ssh_ecdhkex_curve_textname(s->kex_alg), - s->kex_alg->hash->text_name)); - s->ppl.bpp->pls->kctx = SSH2_PKTCTX_ECDHKEX; - - s->ecdh_key = ssh_ecdhkex_newkey(s->kex_alg); - if (!s->ecdh_key) { - ssh_sw_abort(s->ppl.ssh, "Unable to generate key for ECDH"); - return; - } - - pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH2_MSG_KEX_ECDH_INIT); - { - strbuf *pubpoint = strbuf_new(); - ssh_ecdhkex_getpublic(s->ecdh_key, BinarySink_UPCAST(pubpoint)); - put_stringsb(pktout, pubpoint); - } - - pq_push(s->ppl.out_pq, pktout); - - crMaybeWaitUntilV((pktin = ssh2_transport_pop(s)) != NULL); - if (pktin->type != SSH2_MSG_KEX_ECDH_REPLY) { - ssh_proto_error(s->ppl.ssh, "Received unexpected packet when " - "expecting ECDH reply, type %d (%s)", pktin->type, - ssh2_pkt_type(s->ppl.bpp->pls->kctx, - s->ppl.bpp->pls->actx, - pktin->type)); - return; - } - - s->hostkeydata = get_string(pktin); - put_stringpl(s->exhash, s->hostkeydata); - s->hkey = ssh_key_new_pub(s->hostkey_alg, s->hostkeydata); - - { - strbuf *pubpoint = strbuf_new(); - ssh_ecdhkex_getpublic(s->ecdh_key, BinarySink_UPCAST(pubpoint)); - put_string(s->exhash, pubpoint->u, pubpoint->len); - strbuf_free(pubpoint); - } - - { - ptrlen keydata = get_string(pktin); - put_stringpl(s->exhash, keydata); - s->K = ssh_ecdhkex_getkey(s->ecdh_key, keydata.ptr, keydata.len); - if (!get_err(pktin) && !s->K) { - ssh_proto_error(s->ppl.ssh, "Received invalid elliptic curve " - "point in ECDH reply"); - return; - } - } - - s->sigdata = get_string(pktin); - if (get_err(pktin)) { - ssh_proto_error(s->ppl.ssh, "Unable to parse ECDH reply packet"); - return; - } - - ssh_ecdhkex_freekey(s->ecdh_key); - s->ecdh_key = NULL; -#ifndef NO_GSSAPI - } else if (s->kex_alg->main_type == KEXTYPE_GSS) { - ptrlen data; - - s->ppl.bpp->pls->kctx = SSH2_PKTCTX_GSSKEX; - s->init_token_sent = 0; - s->complete_rcvd = 0; - s->hkey = NULL; - s->fingerprint = NULL; - s->keystr = NULL; - - /* - * Work out the number of bits of key we will need from the - * key exchange. We start with the maximum key length of - * either cipher... - * - * This is rote from the KEXTYPE_DH section above. - */ - { - int csbits, scbits; - - csbits = s->out.cipher->real_keybits; - scbits = s->in.cipher->real_keybits; - s->nbits = (csbits > scbits ? csbits : scbits); - } - /* The keys only have hlen-bit entropy, since they're based on - * a hash. So cap the key size at hlen bits. */ - if (s->nbits > s->kex_alg->hash->hlen * 8) - s->nbits = s->kex_alg->hash->hlen * 8; - - if (dh_is_gex(s->kex_alg)) { - /* - * Work out how big a DH group we will need to allow that - * much data. - */ - s->pbits = 512 << ((s->nbits - 1) / 64); - ppl_logevent(("Doing GSSAPI (with Kerberos V5) Diffie-Hellman " - "group exchange, with minimum %d bits", s->pbits)); - pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH2_MSG_KEXGSS_GROUPREQ); - put_uint32(pktout, s->pbits); /* min */ - put_uint32(pktout, s->pbits); /* preferred */ - put_uint32(pktout, s->pbits * 2); /* max */ - pq_push(s->ppl.out_pq, pktout); - - crMaybeWaitUntilV( - (pktin = ssh2_transport_pop(s)) != NULL); - if (pktin->type != SSH2_MSG_KEXGSS_GROUP) { - ssh_proto_error(s->ppl.ssh, "Received unexpected packet when " - "expecting Diffie-Hellman group, type %d (%s)", - pktin->type, - ssh2_pkt_type(s->ppl.bpp->pls->kctx, - s->ppl.bpp->pls->actx, - pktin->type)); - return; - } - s->p = get_mp_ssh2(pktin); - s->g = get_mp_ssh2(pktin); - if (get_err(pktin)) { - ssh_proto_error(s->ppl.ssh, - "Unable to parse Diffie-Hellman group packet"); - return; - } - s->dh_ctx = dh_setup_gex(s->p, s->g); - } else { - s->dh_ctx = dh_setup_group(s->kex_alg); - ppl_logevent(("Using GSSAPI (with Kerberos V5) Diffie-Hellman with" - " standard group \"%s\"", s->kex_alg->groupname)); - } - - ppl_logevent(("Doing GSSAPI (with Kerberos V5) Diffie-Hellman key " - "exchange with hash %s", s->kex_alg->hash->text_name)); - /* Now generate e for Diffie-Hellman. */ - seat_set_busy_status(s->ppl.seat, BUSY_CPU); - s->e = dh_create_e(s->dh_ctx, s->nbits * 2); - - if (s->shgss->lib->gsslogmsg) - ppl_logevent(("%s", s->shgss->lib->gsslogmsg)); - - /* initial tokens are empty */ - SSH_GSS_CLEAR_BUF(&s->gss_rcvtok); - SSH_GSS_CLEAR_BUF(&s->gss_sndtok); - SSH_GSS_CLEAR_BUF(&s->mic); - s->gss_stat = s->shgss->lib->acquire_cred( - s->shgss->lib, &s->shgss->ctx, &s->gss_cred_expiry); - if (s->gss_stat != SSH_GSS_OK) { - ssh_sw_abort(s->ppl.ssh, - "GSSAPI key exchange failed to initialise"); - return; - } - - /* now enter the loop */ - assert(s->shgss->srv_name); - do { - /* - * When acquire_cred yields no useful expiration, go with the - * service ticket expiration. - */ - s->gss_stat = s->shgss->lib->init_sec_context( - s->shgss->lib, &s->shgss->ctx, s->shgss->srv_name, - s->gss_delegate, &s->gss_rcvtok, &s->gss_sndtok, - (s->gss_cred_expiry == GSS_NO_EXPIRATION ? - &s->gss_cred_expiry : NULL), NULL); - SSH_GSS_CLEAR_BUF(&s->gss_rcvtok); - - if (s->gss_stat == SSH_GSS_S_COMPLETE && s->complete_rcvd) - break; /* MIC is verified after the loop */ - - if (s->gss_stat != SSH_GSS_S_COMPLETE && - s->gss_stat != SSH_GSS_S_CONTINUE_NEEDED) { - if (s->shgss->lib->display_status( - s->shgss->lib, s->shgss->ctx, - &s->gss_buf) == SSH_GSS_OK) { - char *err = s->gss_buf.value; - ssh_sw_abort(s->ppl.ssh, - "GSSAPI key exchange failed to initialise " - "context: %s", err); - sfree(err); - return; - } - } - assert(s->gss_stat == SSH_GSS_S_COMPLETE || - s->gss_stat == SSH_GSS_S_CONTINUE_NEEDED); - - if (!s->init_token_sent) { - s->init_token_sent = 1; - pktout = ssh_bpp_new_pktout(s->ppl.bpp, - SSH2_MSG_KEXGSS_INIT); - if (s->gss_sndtok.length == 0) { - ssh_sw_abort(s->ppl.ssh, "GSSAPI key exchange failed: " - "no initial context token"); - return; - } - put_string(pktout, - s->gss_sndtok.value, s->gss_sndtok.length); - put_mp_ssh2(pktout, s->e); - pq_push(s->ppl.out_pq, pktout); - s->shgss->lib->free_tok(s->shgss->lib, &s->gss_sndtok); - ppl_logevent(("GSSAPI key exchange initialised")); - } else if (s->gss_sndtok.length != 0) { - pktout = ssh_bpp_new_pktout( - s->ppl.bpp, SSH2_MSG_KEXGSS_CONTINUE); - put_string(pktout, - s->gss_sndtok.value, s->gss_sndtok.length); - pq_push(s->ppl.out_pq, pktout); - s->shgss->lib->free_tok(s->shgss->lib, &s->gss_sndtok); - } - - if (s->gss_stat == SSH_GSS_S_COMPLETE && s->complete_rcvd) - break; - - wait_for_gss_token: - crMaybeWaitUntilV( - (pktin = ssh2_transport_pop(s)) != NULL); - switch (pktin->type) { - case SSH2_MSG_KEXGSS_CONTINUE: - data = get_string(pktin); - s->gss_rcvtok.value = (char *)data.ptr; - s->gss_rcvtok.length = data.len; - continue; - case SSH2_MSG_KEXGSS_COMPLETE: - s->complete_rcvd = 1; - s->f = get_mp_ssh2(pktin); - data = get_string(pktin); - s->mic.value = (char *)data.ptr; - s->mic.length = data.len; - /* Save expiration time of cred when delegating */ - if (s->gss_delegate && s->gss_cred_expiry != GSS_NO_EXPIRATION) - s->gss_cred_expiry = s->gss_cred_expiry; - /* If there's a final token we loop to consume it */ - if (get_bool(pktin)) { - data = get_string(pktin); - s->gss_rcvtok.value = (char *)data.ptr; - s->gss_rcvtok.length = data.len; - continue; - } - break; - case SSH2_MSG_KEXGSS_HOSTKEY: - s->hostkeydata = get_string(pktin); - if (s->hostkey_alg) { - s->hkey = ssh_key_new_pub(s->hostkey_alg, - s->hostkeydata); - put_string(s->exhash, - s->hostkeydata.ptr, s->hostkeydata.len); - } - /* - * Can't loop as we have no token to pass to - * init_sec_context. - */ - goto wait_for_gss_token; - case SSH2_MSG_KEXGSS_ERROR: - /* - * We have no use for the server's major and minor - * status. The minor status is really only - * meaningful to the server, and with luck the major - * status means something to us (but not really all - * that much). The string is more meaningful, and - * hopefully the server sends any error tokens, as - * that will produce the most useful information for - * us. - */ - get_uint32(pktin); /* server's major status */ - get_uint32(pktin); /* server's minor status */ - data = get_string(pktin); - ppl_logevent(("GSSAPI key exchange failed; " - "server's message: %.*s", PTRLEN_PRINTF(data))); - /* Language tag, but we have no use for it */ - get_string(pktin); - /* - * Wait for an error token, if there is one, or the - * server's disconnect. The error token, if there - * is one, must follow the SSH2_MSG_KEXGSS_ERROR - * message, per the RFC. - */ - goto wait_for_gss_token; - default: - ssh_proto_error(s->ppl.ssh, "Received unexpected packet " - "during GSSAPI key exchange, type %d (%s)", - pktin->type, - ssh2_pkt_type(s->ppl.bpp->pls->kctx, - s->ppl.bpp->pls->actx, - pktin->type)); - return; - } - } while (s->gss_rcvtok.length || - s->gss_stat == SSH_GSS_S_CONTINUE_NEEDED || - !s->complete_rcvd); - - s->K = dh_find_K(s->dh_ctx, s->f); - - /* We assume everything from now on will be quick, and it might - * involve user interaction. */ - seat_set_busy_status(s->ppl.seat, BUSY_NOT); - - if (!s->hkey) - put_stringz(s->exhash, ""); - if (dh_is_gex(s->kex_alg)) { - /* min, preferred, max */ - put_uint32(s->exhash, s->pbits); - put_uint32(s->exhash, s->pbits); - put_uint32(s->exhash, s->pbits * 2); - - put_mp_ssh2(s->exhash, s->p); - put_mp_ssh2(s->exhash, s->g); - } - put_mp_ssh2(s->exhash, s->e); - put_mp_ssh2(s->exhash, s->f); - - /* - * MIC verification is done below, after we compute the hash - * used as the MIC input. - */ - - dh_cleanup(s->dh_ctx); - s->dh_ctx = NULL; - freebn(s->f); s->f = NULL; - if (dh_is_gex(s->kex_alg)) { - freebn(s->g); s->g = NULL; - freebn(s->p); s->p = NULL; - } -#endif - } else { - ptrlen rsakeydata; - - assert(s->kex_alg->main_type == KEXTYPE_RSA); - ppl_logevent(("Doing RSA key exchange with hash %s", - s->kex_alg->hash->text_name)); - s->ppl.bpp->pls->kctx = SSH2_PKTCTX_RSAKEX; - /* - * RSA key exchange. First expect a KEXRSA_PUBKEY packet - * from the server. - */ - crMaybeWaitUntilV((pktin = ssh2_transport_pop(s)) != NULL); - if (pktin->type != SSH2_MSG_KEXRSA_PUBKEY) { - ssh_proto_error(s->ppl.ssh, "Received unexpected packet when " - "expecting RSA public key, type %d (%s)", - pktin->type, - ssh2_pkt_type(s->ppl.bpp->pls->kctx, - s->ppl.bpp->pls->actx, - pktin->type)); - return; - } - - s->hostkeydata = get_string(pktin); - put_stringpl(s->exhash, s->hostkeydata); - s->hkey = ssh_key_new_pub(s->hostkey_alg, s->hostkeydata); - - rsakeydata = get_string(pktin); - - s->rsa_kex_key = ssh_rsakex_newkey(rsakeydata.ptr, rsakeydata.len); - if (!s->rsa_kex_key) { - ssh_proto_error(s->ppl.ssh, - "Unable to parse RSA public key packet"); - return; - } - - put_stringpl(s->exhash, rsakeydata); - - /* - * Next, set up a shared secret K, of precisely KLEN - - * 2*HLEN - 49 bits, where KLEN is the bit length of the - * RSA key modulus and HLEN is the bit length of the hash - * we're using. - */ - { - int klen = ssh_rsakex_klen(s->rsa_kex_key); - int nbits = klen - (2*s->kex_alg->hash->hlen*8 + 49); - int i, byte = 0; - strbuf *buf; - unsigned char *outstr; - int outstrlen; - - s->K = bn_power_2(nbits - 1); - - for (i = 0; i < nbits; i++) { - if ((i & 7) == 0) { - byte = random_byte(); - } - bignum_set_bit(s->K, i, (byte >> (i & 7)) & 1); - } - - /* - * Encode this as an mpint. - */ - buf = strbuf_new(); - put_mp_ssh2(buf, s->K); - - /* - * Encrypt it with the given RSA key. - */ - outstrlen = (klen + 7) / 8; - outstr = snewn(outstrlen, unsigned char); - ssh_rsakex_encrypt(s->kex_alg->hash, buf->u, buf->len, - outstr, outstrlen, s->rsa_kex_key); - - /* - * And send it off in a return packet. - */ - pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH2_MSG_KEXRSA_SECRET); - put_string(pktout, outstr, outstrlen); - pq_push(s->ppl.out_pq, pktout); - - put_string(s->exhash, outstr, outstrlen); - - strbuf_free(buf); - sfree(outstr); - } - - ssh_rsakex_freekey(s->rsa_kex_key); - s->rsa_kex_key = NULL; - - crMaybeWaitUntilV((pktin = ssh2_transport_pop(s)) != NULL); - if (pktin->type != SSH2_MSG_KEXRSA_DONE) { - ssh_proto_error(s->ppl.ssh, "Received unexpected packet when " - "expecting RSA kex signature, type %d (%s)", - pktin->type, - ssh2_pkt_type(s->ppl.bpp->pls->kctx, - s->ppl.bpp->pls->actx, - pktin->type)); - return; - } - - s->sigdata = get_string(pktin); - if (get_err(pktin)) { - ssh_proto_error(s->ppl.ssh, "Unable to parse RSA kex signature"); - return; - } - } - - put_mp_ssh2(s->exhash, s->K); - assert(ssh_hash_alg(s->exhash)->hlen <= sizeof(s->exchange_hash)); - ssh_hash_final(s->exhash, s->exchange_hash); - s->exhash = NULL; - -#ifndef NO_GSSAPI - if (s->kex_alg->main_type == KEXTYPE_GSS) { - Ssh_gss_buf gss_buf; - SSH_GSS_CLEAR_BUF(&s->gss_buf); - - gss_buf.value = s->exchange_hash; - gss_buf.length = s->kex_alg->hash->hlen; - s->gss_stat = s->shgss->lib->verify_mic( - s->shgss->lib, s->shgss->ctx, &gss_buf, &s->mic); - if (s->gss_stat != SSH_GSS_OK) { - if (s->shgss->lib->display_status( - s->shgss->lib, s->shgss->ctx, &s->gss_buf) == SSH_GSS_OK) { - char *err = s->gss_buf.value; - ssh_sw_abort(s->ppl.ssh, "GSSAPI key exchange MIC was " - "not valid: %s", err); - sfree(err); - } else { - ssh_sw_abort(s->ppl.ssh, "GSSAPI key exchange MIC was " - "not valid"); - } - return; - } - - s->gss_kex_used = TRUE; - - /*- - * If this the first KEX, save the GSS context for "gssapi-keyex" - * authentication. - * - * http://tools.ietf.org/html/rfc4462#section-4 - * - * This method may be used only if the initial key exchange was - * performed using a GSS-API-based key exchange method defined in - * accordance with Section 2. The GSS-API context used with this - * method is always that established during an initial GSS-API-based - * key exchange. Any context established during key exchange for the - * purpose of rekeying MUST NOT be used with this method. - */ - if (s->got_session_id) { - s->shgss->lib->release_cred(s->shgss->lib, &s->shgss->ctx); - } - ppl_logevent(("GSSAPI Key Exchange complete!")); - } -#endif - - s->dh_ctx = NULL; - -#if 0 - debug(("Exchange hash is:\n")); - dmemdump(s->exchange_hash, s->kex_alg->hash->hlen); -#endif - - /* In GSS keyex there's no hostkey signature to verify */ - if (s->kex_alg->main_type != KEXTYPE_GSS) { - if (!s->hkey) { - ssh_proto_error(s->ppl.ssh, "Server's host key is invalid"); - return; - } - - if (!ssh_key_verify( - s->hkey, s->sigdata, - make_ptrlen(s->exchange_hash, s->kex_alg->hash->hlen))) { -#ifndef FUZZING - ssh_proto_error(s->ppl.ssh, "Signature from server's host key " - "is invalid"); - return; -#endif - } - } - - s->keystr = (s->hkey ? ssh_key_cache_str(s->hkey) : NULL); -#ifndef NO_GSSAPI - if (s->gss_kex_used) { - /* - * In a GSS-based session, check the host key (if any) against - * the transient host key cache. - */ - if (s->kex_alg->main_type == KEXTYPE_GSS) { - - /* - * We've just done a GSS key exchange. If it gave us a - * host key, store it. - */ - if (s->hkey) { - s->fingerprint = ssh2_fingerprint(s->hkey); - ppl_logevent(("GSS kex provided fallback host key:")); - ppl_logevent(("%s", s->fingerprint)); - sfree(s->fingerprint); - s->fingerprint = NULL; - ssh_transient_hostkey_cache_add(s->thc, s->hkey); - } else if (!ssh_transient_hostkey_cache_non_empty(s->thc)) { - /* - * But if it didn't, then we currently have no - * fallback host key to use in subsequent non-GSS - * rekeys. So we should immediately trigger a non-GSS - * rekey of our own, to set one up, before the session - * keys have been used for anything else. - * - * This is similar to the cross-certification done at - * user request in the permanent host key cache, but - * here we do it automatically, once, at session - * startup, and only add the key to the transient - * cache. - */ - if (s->hostkey_alg) { - s->need_gss_transient_hostkey = TRUE; - } else { - /* - * If we negotiated the "null" host key algorithm - * in the key exchange, that's an indication that - * no host key at all is available from the server - * (both because we listed "null" last, and - * because RFC 4462 section 5 says that a server - * MUST NOT offer "null" as a host key algorithm - * unless that is the only algorithm it provides - * at all). - * - * In that case we actually _can't_ perform a - * non-GSSAPI key exchange, so it's pointless to - * attempt one proactively. This is also likely to - * cause trouble later if a rekey is required at a - * moment whne GSS credentials are not available, - * but someone setting up a server in this - * configuration presumably accepts that as a - * consequence. - */ - if (!s->warned_about_no_gss_transient_hostkey) { - ppl_logevent(("No fallback host key available")); - s->warned_about_no_gss_transient_hostkey = TRUE; - } - } - } - } else { - /* - * We've just done a fallback key exchange, so make - * sure the host key it used is in the cache of keys - * we previously received in GSS kexes. - * - * An exception is if this was the non-GSS key exchange we - * triggered on purpose to populate the transient cache. - */ - assert(s->hkey); /* only KEXTYPE_GSS lets this be null */ - s->fingerprint = ssh2_fingerprint(s->hkey); - - if (s->need_gss_transient_hostkey) { - ppl_logevent(("Post-GSS rekey provided fallback host key:")); - ppl_logevent(("%s", s->fingerprint)); - ssh_transient_hostkey_cache_add(s->thc, s->hkey); - s->need_gss_transient_hostkey = FALSE; - } else if (!ssh_transient_hostkey_cache_verify(s->thc, s->hkey)) { - ppl_logevent(("Non-GSS rekey after initial GSS kex " - "used host key:")); - ppl_logevent(("%s", s->fingerprint)); - ssh_sw_abort(s->ppl.ssh, "Server's host key did not match any " - "used in previous GSS kex"); - return; - } - - sfree(s->fingerprint); - s->fingerprint = NULL; - } - } else -#endif /* NO_GSSAPI */ - if (!s->got_session_id) { - /* - * Make a note of any other host key formats that are available. - */ - { - int i, j, nkeys = 0; - char *list = NULL; - for (i = 0; i < lenof(hostkey_algs); i++) { - if (hostkey_algs[i].alg == s->hostkey_alg) - continue; - - for (j = 0; j < s->n_uncert_hostkeys; j++) - if (s->uncert_hostkeys[j] == i) - break; - - if (j < s->n_uncert_hostkeys) { - char *newlist; - if (list) - newlist = dupprintf("%s/%s", list, - hostkey_algs[i].alg->ssh_id); - else - newlist = dupprintf("%s", hostkey_algs[i].alg->ssh_id); - sfree(list); - list = newlist; - nkeys++; - } - } - if (list) { - ppl_logevent(("Server also has %s host key%s, but we " - "don't know %s", list, - nkeys > 1 ? "s" : "", - nkeys > 1 ? "any of them" : "it")); - sfree(list); - } - } - - /* - * Authenticate remote host: verify host key. (We've already - * checked the signature of the exchange hash.) - */ - s->fingerprint = ssh2_fingerprint(s->hkey); - ppl_logevent(("Host key fingerprint is:")); - ppl_logevent(("%s", s->fingerprint)); - /* First check against manually configured host keys. */ - s->dlgret = verify_ssh_manual_host_key( - s->conf, s->fingerprint, s->hkey); - if (s->dlgret == 0) { /* did not match */ - ssh_sw_abort(s->ppl.ssh, "Host key did not appear in manually " - "configured list"); - return; - } else if (s->dlgret < 0) { /* none configured; use standard handling */ - s->dlgret = seat_verify_ssh_host_key( - s->ppl.seat, s->savedhost, s->savedport, - ssh_key_cache_id(s->hkey), s->keystr, s->fingerprint, - ssh2_transport_dialog_callback, s); -#ifdef FUZZING - s->dlgret = 1; -#endif - crMaybeWaitUntilV(s->dlgret >= 0); - if (s->dlgret == 0) { - ssh_user_close(s->ppl.ssh, - "User aborted at host key verification"); - return; - } - } - sfree(s->fingerprint); - s->fingerprint = NULL; - /* - * Save this host key, to check against the one presented in - * subsequent rekeys. - */ - s->hostkey_str = s->keystr; - s->keystr = NULL; - } else if (s->cross_certifying) { - s->fingerprint = ssh2_fingerprint(s->hkey); - ppl_logevent(("Storing additional host key for this host:")); - ppl_logevent(("%s", s->fingerprint)); - sfree(s->fingerprint); - s->fingerprint = NULL; - store_host_key(s->savedhost, s->savedport, - ssh_key_cache_id(s->hkey), s->keystr); - s->cross_certifying = FALSE; - /* - * Don't forget to store the new key as the one we'll be - * re-checking in future normal rekeys. - */ - s->hostkey_str = s->keystr; - s->keystr = NULL; - } else { - /* - * In a rekey, we never present an interactive host key - * verification request to the user. Instead, we simply - * enforce that the key we're seeing this time is identical to - * the one we saw before. - */ - if (strcmp(s->hostkey_str, s->keystr)) { -#ifndef FUZZING - ssh_sw_abort(s->ppl.ssh, - "Host key was different in repeat key exchange"); - return; -#endif - } - } - sfree(s->keystr); - s->keystr = NULL; - if (s->hkey) { - ssh_key_free(s->hkey); - s->hkey = NULL; + /* + * Actually perform the key exchange. + */ + s->exhash = ssh_hash_new(s->kex_alg->hash); + put_stringz(s->exhash, s->client_greeting); + put_stringz(s->exhash, s->server_greeting); + put_string(s->exhash, s->client_kexinit->u, s->client_kexinit->len); + put_string(s->exhash, s->server_kexinit->u, s->server_kexinit->len); + s->crStateKex = 0; + while (1) { + ssh2kex_coroutine(s); + if (!s->crStateKex) + break; + crReturnV; } /* @@ -2600,7 +1581,7 @@ static int ssh2_transport_timer_update(struct ssh2_transport_state *s, return 0; } -static void ssh2_transport_dialog_callback(void *loginv, int ret) +void ssh2_transport_dialog_callback(void *loginv, int ret) { struct ssh2_transport_state *s = (struct ssh2_transport_state *)loginv; s->dlgret = ret; @@ -2790,7 +1771,7 @@ static int ssh2_transport_get_specials( add_special(ctx, "Cache new host key type", SS_SUBMENU, 0); for (i = 0; i < s->n_uncert_hostkeys; i++) { const ssh_keyalg *alg = - hostkey_algs[s->uncert_hostkeys[i]].alg; + ssh2_hostkey_algs[s->uncert_hostkeys[i]].alg; add_special(ctx, alg->ssh_id, SS_XCERT, s->uncert_hostkeys[i]); } @@ -2815,7 +1796,7 @@ static void ssh2_transport_special_cmd(PacketProtocolLayer *ppl, } } else if (code == SS_XCERT) { if (!s->kex_in_progress) { - s->hostkey_alg = hostkey_algs[arg].alg; + s->hostkey_alg = ssh2_hostkey_algs[arg].alg; s->cross_certifying = TRUE; s->rekey_reason = "cross-certifying new host key"; s->rekey_class = RK_NORMAL; diff --git a/ssh2transport.h b/ssh2transport.h new file mode 100644 index 00000000..924ef38d --- /dev/null +++ b/ssh2transport.h @@ -0,0 +1,219 @@ +/* + * Header connecting the pieces of the SSH-2 transport layer. + */ + +#ifndef PUTTY_SSH2TRANSPORT_H +#define PUTTY_SSH2TRANSPORT_H + +#ifndef NO_GSSAPI +#include "sshgssc.h" +#include "sshgss.h" +#define MIN_CTXT_LIFETIME 5 /* Avoid rekey with short lifetime (seconds) */ +#define GSS_KEX_CAPABLE (1<<0) /* Can do GSS KEX */ +#define GSS_CRED_UPDATED (1<<1) /* Cred updated since previous delegation */ +#define GSS_CTXT_EXPIRES (1<<2) /* Context expires before next timer */ +#define GSS_CTXT_MAYFAIL (1<<3) /* Context may expire during handshake */ +#endif + +#define DH_MIN_SIZE 1024 +#define DH_MAX_SIZE 8192 + +enum kexlist { + KEXLIST_KEX, KEXLIST_HOSTKEY, KEXLIST_CSCIPHER, KEXLIST_SCCIPHER, + KEXLIST_CSMAC, KEXLIST_SCMAC, KEXLIST_CSCOMP, KEXLIST_SCCOMP, + NKEXLIST +}; +#define MAXKEXLIST 16 +struct kexinit_algorithm { + const char *name; + union { + struct { + const struct ssh_kex *kex; + int warn; + } kex; + struct { + const ssh_keyalg *hostkey; + int warn; + } hk; + struct { + const struct ssh2_cipheralg *cipher; + int warn; + } cipher; + struct { + const struct ssh2_macalg *mac; + int etm; + } mac; + struct { + const struct ssh_compression_alg *comp; + int delayed; + } comp; + } u; +}; + +#define HOSTKEY_ALGORITHMS(X) \ + X(HK_ED25519, ssh_ecdsa_ed25519) \ + X(HK_ECDSA, ssh_ecdsa_nistp256) \ + X(HK_ECDSA, ssh_ecdsa_nistp384) \ + X(HK_ECDSA, ssh_ecdsa_nistp521) \ + X(HK_DSA, ssh_dss) \ + X(HK_RSA, ssh_rsa) \ + /* end of list */ +#define COUNT_HOSTKEY_ALGORITHM(type, alg) +1 +#define N_HOSTKEY_ALGORITHMS (0 HOSTKEY_ALGORITHMS(COUNT_HOSTKEY_ALGORITHM)) + +struct ssh_signkey_with_user_pref_id { + const ssh_keyalg *alg; + int id; +}; +extern const struct ssh_signkey_with_user_pref_id + ssh2_hostkey_algs[N_HOSTKEY_ALGORITHMS]; + +/* + * Enumeration of high-level classes of reason why we might need to do + * a repeat key exchange. A full detailed reason in human-readable + * string form for the Event Log is also provided, but this enum type + * is used to discriminate between classes of reason that the code + * needs to treat differently. + * + * RK_NONE == 0 is the value indicating that no rekey is currently + * needed at all. RK_INITIAL indicates that we haven't even done the + * _first_ key exchange yet. RK_SERVER indicates that we're rekeying + * because the server asked for it, not because we decided it + * ourselves. RK_NORMAL is the usual case. RK_GSS_UPDATE indicates + * that we're rekeying because we've just got new GSSAPI credentials + * (hence there's no point in doing a preliminary check for new GSS + * creds, because we already know the answer); RK_POST_USERAUTH + * indicates that _if_ we're going to need a post-userauth immediate + * rekey for any reason, this is the moment to do it. + * + * So RK_POST_USERAUTH only tells the transport layer to _consider_ + * rekeying, not to definitely do it. Also, that one enum value is + * special in that the user-readable reason text is passed in to the + * transport layer as NULL, whereas fills in the reason text after it + * decides whether it needs a rekey at all. In the other cases, + * rekey_reason is passed in to the at the same time as rekey_class. + */ +typedef enum RekeyClass { + RK_NONE = 0, + RK_INITIAL, + RK_SERVER, + RK_NORMAL, + RK_POST_USERAUTH, + RK_GSS_UPDATE +} RekeyClass; + +typedef struct transport_direction { + const struct ssh2_cipheralg *cipher; + const struct ssh2_macalg *mac; + int etm_mode; + const struct ssh_compression_alg *comp; + int comp_delayed; +} transport_direction; + +struct ssh2_transport_state { + int crState, crStateKex; + + PacketProtocolLayer *higher_layer; + PktInQueue pq_in_higher; + PktOutQueue pq_out_higher; + IdempotentCallback ic_pq_out_higher; + + Conf *conf; + char *savedhost; + int savedport; + const char *rekey_reason; + enum RekeyClass rekey_class; + + unsigned long max_data_size; + + const struct ssh_kex *kex_alg; + const ssh_keyalg *hostkey_alg; + char *hostkey_str; /* string representation, for easy checking in rekeys */ + unsigned char session_id[SSH2_KEX_MAX_HASH_LEN]; + int session_id_len; + struct dh_ctx *dh_ctx; + ssh_hash *exhash; + + struct DataTransferStats *stats; + + char *client_greeting, *server_greeting; + + int kex_in_progress; + unsigned long next_rekey, last_rekey; + const char *deferred_rekey_reason; + int higher_layer_ok; + + /* + * Fully qualified host name, which we need if doing GSSAPI. + */ + char *fullhostname; + + /* shgss is outside the ifdef on purpose to keep APIs simple. If + * NO_GSSAPI is not defined, then it's just an opaque structure + * tag and the pointer will be NULL. */ + struct ssh_connection_shared_gss_state *shgss; +#ifndef NO_GSSAPI + int gss_status; + time_t gss_cred_expiry; /* Re-delegate if newer */ + unsigned long gss_ctxt_lifetime; /* Re-delegate when short */ +#endif + ssh_transient_hostkey_cache *thc; + + int gss_kex_used; + + int nbits, pbits, warn_kex, warn_hk, warn_cscipher, warn_sccipher; + Bignum p, g, e, f, K; + strbuf *client_kexinit, *server_kexinit; + int kex_init_value, kex_reply_value; + transport_direction in, out; + ptrlen hostkeydata, sigdata; + char *keystr, *fingerprint; + ssh_key *hkey; /* actual host key */ + struct RSAKey *rsa_kex_key; /* for RSA kex */ + struct ec_key *ecdh_key; /* for ECDH kex */ + unsigned char exchange_hash[SSH2_KEX_MAX_HASH_LEN]; + int can_gssapi_keyex; + int need_gss_transient_hostkey; + int warned_about_no_gss_transient_hostkey; + int got_session_id; + int dlgret; + int guessok; + int ignorepkt; + struct kexinit_algorithm kexlists[NKEXLIST][MAXKEXLIST]; +#ifndef NO_GSSAPI + Ssh_gss_buf gss_buf; + Ssh_gss_buf gss_rcvtok, gss_sndtok; + Ssh_gss_stat gss_stat; + Ssh_gss_buf mic; + int init_token_sent; + int complete_rcvd; + int gss_delegate; +#endif + + /* + * List of host key algorithms for which we _don't_ have a stored + * host key. These are indices into the main hostkey_algs[] array + */ + int uncert_hostkeys[N_HOSTKEY_ALGORITHMS]; + int n_uncert_hostkeys; + + /* + * Flag indicating that the current rekey is intended to finish + * with a newly cross-certified host key. + */ + int cross_certifying; + + PacketProtocolLayer ppl; +}; + +/* Helpers shared between transport and kex */ +PktIn *ssh2_transport_pop(struct ssh2_transport_state *s); +void ssh2_transport_dialog_callback(void *, int); + +/* Provided by transport for use in kex */ +void ssh2transport_finalise_exhash(struct ssh2_transport_state *s); + +/* Provided by kex for use in transport */ +void ssh2kex_coroutine(struct ssh2_transport_state *s); + +#endif /* PUTTY_SSH2TRANSPORT_H */ diff --git a/sshcommon.c b/sshcommon.c index 48eeff1b..f0ef7009 100644 --- a/sshcommon.c +++ b/sshcommon.c @@ -857,7 +857,7 @@ int verify_ssh_manual_host_key( } /* ---------------------------------------------------------------------- - * Common get_specials function for the two SSH-1 layers. + * Common functions shared between SSH-1 layers. */ int ssh1_common_get_specials( @@ -876,6 +876,56 @@ int ssh1_common_get_specials( return FALSE; } +int ssh1_common_filter_queue(PacketProtocolLayer *ppl) +{ + PktIn *pktin; + ptrlen msg; + + while ((pktin = pq_peek(ppl->in_pq)) != NULL) { + switch (pktin->type) { + case SSH1_MSG_DISCONNECT: + msg = get_string(pktin); + ssh_remote_error(ppl->ssh, + "Remote side sent disconnect message:\n\"%.*s\"", + PTRLEN_PRINTF(msg)); + pq_pop(ppl->in_pq); + return TRUE; /* indicate that we've been freed */ + + case SSH1_MSG_DEBUG: + msg = get_string(pktin); + ppl_logevent(("Remote debug message: %.*s", PTRLEN_PRINTF(msg))); + pq_pop(ppl->in_pq); + break; + + case SSH1_MSG_IGNORE: + /* Do nothing, because we're ignoring it! Duhh. */ + pq_pop(ppl->in_pq); + break; + + default: + return FALSE; + } + } + + return FALSE; +} + +void ssh1_compute_session_id( + unsigned char *session_id, const unsigned char *cookie, + struct RSAKey *hostkey, struct RSAKey *servkey) +{ + struct MD5Context md5c; + int i; + + MD5Init(&md5c); + for (i = (bignum_bitcount(hostkey->modulus) + 7) / 8; i-- ;) + put_byte(&md5c, bignum_byte(hostkey->modulus, i)); + for (i = (bignum_bitcount(servkey->modulus) + 7) / 8; i-- ;) + put_byte(&md5c, bignum_byte(servkey->modulus, i)); + put_data(&md5c, cookie, 8); + MD5Final(session_id, &md5c); +} + /* ---------------------------------------------------------------------- * Other miscellaneous utility functions. */ diff --git a/sshppl.h b/sshppl.h index e1d4c7c3..fa50d639 100644 --- a/sshppl.h +++ b/sshppl.h @@ -140,4 +140,10 @@ void ssh1_connection_set_local_protoflags(PacketProtocolLayer *ppl, int flags); /* Shared get_specials method between the two ssh1 layers */ int ssh1_common_get_specials(PacketProtocolLayer *, add_special_fn_t, void *); +/* Other shared functions between ssh1 layers */ +int ssh1_common_filter_queue(PacketProtocolLayer *ppl); +void ssh1_compute_session_id( + unsigned char *session_id, const unsigned char *cookie, + struct RSAKey *hostkey, struct RSAKey *servkey); + #endif /* PUTTY_SSHPPL_H */ From f4db9196da28d7d85772690d33faf02ab516d60a Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 14 Oct 2018 18:48:02 +0100 Subject: [PATCH 544/607] Factor out Unix Pageant's socket creation. The code in Pageant that sets up the Unix socket and its containing directory now lives in a separate file, uxagentsock.c, where it will also be callable from the upcoming new SSH server when it wants to create a similar socket for agent forwarding. While I'm at it, I've also added a feature to create a watchdog subprocess that will try to clean up the socket and directory once Pageant itself terminates, in the hope of leaving less cruft lying around /tmp. --- Recipe | 2 +- ssh.h | 3 ++ unix/unix.h | 4 ++- unix/uxagentsock.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++ unix/uxpgnt.c | 22 ++++-------- 5 files changed, 98 insertions(+), 18 deletions(-) create mode 100644 unix/uxagentsock.c diff --git a/Recipe b/Recipe index f276b86f..b819c546 100644 --- a/Recipe +++ b/Recipe @@ -349,7 +349,7 @@ psftp : [U] psftp uxsftp uxcons UXSSH BE_SSH SFTP wildcard UXMISC uxnogtk pageant : [X] uxpgnt uxagentc aqsync pageant sshrsa sshpubk sshdes sshbn + sshmd5 version tree234 misc sshaes sshsha sshdss sshsh256 sshsh512 + sshecc CONF uxsignal nocproxy nogss be_none x11fwd ux_x11 uxcons - + gtkask gtkmisc nullplug logging UXMISC + + gtkask gtkmisc nullplug logging UXMISC uxagentsock ptermapp : [XT] GTKTERM uxmisc misc ldisc settings uxpty uxsel BE_NONE uxstore + uxsignal CHARSET uxpterm version time xpmpterm xpmptcfg diff --git a/ssh.h b/ssh.h index bf7eda97..3e61de15 100644 --- a/ssh.h +++ b/ssh.h @@ -344,6 +344,9 @@ char *portfwdmgr_connect(PortFwdManager *mgr, Channel **chan_ret, char *hostname, int port, SshChannel *c, int addressfamily); +Socket *platform_make_agent_socket(Plug *plug, const char *dirprefix, + char **error, char **name); + LogContext *ssh_get_logctx(Ssh *ssh); /* Communications back to ssh.c from connection layers */ diff --git a/unix/unix.h b/unix/unix.h index 71dfc953..521c5a87 100644 --- a/unix/unix.h +++ b/unix/unix.h @@ -321,9 +321,11 @@ int init_ucs(struct unicode_data *ucsdata, char *line_codepage, int utf8_override, int font_charset, int vtmode); /* - * Spare function exported directly from uxnet.c. + * Spare functions exported directly from uxnet.c. */ void *sk_getxdmdata(Socket *sock, int *lenp); +SockAddr *unix_sock_addr(const char *path); +Socket *new_unix_listener(SockAddr *listenaddr, Plug *plug); /* * General helpful Unix stuff: more helpful version of the FD_SET diff --git a/unix/uxagentsock.c b/unix/uxagentsock.c new file mode 100644 index 00000000..90e701ff --- /dev/null +++ b/unix/uxagentsock.c @@ -0,0 +1,85 @@ +#include +#include +#include +#include +#include +#include + +#include + +#include "putty.h" +#include "ssh.h" +#include "misc.h" +#include "pageant.h" + +Socket *platform_make_agent_socket( + Plug *plug, const char *dirprefix, char **error, char **name) +{ + char *username, *socketdir, *socketname, *errw; + const char *errr; + Socket *sock; + + *name = NULL; + + username = get_username(); + socketdir = dupprintf("%s.%s", dirprefix, username); + sfree(username); + + assert(*socketdir == '/'); + if ((errw = make_dir_and_check_ours(socketdir)) != NULL) { + *error = dupprintf("%s: %s\n", socketdir, errw); + sfree(errw); + return NULL; + } + + socketname = dupprintf("%s/pageant.%d", socketdir, (int)getpid()); + sock = new_unix_listener(unix_sock_addr(socketname), plug); + if ((errr = sk_socket_error(sock)) != NULL) { + *error = dupprintf("%s: %s\n", socketname, errr); + sk_close(sock); + sfree(socketname); + rmdir(socketdir); + sfree(socketdir); + return NULL; + } + + /* + * Spawn a subprocess which will try to reliably delete our socket + * and its containing directory when we terminate, in case we die + * unexpectedly. + */ + { + int cleanup_pipe[2]; + pid_t pid; + + /* Don't worry if pipe or fork fails; it's not _that_ critical. */ + if (!pipe(cleanup_pipe)) { + if ((pid = fork()) == 0) { + int buf[1024]; + /* + * Our parent process holds the writing end of + * this pipe, and writes nothing to it. Hence, + * we expect read() to return EOF as soon as + * that process terminates. + */ + setpgid(0, 0); + close(cleanup_pipe[1]); + while (read(cleanup_pipe[0], buf, sizeof(buf)) > 0); + unlink(socketname); + rmdir(socketdir); + _exit(0); + } else if (pid < 0) { + close(cleanup_pipe[0]); + close(cleanup_pipe[1]); + } else { + close(cleanup_pipe[0]); + cloexec(cleanup_pipe[1]); + } + } + } + + *name = socketname; + *error = NULL; + sfree(socketdir); + return sock; +} diff --git a/unix/uxpgnt.c b/unix/uxpgnt.c index a0c48ca3..86d4e2c1 100644 --- a/unix/uxpgnt.c +++ b/unix/uxpgnt.c @@ -20,9 +20,6 @@ #include "misc.h" #include "pageant.h" -SockAddr *unix_sock_addr(const char *path); -Socket *new_unix_listener(SockAddr *listenaddr, Plug *plug); - void cmdline_error(const char *fmt, ...) { va_list ap; @@ -711,7 +708,7 @@ static const PlugVtable X11Connection_plugvt = { void run_agent(void) { const char *err; - char *username, *socketdir; + char *errw; struct pageant_listen_state *pl; Plug *pl_plug; Socket *sock; @@ -743,19 +740,12 @@ void run_agent(void) /* * Set up a listening socket and run Pageant on it. */ - username = get_username(); - socketdir = dupprintf("%s.%s", PAGEANT_DIR_PREFIX, username); - sfree(username); - assert(*socketdir == '/'); - if ((err = make_dir_and_check_ours(socketdir)) != NULL) { - fprintf(stderr, "pageant: %s: %s\n", socketdir, err); - exit(1); - } - socketname = dupprintf("%s/pageant.%d", socketdir, (int)getpid()); pl = pageant_listener_new(&pl_plug); - sock = new_unix_listener(unix_sock_addr(socketname), pl_plug); - if ((err = sk_socket_error(sock)) != NULL) { - fprintf(stderr, "pageant: %s: %s\n", socketname, err); + sock = platform_make_agent_socket(pl_plug, PAGEANT_DIR_PREFIX, + &errw, &socketname); + if (!sock) { + fprintf(stderr, "pageant: %s\n", errw); + sfree(errw); exit(1); } pageant_listener_got_socket(pl, sock); From 61976b417e8ba44e6340c8bc23c8a5bd4563f80b Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 20 Oct 2018 22:42:17 +0100 Subject: [PATCH 545/607] Server prep: routine to create a local X display. This will be used for the server side of X forwarding. It wraps up the mechanics of listening on the right TCP port and (if possible) the associated AF_UNIX socket, and also creates an appropriate X authority file containing authorisation data provided by its caller. Like the new platform_create_agent_socket, this function spawns a watchdog subprocess to clean up the mess afterwards, in the hope of at least _most_ of the time not leaving old sockets and authority files lying around /tmp, --- ssh.h | 3 + unix/ux_x11.c | 165 ++++++++++++++++++++++++++++++++++++++++++++++++++ x11fwd.c | 42 +++++++++++++ 3 files changed, 210 insertions(+) diff --git a/ssh.h b/ssh.h index 3e61de15..bb99997e 100644 --- a/ssh.h +++ b/ssh.h @@ -1002,6 +1002,9 @@ char *platform_get_x_display(void); */ void x11_get_auth_from_authfile(struct X11Display *display, const char *authfilename); +void x11_format_auth_for_authfile( + BinarySink *bs, SockAddr *addr, int display_no, + ptrlen authproto, ptrlen authdata); int x11_identify_auth_proto(ptrlen protoname); void *x11_dehexify(ptrlen hex, int *outlen); diff --git a/unix/ux_x11.c b/unix/ux_x11.c index 63a92b58..91c95bbc 100644 --- a/unix/ux_x11.c +++ b/unix/ux_x11.c @@ -7,6 +7,8 @@ #include #include #include +#include +#include #include "putty.h" #include "ssh.h" @@ -38,3 +40,166 @@ void platform_get_x11_auth(struct X11Display *disp, Conf *conf) } const int platform_uses_x11_unix_by_default = TRUE; + +int platform_make_x11_server(Plug *plug, const char *progname, int mindisp, + const char *screen_number_suffix, + ptrlen authproto, ptrlen authdata, + Socket **sockets, Conf *conf) +{ + char *tmpdir; + char *authfilename = NULL; + strbuf *authfiledata = NULL; + char *unix_path = NULL; + + SockAddr *a_tcp = NULL, *a_unix = NULL; + + int authfd; + FILE *authfp; + + int displayno; + + authfiledata = strbuf_new(); + + int nsockets = 0; + + /* + * Look for a free TCP port to run our server on. + */ + for (displayno = mindisp;; displayno++) { + const char *err; + int tcp_port = displayno + 6000; + int addrtype = ADDRTYPE_IPV4; + + sockets[nsockets] = new_listener( + NULL, tcp_port, plug, FALSE, conf, addrtype); + + err = sk_socket_error(sockets[nsockets]); + if (!err) { + char *hostname = get_hostname(); + if (hostname) { + char *canonicalname = NULL; + a_tcp = name_lookup(hostname, tcp_port, &canonicalname, + conf, addrtype, NULL, ""); + sfree(canonicalname); + } + sfree(hostname); + nsockets++; + break; /* success! */ + } else { + sk_close(sockets[nsockets]); + } + + if (!strcmp(err, strerror(EADDRINUSE))) /* yuck! */ + goto out; + } + + if (a_tcp) { + x11_format_auth_for_authfile( + BinarySink_UPCAST(authfiledata), + a_tcp, displayno, authproto, authdata); + } + + /* + * Try to establish the Unix-domain analogue. That may or may not + * work - file permissions in /tmp may prevent it, for example - + * but it's worth a try, and we don't consider it a fatal error if + * it doesn't work. + */ + unix_path = dupprintf("/tmp/.X11-unix/X%d", displayno); + a_unix = unix_sock_addr(unix_path); + + sockets[nsockets] = new_unix_listener(a_unix, plug); + if (!sk_socket_error(sockets[nsockets])) { + x11_format_auth_for_authfile( + BinarySink_UPCAST(authfiledata), + a_unix, displayno, authproto, authdata); + nsockets++; + } else { + sk_close(sockets[nsockets]); + sfree(unix_path); + unix_path = NULL; + } + + /* + * Decide where the authority data will be written. + */ + + tmpdir = getenv("TMPDIR"); + if (!tmpdir || !*tmpdir) + tmpdir = "/tmp"; + + authfilename = dupcat(tmpdir, "/", progname, "-Xauthority-XXXXXX"); + + { + int oldumask = umask(077); + authfd = mkstemp(authfilename); + umask(oldumask); + } + if (authfd < 0) { + while (nsockets-- > 0) + sk_close(sockets[nsockets]); + goto out; + } + + /* + * Spawn a subprocess which will try to reliably delete our + * auth file when we terminate, in case we die unexpectedly. + */ + { + int cleanup_pipe[2]; + pid_t pid; + + /* Don't worry if pipe or fork fails; it's not _that_ critical. */ + if (!pipe(cleanup_pipe)) { + if ((pid = fork()) == 0) { + int buf[1024]; + /* + * Our parent process holds the writing end of + * this pipe, and writes nothing to it. Hence, + * we expect read() to return EOF as soon as + * that process terminates. + */ + setpgid(0, 0); + close(cleanup_pipe[1]); + close(authfd); + while (read(cleanup_pipe[0], buf, sizeof(buf)) > 0); + unlink(authfilename); + if (unix_path) + unlink(unix_path); + _exit(0); + } else if (pid < 0) { + close(cleanup_pipe[0]); + close(cleanup_pipe[1]); + } else { + close(cleanup_pipe[0]); + cloexec(cleanup_pipe[1]); + } + } + } + + authfp = fdopen(authfd, "wb"); + fwrite(authfiledata->u, 1, authfiledata->len, authfp); + fclose(authfp); + + { + char *display = dupprintf(":%d%s", displayno, screen_number_suffix); + conf_set_str_str(conf, CONF_environmt, "DISPLAY", display); + sfree(display); + } + conf_set_str_str(conf, CONF_environmt, "XAUTHORITY", authfilename); + + /* + * FIXME: return at least the DISPLAY and XAUTHORITY env settings, + * and perhaps also the display number + */ + + out: + if (a_tcp) + sk_addr_free(a_tcp); + if (a_unix) + sk_addr_free(a_unix); + sfree(authfilename); + strbuf_free(authfiledata); + sfree(unix_path); + return nsockets; +} diff --git a/x11fwd.c b/x11fwd.c index 8e306f42..7feb2a63 100644 --- a/x11fwd.c +++ b/x11fwd.c @@ -449,6 +449,15 @@ ptrlen BinarySource_get_string_xauth(BinarySource *src) #define get_string_xauth(src) \ BinarySource_get_string_xauth(BinarySource_UPCAST(src)) +void BinarySink_put_stringpl_xauth(BinarySink *bs, ptrlen pl) +{ + assert((pl.len >> 16) == 0); + put_uint16(bs, pl.len); + put_data(bs, pl.ptr, pl.len); +} +#define put_stringpl_xauth(bs, ptrlen) \ + BinarySink_put_stringpl_xauth(BinarySink_UPCAST(bs),ptrlen) + void x11_get_auth_from_authfile(struct X11Display *disp, const char *authfilename) { @@ -631,6 +640,39 @@ void x11_get_auth_from_authfile(struct X11Display *disp, sfree(ourhostname); } +void x11_format_auth_for_authfile( + BinarySink *bs, SockAddr *addr, int display_no, + ptrlen authproto, ptrlen authdata) +{ + if (sk_address_is_special_local(addr)) { + char *ourhostname = get_hostname(); + put_uint16(bs, 256); /* indicates Unix-domain socket */ + put_stringpl_xauth(bs, ptrlen_from_asciz(ourhostname)); + sfree(ourhostname); + } else if (sk_addrtype(addr) == ADDRTYPE_IPV4) { + char ipv4buf[4]; + sk_addrcopy(addr, ipv4buf); + put_uint16(bs, 0); /* indicates IPv4 */ + put_stringpl_xauth(bs, make_ptrlen(ipv4buf, 4)); + } else if (sk_addrtype(addr) == ADDRTYPE_IPV6) { + char ipv6buf[16]; + sk_addrcopy(addr, ipv6buf); + put_uint16(bs, 6); /* indicates IPv6 */ + put_stringpl_xauth(bs, make_ptrlen(ipv6buf, 16)); + } else { + assert(FALSE && "Bad address type in x11_format_auth_for_authfile"); + } + + { + char *numberbuf = dupprintf("%d", display_no); + put_stringpl_xauth(bs, ptrlen_from_asciz(numberbuf)); + sfree(numberbuf); + } + + put_stringpl_xauth(bs, authproto); + put_stringpl_xauth(bs, authdata); +} + static void x11_log(Plug *p, int type, SockAddr *addr, int port, const char *error_msg, int error_code) { From 445030b3ea3c658187fd0012516e888ea739248f Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 20 Oct 2018 21:41:28 +0100 Subject: [PATCH 546/607] Server prep: support stderr output on channels. The vtable method underneath sshfwd_write now takes an is_stderr parameter, and in SSH-2, this is implemented by having separate stdout and stderr bufchains in each outgoing channel, and counting the size of both for the purposes of measuring backlog and so forth. To avoid making _most_ call sites more verbose, the usual macro wrapper hasn't changed its API; it just sets is_stderr=FALSE. To use the new feature, there's an sshfwd_write_ext macro that exposes the extra parameter. --- ssh1connection-client.c | 3 ++- ssh1connection.c | 6 ++++-- ssh2connection.c | 40 +++++++++++++++++++++++++++++----------- ssh2connection.h | 2 +- sshchan.h | 6 ++++-- 5 files changed, 40 insertions(+), 17 deletions(-) diff --git a/ssh1connection-client.c b/ssh1connection-client.c index 4098bb22..24a6df7d 100644 --- a/ssh1connection-client.c +++ b/ssh1connection-client.c @@ -397,7 +397,8 @@ static void ssh1mainchan_hint_channel_is_simple(SshChannel *sc) { } -static int ssh1mainchan_write(SshChannel *sc, const void *data, int len) +static int ssh1mainchan_write( + SshChannel *sc, int is_stderr, const void *data, int len) { struct ssh1_connection_state *s = container_of(sc, struct ssh1_connection_state, mainchan_sc); diff --git a/ssh1connection.c b/ssh1connection.c index d44a21f0..5461eec4 100644 --- a/ssh1connection.c +++ b/ssh1connection.c @@ -89,7 +89,8 @@ static const struct ConnectionLayerVtable ssh1_connlayer_vtable = { ssh1_set_wants_user_input, }; -static int ssh1channel_write(SshChannel *c, const void *buf, int len); +static int ssh1channel_write( + SshChannel *c, int is_stderr, const void *buf, int len); static void ssh1channel_write_eof(SshChannel *c); static void ssh1channel_initiate_close(SshChannel *c, const char *err); static void ssh1channel_unthrottle(SshChannel *c, int bufsize); @@ -581,7 +582,8 @@ static void ssh1channel_unthrottle(SshChannel *sc, int bufsize) } } -static int ssh1channel_write(SshChannel *sc, const void *buf, int len) +static int ssh1channel_write( + SshChannel *sc, int is_stderr, const void *buf, int len) { struct ssh1_channel *c = container_of(sc, struct ssh1_channel, sc); struct ssh1_connection_state *s = c->connlayer; diff --git a/ssh2connection.c b/ssh2connection.c index 543e8496..fbda961f 100644 --- a/ssh2connection.c +++ b/ssh2connection.c @@ -116,7 +116,8 @@ static char *ssh2_channel_open_failure_error_text(PktIn *pktin) return dupprintf("%s [%.*s]", reason_code_string, PTRLEN_PRINTF(reason)); } -static int ssh2channel_write(SshChannel *c, const void *buf, int len); +static int ssh2channel_write( + SshChannel *c, int is_stderr, const void *buf, int len); static void ssh2channel_write_eof(SshChannel *c); static void ssh2channel_initiate_close(SshChannel *c, const char *err); static void ssh2channel_unthrottle(SshChannel *c, int bufsize); @@ -215,6 +216,7 @@ struct outstanding_channel_request { static void ssh2_channel_free(struct ssh2_channel *c) { bufchain_clear(&c->outbuffer); + bufchain_clear(&c->errbuffer); while (c->chanreq_head) { struct outstanding_channel_request *chanreq = c->chanreq_head; c->chanreq_head = c->chanreq_head->next; @@ -741,6 +743,7 @@ static int ssh2_connection_filter_queue(struct ssh2_connection_state *s) * stuff. */ bufchain_clear(&c->outbuffer); + bufchain_clear(&c->errbuffer); /* * Send outgoing EOF. @@ -980,7 +983,7 @@ static void ssh2_channel_try_eof(struct ssh2_channel *c) assert(c->pending_eof); /* precondition for calling us */ if (c->halfopen) return; /* can't close: not even opened yet */ - if (bufchain_size(&c->outbuffer) > 0) + if (bufchain_size(&c->outbuffer) > 0 || bufchain_size(&c->errbuffer) > 0) return; /* can't send EOF: pending outgoing data */ c->pending_eof = FALSE; /* we're about to send it */ @@ -1001,19 +1004,31 @@ static int ssh2_try_send(struct ssh2_channel *c) PktOut *pktout; int bufsize; - while (c->remwindow > 0 && bufchain_size(&c->outbuffer) > 0) { + while (c->remwindow > 0 && + (bufchain_size(&c->outbuffer) > 0 || + bufchain_size(&c->errbuffer) > 0)) { int len; void *data; - bufchain_prefix(&c->outbuffer, &data, &len); + bufchain *buf = (bufchain_size(&c->errbuffer) > 0 ? + &c->errbuffer : &c->outbuffer); + + bufchain_prefix(buf, &data, &len); if ((unsigned)len > c->remwindow) len = c->remwindow; if ((unsigned)len > c->remmaxpkt) len = c->remmaxpkt; - pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH2_MSG_CHANNEL_DATA); - put_uint32(pktout, c->remoteid); + if (buf == &c->errbuffer) { + pktout = ssh_bpp_new_pktout( + s->ppl.bpp, SSH2_MSG_CHANNEL_EXTENDED_DATA); + put_uint32(pktout, c->remoteid); + put_uint32(pktout, SSH2_EXTENDED_DATA_STDERR); + } else { + pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH2_MSG_CHANNEL_DATA); + put_uint32(pktout, c->remoteid); + } put_string(pktout, data, len); pq_push(s->ppl.out_pq, pktout); - bufchain_consume(&c->outbuffer, len); + bufchain_consume(buf, len); c->remwindow -= len; } @@ -1021,7 +1036,7 @@ static int ssh2_try_send(struct ssh2_channel *c) * After having sent as much data as we can, return the amount * still buffered. */ - bufsize = bufchain_size(&c->outbuffer); + bufsize = bufchain_size(&c->outbuffer) + bufchain_size(&c->errbuffer); /* * And if there's no data pending but we need to send an EOF, send @@ -1155,6 +1170,7 @@ void ssh2_channel_init(struct ssh2_channel *c) c->chanreq_head = NULL; c->throttle_state = UNTHROTTLED; bufchain_init(&c->outbuffer); + bufchain_init(&c->errbuffer); c->sc.vt = &ssh2channel_vtable; c->sc.cl = &s->cl; c->localid = alloc_channel_id(s->channels, struct ssh2_channel); @@ -1264,11 +1280,12 @@ static void ssh2channel_unthrottle(SshChannel *sc, int bufsize) } } -static int ssh2channel_write(SshChannel *sc, const void *buf, int len) +static int ssh2channel_write( + SshChannel *sc, int is_stderr, const void *buf, int len) { struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc); assert(!(c->closes & CLOSES_SENT_EOF)); - bufchain_add(&c->outbuffer, buf, len); + bufchain_add(is_stderr ? &c->errbuffer : &c->outbuffer, buf, len); return ssh2_try_send(c); } @@ -1521,7 +1538,8 @@ static int ssh2_stdin_backlog(ConnectionLayer *cl) if (!s->mainchan) return 0; c = container_of(s->mainchan_sc, struct ssh2_channel, sc); - return s->mainchan ? bufchain_size(&c->outbuffer) : 0; + return s->mainchan ? + bufchain_size(&c->outbuffer) + bufchain_size(&c->errbuffer) : 0; } static void ssh2_throttle_all_channels(ConnectionLayer *cl, int throttled) diff --git a/ssh2connection.h b/ssh2connection.h index eb958bf1..c898d6bd 100644 --- a/ssh2connection.h +++ b/ssh2connection.h @@ -94,7 +94,7 @@ struct ssh2_channel { */ int throttled_by_backlog; - bufchain outbuffer; + bufchain outbuffer, errbuffer; unsigned remwindow, remmaxpkt; /* locwindow is signed so we can cope with excess data. */ int locwindow, locmaxwin; diff --git a/sshchan.h b/sshchan.h index 63f13136..382023ab 100644 --- a/sshchan.h +++ b/sshchan.h @@ -104,7 +104,7 @@ Channel *zombiechan_new(void); */ struct SshChannelVtable { - int (*write)(SshChannel *c, const void *, int); + int (*write)(SshChannel *c, int is_stderr, const void *, int); void (*write_eof)(SshChannel *c); void (*initiate_close)(SshChannel *c, const char *err); void (*unthrottle)(SshChannel *c, int bufsize); @@ -160,7 +160,9 @@ struct SshChannel { ConnectionLayer *cl; }; -#define sshfwd_write(c, buf, len) ((c)->vt->write(c, buf, len)) +#define sshfwd_write(c, buf, len) ((c)->vt->write(c, FALSE, buf, len)) +#define sshfwd_write_ext(c, stderr, buf, len) \ + ((c)->vt->write(c, stderr, buf, len)) #define sshfwd_write_eof(c) ((c)->vt->write_eof(c)) #define sshfwd_initiate_close(c, err) ((c)->vt->initiate_close(c, err)) #define sshfwd_unthrottle(c, bufsize) ((c)->vt->unthrottle(c, bufsize)) From 9fe719f47dc5e8aee98af4b6a302e67c4f577dbc Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 20 Oct 2018 21:48:49 +0100 Subject: [PATCH 547/607] Server prep: parse a lot of new channel requests. ssh2connection.c now knows how to unmarshal the message formats for all the channel requests we'll need to handle when we're the server and a client sends them. Each one is translated into a call to a new method in the Channel vtable, which is implemented by a trivial 'always fail' routine in every channel type we know about so far. --- agentf.c | 10 +++ mainchan.c | 10 +++ portfwd.c | 10 +++ ssh.h | 2 + ssh1connection-client.c | 3 + ssh1connection.c | 3 + ssh2connection-client.c | 17 ++++++ ssh2connection.c | 63 +++++++++++++++++++ ssh2connection.h | 5 ++ sshchan.h | 63 +++++++++++++++++++ sshcommon.c | 132 ++++++++++++++++++++++++++++++++++++++++ unix/uxpgnt.c | 17 ++++++ x11fwd.c | 10 +++ 13 files changed, 345 insertions(+) diff --git a/agentf.c b/agentf.c index 3fab01a9..e2a26065 100644 --- a/agentf.c +++ b/agentf.c @@ -159,6 +159,16 @@ static const struct ChannelVtable agentf_channelvt = { chan_no_exit_status, chan_no_exit_signal, chan_no_exit_signal_numeric, + chan_no_run_shell, + chan_no_run_command, + chan_no_run_subsystem, + chan_no_enable_x11_forwarding, + chan_no_enable_agent_forwarding, + chan_no_allocate_pty, + chan_no_set_env, + chan_no_send_break, + chan_no_send_signal, + chan_no_change_window_size, chan_no_request_response, }; diff --git a/mainchan.c b/mainchan.c index 1ee731a6..c196da52 100644 --- a/mainchan.c +++ b/mainchan.c @@ -37,6 +37,16 @@ static const struct ChannelVtable mainchan_channelvt = { mainchan_rcvd_exit_status, mainchan_rcvd_exit_signal, mainchan_rcvd_exit_signal_numeric, + chan_no_run_shell, + chan_no_run_command, + chan_no_run_subsystem, + chan_no_enable_x11_forwarding, + chan_no_enable_agent_forwarding, + chan_no_allocate_pty, + chan_no_set_env, + chan_no_send_break, + chan_no_send_signal, + chan_no_change_window_size, mainchan_request_response, }; diff --git a/portfwd.c b/portfwd.c index 6d8d1153..b7acc98b 100644 --- a/portfwd.c +++ b/portfwd.c @@ -454,6 +454,16 @@ static const struct ChannelVtable PortForwarding_channelvt = { chan_no_exit_status, chan_no_exit_signal, chan_no_exit_signal_numeric, + chan_no_run_shell, + chan_no_run_command, + chan_no_run_subsystem, + chan_no_enable_x11_forwarding, + chan_no_enable_agent_forwarding, + chan_no_allocate_pty, + chan_no_set_env, + chan_no_send_break, + chan_no_send_signal, + chan_no_change_window_size, chan_no_request_response, }; diff --git a/ssh.h b/ssh.h index bb99997e..c771604b 100644 --- a/ssh.h +++ b/ssh.h @@ -1435,6 +1435,8 @@ struct ssh_ttymodes { }; struct ssh_ttymodes get_ttymodes_from_conf(Seat *seat, Conf *conf); +struct ssh_ttymodes read_ttymodes_from_packet( + BinarySource *bs, int ssh_version); void write_ttymodes_to_packet(BinarySink *bs, int ssh_version, struct ssh_ttymodes modes); diff --git a/ssh1connection-client.c b/ssh1connection-client.c index 24a6df7d..3018b68d 100644 --- a/ssh1connection-client.c +++ b/ssh1connection-client.c @@ -429,6 +429,9 @@ static const struct SshChannelVtable ssh1mainchan_vtable = { NULL /* get_conf */, NULL /* window_override_removed is only used by SSH-2 sharing */, NULL /* x11_sharing_handover, likewise */, + NULL /* send_exit_status */, + NULL /* send_exit_signal */, + NULL /* send_exit_signal_numeric */, ssh1mainchan_request_x11_forwarding, ssh1mainchan_request_agent_forwarding, ssh1mainchan_request_pty, diff --git a/ssh1connection.c b/ssh1connection.c index 5461eec4..d7c9144d 100644 --- a/ssh1connection.c +++ b/ssh1connection.c @@ -105,6 +105,9 @@ static const struct SshChannelVtable ssh1channel_vtable = { ssh1channel_get_conf, ssh1channel_window_override_removed, NULL /* x11_sharing_handover is only used by SSH-2 connection sharing */, + NULL /* send_exit_status */, + NULL /* send_exit_signal */, + NULL /* send_exit_signal_numeric */, NULL /* request_x11_forwarding */, NULL /* request_agent_forwarding */, NULL /* request_pty */, diff --git a/ssh2connection-client.c b/ssh2connection-client.c index 8cef6aca..5df69fd8 100644 --- a/ssh2connection-client.c +++ b/ssh2connection-client.c @@ -343,6 +343,23 @@ int ssh2channel_start_subsystem( return TRUE; } +void ssh2channel_send_exit_status(SshChannel *sc, int status) +{ + assert(FALSE && "Should never be called in the client"); +} + +void ssh2channel_send_exit_signal( + SshChannel *sc, ptrlen signame, int core_dumped, ptrlen msg) +{ + assert(FALSE && "Should never be called in the client"); +} + +void ssh2channel_send_exit_signal_numeric( + SshChannel *sc, int signum, int core_dumped, ptrlen msg) +{ + assert(FALSE && "Should never be called in the client"); +} + void ssh2channel_request_x11_forwarding( SshChannel *sc, int want_reply, const char *authproto, const char *authdata, int screen_number, int oneshot) diff --git a/ssh2connection.c b/ssh2connection.c index fbda961f..9c27a715 100644 --- a/ssh2connection.c +++ b/ssh2connection.c @@ -137,6 +137,9 @@ static const struct SshChannelVtable ssh2channel_vtable = { ssh2channel_get_conf, ssh2channel_window_override_removed, ssh2channel_x11_sharing_handover, + ssh2channel_send_exit_status, + ssh2channel_send_exit_signal, + ssh2channel_send_exit_signal_numeric, ssh2channel_request_x11_forwarding, ssh2channel_request_agent_forwarding, ssh2channel_request_pty, @@ -655,6 +658,66 @@ static int ssh2_connection_filter_queue(struct ssh2_connection_state *s) reply_success = FALSE; break; } + } else if (ptrlen_eq_string(type, "shell")) { + reply_success = chan_run_shell(c->chan); + } else if (ptrlen_eq_string(type, "exec")) { + ptrlen command = get_string(pktin); + reply_success = chan_run_command(c->chan, command); + } else if (ptrlen_eq_string(type, "subsystem")) { + ptrlen subsys = get_string(pktin); + reply_success = chan_run_subsystem(c->chan, subsys); + } else if (ptrlen_eq_string(type, "x11-req")) { + int oneshot = get_bool(pktin); + ptrlen authproto = get_string(pktin); + ptrlen authdata = get_string(pktin); + unsigned screen_number = get_uint32(pktin); + reply_success = chan_enable_x11_forwarding( + c->chan, oneshot, authproto, authdata, screen_number); + } else if (ptrlen_eq_string(type, + "auth-agent-req@openssh.com")) { + reply_success = chan_enable_agent_forwarding(c->chan); + } else if (ptrlen_eq_string(type, "pty-req")) { + ptrlen termtype = get_string(pktin); + unsigned width = get_uint32(pktin); + unsigned height = get_uint32(pktin); + unsigned pixwidth = get_uint32(pktin); + unsigned pixheight = get_uint32(pktin); + ptrlen encoded_modes = get_string(pktin); + BinarySource bs_modes[1]; + struct ssh_ttymodes modes; + + BinarySource_BARE_INIT( + bs_modes, encoded_modes.ptr, encoded_modes.len); + modes = read_ttymodes_from_packet(bs_modes, 2); + if (get_err(bs_modes) || get_avail(bs_modes) > 0) { + ppl_logevent(("Unable to decode terminal mode " + "string")); + reply_success = FALSE; + } else { + reply_success = chan_allocate_pty( + c->chan, termtype, width, height, + pixwidth, pixheight, modes); + } + } else if (ptrlen_eq_string(type, "env")) { + ptrlen var = get_string(pktin); + ptrlen value = get_string(pktin); + + reply_success = chan_set_env(c->chan, var, value); + } else if (ptrlen_eq_string(type, "break")) { + unsigned length = get_uint32(pktin); + + reply_success = chan_send_break(c->chan, length); + } else if (ptrlen_eq_string(type, "signal")) { + ptrlen signame = get_string(pktin); + + reply_success = chan_send_signal(c->chan, signame); + } else if (ptrlen_eq_string(type, "window-change")) { + unsigned width = get_uint32(pktin); + unsigned height = get_uint32(pktin); + unsigned pixwidth = get_uint32(pktin); + unsigned pixheight = get_uint32(pktin); + reply_success = chan_change_window_size( + c->chan, width, height, pixwidth, pixheight); } if (want_reply) { int type = (reply_success ? SSH2_MSG_CHANNEL_SUCCESS : diff --git a/ssh2connection.h b/ssh2connection.h index c898d6bd..11e62419 100644 --- a/ssh2connection.h +++ b/ssh2connection.h @@ -166,6 +166,11 @@ void ssh2_rportfwd_remove( SshChannel *ssh2_session_open(ConnectionLayer *cl, Channel *chan); +void ssh2channel_send_exit_status(SshChannel *c, int status); +void ssh2channel_send_exit_signal( + SshChannel *c, ptrlen signame, int core_dumped, ptrlen msg); +void ssh2channel_send_exit_signal_numeric( + SshChannel *c, int signum, int core_dumped, ptrlen msg); void ssh2channel_request_x11_forwarding( SshChannel *c, int want_reply, const char *authproto, const char *authdata, int screen_number, int oneshot); diff --git a/sshchan.h b/sshchan.h index 382023ab..e01d6bb5 100644 --- a/sshchan.h +++ b/sshchan.h @@ -34,6 +34,22 @@ struct ChannelVtable { Channel *chan, ptrlen signame, int core_dumped, ptrlen msg); int (*rcvd_exit_signal_numeric)( Channel *chan, int signum, int core_dumped, ptrlen msg); + int (*run_shell)(Channel *chan); + int (*run_command)(Channel *chan, ptrlen command); + int (*run_subsystem)(Channel *chan, ptrlen subsys); + int (*enable_x11_forwarding)( + Channel *chan, int oneshot, ptrlen authproto, ptrlen authdata, + unsigned screen_number); + int (*enable_agent_forwarding)(Channel *chan); + int (*allocate_pty)( + Channel *chan, ptrlen termtype, unsigned width, unsigned height, + unsigned pixwidth, unsigned pixheight, struct ssh_ttymodes modes); + int (*set_env)(Channel *chan, ptrlen var, ptrlen value); + int (*send_break)(Channel *chan, unsigned length); + int (*send_signal)(Channel *chan, ptrlen signame); + int (*change_window_size)( + Channel *chan, unsigned width, unsigned height, + unsigned pixwidth, unsigned pixheight); /* A method for signalling success/failure responses to channel * requests initiated from the SshChannel vtable with want_reply @@ -61,6 +77,26 @@ struct Channel { ((ch)->vt->rcvd_exit_signal(ch, sig, core, msg)) #define chan_rcvd_exit_signal_numeric(ch, sig, core, msg) \ ((ch)->vt->rcvd_exit_signal_numeric(ch, sig, core, msg)) +#define chan_run_shell(ch) \ + ((ch)->vt->run_shell(ch)) +#define chan_run_command(ch, cmd) \ + ((ch)->vt->run_command(ch, cmd)) +#define chan_run_subsystem(ch, subsys) \ + ((ch)->vt->run_subsystem(ch, subsys)) +#define chan_enable_x11_forwarding(ch, oneshot, ap, ad, scr) \ + ((ch)->vt->enable_x11_forwarding(ch, oneshot, ap, ad, scr)) +#define chan_enable_agent_forwarding(ch) \ + ((ch)->vt->enable_agent_forwarding(ch)) +#define chan_allocate_pty(ch, termtype, w, h, pw, ph, modes) \ + ((ch)->vt->allocate_pty(ch, termtype, w, h, pw, ph, modes)) +#define chan_set_env(ch, var, value) \ + ((ch)->vt->set_env(ch, var, value)) +#define chan_send_break(ch, length) \ + ((ch)->vt->send_break(ch, length)) +#define chan_send_signal(ch, signame) \ + ((ch)->vt->send_signal(ch, signame)) +#define chan_change_window_size(ch, w, h, pw, ph) \ + ((ch)->vt->change_window_size(ch, w, h, pw, ph)) #define chan_request_response(ch, success) \ ((ch)->vt->request_response(ch, success)) @@ -81,6 +117,22 @@ int chan_default_want_close(Channel *, int, int); int chan_no_exit_status(Channel *, int); int chan_no_exit_signal(Channel *, ptrlen, int, ptrlen); int chan_no_exit_signal_numeric(Channel *, int, int, ptrlen); +int chan_no_run_shell(Channel *chan); +int chan_no_run_command(Channel *chan, ptrlen command); +int chan_no_run_subsystem(Channel *chan, ptrlen subsys); +int chan_no_enable_x11_forwarding( + Channel *chan, int oneshot, ptrlen authproto, ptrlen authdata, + unsigned screen_number); +int chan_no_enable_agent_forwarding(Channel *chan); +int chan_no_allocate_pty( + Channel *chan, ptrlen termtype, unsigned width, unsigned height, + unsigned pixwidth, unsigned pixheight, struct ssh_ttymodes modes); +int chan_no_set_env(Channel *chan, ptrlen var, ptrlen value); +int chan_no_send_break(Channel *chan, unsigned length); +int chan_no_send_signal(Channel *chan, ptrlen signame); +int chan_no_change_window_size( + Channel *chan, unsigned width, unsigned height, + unsigned pixwidth, unsigned pixheight); /* default implementation that never expects to receive a response */ void chan_no_request_response(Channel *, int); @@ -131,6 +183,11 @@ struct SshChannelVtable { * wouldn't do anything usefully different with the reply in any * case.) */ + void (*send_exit_status)(SshChannel *c, int status); + void (*send_exit_signal)( + SshChannel *c, ptrlen signame, int core_dumped, ptrlen msg); + void (*send_exit_signal_numeric)( + SshChannel *c, int signum, int core_dumped, ptrlen msg); void (*request_x11_forwarding)( SshChannel *c, int want_reply, const char *authproto, const char *authdata, int screen_number, int oneshot); @@ -170,6 +227,12 @@ struct SshChannel { #define sshfwd_window_override_removed(c) ((c)->vt->window_override_removed(c)) #define sshfwd_x11_sharing_handover(c, cs, ch, pa, pp, e, pmaj, pmin, d, l) \ ((c)->vt->x11_sharing_handover(c, cs, ch, pa, pp, e, pmaj, pmin, d, l)) +#define sshfwd_send_exit_status(c, status) \ + ((c)->vt->send_exit_status(c, status)) +#define sshfwd_send_exit_signal(c, sig, core, msg) \ + ((c)->vt->send_exit_signal(c, sig, core, msg)) +#define sshfwd_send_exit_signal_numeric(c, sig, core, msg) \ + ((c)->vt->send_exit_signal_numeric(c, sig, core, msg)) #define sshfwd_request_x11_forwarding(c, wr, ap, ad, scr, oneshot) \ ((c)->vt->request_x11_forwarding(c, wr, ap, ad, scr, oneshot)) #define sshfwd_request_agent_forwarding(c, wr) \ diff --git a/sshcommon.c b/sshcommon.c index f0ef7009..56f4b420 100644 --- a/sshcommon.c +++ b/sshcommon.c @@ -280,6 +280,16 @@ static const struct ChannelVtable zombiechan_channelvt = { chan_no_exit_status, chan_no_exit_signal, chan_no_exit_signal_numeric, + chan_no_run_shell, + chan_no_run_command, + chan_no_run_subsystem, + chan_no_enable_x11_forwarding, + chan_no_enable_agent_forwarding, + chan_no_allocate_pty, + chan_no_set_env, + chan_no_send_break, + chan_no_send_signal, + chan_no_change_window_size, chan_no_request_response, }; @@ -366,6 +376,62 @@ int chan_no_exit_signal_numeric( return FALSE; } +int chan_no_run_shell(Channel *chan) +{ + return FALSE; +} + +int chan_no_run_command(Channel *chan, ptrlen command) +{ + return FALSE; +} + +int chan_no_run_subsystem(Channel *chan, ptrlen subsys) +{ + return FALSE; +} + +int chan_no_enable_x11_forwarding( + Channel *chan, int oneshot, ptrlen authproto, ptrlen authdata, + unsigned screen_number) +{ + return FALSE; +} + +int chan_no_enable_agent_forwarding(Channel *chan) +{ + return FALSE; +} + +int chan_no_allocate_pty( + Channel *chan, ptrlen termtype, unsigned width, unsigned height, + unsigned pixwidth, unsigned pixheight, struct ssh_ttymodes modes) +{ + return FALSE; +} + +int chan_no_set_env(Channel *chan, ptrlen var, ptrlen value) +{ + return FALSE; +} + +int chan_no_send_break(Channel *chan, unsigned length) +{ + return FALSE; +} + +int chan_no_send_signal(Channel *chan, ptrlen signame) +{ + return FALSE; +} + +int chan_no_change_window_size( + Channel *chan, unsigned width, unsigned height, + unsigned pixwidth, unsigned pixheight) +{ + return FALSE; +} + void chan_no_request_response(Channel *chan, int success) { assert(0 && "this channel type should never send a want-reply request"); @@ -387,6 +453,29 @@ static unsigned real_ttymode_opcode(unsigned our_opcode, int ssh_version) } } +static unsigned our_ttymode_opcode(unsigned real_opcode, int ssh_version) +{ + if (ssh_version == 1) { + switch (real_opcode) { + case TTYMODE_ISPEED_SSH1: + return TTYMODE_ISPEED; + case TTYMODE_OSPEED_SSH1: + return TTYMODE_OSPEED; + default: + return real_opcode; + } + } else { + switch (real_opcode) { + case TTYMODE_ISPEED_SSH2: + return TTYMODE_ISPEED; + case TTYMODE_OSPEED_SSH2: + return TTYMODE_OSPEED; + default: + return real_opcode; + } + } +} + struct ssh_ttymodes get_ttymodes_from_conf(Seat *seat, Conf *conf) { struct ssh_ttymodes modes; @@ -492,6 +581,49 @@ struct ssh_ttymodes get_ttymodes_from_conf(Seat *seat, Conf *conf) return modes; } +struct ssh_ttymodes read_ttymodes_from_packet( + BinarySource *bs, int ssh_version) +{ + struct ssh_ttymodes modes; + memset(&modes, 0, sizeof(modes)); + + while (1) { + unsigned real_opcode, our_opcode; + + real_opcode = get_byte(bs); + if (real_opcode == TTYMODE_END_OF_LIST) + break; + if (real_opcode >= 160) { + /* + * RFC 4254 (and the SSH 1.5 spec): "Opcodes 160 to 255 + * are not yet defined, and cause parsing to stop (they + * should only be used after any other data)." + * + * My interpretation of this is that if one of these + * opcodes appears, it's not a parse _error_, but it is + * something that we don't know how to parse even well + * enough to step over it to find the next opcode, so we + * stop parsing now and assume that the rest of the string + * is composed entirely of things we don't understand and + * (as usual for unsupported terminal modes) silently + * ignore. + */ + return modes; + } + + our_opcode = our_ttymode_opcode(real_opcode, ssh_version); + assert(our_opcode < TTYMODE_LIMIT); + modes.have_mode[our_opcode] = TRUE; + + if (ssh_version == 1 && real_opcode >= 1 && real_opcode <= 127) + modes.mode_val[our_opcode] = get_byte(bs); + else + modes.mode_val[our_opcode] = get_uint32(bs); + } + + return modes; +} + void write_ttymodes_to_packet(BinarySink *bs, int ssh_version, struct ssh_ttymodes modes) { diff --git a/unix/uxpgnt.c b/unix/uxpgnt.c index 86d4e2c1..ca1be2fe 100644 --- a/unix/uxpgnt.c +++ b/unix/uxpgnt.c @@ -127,6 +127,23 @@ int chan_no_exit_signal(Channel *ch, ptrlen s, int c, ptrlen m) { return FALSE; } int chan_no_exit_signal_numeric(Channel *ch, int s, int c, ptrlen m) { return FALSE; } +int chan_no_run_shell(Channel *chan) { return FALSE; } +int chan_no_run_command(Channel *chan, ptrlen command) { return FALSE; } +int chan_no_run_subsystem(Channel *chan, ptrlen subsys) { return FALSE; } +int chan_no_enable_x11_forwarding( + Channel *chan, int oneshot, ptrlen authproto, ptrlen authdata, + unsigned screen_number) { return FALSE; } +int chan_no_enable_agent_forwarding(Channel *chan) { return FALSE; } +int chan_no_allocate_pty( + Channel *chan, ptrlen termtype, unsigned width, unsigned height, + unsigned pixwidth, unsigned pixheight, struct ssh_ttymodes modes) +{ return FALSE; } +int chan_no_set_env(Channel *chan, ptrlen var, ptrlen value) { return FALSE; } +int chan_no_send_break(Channel *chan, unsigned length) { return FALSE; } +int chan_no_send_signal(Channel *chan, ptrlen signame) { return FALSE; } +int chan_no_change_window_size( + Channel *chan, unsigned width, unsigned height, + unsigned pixwidth, unsigned pixheight) { return FALSE; } void chan_no_request_response(Channel *chan, int success) {} /* diff --git a/x11fwd.c b/x11fwd.c index 7feb2a63..287003fd 100644 --- a/x11fwd.c +++ b/x11fwd.c @@ -776,6 +776,16 @@ static const struct ChannelVtable X11Connection_channelvt = { chan_no_exit_status, chan_no_exit_signal, chan_no_exit_signal_numeric, + chan_no_run_shell, + chan_no_run_command, + chan_no_run_subsystem, + chan_no_enable_x11_forwarding, + chan_no_enable_agent_forwarding, + chan_no_allocate_pty, + chan_no_set_env, + chan_no_send_break, + chan_no_send_signal, + chan_no_change_window_size, chan_no_request_response, }; From 21a7ce7a078dd89a2f9bfff649b58bad40e7ec63 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 20 Oct 2018 21:52:45 +0100 Subject: [PATCH 548/607] Server prep: reword messages to be client/server agnostic. Lots of user-facing messages that claim that the 'server' just did something or other unexpected will now need to be issued _by_ the server, when the client does the same unexpected thing. So I've reworded them all to talk about the 'remote side' instead of the 'server', and the SSH-2 key setup messages talk about initialising inbound and outbound crypto primitives rather than client->server and server->client. --- portfwd.c | 2 +- ssh1bpp.c | 6 +++--- ssh2bpp-bare.c | 4 ++-- ssh2bpp.c | 13 ++++++------- ssh2transport.c | 6 +++--- sshverstring.c | 2 +- 6 files changed, 16 insertions(+), 17 deletions(-) diff --git a/portfwd.c b/portfwd.c index b7acc98b..99076b99 100644 --- a/portfwd.c +++ b/portfwd.c @@ -645,7 +645,7 @@ static void pfd_open_failure(Channel *chan, const char *errtext) PortForwarding *pf = container_of(chan, PortForwarding, chan); logeventf(pf->cl->logctx, - "Forwarded connection refused by server%s%s", + "Forwarded connection refused by remote%s%s", errtext ? ": " : "", errtext ? errtext : ""); } diff --git a/ssh1bpp.c b/ssh1bpp.c index 9ec22ce1..2f306dd0 100644 --- a/ssh1bpp.c +++ b/ssh1bpp.c @@ -116,7 +116,7 @@ static void ssh1_bpp_handle_input(BinaryPacketProtocol *bpp) if (s->len < 0 || s->len > 262144) { /* SSH1.5-mandated max size */ ssh_sw_abort(s->bpp.ssh, - "Extremely large packet length from server suggests" + "Extremely large packet length from remote suggests" " data stream corruption"); crStopV; } @@ -246,9 +246,9 @@ static void ssh1_bpp_handle_input(BinaryPacketProtocol *bpp) eof: if (!s->bpp.expect_close) { ssh_remote_error(s->bpp.ssh, - "Server unexpectedly closed network connection"); + "Remote side unexpectedly closed network connection"); } else { - ssh_remote_eof(s->bpp.ssh, "Server closed network connection"); + ssh_remote_eof(s->bpp.ssh, "Remote side closed network connection"); } return; /* avoid touching s now it's been freed */ diff --git a/ssh2bpp-bare.c b/ssh2bpp-bare.c index 7d3cfed9..e6dfb710 100644 --- a/ssh2bpp-bare.c +++ b/ssh2bpp-bare.c @@ -133,9 +133,9 @@ static void ssh2_bare_bpp_handle_input(BinaryPacketProtocol *bpp) eof: if (!s->bpp.expect_close) { ssh_remote_error(s->bpp.ssh, - "Server unexpectedly closed network connection"); + "Remote side unexpectedly closed network connection"); } else { - ssh_remote_eof(s->bpp.ssh, "Server closed network connection"); + ssh_remote_eof(s->bpp.ssh, "Remote side closed network connection"); } return; /* avoid touching s now it's been freed */ diff --git a/ssh2bpp.c b/ssh2bpp.c index 5b088676..225fed28 100644 --- a/ssh2bpp.c +++ b/ssh2bpp.c @@ -111,7 +111,7 @@ void ssh2_bpp_new_outgoing_crypto( (ssh2_cipher_alg(s->out.cipher)->flags & SSH_CIPHER_IS_CBC) && !(s->bpp.remote_bugs & BUG_CHOKES_ON_SSH2_IGNORE)); - bpp_logevent(("Initialised %.200s client->server encryption", + bpp_logevent(("Initialised %.200s outbound encryption", ssh2_cipher_alg(s->out.cipher)->text_name)); } else { s->out.cipher = NULL; @@ -122,8 +122,7 @@ void ssh2_bpp_new_outgoing_crypto( s->out.mac = ssh2_mac_new(mac, s->out.cipher); mac->setkey(s->out.mac, mac_key); - bpp_logevent(("Initialised %.200s client->server" - " MAC algorithm%s%s", + bpp_logevent(("Initialised %.200s outbound MAC algorithm%s%s", ssh2_mac_alg(s->out.mac)->text_name, etm_mode ? " (in ETM mode)" : "", (s->out.cipher && @@ -175,7 +174,7 @@ void ssh2_bpp_new_incoming_crypto( ssh2_cipher_setkey(s->in.cipher, ckey); ssh2_cipher_setiv(s->in.cipher, iv); - bpp_logevent(("Initialised %.200s server->client encryption", + bpp_logevent(("Initialised %.200s inbound encryption", ssh2_cipher_alg(s->in.cipher)->text_name)); } else { s->in.cipher = NULL; @@ -185,7 +184,7 @@ void ssh2_bpp_new_incoming_crypto( s->in.mac = ssh2_mac_new(mac, s->in.cipher); mac->setkey(s->in.mac, mac_key); - bpp_logevent(("Initialised %.200s server->client MAC algorithm%s%s", + bpp_logevent(("Initialised %.200s inbound MAC algorithm%s%s", ssh2_mac_alg(s->in.mac)->text_name, etm_mode ? " (in ETM mode)" : "", (s->in.cipher && @@ -628,9 +627,9 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp) eof: if (!s->bpp.expect_close) { ssh_remote_error(s->bpp.ssh, - "Server unexpectedly closed network connection"); + "Remote side unexpectedly closed network connection"); } else { - ssh_remote_eof(s->bpp.ssh, "Server closed network connection"); + ssh_remote_eof(s->bpp.ssh, "Remote side closed network connection"); } return; /* avoid touching s now it's been freed */ diff --git a/ssh2transport.c b/ssh2transport.c index 24597ece..22960f01 100644 --- a/ssh2transport.c +++ b/ssh2transport.c @@ -319,7 +319,7 @@ int ssh2_common_filter_queue(PacketProtocolLayer *ppl) msg = get_string(pktin); ssh_remote_error( - ppl->ssh, "Server sent disconnect message\n" + ppl->ssh, "Remote side sent disconnect message\n" "type %d (%s):\n\"%.*s\"", reason, ((reason > 0 && reason < lenof(ssh2_disconnect_reasons)) ? ssh2_disconnect_reasons[reason] : "unknown"), @@ -1400,7 +1400,7 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) return; } pq_push_front(s->ppl.in_pq, pktin); - ppl_logevent(("Server initiated key re-exchange")); + ppl_logevent(("Remote side initiated key re-exchange")); s->rekey_class = RK_SERVER; } @@ -1445,7 +1445,7 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) * rekey, we process it anyway!) */ if ((s->ppl.remote_bugs & BUG_SSH2_REKEY)) { - ppl_logevent(("Server bug prevents key re-exchange (%s)", + ppl_logevent(("Remote bug prevents key re-exchange (%s)", s->rekey_reason)); /* Reset the counters, so that at least this message doesn't * hit the event log _too_ often. */ diff --git a/sshverstring.c b/sshverstring.c index c9412a2f..d68954c7 100644 --- a/sshverstring.c +++ b/sshverstring.c @@ -392,7 +392,7 @@ void ssh_verstring_handle_input(BinaryPacketProtocol *bpp) eof: ssh_remote_error(s->bpp.ssh, - "Server unexpectedly closed network connection"); + "Remote side unexpectedly closed network connection"); return; /* avoid touching s now it's been freed */ crFinishV; From 82661b7bf21b7133c45e8fbf4155560c11c944c4 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 20 Oct 2018 22:37:51 +0100 Subject: [PATCH 549/607] Server prep: extra RSA crypto primitives. I've written the decryption side of the PKCS#1 encryption used in SSH-1, and also the RSAES-OAEP system used by SSH-2 RSA kex. Also, the RSA kex structures now each come with an 'extra' pointer giving the minimum key length. --- ssh.h | 6 +++ sshrsa.c | 116 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 120 insertions(+), 2 deletions(-) diff --git a/ssh.h b/ssh.h index c771604b..0014a502 100644 --- a/ssh.h +++ b/ssh.h @@ -478,6 +478,7 @@ void BinarySource_get_rsa_ssh1_priv( BinarySource *src, struct RSAKey *rsa); int rsa_ssh1_encrypt(unsigned char *data, int length, struct RSAKey *key); Bignum rsa_ssh1_decrypt(Bignum input, struct RSAKey *key); +int rsa_ssh1_decrypt_pkcs1(Bignum input, struct RSAKey *key, strbuf *outbuf); void rsasanitise(struct RSAKey *key); int rsastr_len(struct RSAKey *key); void rsastr_fmt(char *str, struct RSAKey *key); @@ -504,12 +505,17 @@ int detect_attack(struct crcda_ctx *ctx, unsigned char *buf, uint32 len, * SSH2 RSA key exchange functions */ struct ssh_hashalg; +struct ssh_rsa_kex_extra { + int minklen; +}; struct RSAKey *ssh_rsakex_newkey(const void *data, int len); void ssh_rsakex_freekey(struct RSAKey *key); int ssh_rsakex_klen(struct RSAKey *key); void ssh_rsakex_encrypt(const struct ssh_hashalg *h, unsigned char *in, int inlen, unsigned char *out, int outlen, struct RSAKey *key); +Bignum ssh_rsakex_decrypt(const struct ssh_hashalg *h, ptrlen ciphertext, + struct RSAKey *rsa); /* * SSH2 ECDH key exchange functions diff --git a/sshrsa.c b/sshrsa.c index 4d4ea5b1..86a392eb 100644 --- a/sshrsa.c +++ b/sshrsa.c @@ -285,6 +285,42 @@ Bignum rsa_ssh1_decrypt(Bignum input, struct RSAKey *key) return rsa_privkey_op(input, key); } +int rsa_ssh1_decrypt_pkcs1(Bignum input, struct RSAKey *key, strbuf *outbuf) +{ + strbuf *data = strbuf_new(); + int success = FALSE; + BinarySource src[1]; + + { + Bignum *b = rsa_ssh1_decrypt(input, key); + int i; + for (i = (bignum_bitcount(key->modulus) + 7) / 8; i-- > 0 ;) { + put_byte(data, bignum_byte(b, i)); + } + freebn(b); + } + + BinarySource_BARE_INIT(src, data->u, data->len); + + /* Check PKCS#1 formatting prefix */ + if (get_byte(src) != 0) goto out; + if (get_byte(src) != 2) goto out; + while (1) { + unsigned char byte = get_byte(src); + if (get_err(src)) goto out; + if (byte == 0) + break; + } + + /* Everything else is the payload */ + success = TRUE; + put_data(outbuf, get_ptr(src), get_avail(src)); + + out: + strbuf_free(data); + return success; +} + int rsastr_len(struct RSAKey *key) { Bignum md, ex; @@ -903,12 +939,88 @@ void ssh_rsakex_encrypt(const struct ssh_hashalg *h, */ } +Bignum ssh_rsakex_decrypt(const struct ssh_hashalg *h, ptrlen ciphertext, + struct RSAKey *rsa) +{ + Bignum b1, b2; + int outlen, i; + unsigned char *out; + unsigned char labelhash[64]; + ssh_hash *hash; + BinarySource src[1]; + const int HLEN = h->hlen; + + /* + * Decryption side of the RSA key exchange operation. + */ + + /* The length of the encrypted data should be exactly the length + * in octets of the RSA modulus.. */ + outlen = (7 + bignum_bitcount(rsa->modulus)) / 8; + if (ciphertext.len != outlen) + return NULL; + + /* Do the RSA decryption, and extract the result into a byte array. */ + b1 = bignum_from_bytes(ciphertext.ptr, ciphertext.len); + b2 = rsa_privkey_op(b1, rsa); + out = snewn(outlen, unsigned char); + for (i = 0; i < outlen; i++) + out[i] = bignum_byte(b2, outlen-1-i); + freebn(b1); + freebn(b2); + + /* Do the OAEP masking operations, in the reverse order from encryption */ + oaep_mask(h, out+HLEN+1, outlen-HLEN-1, out+1, HLEN); + oaep_mask(h, out+1, HLEN, out+HLEN+1, outlen-HLEN-1); + + /* Check the leading byte is zero. */ + if (out[0] != 0) { + sfree(out); + return NULL; + } + /* Check the label hash at position 1+HLEN */ + assert(HLEN <= lenof(labelhash)); + hash = ssh_hash_new(h); + ssh_hash_final(hash, labelhash); + if (memcmp(out + HLEN + 1, labelhash, HLEN)) { + sfree(out); + return NULL; + } + /* Expect zero bytes followed by a 1 byte */ + for (i = 1 + 2 * HLEN; i < outlen; i++) { + if (out[i] == 1) { + i++; /* skip over the 1 byte */ + break; + } else if (out[i] != 1) { + sfree(out); + return NULL; + } + } + /* And what's left is the input message data, which should be + * encoded as an ordinary SSH-2 mpint. */ + BinarySource_BARE_INIT(src, out + i, outlen - i); + b1 = get_mp_ssh2(src); + sfree(out); + if (get_err(src) || get_avail(src) != 0) { + freebn(b1); + return NULL; + } + + /* Success! */ + return b1; +} + +static const struct ssh_rsa_kex_extra ssh_rsa_kex_extra_sha1 = { 1024 }; +static const struct ssh_rsa_kex_extra ssh_rsa_kex_extra_sha256 = { 2048 }; + static const struct ssh_kex ssh_rsa_kex_sha1 = { - "rsa1024-sha1", NULL, KEXTYPE_RSA, &ssh_sha1, NULL, + "rsa1024-sha1", NULL, KEXTYPE_RSA, + &ssh_sha1, &ssh_rsa_kex_extra_sha1, }; static const struct ssh_kex ssh_rsa_kex_sha256 = { - "rsa2048-sha256", NULL, KEXTYPE_RSA, &ssh_sha256, NULL, + "rsa2048-sha256", NULL, KEXTYPE_RSA, + &ssh_sha256, &ssh_rsa_kex_extra_sha256, }; static const struct ssh_kex *const rsa_kex_list[] = { From 83439617051112744e4b5797927d7b5ce786f899 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 20 Oct 2018 22:47:49 +0100 Subject: [PATCH 550/607] Server prep: factor out portfwd_raw_new(). This new function contains the core setup for a PortForwarding structure, and should be reusable for any kind of forwarding that will simply be passing data between a local socket and an SSH channel without any tricky modifications. On the server side, X11 and agent forwarding both work exactly like this, so they will find this refactored function useful during setup. The contents of the function was originally part of pfl_accepting, which now does all that by calling the new function. pfl_accepting is not _quite_ doing a simple unmodified forwarding, because it might have to prefix it with a SOCKS exchange; in that situation it rewrites a few fields of the PortForwarding to some less generic values once portfwd_raw_new() has returned. --- portfwd.c | 71 +++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 53 insertions(+), 18 deletions(-) diff --git a/portfwd.c b/portfwd.c index 99076b99..87c6dae3 100644 --- a/portfwd.c +++ b/portfwd.c @@ -467,18 +467,10 @@ static const struct ChannelVtable PortForwarding_channelvt = { chan_no_request_response, }; -/* - called when someone connects to the local port - */ - -static int pfl_accepting(Plug *p, accept_fn_t constructor, accept_ctx_t ctx) +Channel *portfwd_raw_new(ConnectionLayer *cl, Plug **plug) { struct PortForwarding *pf; - struct PortListener *pl; - Socket *s; - const char *err; - pl = container_of(p, struct PortListener, plug); pf = new_portfwd_state(); pf->plug.vt = &PortForwarding_plugvt; pf->chan.initial_fixed_window_size = 0; @@ -486,29 +478,72 @@ static int pfl_accepting(Plug *p, accept_fn_t constructor, accept_ctx_t ctx) pf->input_wanted = TRUE; pf->c = NULL; - pf->cl = pl->cl; - pf->s = s = constructor(ctx, &pf->plug); + pf->cl = cl; + pf->input_wanted = TRUE; + pf->ready = 0; + + pf->socks_state = SOCKS_NONE; + pf->hostname = NULL; + pf->port = 0; + + *plug = &pf->plug; + return &pf->chan; +} + +void portfwd_raw_free(Channel *pfchan) +{ + struct PortForwarding *pf; + assert(pfchan->vt == &PortForwarding_channelvt); + pf = container_of(pfchan, struct PortForwarding, chan); + free_portfwd_state(pf); +} + +void portfwd_raw_setup(Channel *pfchan, Socket *s, SshChannel *sc) +{ + struct PortForwarding *pf; + assert(pfchan->vt == &PortForwarding_channelvt); + pf = container_of(pfchan, struct PortForwarding, chan); + + pf->s = s; + pf->c = sc; +} + +/* + called when someone connects to the local port + */ + +static int pfl_accepting(Plug *p, accept_fn_t constructor, accept_ctx_t ctx) +{ + struct PortListener *pl = container_of(p, struct PortListener, plug); + struct PortForwarding *pf; + Channel *chan; + Plug *plug; + Socket *s; + const char *err; + + chan = portfwd_raw_new(pl->cl, &plug); + s = constructor(ctx, plug); if ((err = sk_socket_error(s)) != NULL) { - free_portfwd_state(pf); - return err != NULL; + portfwd_raw_free(chan); + return TRUE; } - pf->input_wanted = TRUE; - pf->ready = 0; + pf = container_of(chan, struct PortForwarding, chan); if (pl->is_dynamic) { + pf->s = s; pf->socks_state = SOCKS_INITIAL; pf->socksbuf = strbuf_new(); pf->socksbuf_consumed = 0; pf->port = 0; /* "hostname" buffer is so far empty */ sk_set_frozen(s, 0); /* we want to receive SOCKS _now_! */ } else { - pf->socks_state = SOCKS_NONE; pf->hostname = dupstr(pl->hostname); pf->port = pl->port; - pf->c = wrap_lportfwd_open(pl->cl, pf->hostname, pf->port, - s, &pf->chan); + portfwd_raw_setup( + chan, s, + wrap_lportfwd_open(pl->cl, pf->hostname, pf->port, s, &pf->chan)); } return 0; From 650404f32c5d673168b8b79b5a0688fa6ce4dea1 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 21 Oct 2018 09:29:17 +0100 Subject: [PATCH 551/607] Server prep: pass "implementation name" to ssh_verstring_new. The word 'PuTTY' in the outgoing SSH version string has always represented the name of the *SSH implementation* as opposed to the name of the specific program containing it (for example, PSCP and PSFTP don't announce themselves with a different banner). But I think that a change from client to server merits a change in that implementation name, so I'm removing the prefix "PuTTY" from the constant string sshver[], and moving it to a parameter passed in separately to ssh_verstring_new, so that the upcoming server can pass in a different one. --- Buildscr | 8 ++++---- ssh.c | 2 +- sshbpp.h | 3 ++- sshverstring.c | 10 +++++++--- version.h | 2 +- 5 files changed, 15 insertions(+), 10 deletions(-) diff --git a/Buildscr b/Buildscr index 12ff2fcf..4656dde4 100644 --- a/Buildscr +++ b/Buildscr @@ -63,10 +63,10 @@ set Docmakever VERSION="$(Puttytextver)" # make sure it's under 40 characters, which is a hard limit in the SSH # protocol spec (and enforced by a compile-time assertion in # version.c). -ifneq "$(RELEASE)" "" set Sshver PuTTY-Release-$(RELEASE) -ifneq "$(PRERELEASE)" "" set Sshver PuTTY-Prerelease-$(PRERELEASE):$(Ndate).$(vcsid) -ifneq "$(SNAPSHOT)" "" set Sshver PuTTY-Snapshot-$(Date).$(vcsid) -ifeq "$(RELEASE)$(PRERELEASE)$(SNAPSHOT)" "" set Sshver PuTTY-Custom-$(Date).$(vcsid) +ifneq "$(RELEASE)" "" set Sshver -Release-$(RELEASE) +ifneq "$(PRERELEASE)" "" set Sshver -Prerelease-$(PRERELEASE):$(Ndate).$(vcsid) +ifneq "$(SNAPSHOT)" "" set Sshver -Snapshot-$(Date).$(vcsid) +ifeq "$(RELEASE)$(PRERELEASE)$(SNAPSHOT)" "" set Sshver -Custom-$(Date).$(vcsid) # Set up the filename suffix for the Unix source archive. ifneq "$(RELEASE)" "" set Uxarcsuffix -$(RELEASE) diff --git a/ssh.c b/ssh.c index 2f81d9f6..1a881c80 100644 --- a/ssh.c +++ b/ssh.c @@ -717,7 +717,7 @@ static const char *connect_to_host(Ssh *ssh, const char *host, int port, ssh->version_receiver.got_ssh_version = ssh_got_ssh_version; ssh->bpp = ssh_verstring_new( ssh->conf, ssh->logctx, ssh->bare_connection, - ssh->version == 1 ? "1.5" : "2.0", &ssh->version_receiver); + ssh->version == 1 ? "1.5" : "2.0", &ssh->version_receiver, "PuTTY"); ssh_connect_bpp(ssh); queue_idempotent_callback(&ssh->bpp->ic_in_raw); diff --git a/sshbpp.h b/sshbpp.h index e1b4622d..264c37c4 100644 --- a/sshbpp.h +++ b/sshbpp.h @@ -136,7 +136,8 @@ struct ssh_version_receiver { }; BinaryPacketProtocol *ssh_verstring_new( Conf *conf, LogContext *logctx, int bare_connection_mode, - const char *protoversion, struct ssh_version_receiver *rcv); + const char *protoversion, struct ssh_version_receiver *rcv, + const char *impl_name); const char *ssh_verstring_get_remote(BinaryPacketProtocol *); const char *ssh_verstring_get_local(BinaryPacketProtocol *); int ssh_verstring_get_bugs(BinaryPacketProtocol *); diff --git a/sshverstring.c b/sshverstring.c index d68954c7..f11c35ea 100644 --- a/sshverstring.c +++ b/sshverstring.c @@ -27,6 +27,7 @@ struct ssh_verstring_state { int major_protoversion; int remote_bugs; char prefix[PREFIX_MAXLEN]; + char *impl_name; char *vstring; int vslen, vstrsize; char *protoversion; @@ -59,7 +60,8 @@ static int ssh_version_includes_v2(const char *ver); BinaryPacketProtocol *ssh_verstring_new( Conf *conf, LogContext *logctx, int bare_connection_mode, - const char *protoversion, struct ssh_version_receiver *rcv) + const char *protoversion, struct ssh_version_receiver *rcv, + const char *impl_name) { struct ssh_verstring_state *s = snew(struct ssh_verstring_state); @@ -90,6 +92,7 @@ BinaryPacketProtocol *ssh_verstring_new( s->bpp.logctx = logctx; s->our_protoversion = dupstr(protoversion); s->receiver = rcv; + s->impl_name = dupstr(impl_name); /* * We send our version string early if we can. But if it includes @@ -108,6 +111,7 @@ void ssh_verstring_free(BinaryPacketProtocol *bpp) struct ssh_verstring_state *s = container_of(bpp, struct ssh_verstring_state, bpp); conf_free(s->conf); + sfree(s->impl_name); sfree(s->vstring); sfree(s->protoversion); sfree(s->our_vstring); @@ -155,9 +159,9 @@ static void ssh_verstring_send(struct ssh_verstring_state *s) * Construct our outgoing version string. */ s->our_vstring = dupprintf( - "%.*s%s-%s", + "%.*s%s-%s%s", (int)s->prefix_wanted.len, (const char *)s->prefix_wanted.ptr, - s->our_protoversion, sshver); + s->our_protoversion, s->impl_name, sshver); sv_pos = s->prefix_wanted.len + strlen(s->our_protoversion) + 1; /* Convert minus signs and spaces in the software version string diff --git a/version.h b/version.h index 26242ad6..74be18f4 100644 --- a/version.h +++ b/version.h @@ -9,7 +9,7 @@ */ #define TEXTVER "Unidentified build" -#define SSHVER "PuTTY-Unidentified-Local-Build" +#define SSHVER "-Unidentified-Local-Build" #define BINARY_VERSION 0,0,0,0 #ifndef SOURCE_COMMIT From c970d2b694e6c3410bd1d8fdd449cf6a3b9076ec Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 13 Oct 2018 10:15:47 +0100 Subject: [PATCH 552/607] uxpty: send seat_eof when the pty master gives EIO. The uxpty backend is going to be reused to implement the "session" channel type in the upcoming SSH server implementation, which puts quite a few new requirements on it. The first of them is that when we get EOF from the subprocess's output channel (or rather, EIO from the pty), we should actually notify the Seat of this. In principle we should have been doing this all along, I'm pretty sure. It hasn't happened to matter until now because the receiving Seats haven't done much with that notification. But it will matter when that's what controls the sending of SSH_MSG_CHANNEL_EOF. --- unix/uxpty.c | 1 + 1 file changed, 1 insertion(+) diff --git a/unix/uxpty.c b/unix/uxpty.c index 5ae1acca..57b3308f 100644 --- a/unix/uxpty.c +++ b/unix/uxpty.c @@ -678,6 +678,7 @@ void pty_real_select_result(Pty *pty, int event, int status) seat_stdout(pty->seat, message, strlen(message)); } + seat_eof(pty->seat); seat_notify_remote_exit(pty->seat); } } From 0ee204f699886315340d16bf8a9de47451ae3819 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 13 Oct 2018 10:36:18 +0100 Subject: [PATCH 553/607] uxpty: propagate exit code more reliably on pty EIO. There was a bit of a race condition depending on whether uxpty spotted the EOF/EIO on the process's output first, or the SIGCHLD for its actual termination: if the former came first, it would never bother to reap the exit code at all. It still doesn't bother if it's closing the session immediately and the process genuinely _hasn't_ died (say, if it detaches itself completely from the controlling tty to run in the background like a weird parody of an old DOS TSR). But now when we see EOF, we make an immediate (but nonblocking) attempt to wait for the child process, in case its exit code was already available and we just hadn't noticed yet. --- unix/uxpty.c | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/unix/uxpty.c b/unix/uxpty.c index 57b3308f..834d360f 100644 --- a/unix/uxpty.c +++ b/unix/uxpty.c @@ -580,7 +580,9 @@ void pty_pre_init(void) } -void pty_real_select_result(Pty *pty, int event, int status) +static void pty_try_wait(void); + +static void pty_real_select_result(Pty *pty, int event, int status) { char buf[4096]; int ret; @@ -627,6 +629,7 @@ void pty_real_select_result(Pty *pty, int event, int status) * the pterm window to hang around! */ finished = TRUE; + pty_try_wait(); /* one last effort to collect exit code */ if (!pty->child_dead) pty->exit_code = 0; } else if (ret < 0) { @@ -683,27 +686,34 @@ void pty_real_select_result(Pty *pty, int event, int status) } } +static void pty_try_wait(void) +{ + Pty *pty; + pid_t pid; + int status; + + do { + pid = waitpid(-1, &status, WNOHANG); + + pty = find234(ptys_by_pid, &pid, pty_find_by_pid); + + if (pty) + pty_real_select_result(pty, -1, status); + } while (pid > 0); +} + void pty_select_result(int fd, int event) { Pty *pty; if (fd == pty_signal_pipe[0]) { - pid_t pid; - int status; char c[1]; if (read(pty_signal_pipe[0], c, 1) <= 0) /* ignore error */; /* ignore its value; it'll be `x' */ - do { - pid = waitpid(-1, &status, WNOHANG); - - pty = find234(ptys_by_pid, &pid, pty_find_by_pid); - - if (pty) - pty_real_select_result(pty, -1, status); - } while (pid > 0); + pty_try_wait(); } else { pty = find234(ptys_by_fd, &fd, pty_find_by_fd); From 105672e324422b986a53960d9d53461f2ffcd4df Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 13 Oct 2018 08:32:40 +0100 Subject: [PATCH 554/607] uxpty: new specialist backend-creation API. The function that does the main pty setup is now called pty_backend_create(), and has an API better suited to uxpty in particular than the standard backend_init() virtual constructor. It leaves off a load of standard parameters to backend_init() which aren't really relevant to this backend, and it adds the 'argv' parameter to pass in a split-up command line, which is unique to it. The old creation function still exists, as a tiny wrapper that calls the new pty_backend_create. And that version still gets the argv parameter from the process-global variable pty_argv[], so the call sites in pterm haven't had to change for this. This will make it possible to instantiate a pty backend directly from the SSH server code, without having to do anything really excessively cumbersome to pass in a subcommand in the form of pre-split argv. (And I'll add a few more specialist parameters to the new function shortly.) --- unix/uxpty.c | 112 +++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 95 insertions(+), 17 deletions(-) diff --git a/unix/uxpty.c b/unix/uxpty.c index 834d360f..ca4d3c04 100644 --- a/unix/uxpty.c +++ b/unix/uxpty.c @@ -740,17 +740,15 @@ static void pty_uxsel_setup(Pty *pty) } /* - * Called to set up the pty. - * - * Returns an error message, or NULL on success. - * - * Also places the canonical host name into `realhost'. It must be - * freed by the caller. + * The main setup function for the pty back end. This doesn't match + * the signature of backend_init(), partly because it has to be able + * to take extra arguments such as an argv array, and also because + * once we're changing the type signature _anyway_ we can discard the + * stuff that's not really applicable to this backend like host names + * and port numbers. */ -static const char *pty_init(Seat *seat, Backend **backend_handle, - LogContext *logctx, Conf *conf, - const char *host, int port, - char **realhost, int nodelay, int keepalive) +Backend *pty_backend_create( + Seat *seat, LogContext *logctx, Conf *conf, char **argv) { int slavefd; pid_t pid, pgrp; @@ -773,7 +771,6 @@ static const char *pty_init(Seat *seat, Backend **backend_handle, pty->seat = seat; pty->backend.vt = &pty_backend; - *backend_handle = &pty->backend; pty->conf = conf_copy(conf); pty->term_width = conf_get_int(conf, CONF_width); @@ -973,11 +970,11 @@ static const char *pty_init(Seat *seat, Backend **backend_handle, putty_signal(SIGQUIT, SIG_DFL); putty_signal(SIGPIPE, SIG_DFL); block_signal(SIGPIPE, 0); - if (pty_argv) { + if (argv) { /* * Exec the exact argument list we were given. */ - execvp(pty_argv[0], pty_argv); + execvp(argv[0], argv); /* * If that fails, and if we had exactly one argument, pass * that argument to $SHELL -c. @@ -1002,10 +999,10 @@ static const char *pty_init(Seat *seat, Backend **backend_handle, * plausible uses of the Debian-style alias * 'x-terminal-emulator'... */ - if (pty_argv[1] == NULL) { + if (argv[1] == NULL) { char *shell = getenv("SHELL"); if (shell) - execl(shell, shell, "-c", pty_argv[0], (void *)NULL); + execl(shell, shell, "-c", argv[0], (void *)NULL); } } else { char *shell = getenv("SHELL"); @@ -1046,8 +1043,23 @@ static const char *pty_init(Seat *seat, Backend **backend_handle, } pty_uxsel_setup(pty); - *realhost = dupstr(""); + return &pty->backend; +} +/* + * This is the pty backend's _official_ init method, for BackendVtable + * purposes. Its job is just to be an API converter, ignoring the + * irrelevant input parameters and making up auxiliary outputs. Also + * it gets the argv array from the global variable pty_argv, expecting + * that it will have been invoked by pterm. + */ +static const char *pty_init(Seat *seat, Backend **backend_handle, + LogContext *logctx, Conf *conf, + const char *host, int port, + char **realhost, int nodelay, int keepalive) +{ + *backend_handle= pty_backend_create(seat, logctx, conf, pty_argv); + *realhost = dupstr(""); return NULL; } @@ -1237,8 +1249,74 @@ static int pty_exitcode(Backend *be) Pty *pty = container_of(be, Pty, backend); if (!pty->finished) return -1; /* not dead yet */ + else if (WIFSIGNALED(pty->exit_code)) + return 128 + WTERMSIG(pty->exit_code); else - return pty->exit_code; + return WEXITSTATUS(pty->exit_code); +} + +ptrlen pty_backend_exit_signame(Backend *be, char **aux_msg) +{ + Pty *pty = container_of(be, Pty, backend); + int sig; + + *aux_msg = NULL; + + if (!pty->finished || !WIFSIGNALED(pty->exit_code)) + return PTRLEN_LITERAL(""); + + sig = WTERMSIG(pty->exit_code); + +#define TRANSLATE_SIGNAL(s) do \ + { \ + if (sig == SIG ## s) \ + return PTRLEN_LITERAL(#s); \ + } while (0) + +#ifdef SIGABRT + TRANSLATE_SIGNAL(ABRT); +#endif +#ifdef SIGALRM + TRANSLATE_SIGNAL(ALRM); +#endif +#ifdef SIGFPE + TRANSLATE_SIGNAL(FPE); +#endif +#ifdef SIGHUP + TRANSLATE_SIGNAL(HUP); +#endif +#ifdef SIGILL + TRANSLATE_SIGNAL(ILL); +#endif +#ifdef SIGINT + TRANSLATE_SIGNAL(INT); +#endif +#ifdef SIGKILL + TRANSLATE_SIGNAL(KILL); +#endif +#ifdef SIGPIPE + TRANSLATE_SIGNAL(PIPE); +#endif +#ifdef SIGQUIT + TRANSLATE_SIGNAL(QUIT); +#endif +#ifdef SIGSEGV + TRANSLATE_SIGNAL(SEGV); +#endif +#ifdef SIGTERM + TRANSLATE_SIGNAL(TERM); +#endif +#ifdef SIGUSR1 + TRANSLATE_SIGNAL(USR1); +#endif +#ifdef SIGUSR2 + TRANSLATE_SIGNAL(USR2); +#endif +#undef TRANSLATE_SIGNAL + + *aux_msg = dupprintf("untranslatable signal number %d: %s", + sig, strsignal(sig)); + return PTRLEN_LITERAL("HUP"); /* need some kind of default */ } static int pty_cfg_info(Backend *be) From f2edea161ac6aa873065cf089629f952756fd28f Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Thu, 18 Oct 2018 20:37:33 +0100 Subject: [PATCH 555/607] uxpty: give pty_backend_create a struct ssh_ttymodes. This will be applied to the pty's termios settings at creation time, superseding the default settings uxpty has always used. It works by including the new sshttymodes.h with TTYMODES_LOCAL_ONLY defined, so that modes not supported by a particular Unix system are automatically quietly ignored. Of course, a struct ssh_ttymodes always has the option of representing "please make no change to the defaults", and of course, that's precisely what is done by the one that pty_init constructs for clients that aren't calling pty_backend_create directly. --- unix/uxpty.c | 40 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/unix/uxpty.c b/unix/uxpty.c index ca4d3c04..a2b01e70 100644 --- a/unix/uxpty.c +++ b/unix/uxpty.c @@ -21,8 +21,10 @@ #include #include #include +#include #include "putty.h" +#include "ssh.h" #include "tree234.h" #ifndef OMIT_UTMP @@ -739,6 +741,35 @@ static void pty_uxsel_setup(Pty *pty) uxsel_set(pty_signal_pipe[0], 1, pty_select_result); } +static void copy_ttymodes_into_termios( + struct termios *attrs, struct ssh_ttymodes modes) +{ +#define TTYMODE_CHAR(name, ssh_opcode, cc_index) { \ + if (modes.have_mode[ssh_opcode]) \ + attrs->c_cc[cc_index] = modes.mode_val[ssh_opcode]; \ + } + +#define TTYMODE_FLAG(flagval, ssh_opcode, field, flagmask) { \ + if (modes.have_mode[ssh_opcode]) { \ + attrs->c_##field##flag &= ~flagmask; \ + if (modes.mode_val[ssh_opcode]) \ + attrs->c_##field##flag |= flagval; \ + } \ + } + +#define TTYMODES_LOCAL_ONLY /* omit any that this platform doesn't know */ +#include "sshttymodes.h" + +#undef TTYMODES_LOCAL_ONLY +#undef TTYMODE_CHAR +#undef TTYMODE_FLAG + + if (modes.have_mode[TTYMODE_ISPEED]) + cfsetispeed(attrs, modes.mode_val[TTYMODE_ISPEED]); + if (modes.have_mode[TTYMODE_OSPEED]) + cfsetospeed(attrs, modes.mode_val[TTYMODE_OSPEED]); +} + /* * The main setup function for the pty back end. This doesn't match * the signature of backend_init(), partly because it has to be able @@ -748,7 +779,8 @@ static void pty_uxsel_setup(Pty *pty) * and port numbers. */ Backend *pty_backend_create( - Seat *seat, LogContext *logctx, Conf *conf, char **argv) + Seat *seat, LogContext *logctx, Conf *conf, char **argv, + struct ssh_ttymodes ttymodes) { int slavefd; pid_t pid, pgrp; @@ -902,6 +934,8 @@ Backend *pty_backend_create( attrs.c_iflag &= ~IUTF8; #endif + copy_ttymodes_into_termios(&attrs, ttymodes); + tcsetattr(0, TCSANOW, &attrs); } @@ -1058,7 +1092,9 @@ static const char *pty_init(Seat *seat, Backend **backend_handle, const char *host, int port, char **realhost, int nodelay, int keepalive) { - *backend_handle= pty_backend_create(seat, logctx, conf, pty_argv); + struct ssh_ttymodes modes; + memset(&modes, 0, sizeof(modes)); + *backend_handle= pty_backend_create(seat, logctx, conf, pty_argv, modes); *realhost = dupstr(""); return NULL; } From 63d08fc308767b775c883eaf89e3b865ebd965af Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Thu, 18 Oct 2018 20:37:59 +0100 Subject: [PATCH 556/607] uxpty: support SS_SIG* and SS_BRK specials. The SS_SIGFOO family are implemented by sending a signal directly to the pid of the immediate child process. I had had the vague idea that it might be more desirable to send the specified signal to the foreground process group in the tty. That way, you'd be able to SIGINT (say) the foreground job in a shell session, and return to the shell _prompt_ without terminating the whole session, and you could do this in an emergency even if the job was a full-screen application which had configured termios so that no keystroke generated SIGINT. But as far as I can see there's no actual way to do that. I wasn't able to find any ioctl or termios call to send a signal to a pty's foreground pgrp, and you can't even do it manually via kill(2) because first you'd have to find out what the pgrp id _is_, and according to the man pages, you can only call tcgetpgrp on the slave end of the pty and even then only if it's your controlling terminal. So SS_SIGFOO goes to the child process, because that's the only place I can find that I _can_ send it to sensibly. SS_BRK translates to tcsendbreak, of course (though I haven't actually seen any effect of calling this on a pty master, not even if I set PARMRK on the slave end which by my understanding _ought_ to show me when break events occur). --- unix/uxpty.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/unix/uxpty.c b/unix/uxpty.c index a2b01e70..6ff62b69 100644 --- a/unix/uxpty.c +++ b/unix/uxpty.c @@ -1229,8 +1229,31 @@ static void pty_size(Backend *be, int width, int height) */ static void pty_special(Backend *be, SessionSpecialCode code, int arg) { - /* Pty *pty = container_of(be, Pty, backend); */ - /* Do nothing! */ + Pty *pty = container_of(be, Pty, backend); + + if (code == SS_BRK) { + tcsendbreak(pty->master_fd, 0); + return; + } + + { + int sig = -1; + + #define SIGNAL_SUB(name) if (code == SS_SIG ## name) sig = SIG ## name; + #define SIGNAL_MAIN(name, text) SIGNAL_SUB(name) + #define SIGNALS_LOCAL_ONLY + #include "sshsignals.h" + #undef SIGNAL_SUB + #undef SIGNAL_MAIN + #undef SIGNALS_LOCAL_ONLY + + if (sig != -1) { + if (!pty->child_dead) + kill(pty->child_pid, sig); + return; + } + } + return; } From 6b7a1cd1c18981a45bf96176dab8e53377ddc7b1 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Thu, 18 Oct 2018 20:31:13 +0100 Subject: [PATCH 557/607] uxpty: option to make three pipes instead of a pty. Not every "session" channel in SSH allocates a pty at all, of course, and so I'll need a way to run a subprocess without doing so. The simplest approach seems to be to expand uxpty's remit so that the pty is optional: now it can open either a pty or a set of pipes for stdin/out/err, according to an option provided to pty_backend_create. (It amuses me that without this option I'd have an SSH server which is incapable of _not_ honouring the "pty-req" channel request. That's normally the easy part!) This breaks the previous one-to-one coupling between pty backend instances and file descriptors passed to uxsel, which I was using to look up the Pty structure in a tree234 indexed by fd when an uxsel notification came back. So now each Pty structure contains a collection of subobjects of a new type PtyFd, and _those_ are what's stored in the fd-indexed tree. Another awkward part is that uxsel_set is not incremental: the rwx flags you pass to it completely supersede the previous set for that file descriptor, so I had to set up the logic that decides whether we're trying to read or write each fd in a way that can cope equally well with the fd aliasing another one (if it's the pty master) or not (if there are three completely separate pipes). --- unix/uxpty.c | 475 +++++++++++++++++++++++++++++++++++---------------- 1 file changed, 325 insertions(+), 150 deletions(-) diff --git a/unix/uxpty.c b/unix/uxpty.c index 6ff62b69..dea208f7 100644 --- a/unix/uxpty.c +++ b/unix/uxpty.c @@ -70,9 +70,19 @@ typedef struct Pty Pty; */ static int pty_signal_pipe[2] = { -1, -1 }; /* obviously bogus initial val */ +typedef struct PtyFd { + int fd; + Pty *pty; +} PtyFd; + struct Pty { Conf *conf; + int master_fd, slave_fd; + int pipefds[6]; + PtyFd fds[3]; + int master_i, master_o, master_e; + Seat *seat; char name[FILENAME_MAX]; pid_t child_pid; @@ -84,40 +94,42 @@ struct Pty { }; /* - * We store our pty backends in a tree sorted by master fd, so that - * when we get an uxsel notification we know which backend instance - * is the owner of the pty that caused it. + * We store all the (active) PtyFd structures in a tree sorted by fd, + * so that when we get an uxsel notification we know which backend + * instance is the owner of the pty that caused it, and then we can + * find out which fd is the relevant one too. */ -static int pty_compare_by_fd(void *av, void *bv) +static int ptyfd_compare(void *av, void *bv) { - Pty *a = (Pty *)av; - Pty *b = (Pty *)bv; + PtyFd *a = (PtyFd *)av; + PtyFd *b = (PtyFd *)bv; - if (a->master_fd < b->master_fd) + if (a->fd < b->fd) return -1; - else if (a->master_fd > b->master_fd) + else if (a->fd > b->fd) return +1; return 0; } -static int pty_find_by_fd(void *av, void *bv) +static int ptyfd_find(void *av, void *bv) { int a = *(int *)av; - Pty *b = (Pty *)bv; + PtyFd *b = (PtyFd *)bv; - if (a < b->master_fd) + if (a < b->fd) return -1; - else if (a > b->master_fd) + else if (a > b->fd) return +1; return 0; } -static tree234 *ptys_by_fd = NULL; +static tree234 *ptyfds = NULL; /* - * We also have a tree sorted by child pid, so that when we wait() - * in response to the signal we know which backend instance is the - * owner of the process that caused the signal. + * We also have a tree of Pty structures themselves, sorted by child + * pid, so that when we wait() in response to the signal we know which + * backend instance is the owner of the process that caused the + * signal. */ static int pty_compare_by_pid(void *av, void *bv) { @@ -401,10 +413,6 @@ static void pty_open_master(Pty *pty) #ifndef SET_NONBLOCK_VIA_OPENPT nonblock(pty->master_fd); #endif - - if (!ptys_by_fd) - ptys_by_fd = newtree234(pty_compare_by_fd); - add234(ptys_by_fd, pty); } static Pty *new_pty_struct(void) @@ -584,7 +592,7 @@ void pty_pre_init(void) static void pty_try_wait(void); -static void pty_real_select_result(Pty *pty, int event, int status) +static void pty_real_select_result(Pty *pty, int fd, int event, int status) { char buf[4096]; int ret; @@ -597,48 +605,77 @@ static void pty_real_select_result(Pty *pty, int event, int status) */ if ((WIFEXITED(status) || WIFSIGNALED(status))) { /* - * The primary child process died. We could keep - * the terminal open for remaining subprocesses to - * output to, but conventional wisdom seems to feel - * that that's the Wrong Thing for an xterm-alike, - * so we bail out now (though we don't necessarily - * _close_ the window, depending on the state of - * Close On Exit). This would be easy enough to - * change or make configurable if necessary. + * The primary child process died. + */ + pty->child_dead = TRUE; + del234(ptys_by_pid, pty); + pty->exit_code = status; + + /* + * If this is an ordinary pty session, this is also the + * moment to terminate the whole backend. + * + * We _could_ instead keep the terminal open for remaining + * subprocesses to output to, but conventional wisdom + * seems to feel that that's the Wrong Thing for an + * xterm-alike, so we bail out now (though we don't + * necessarily _close_ the window, depending on the state + * of Close On Exit). This would be easy enough to change + * or make configurable if necessary. */ - pty->exit_code = status; - pty->child_dead = TRUE; - del234(ptys_by_pid, pty); - finished = TRUE; + if (pty->master_fd >= 0) + finished = TRUE; } } else { if (event == 1) { + int is_stdout = (fd == pty->master_o); - ret = read(pty->master_fd, buf, sizeof(buf)); + ret = read(fd, buf, sizeof(buf)); - /* - * Clean termination condition is that either ret == 0, or ret - * < 0 and errno == EIO. Not sure why the latter, but it seems - * to happen. Boo. - */ - if (ret == 0 || (ret < 0 && errno == EIO)) { - /* - * We assume a clean exit if the pty has closed but the - * actual child process hasn't. The only way I can - * imagine this happening is if it detaches itself from - * the pty and goes daemonic - in which case the - * expected usage model would precisely _not_ be for - * the pterm window to hang around! - */ - finished = TRUE; - pty_try_wait(); /* one last effort to collect exit code */ - if (!pty->child_dead) - pty->exit_code = 0; + /* + * Treat EIO on a pty master as equivalent to EOF (because + * that's how the kernel seems to report the event where + * the last process connected to the other end of the pty + * went away). + */ + if (fd == pty->master_fd && ret < 0 && errno == EIO) + ret = 0; + + if (ret == 0) { + /* + * EOF on this input fd, so to begin with, we may as + * well close it, and remove all references to it in + * the pty's fd fields. + */ + uxsel_del(fd); + close(fd); + if (pty->master_fd == fd) + pty->master_fd = -1; + if (pty->master_o == fd) + pty->master_o = -1; + if (pty->master_e == fd) + pty->master_e = -1; + + if (is_stdout) { + /* + * We assume a clean exit if the pty (or stdout + * pipe) has closed, but the actual child process + * hasn't. The only way I can imagine this + * happening is if it detaches itself from the pty + * and goes daemonic - in which case the expected + * usage model would precisely _not_ be for the + * pterm window to hang around! + */ + finished = TRUE; + pty_try_wait(); /* one last effort to collect exit code */ + if (!pty->child_dead) + pty->exit_code = 0; + } } else if (ret < 0) { perror("read pty master"); exit(1); } else if (ret > 0) { - seat_stdout(pty->seat, buf, ret); + seat_output(pty->seat, !is_stdout, buf, ret); } } else if (event == 2) { /* @@ -650,10 +687,13 @@ static void pty_real_select_result(Pty *pty, int event, int status) if (finished && !pty->finished) { int close_on_exit; + int i; - uxsel_del(pty->master_fd); - pty_close(pty); - pty->master_fd = -1; + for (i = 0; i < 3; i++) + if (pty->fds[i].fd >= 0) + uxsel_del(pty->fds[i].fd); + + pty_close(pty); pty->finished = TRUE; @@ -700,14 +740,12 @@ static void pty_try_wait(void) pty = find234(ptys_by_pid, &pid, pty_find_by_pid); if (pty) - pty_real_select_result(pty, -1, status); + pty_real_select_result(pty, -1, -1, status); } while (pid > 0); } void pty_select_result(int fd, int event) { - Pty *pty; - if (fd == pty_signal_pipe[0]) { char c[1]; @@ -717,21 +755,46 @@ void pty_select_result(int fd, int event) pty_try_wait(); } else { - pty = find234(ptys_by_fd, &fd, pty_find_by_fd); + PtyFd *ptyfd = find234(ptyfds, &fd, ptyfd_find); - if (pty) - pty_real_select_result(pty, event, 0); + if (ptyfd) + pty_real_select_result(ptyfd->pty, fd, event, 0); } } -static void pty_uxsel_setup(Pty *pty) +static void pty_uxsel_setup_fd(Pty *pty, int fd) { - int rwx; + int rwx = 0; + + if (fd < 0) + return; + + /* read from standard output and standard error pipes */ + if (pty->master_o == fd || pty->master_e == fd) + rwx |= 1; + /* write to standard input pipe if we have any data */ + if (pty->master_i == fd && bufchain_size(&pty->output_data)) + rwx |= 2; - rwx = 1; /* always want to read from pty */ - if (bufchain_size(&pty->output_data)) - rwx |= 2; /* might also want to write to it */ - uxsel_set(pty->master_fd, rwx, pty_select_result); + uxsel_set(fd, rwx, pty_select_result); +} + +static void pty_uxsel_setup(Pty *pty) +{ + /* + * We potentially have three separate fds here, but on the other + * hand, some of them might be the same (if they're a pty master). + * So we can't just call uxsel_set(master_o, 1) and then + * uxsel_set(master_i, 2), without the latter potentially undoing + * the work of the former if master_o == master_i. + * + * Instead, here we call a single uxsel on each one of these fds + * (if it exists at all), and for each one, check it against all + * three to see which bits to set. + */ + pty_uxsel_setup_fd(pty, pty->master_o); + pty_uxsel_setup_fd(pty, pty->master_e); + pty_uxsel_setup_fd(pty, pty->master_i); /* * In principle this only needs calling once for all pty @@ -779,8 +842,8 @@ static void copy_ttymodes_into_termios( * and port numbers. */ Backend *pty_backend_create( - Seat *seat, LogContext *logctx, Conf *conf, char **argv, - struct ssh_ttymodes ttymodes) + Seat *seat, LogContext *logctx, Conf *conf, char **argv, const char *cmd, + struct ssh_ttymodes ttymodes, int pipes_instead) { int slavefd; pid_t pid, pgrp; @@ -789,6 +852,7 @@ Backend *pty_backend_create( long windowid; #endif Pty *pty; + int i; if (single_pty) { pty = single_pty; @@ -800,6 +864,12 @@ Backend *pty_backend_create( pty_stamped_utmp = FALSE; #endif } + for (i = 0; i < 6; i++) + pty->pipefds[i] = -1; + for (i = 0; i < 3; i++) { + pty->fds[i].fd = -1; + pty->fds[i].pty = pty; + } pty->seat = seat; pty->backend.vt = &pty_backend; @@ -808,35 +878,76 @@ Backend *pty_backend_create( pty->term_width = conf_get_int(conf, CONF_width); pty->term_height = conf_get_int(conf, CONF_height); - if (pty->master_fd < 0) - pty_open_master(pty); + if (!ptyfds) + ptyfds = newtree234(ptyfd_compare); + + if (pipes_instead) { + if (pty->master_fd >= 0) { + /* If somehow we've got a pty master already and don't + * need it, throw it away! */ + close(pty->master_fd); + if (pty_utmp_helper_pipe >= 0) { + close(pty_utmp_helper_pipe); /* don't need this either */ + pty_utmp_helper_pipe = -1; + } + } + + + for (i = 0; i < 6; i += 2) { + if (pipe(pty->pipefds + i) < 0) { + backend_free(&pty->backend); + return NULL; + } + } + + pty->fds[0].fd = pty->master_i = pty->pipefds[1]; + pty->fds[1].fd = pty->master_o = pty->pipefds[2]; + pty->fds[2].fd = pty->master_e = pty->pipefds[4]; + + add234(ptyfds, &pty->fds[0]); + add234(ptyfds, &pty->fds[1]); + add234(ptyfds, &pty->fds[2]); + } else { + if (pty->master_fd < 0) + pty_open_master(pty); #ifndef OMIT_UTMP - /* - * Stamp utmp (that is, tell the utmp helper process to do so), - * or not. - */ - if (pty_utmp_helper_pipe >= 0) { /* if it's < 0, we can't anyway */ - if (!conf_get_int(conf, CONF_stamp_utmp)) { - close(pty_utmp_helper_pipe); /* just let the child process die */ - pty_utmp_helper_pipe = -1; - } else { - const char *location = seat_get_x_display(pty->seat); - int len = strlen(location)+1, pos = 0; /* +1 to include NUL */ - while (pos < len) { - int ret = write(pty_utmp_helper_pipe, location+pos, len - pos); - if (ret < 0) { - perror("pterm: writing to utmp helper process"); - close(pty_utmp_helper_pipe); /* arrgh, just give up */ - pty_utmp_helper_pipe = -1; - break; + /* + * Stamp utmp (that is, tell the utmp helper process to do so), + * or not. + */ + if (pty_utmp_helper_pipe >= 0) { /* if it's < 0, we can't anyway */ + if (!conf_get_int(conf, CONF_stamp_utmp)) { + /* We're not stamping utmp, so just let the child + * process die that was waiting to unstamp it later. */ + close(pty_utmp_helper_pipe); + pty_utmp_helper_pipe = -1; + } else { + const char *location = seat_get_x_display(pty->seat); + int len = strlen(location)+1, pos = 0; /* +1 to include NUL */ + while (pos < len) { + int ret = write(pty_utmp_helper_pipe, + location + pos, len - pos); + if (ret < 0) { + perror("pterm: writing to utmp helper process"); + close(pty_utmp_helper_pipe); /* arrgh, just give up */ + pty_utmp_helper_pipe = -1; + break; + } + pos += ret; } - pos += ret; } - } - } + } #endif + pty->master_i = pty->master_fd; + pty->master_o = pty->master_fd; + pty->master_e = -1; + + pty->fds[0].fd = pty->master_fd; + add234(ptyfds, &pty->fds[0]); + } + #ifndef NOT_X_WINDOWS /* for Mac OS X native compilation */ got_windowid = seat_get_windowid(pty->seat, &windowid); #endif @@ -891,62 +1002,74 @@ Backend *pty_backend_create( } } - slavefd = pty_open_slave(pty); - if (slavefd < 0) { - perror("slave pty: open"); - _exit(1); - } + pgrp = getpid(); - close(pty->master_fd); - noncloexec(slavefd); - dup2(slavefd, 0); - dup2(slavefd, 1); - dup2(slavefd, 2); - close(slavefd); - setsid(); + if (pipes_instead) { + int i; + dup2(pty->pipefds[0], 0); + dup2(pty->pipefds[3], 1); + dup2(pty->pipefds[5], 2); + for (i = 0; i < 6; i++) + close(pty->pipefds[i]); + + setsid(); + } else { + slavefd = pty_open_slave(pty); + if (slavefd < 0) { + perror("slave pty: open"); + _exit(1); + } + + close(pty->master_fd); + noncloexec(slavefd); + dup2(slavefd, 0); + dup2(slavefd, 1); + dup2(slavefd, 2); + close(slavefd); + setsid(); #ifdef TIOCSCTTY - ioctl(0, TIOCSCTTY, 1); + ioctl(0, TIOCSCTTY, 1); #endif - pgrp = getpid(); - tcsetpgrp(0, pgrp); + tcsetpgrp(0, pgrp); - /* - * Set up configuration-dependent termios settings on the new - * pty. Linux would have let us do this on the pty master - * before we forked, but that fails on OS X, so we do it here - * instead. - */ - if (tcgetattr(0, &attrs) == 0) { /* - * Set the backspace character to be whichever of ^H and - * ^? is specified by bksp_is_delete. - */ - attrs.c_cc[VERASE] = conf_get_int(conf, CONF_bksp_is_delete) - ? '\177' : '\010'; - - /* - * Set the IUTF8 bit iff the character set is UTF-8. + * Set up configuration-dependent termios settings on the new + * pty. Linux would have let us do this on the pty master + * before we forked, but that fails on OS X, so we do it here + * instead. */ + if (tcgetattr(0, &attrs) == 0) { + /* + * Set the backspace character to be whichever of ^H and + * ^? is specified by bksp_is_delete. + */ + attrs.c_cc[VERASE] = conf_get_int(conf, CONF_bksp_is_delete) + ? '\177' : '\010'; + + /* + * Set the IUTF8 bit iff the character set is UTF-8. + */ #ifdef IUTF8 - if (seat_is_utf8(seat)) - attrs.c_iflag |= IUTF8; - else - attrs.c_iflag &= ~IUTF8; + if (seat_is_utf8(seat)) + attrs.c_iflag |= IUTF8; + else + attrs.c_iflag &= ~IUTF8; #endif - copy_ttymodes_into_termios(&attrs, ttymodes); + copy_ttymodes_into_termios(&attrs, ttymodes); - tcsetattr(0, TCSANOW, &attrs); + tcsetattr(0, TCSANOW, &attrs); + } } setpgid(pgrp, pgrp); - { + if (!pipes_instead) { int ptyfd = open(pty->name, O_WRONLY, 0); if (ptyfd >= 0) close(ptyfd); } setpgid(pgrp, pgrp); - { + if (!pipes_instead) { char *term_env_var = dupprintf("TERM=%s", conf_get_str(conf, CONF_termtype)); putenv(term_env_var); @@ -1004,20 +1127,26 @@ Backend *pty_backend_create( putty_signal(SIGQUIT, SIG_DFL); putty_signal(SIGPIPE, SIG_DFL); block_signal(SIGPIPE, 0); - if (argv) { + if (argv || cmd) { /* - * Exec the exact argument list we were given. + * If we were given a separated argument list, try to exec + * it. */ - execvp(argv[0], argv); + if (argv) { + execvp(argv[0], argv); + } /* - * If that fails, and if we had exactly one argument, pass - * that argument to $SHELL -c. + * Otherwise, if we were given a single command string, + * try passing that to $SHELL -c. * - * This arranges that we can _either_ follow 'pterm -e' - * with a list of argv elements to be fed directly to - * exec, _or_ with a single argument containing a command - * to be parsed by a shell (but, in cases of doubt, the - * former is more reliable). + * In the case of pterm, this system of fallbacks arranges + * that we can _either_ follow 'pterm -e' with a list of + * argv elements to be fed directly to exec, _or_ with a + * single argument containing a command to be parsed by a + * shell (but, in cases of doubt, the former is more + * reliable). We arrange this by setting argv to the full + * argument list, and also setting cmd to the single + * element of argv if it's a length-1 list. * * A quick survey of other terminal emulators' -e options * (as of Debian squeeze) suggests that: @@ -1031,12 +1160,15 @@ Backend *pty_backend_create( * modes in order to be a drop-in replacement for either * xterm or gnome-terminal, and hence for anyone's * plausible uses of the Debian-style alias - * 'x-terminal-emulator'... + * 'x-terminal-emulator'. + * + * In other use cases, a caller can set only one of argv + * and cmd to get a fixed handling of the input. */ - if (argv[1] == NULL) { + if (cmd) { char *shell = getenv("SHELL"); if (shell) - execl(shell, shell, "-c", argv[0], (void *)NULL); + execl(shell, shell, "-c", cmd, (void *)NULL); } } else { char *shell = getenv("SHELL"); @@ -1064,6 +1196,18 @@ Backend *pty_backend_create( close(pty->slave_fd); if (!ptys_by_pid) ptys_by_pid = newtree234(pty_compare_by_pid); + if (pty->pipefds[0] >= 0) { + close(pty->pipefds[0]); + pty->pipefds[0] = -1; + } + if (pty->pipefds[3] >= 0) { + close(pty->pipefds[3]); + pty->pipefds[3] = -1; + } + if (pty->pipefds[5] >= 0) { + close(pty->pipefds[5]); + pty->pipefds[5] = -1; + } add234(ptys_by_pid, pty); } @@ -1092,9 +1236,16 @@ static const char *pty_init(Seat *seat, Backend **backend_handle, const char *host, int port, char **realhost, int nodelay, int keepalive) { + const char *cmd = NULL; struct ssh_ttymodes modes; + memset(&modes, 0, sizeof(modes)); - *backend_handle= pty_backend_create(seat, logctx, conf, pty_argv, modes); + + if (pty_argv && pty_argv[0] && !pty_argv[1]) + cmd = pty_argv[0]; + + *backend_handle= pty_backend_create( + seat, logctx, conf, pty_argv, cmd, modes, FALSE); *realhost = dupstr(""); return NULL; } @@ -1116,10 +1267,15 @@ static void pty_reconfig(Backend *be, Conf *conf) static void pty_free(Backend *be) { Pty *pty = container_of(be, Pty, backend); + int i; + + pty_close(pty); /* Either of these may fail `not found'. That's fine with us. */ del234(ptys_by_pid, pty); - del234(ptys_by_fd, pty); + for (i = 0; i < 3; i++) + if (pty->fds[i].fd >= 0) + del234(ptyfds, &pty->fds[i]); bufchain_clear(&pty->output_data); @@ -1141,11 +1297,11 @@ static void pty_try_write(Pty *pty) void *data; int len, ret; - assert(pty->master_fd >= 0); + assert(pty->master_i >= 0); while (bufchain_size(&pty->output_data) > 0) { bufchain_prefix(&pty->output_data, &data, &len); - ret = write(pty->master_fd, data, len); + ret = write(pty->master_i, data, len); if (ret < 0 && (errno == EWOULDBLOCK)) { /* @@ -1170,7 +1326,7 @@ static int pty_send(Backend *be, const char *buf, int len) { Pty *pty = container_of(be, Pty, backend); - if (pty->master_fd < 0) + if (pty->master_i < 0) return 0; /* ignore all writes if fd closed */ bufchain_add(&pty->output_data, buf, len); @@ -1181,10 +1337,25 @@ static int pty_send(Backend *be, const char *buf, int len) static void pty_close(Pty *pty) { + int i; + + if (pty->master_o >= 0) + uxsel_del(pty->master_o); + if (pty->master_e >= 0) + uxsel_del(pty->master_e); + if (pty->master_i >= 0) + uxsel_del(pty->master_i); + if (pty->master_fd >= 0) { close(pty->master_fd); pty->master_fd = -1; } + for (i = 0; i < 6; i++) { + if (pty->pipefds[i] >= 0) + close(pty->pipefds[i]); + pty->pipefds[i] = -1; + } + pty->master_i = pty->master_o = pty->master_e = -1; #ifndef OMIT_UTMP if (pty_utmp_helper_pipe >= 0) { close(pty_utmp_helper_pipe); /* this causes utmp to be cleaned up */ @@ -1214,6 +1385,9 @@ static void pty_size(Backend *be, int width, int height) pty->term_width = width; pty->term_height = height; + if (pty->master_fd < 0) + return; + seat_get_window_pixel_size(pty->seat, &xpixel, &ypixel); size.ws_row = (unsigned short)pty->term_height; @@ -1232,7 +1406,8 @@ static void pty_special(Backend *be, SessionSpecialCode code, int arg) Pty *pty = container_of(be, Pty, backend); if (code == SS_BRK) { - tcsendbreak(pty->master_fd, 0); + if (pty->master_fd >= 0) + tcsendbreak(pty->master_fd, 0); return; } From a48e897f26c041f53802fe6d90bb3d8eb2bb7c07 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Thu, 18 Oct 2018 18:04:31 +0100 Subject: [PATCH 558/607] uxpty: support SS_EOF, when in pipe mode. If the child process's standard input is provided by a pipe that's separate from its output channels, we can - and should - honour a request to cause that process to receive input EOF, by closing the output end of that pipe. As usual, we do this by setting a pending-EOF flag and calling try_write, to ensure that any buffered output data is sent before the pipe actually closes. --- unix/uxpty.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/unix/uxpty.c b/unix/uxpty.c index dea208f7..d0fc2798 100644 --- a/unix/uxpty.c +++ b/unix/uxpty.c @@ -90,6 +90,7 @@ struct Pty { int child_dead, finished; int exit_code; bufchain output_data; + int pending_eof; Backend backend; }; @@ -1316,6 +1317,17 @@ static void pty_try_write(Pty *pty) bufchain_consume(&pty->output_data, ret); } + if (pty->pending_eof && bufchain_size(&pty->output_data) == 0) { + /* This should only happen if pty->master_i is a pipe that + * doesn't alias either output fd */ + assert(pty->master_i != pty->master_o); + assert(pty->master_i != pty->master_e); + uxsel_del(pty->master_i); + close(pty->master_i); + pty->master_i = -1; + pty->pending_eof = FALSE; + } + pty_uxsel_setup(pty); } @@ -1326,7 +1338,7 @@ static int pty_send(Backend *be, const char *buf, int len) { Pty *pty = container_of(be, Pty, backend); - if (pty->master_i < 0) + if (pty->master_i < 0 || pty->pending_eof) return 0; /* ignore all writes if fd closed */ bufchain_add(&pty->output_data, buf, len); @@ -1411,6 +1423,14 @@ static void pty_special(Backend *be, SessionSpecialCode code, int arg) return; } + if (code == SS_EOF) { + if (pty->master_i >= 0 && pty->master_i != pty->master_fd) { + pty->pending_eof = TRUE; + pty_try_write(pty); + } + return; + } + { int sig = -1; From 1d323d5c804eaf7f8ac9e4a80702ded7b6c7bdd2 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 20 Oct 2018 22:09:54 +0100 Subject: [PATCH 559/607] Add an actual SSH server program. This server is NOT SECURE! If anyone is reading this commit message, DO NOT DEPLOY IT IN A HOSTILE-FACING ENVIRONMENT! Its purpose is to speak the server end of everything PuTTY speaks on the client side, so that I can test that I haven't broken PuTTY when I reorganise its code, even things like RSA key exchange or chained auth methods which it's hard to find a server that speaks at all. (For this reason, it's declared with [UT] in the Recipe file, so that it falls into the same category as programs like testbn, which won't be installed by 'make install'.) Working title is 'Uppity', partly for 'Universal PuTTY Protocol Interaction Test Yoke', but mostly because it looks quite like the word 'PuTTY' with part of it reversed. (Apparently 'test yoke' is a very rarely used term meaning something not altogether unlike 'test harness', which is a bit of a stretch, but it'll do.) It doesn't actually _support_ everything I want yet. At the moment, it's a proof of concept only. But it has most of the machinery present, and the parts it's missing - such as chained auth methods - should be easy enough to add because I've built in the required flexibility, in the form of an AuthPolicy object which can request them if it wants to. However, the current AuthPolicy object is entirely trivial, and will let in any user with the password "weasel". (Another way in which this is not a production-ready server is that it also has no interaction with the OS's authentication system. In particular, it will not only let in any user with the same password, but it won't even change uid - it will open shells and forwardings under whatever user id you started it up as.) Currently, the program can only speak the SSH protocol on its standard I/O channels (using the new FdSocket facility), so if you want it to listen on a network port, you'll have to run it from some kind of separate listening program similar to inetd. For my own tests, I'm not even doing that: I'm just having PuTTY spawn it as a local proxy process, which also conveniently eliminates the risk of anyone hostile connecting to it. The bulk of the actual code reorganisation is already done by previous commits, so this change is _mostly_ just dropping in a new set of server-specific source files alongside the client-specific ones I created recently. The remaining changes in the shared SSH code are numerous, but all minor: - a few extra parameters to BPP and PPL constructors (e.g. 'are you in server mode?'), and pass both sets of SSH-1 protocol flags from the login to the connection layer - in server mode, unconditionally send our version string _before_ waiting for the remote one - a new hook in the SSH-1 BPP to handle enabling compression in server mode, where the message exchange works the other way round - new code in the SSH-2 BPP to do _deferred_ compression the other way round (the non-deferred version is still nicely symmetric) - in the SSH-2 transport layer, some adjustments to do key derivation either way round (swapping round the identifying letters in the various hash preimages, and making sure to list the KEXINITs in the right order) - also in the SSH-2 transport layer, an if statement that controls whether we send SERVICE_REQUEST and wait for SERVICE_ACCEPT, or vice versa - new ConnectionLayer methods for opening outgoing channels for X and agent forwardings - new functions in portfwd.c to establish listening sockets suitable for remote-to-local port forwarding (i.e. not under the direction of a Conf the way it's done on the client side). --- .gitignore | 1 + Recipe | 37 ++- portfwd.c | 66 +++++ sesschan.c | 559 ++++++++++++++++++++++++++++++++++++++++ ssh.c | 7 +- ssh.h | 18 ++ ssh1bpp.c | 23 +- ssh1connection-client.c | 13 + ssh1connection-server.c | 355 +++++++++++++++++++++++++ ssh1connection.c | 8 +- ssh1connection.h | 7 +- ssh1login-server.c | 376 +++++++++++++++++++++++++++ ssh1login.c | 4 +- ssh2bpp.c | 53 ++-- ssh2connection-client.c | 11 + ssh2connection-server.c | 290 +++++++++++++++++++++ ssh2connection.c | 2 + ssh2connection.h | 4 +- ssh2kex-server.c | 289 +++++++++++++++++++++ ssh2transport.c | 135 +++++++--- ssh2transport.h | 9 +- ssh2userauth-server.c | 269 +++++++++++++++++++ ssh2userauth.c | 3 +- sshbpp.h | 8 +- sshppl.h | 11 +- sshserver.c | 464 +++++++++++++++++++++++++++++++++ sshserver.h | 65 +++++ sshverstring.c | 6 +- unix/uxserver.c | 529 +++++++++++++++++++++++++++++++++++++ 29 files changed, 3526 insertions(+), 96 deletions(-) create mode 100644 sesschan.c create mode 100644 ssh1connection-server.c create mode 100644 ssh1login-server.c create mode 100644 ssh2connection-server.c create mode 100644 ssh2kex-server.c create mode 100644 ssh2userauth-server.c create mode 100644 sshserver.c create mode 100644 sshserver.h create mode 100644 unix/uxserver.c diff --git a/.gitignore b/.gitignore index c04f119b..890f8b23 100644 --- a/.gitignore +++ b/.gitignore @@ -38,6 +38,7 @@ /puttyapp /ptermapp /osxlaunch +/uppity /unix/PuTTY.app /unix/Pterm.app /fuzzterm diff --git a/Recipe b/Recipe index b819c546..72b899b6 100644 --- a/Recipe +++ b/Recipe @@ -250,14 +250,18 @@ GTKMAIN = gtkmain cmdline NONSSH = telnet raw rlogin ldisc pinger # SSH back end (putty, plink, pscp, psftp). -SSH = ssh sshcommon ssh1bpp ssh2bpp ssh2bpp-bare ssh1censor ssh2censor - + ssh1login ssh1connection ssh2transport ssh2userauth ssh2connection - + sshverstring sshcrc sshdes sshmd5 sshrsa sshrand sshsha sshblowf - + sshdh sshcrcda sshpubk sshzlib sshdss x11fwd portfwd - + sshaes sshccp sshsh256 sshsh512 sshbn wildcard pinger ssharcf - + sshgssc pgssapi sshshare sshecc aqsync marshal nullplug agentf - + sshmac mainchan ssh2transhk ssh2kex-client ssh2connection-client - + ssh1connection-client +SSHCOMMON = sshcommon sshrand + + sshverstring sshcrc sshdes sshmd5 sshrsa sshsha sshblowf + + sshdh sshcrcda sshpubk sshzlib sshdss ssharcf + + sshaes sshccp sshsh256 sshsh512 sshbn sshmac marshal nullplug + + sshgssc pgssapi sshecc wildcard ssh1censor ssh2censor ssh2bpp + + ssh2transport ssh2transhk ssh2connection portfwd x11fwd + + ssh1connection ssh1bpp +SSH = SSHCOMMON ssh ssh2bpp-bare + + ssh1login ssh2userauth + + pinger + + sshshare aqsync agentf + + mainchan ssh2kex-client ssh2connection-client ssh1connection-client WINSSH = SSH winnoise wincapi winpgntc wingss winshare winnps winnpc + winhsock errsock UXSSH = SSH uxnoise uxagentc uxgss uxshare @@ -268,11 +272,19 @@ SFTP = sftp int64 logging cmdline # Miscellaneous objects appearing in all the utilities, or all the # network ones, or the Unix or Windows subsets of those in turn. MISC = misc marshal -MISCNET = timing callback MISC version settings tree234 proxy CONF be_misc +MISCNETCOMMON = timing callback MISC version tree234 CONF +MISCNET = MISCNETCOMMON be_misc settings proxy WINMISC = MISCNET winstore winnet winhandl cmdline windefs winmisc winproxy + wintime winhsock errsock winsecur winucs miscucs -UXMISC = MISCNET uxstore uxsel uxnet uxpeer uxmisc time - + uxproxy uxfdsock errsock +UXMISCCOMMON = MISCNETCOMMON uxstore uxsel uxnet uxpeer uxmisc time + + uxfdsock errsock +UXMISC = MISCNET UXMISCCOMMON uxproxy + +# SSH server. +SSHSERVER = SSHCOMMON sshserver settings be_none logging ssh2kex-server + + ssh2userauth-server sshrsag sshprime ssh2connection-server + + sesschan int64 proxy cproxy ssh1login-server + + ssh1connection-server # import.c and dependencies, for PuTTYgen-like utilities that have to # load foreign key files. @@ -364,6 +376,9 @@ fuzzterm : [UT] UXTERM CHARSET misc version uxmisc uxucs fuzzterm time settings testbn : [UT] testbn sshbn MISC version CONF tree234 uxmisc uxnogtk testbn : [C] testbn sshbn MISC version CONF tree234 winmisc LIBS +uppity : [UT] uxserver SSHSERVER UXMISC uxsignal uxnoise uxgss uxnogtk + + uxpty ux_x11 uxagentsock + # ---------------------------------------------------------------------- # On Windows, provide a means of removing local test binaries that we # aren't going to actually ship. (I prefer this to not building them diff --git a/portfwd.c b/portfwd.c index 87c6dae3..af4b541d 100644 --- a/portfwd.c +++ b/portfwd.c @@ -1050,6 +1050,72 @@ void portfwdmgr_config(PortFwdManager *mgr, Conf *conf) } } +int portfwdmgr_listen(PortFwdManager *mgr, const char *host, int port, + const char *keyhost, int keyport, Conf *conf) +{ + PortFwdRecord *pfr; + + pfr = snew(PortFwdRecord); + pfr->type = 'L'; + pfr->saddr = host ? dupstr(host) : NULL; + pfr->daddr = keyhost ? dupstr(keyhost) : NULL; + pfr->sserv = pfr->dserv = NULL; + pfr->sport = port; + pfr->dport = keyport; + pfr->local = NULL; + pfr->remote = NULL; + pfr->addressfamily = ADDRTYPE_UNSPEC; + + PortFwdRecord *existing = add234(mgr->forwardings, pfr); + if (existing != pfr) { + /* + * We had this record already. Return failure. + */ + pfr_free(pfr); + return FALSE; + } + + char *err = pfl_listen(keyhost, keyport, host, port, + mgr->cl, conf, &pfr->local, pfr->addressfamily); + logeventf(mgr->cl->logctx, + "%s on port %s:%d to forward to client%s%s", + err ? "Failed to listen" : "Listening", host, port, + err ? ": " : "", err ? err : ""); + if (err) { + sfree(err); + del234(mgr->forwardings, pfr); + pfr_free(pfr); + return FALSE; + } + + return TRUE; +} + +int portfwdmgr_unlisten(PortFwdManager *mgr, const char *host, int port) +{ + PortFwdRecord pfr_key; + + pfr_key.type = 'L'; + /* Safe to cast the const away here, because it will only be used + * by pfr_cmp, which won't write to the string */ + pfr_key.saddr = pfr_key.daddr = (char *)host; + pfr_key.sserv = pfr_key.dserv = NULL; + pfr_key.sport = pfr_key.dport = port; + pfr_key.local = NULL; + pfr_key.remote = NULL; + pfr_key.addressfamily = ADDRTYPE_UNSPEC; + + PortFwdRecord *pfr = del234(mgr->forwardings, &pfr_key); + + if (!pfr) + return FALSE; + + logeventf(mgr->cl->logctx, "Closing listening port %s:%d", host, port); + + pfr_free(pfr); + return TRUE; +} + /* * Called when receiving a PORT OPEN from the server to make a * connection to a destination host. diff --git a/sesschan.c b/sesschan.c new file mode 100644 index 00000000..577c5feb --- /dev/null +++ b/sesschan.c @@ -0,0 +1,559 @@ +/* + * Implement the "session" channel type for the SSH server. + */ + +#include +#include +#include +#include + +#include "putty.h" +#include "ssh.h" +#include "sshchan.h" +#include "sshserver.h" + +typedef struct sesschan { + SshChannel *c; + + LogContext *parent_logctx, *child_logctx; + Conf *conf; + + LogPolicy logpolicy; + Seat seat; + + int want_pty; + struct ssh_ttymodes ttymodes; + int wc, hc, wp, hp; + strbuf *termtype; + + int ignoring_input; + int seen_eof, seen_exit; + + Plug xfwd_plug; + int n_x11_sockets; + Socket *x11_sockets[MAX_X11_SOCKETS]; + + Plug agentfwd_plug; + Socket *agentfwd_socket; + + Backend *backend; + + bufchain subsys_input; + + Channel chan; +} sesschan; + +static void sesschan_free(Channel *chan); +static int sesschan_send(Channel *chan, int is_stderr, const void *, int); +static void sesschan_send_eof(Channel *chan); +static char *sesschan_log_close_msg(Channel *chan); +static int sesschan_want_close(Channel *, int, int); +static void sesschan_set_input_wanted(Channel *chan, int wanted); +static int sesschan_run_shell(Channel *chan); +static int sesschan_run_command(Channel *chan, ptrlen command); +static int sesschan_run_subsystem(Channel *chan, ptrlen subsys); +static int sesschan_enable_x11_forwarding( + Channel *chan, int oneshot, ptrlen authproto, ptrlen authdata, + unsigned screen_number); +static int sesschan_enable_agent_forwarding(Channel *chan); +static int sesschan_allocate_pty( + Channel *chan, ptrlen termtype, unsigned width, unsigned height, + unsigned pixwidth, unsigned pixheight, struct ssh_ttymodes modes); +static int sesschan_set_env(Channel *chan, ptrlen var, ptrlen value); +static int sesschan_send_break(Channel *chan, unsigned length); +static int sesschan_send_signal(Channel *chan, ptrlen signame); +static int sesschan_change_window_size( + Channel *chan, unsigned width, unsigned height, + unsigned pixwidth, unsigned pixheight); + +static const struct ChannelVtable sesschan_channelvt = { + sesschan_free, + chan_remotely_opened_confirmation, + chan_remotely_opened_failure, + sesschan_send, + sesschan_send_eof, + sesschan_set_input_wanted, + sesschan_log_close_msg, + sesschan_want_close, + chan_no_exit_status, + chan_no_exit_signal, + chan_no_exit_signal_numeric, + sesschan_run_shell, + sesschan_run_command, + sesschan_run_subsystem, + sesschan_enable_x11_forwarding, + sesschan_enable_agent_forwarding, + sesschan_allocate_pty, + sesschan_set_env, + sesschan_send_break, + sesschan_send_signal, + sesschan_change_window_size, + chan_no_request_response, +}; + +static void sesschan_eventlog(LogPolicy *lp, const char *event) {} +static void sesschan_logging_error(LogPolicy *lp, const char *event) {} +static int sesschan_askappend( + LogPolicy *lp, Filename *filename, + void (*callback)(void *ctx, int result), void *ctx) { return 2; } + +static const LogPolicyVtable sesschan_logpolicy_vt = { + sesschan_eventlog, + sesschan_askappend, + sesschan_logging_error, +}; + +static int sesschan_seat_output(Seat *, int is_stderr, const void *, int); +static int sesschan_seat_eof(Seat *); +static void sesschan_notify_remote_exit(Seat *seat); +static void sesschan_connection_fatal(Seat *seat, const char *message); +static int sesschan_get_window_pixel_size(Seat *seat, int *width, int *height); + +static const SeatVtable sesschan_seat_vt = { + sesschan_seat_output, + sesschan_seat_eof, + nullseat_get_userpass_input, + sesschan_notify_remote_exit, + sesschan_connection_fatal, + nullseat_update_specials_menu, + nullseat_get_ttymode, + nullseat_set_busy_status, + nullseat_verify_ssh_host_key, + nullseat_confirm_weak_crypto_primitive, + nullseat_confirm_weak_cached_hostkey, + nullseat_is_never_utf8, + nullseat_echoedit_update, + nullseat_get_x_display, + nullseat_get_windowid, + sesschan_get_window_pixel_size, +}; + +Channel *sesschan_new(SshChannel *c, LogContext *logctx) +{ + sesschan *sess = snew(sesschan); + memset(sess, 0, sizeof(sesschan)); + + sess->c = c; + sess->chan.vt = &sesschan_channelvt; + sess->chan.initial_fixed_window_size = 0; + sess->parent_logctx = logctx; + + /* Start with a completely default Conf */ + sess->conf = conf_new(); + load_open_settings(NULL, sess->conf); + + /* Set close-on-exit = TRUE to suppress uxpty.c's "[pterm: process + * terminated with status x]" message */ + conf_set_int(sess->conf, CONF_close_on_exit, FORCE_ON); + + sess->seat.vt = &sesschan_seat_vt; + sess->logpolicy.vt = &sesschan_logpolicy_vt; + sess->child_logctx = log_init(&sess->logpolicy, sess->conf); + + bufchain_init(&sess->subsys_input); + + return &sess->chan; +} + +static void sesschan_free(Channel *chan) +{ + sesschan *sess = container_of(chan, sesschan, chan); + int i; + + delete_callbacks_for_context(sess); + conf_free(sess->conf); + if (sess->backend) + backend_free(sess->backend); + bufchain_clear(&sess->subsys_input); + for (i = 0; i < sess->n_x11_sockets; i++) + sk_close(sess->x11_sockets[i]); + if (sess->agentfwd_socket) + sk_close(sess->agentfwd_socket); + + sfree(sess); +} + +static int sesschan_send(Channel *chan, int is_stderr, + const void *data, int length) +{ + sesschan *sess = container_of(chan, sesschan, chan); + + if (!sess->backend || sess->ignoring_input) + return 0; + + return backend_send(sess->backend, data, length); +} + +static void sesschan_send_eof(Channel *chan) +{ + sesschan *sess = container_of(chan, sesschan, chan); + if (sess->backend) + backend_special(sess->backend, SS_EOF, 0); +} + +static char *sesschan_log_close_msg(Channel *chan) +{ + return dupstr("Session channel closed"); +} + +static void sesschan_set_input_wanted(Channel *chan, int wanted) +{ + /* I don't think we need to do anything here */ +} + +static void sesschan_start_backend(sesschan *sess, const char *cmd) +{ + sess->backend = pty_backend_create( + &sess->seat, sess->child_logctx, sess->conf, NULL, cmd, + sess->ttymodes, !sess->want_pty); + backend_size(sess->backend, sess->wc, sess->hc); +} + +int sesschan_run_shell(Channel *chan) +{ + sesschan *sess = container_of(chan, sesschan, chan); + + if (sess->backend) + return FALSE; + + sesschan_start_backend(sess, NULL); + return TRUE; +} + +int sesschan_run_command(Channel *chan, ptrlen command) +{ + sesschan *sess = container_of(chan, sesschan, chan); + + if (sess->backend) + return FALSE; + + char *command_str = mkstr(command); + sesschan_start_backend(sess, command_str); + sfree(command_str); + + return TRUE; +} + +int sesschan_run_subsystem(Channel *chan, ptrlen subsys) +{ + return FALSE; +} + +static void fwd_log(Plug *plug, int type, SockAddr *addr, int port, + const char *error_msg, int error_code) +{ /* don't expect any weirdnesses from a listening socket */ } +static void fwd_closing(Plug *plug, const char *error_msg, int error_code, + int calling_back) +{ /* not here, either */ } + +static int xfwd_accepting(Plug *p, accept_fn_t constructor, accept_ctx_t ctx) +{ + sesschan *sess = container_of(p, sesschan, xfwd_plug); + Plug *plug; + Channel *chan; + Socket *s; + SocketPeerInfo *pi; + const char *err; + + chan = portfwd_raw_new(sess->c->cl, &plug); + s = constructor(ctx, plug); + if ((err = sk_socket_error(s)) != NULL) { + portfwd_raw_free(chan); + return TRUE; + } + pi = sk_peer_info(s); + portfwd_raw_setup(chan, s, ssh_serverside_x11_open(sess->c->cl, chan, pi)); + sk_free_peer_info(pi); + + return FALSE; +} + +static const PlugVtable xfwd_plugvt = { + fwd_log, + fwd_closing, + NULL, /* recv */ + NULL, /* send */ + xfwd_accepting, +}; + +int sesschan_enable_x11_forwarding( + Channel *chan, int oneshot, ptrlen authproto, ptrlen authdata_hex, + unsigned screen_number) +{ + sesschan *sess = container_of(chan, sesschan, chan); + strbuf *authdata_bin; + size_t i; + char screensuffix[32]; + + if (oneshot) + return FALSE; /* not supported */ + + snprintf(screensuffix, sizeof(screensuffix), ".%u", screen_number); + + /* + * Decode the authorisation data from ASCII hex into binary. + */ + if (authdata_hex.len % 2) + return FALSE; /* expected an even number of digits */ + authdata_bin = strbuf_new(); + for (i = 0; i < authdata_hex.len; i += 2) { + const unsigned char *hex = authdata_hex.ptr; + char hexbuf[3]; + + if (!isxdigit(hex[i]) || !isxdigit(hex[i+1])) { + strbuf_free(authdata_bin); + return FALSE; /* not hex */ + } + + hexbuf[0] = hex[i]; + hexbuf[1] = hex[i+1]; + hexbuf[2] = '\0'; + put_byte(authdata_bin, strtoul(hexbuf, NULL, 16)); + } + + sess->xfwd_plug.vt = &xfwd_plugvt; + + sess->n_x11_sockets = platform_make_x11_server( + &sess->xfwd_plug, appname, 10, screensuffix, + authproto, ptrlen_from_strbuf(authdata_bin), + sess->x11_sockets, sess->conf); + + strbuf_free(authdata_bin); + return sess->n_x11_sockets != 0; +} + +static int agentfwd_accepting( + Plug *p, accept_fn_t constructor, accept_ctx_t ctx) +{ + sesschan *sess = container_of(p, sesschan, agentfwd_plug); + Plug *plug; + Channel *chan; + Socket *s; + const char *err; + + chan = portfwd_raw_new(sess->c->cl, &plug); + s = constructor(ctx, plug); + if ((err = sk_socket_error(s)) != NULL) { + portfwd_raw_free(chan); + return TRUE; + } + portfwd_raw_setup(chan, s, ssh_serverside_agent_open(sess->c->cl, chan)); + + return FALSE; +} + +static const PlugVtable agentfwd_plugvt = { + fwd_log, + fwd_closing, + NULL, /* recv */ + NULL, /* send */ + agentfwd_accepting, +}; + +int sesschan_enable_agent_forwarding(Channel *chan) +{ + sesschan *sess = container_of(chan, sesschan, chan); + char *error, *socketname, *dir_prefix; + + dir_prefix = dupprintf("/tmp/%s-agentfwd", appname); + + sess->agentfwd_plug.vt = &agentfwd_plugvt; + sess->agentfwd_socket = platform_make_agent_socket( + &sess->agentfwd_plug, dir_prefix, &error, &socketname); + + sfree(dir_prefix); + + if (sess->agentfwd_socket) { + conf_set_str_str(sess->conf, CONF_environmt, + "SSH_AUTH_SOCK", socketname); + } + + sfree(error); + sfree(socketname); + + return sess->agentfwd_socket != NULL; +} + +int sesschan_allocate_pty( + Channel *chan, ptrlen termtype, unsigned width, unsigned height, + unsigned pixwidth, unsigned pixheight, struct ssh_ttymodes modes) +{ + sesschan *sess = container_of(chan, sesschan, chan); + char *s; + + if (sess->want_pty) + return FALSE; + + s = mkstr(termtype); + conf_set_str(sess->conf, CONF_termtype, s); + sfree(s); + + sess->want_pty = TRUE; + sess->ttymodes = modes; + sess->wc = width; + sess->hc = height; + sess->wp = pixwidth; + sess->hp = pixheight; + + return TRUE; +} + +int sesschan_set_env(Channel *chan, ptrlen var, ptrlen value) +{ + sesschan *sess = container_of(chan, sesschan, chan); + + char *svar = mkstr(var), *svalue = mkstr(value); + conf_set_str_str(sess->conf, CONF_environmt, svar, svalue); + sfree(svar); + sfree(svalue); + + return TRUE; +} + +int sesschan_send_break(Channel *chan, unsigned length) +{ + sesschan *sess = container_of(chan, sesschan, chan); + + if (sess->backend) { + /* We ignore the break length. We could pass it through as the + * 'arg' parameter, and have uxpty.c collect it and pass it on + * to tcsendbreak, but since tcsendbreak in turn assigns + * implementation-defined semantics to _its_ duration + * parameter, this all just sounds too difficult. */ + backend_special(sess->backend, SS_BRK, 0); + return TRUE; + } + return FALSE; +} + +int sesschan_send_signal(Channel *chan, ptrlen signame) +{ + sesschan *sess = container_of(chan, sesschan, chan); + + /* Start with a code that definitely isn't a signal (or indeed a + * special command at all), to indicate 'nothing matched'. */ + SessionSpecialCode code = SS_EXITMENU; + + #define SIGNAL_SUB(name) \ + if (ptrlen_eq_string(signame, #name)) code = SS_SIG ## name; + #define SIGNAL_MAIN(name, text) SIGNAL_SUB(name) + #include "sshsignals.h" + #undef SIGNAL_MAIN + #undef SIGNAL_SUB + + if (code == SS_EXITMENU) + return FALSE; + + backend_special(sess->backend, code, 0); + return TRUE; +} + +int sesschan_change_window_size( + Channel *chan, unsigned width, unsigned height, + unsigned pixwidth, unsigned pixheight) +{ + sesschan *sess = container_of(chan, sesschan, chan); + + if (!sess->want_pty) + return FALSE; + + sess->wc = width; + sess->hc = height; + sess->wp = pixwidth; + sess->hp = pixheight; + + if (sess->backend) + backend_size(sess->backend, sess->wc, sess->hc); + + return TRUE; +} + +static int sesschan_seat_output( + Seat *seat, int is_stderr, const void *data, int len) +{ + sesschan *sess = container_of(seat, sesschan, seat); + return sshfwd_write_ext(sess->c, is_stderr, data, len); +} + +static void sesschan_check_close_callback(void *vctx) +{ + sesschan *sess = (sesschan *)vctx; + + /* + * Once we've seen incoming EOF from the backend (aka EIO from the + * pty master) and also passed on the process's exit status, we + * should proactively initiate closure of the session channel. + */ + if (sess->seen_eof && sess->seen_exit) + sshfwd_initiate_close(sess->c, NULL); +} + +static int sesschan_want_close(Channel *chan, int seen_eof, int rcvd_eof) +{ + sesschan *sess = container_of(chan, sesschan, chan); + + /* + * Similarly to above, we don't want to initiate channel closure + * until we've sent the process's exit status, _even_ if EOF of + * the actual data stream has happened in both directions. + */ + return (sess->seen_eof && sess->seen_exit); +} + +static int sesschan_seat_eof(Seat *seat) +{ + sesschan *sess = container_of(seat, sesschan, seat); + + sshfwd_write_eof(sess->c); + sess->seen_eof = TRUE; + + queue_toplevel_callback(sesschan_check_close_callback, sess); + return TRUE; +} + +static void sesschan_notify_remote_exit(Seat *seat) +{ + sesschan *sess = container_of(seat, sesschan, seat); + ptrlen signame; + char *sigmsg; + + if (!sess->backend) + return; + + signame = pty_backend_exit_signame(sess->backend, &sigmsg); + if (signame.len) { + if (!sigmsg) + sigmsg = dupstr(""); + + sshfwd_send_exit_signal( + sess->c, signame, FALSE, ptrlen_from_asciz(sigmsg)); + + sfree(sigmsg); + } else { + sshfwd_send_exit_status(sess->c, backend_exitcode(sess->backend)); + } + + sess->seen_exit = TRUE; + queue_toplevel_callback(sesschan_check_close_callback, sess); +} + +static void sesschan_connection_fatal(Seat *seat, const char *message) +{ + sesschan *sess = container_of(seat, sesschan, seat); + + /* Closest translation I can think of */ + sshfwd_send_exit_signal( + sess->c, PTRLEN_LITERAL("HUP"), FALSE, ptrlen_from_asciz(message)); + + sess->ignoring_input = TRUE; +} + +static int sesschan_get_window_pixel_size(Seat *seat, int *width, int *height) +{ + sesschan *sess = container_of(seat, sesschan, seat); + + *width = sess->wp; + *height = sess->hp; + + return TRUE; +} diff --git a/ssh.c b/ssh.c index 1a881c80..251634f1 100644 --- a/ssh.c +++ b/ssh.c @@ -180,7 +180,7 @@ static void ssh_got_ssh_version(struct ssh_version_receiver *rcv, int is_simple = (conf_get_int(ssh->conf, CONF_ssh_simple) && !ssh->connshare); - ssh->bpp = ssh2_bpp_new(ssh->logctx, &ssh->stats); + ssh->bpp = ssh2_bpp_new(ssh->logctx, &ssh->stats, FALSE); ssh_connect_bpp(ssh); #ifndef NO_GSSAPI @@ -246,7 +246,7 @@ static void ssh_got_ssh_version(struct ssh_version_receiver *rcv, ssh_verstring_get_local(old_bpp), ssh_verstring_get_remote(old_bpp), &ssh->gss_state, - &ssh->stats, transport_child_layer); + &ssh->stats, transport_child_layer, FALSE); ssh_connect_ppl(ssh, ssh->base_layer); if (userauth_layer) @@ -717,7 +717,8 @@ static const char *connect_to_host(Ssh *ssh, const char *host, int port, ssh->version_receiver.got_ssh_version = ssh_got_ssh_version; ssh->bpp = ssh_verstring_new( ssh->conf, ssh->logctx, ssh->bare_connection, - ssh->version == 1 ? "1.5" : "2.0", &ssh->version_receiver, "PuTTY"); + ssh->version == 1 ? "1.5" : "2.0", &ssh->version_receiver, + FALSE, "PuTTY"); ssh_connect_bpp(ssh); queue_idempotent_callback(&ssh->bpp->ic_in_raw); diff --git a/ssh.h b/ssh.h index 0014a502..439eebb1 100644 --- a/ssh.h +++ b/ssh.h @@ -222,6 +222,12 @@ struct ConnectionLayerVtable { /* Initiate opening of a 'session'-type channel */ SshChannel *(*session_open)(ConnectionLayer *cl, Channel *chan); + /* Open outgoing channels for X and agent forwarding. (Used in the + * SSH server.) */ + SshChannel *(*serverside_x11_open)(ConnectionLayer *cl, Channel *chan, + const SocketPeerInfo *pi); + SshChannel *(*serverside_agent_open)(ConnectionLayer *cl, Channel *chan); + /* Add an X11 display for ordinary X forwarding */ struct X11FakeAuth *(*add_x11_display)( ConnectionLayer *cl, int authtype, struct X11Display *x11disp); @@ -300,6 +306,10 @@ struct ConnectionLayer { #define ssh_rportfwd_remove(cl, rpf) ((cl)->vt->rportfwd_remove(cl, rpf)) #define ssh_lportfwd_open(cl, h, p, desc, pi, chan) \ ((cl)->vt->lportfwd_open(cl, h, p, desc, pi, chan)) +#define ssh_serverside_x11_open(cl, chan, pi) \ + ((cl)->vt->serverside_x11_open(cl, chan, pi)) +#define ssh_serverside_agent_open(cl, chan) \ + ((cl)->vt->serverside_agent_open(cl, chan)) #define ssh_session_open(cl, chan) \ ((cl)->vt->session_open(cl, chan)) #define ssh_add_x11_display(cl, auth, disp) \ @@ -333,6 +343,8 @@ struct ConnectionLayer { #define ssh_enable_agent_fwd(cl) ((cl)->vt->enable_agent_fwd(cl)) #define ssh_set_wants_user_input(cl, wanted) \ ((cl)->vt->set_wants_user_input(cl, wanted)) +#define ssh_setup_server_x_forwarding(cl, conf, ap, ad, scr) \ + ((cl)->vt->setup_server_x_forwarding(cl, conf, ap, ad, scr)) /* Exports from portfwd.c */ PortFwdManager *portfwdmgr_new(ConnectionLayer *cl); @@ -343,6 +355,12 @@ void portfwdmgr_close_all(PortFwdManager *mgr); char *portfwdmgr_connect(PortFwdManager *mgr, Channel **chan_ret, char *hostname, int port, SshChannel *c, int addressfamily); +int portfwdmgr_listen(PortFwdManager *mgr, const char *host, int port, + const char *keyhost, int keyport, Conf *conf); +int portfwdmgr_unlisten(PortFwdManager *mgr, const char *host, int port); +Channel *portfwd_raw_new(ConnectionLayer *cl, Plug **plug); +void portfwd_raw_free(Channel *pfchan); +void portfwd_raw_setup(Channel *pfchan, Socket *s, SshChannel *sc); Socket *platform_make_agent_socket(Plug *plug, const char *dirprefix, char **error, char **name); diff --git a/ssh1bpp.c b/ssh1bpp.c index 2f306dd0..59fe5104 100644 --- a/ssh1bpp.c +++ b/ssh1bpp.c @@ -89,6 +89,21 @@ void ssh1_bpp_new_cipher(BinaryPacketProtocol *bpp, } } +void ssh1_bpp_start_compression(BinaryPacketProtocol *bpp) +{ + struct ssh1_bpp_state *s; + assert(bpp->vt == &ssh1_bpp_vtable); + s = container_of(bpp, struct ssh1_bpp_state, bpp); + + assert(!s->compctx); + assert(!s->decompctx); + + s->compctx = ssh_compressor_new(&ssh_zlib); + s->decompctx = ssh_decompressor_new(&ssh_zlib); + + bpp_logevent(("Started zlib (RFC1950) compression")); +} + #define BPP_READ(ptr, len) do \ { \ crMaybeWaitUntilV(s->bpp.input_eof || \ @@ -221,13 +236,7 @@ static void ssh1_bpp_handle_input(BinaryPacketProtocol *bpp) * If the response was positive, start * compression. */ - assert(!s->compctx); - assert(!s->decompctx); - - s->compctx = ssh_compressor_new(&ssh_zlib); - s->decompctx = ssh_decompressor_new(&ssh_zlib); - - bpp_logevent(("Started zlib (RFC1950) compression")); + ssh1_bpp_start_compression(&s->bpp); } /* diff --git a/ssh1connection-client.c b/ssh1connection-client.c index 3018b68d..db2d5b23 100644 --- a/ssh1connection-client.c +++ b/ssh1connection-client.c @@ -516,3 +516,16 @@ struct ssh_rportfwd *ssh1_rportfwd_alloc( return rpf; } + +SshChannel *ssh1_serverside_x11_open( + ConnectionLayer *cl, Channel *chan, const SocketPeerInfo *pi) +{ + assert(FALSE && "Should never be called in the client"); + return NULL; +} + +SshChannel *ssh1_serverside_agent_open(ConnectionLayer *cl, Channel *chan) +{ + assert(FALSE && "Should never be called in the client"); + return NULL; +} diff --git a/ssh1connection-server.c b/ssh1connection-server.c new file mode 100644 index 00000000..01ea6f8d --- /dev/null +++ b/ssh1connection-server.c @@ -0,0 +1,355 @@ +/* + * Server-specific parts of the SSH-1 connection layer. + */ + +#include + +#include "putty.h" +#include "ssh.h" +#include "sshbpp.h" +#include "sshppl.h" +#include "sshchan.h" +#include "sshcr.h" +#include "ssh1connection.h" +#include "sshserver.h" + +static int ssh1sesschan_write(SshChannel *c, int is_stderr, const void *, int); +static void ssh1sesschan_write_eof(SshChannel *c); +static void ssh1sesschan_initiate_close(SshChannel *c, const char *err); +static void ssh1sesschan_send_exit_status(SshChannel *c, int status); +static void ssh1sesschan_send_exit_signal( + SshChannel *c, ptrlen signame, int core_dumped, ptrlen msg); + +static const struct SshChannelVtable ssh1sesschan_vtable = { + ssh1sesschan_write, + ssh1sesschan_write_eof, + ssh1sesschan_initiate_close, + NULL /* unthrottle */, + NULL /* get_conf */, + NULL /* window_override_removed is only used by SSH-2 sharing */, + NULL /* x11_sharing_handover, likewise */, + ssh1sesschan_send_exit_status, + ssh1sesschan_send_exit_signal, + NULL /* send_exit_signal_numeric */, + NULL /* request_x11_forwarding */, + NULL /* request_agent_forwarding */, + NULL /* request_pty */, + NULL /* send_env_var */, + NULL /* start_shell */, + NULL /* start_command */, + NULL /* start_subsystem */, + NULL /* send_serial_break */, + NULL /* send_signal */, + NULL /* send_terminal_size_change */, + NULL /* hint_channel_is_simple */, +}; + +void ssh1_connection_direction_specific_setup( + struct ssh1_connection_state *s) +{ + if (!s->mainchan_chan) { + s->mainchan_sc.vt = &ssh1sesschan_vtable; + s->mainchan_sc.cl = &s->cl; + s->mainchan_chan = sesschan_new(&s->mainchan_sc, s->ppl.logctx); + } +} + +int ssh1_handle_direction_specific_packet( + struct ssh1_connection_state *s, PktIn *pktin) +{ + PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */ + PktOut *pktout; + struct ssh1_channel *c; + unsigned remid; + ptrlen host, cmd, data; + char *host_str, *err; + int port, listenport, success; + + switch (pktin->type) { + case SSH1_CMSG_EXEC_SHELL: + if (s->finished_setup) + goto unexpected_setup_packet; + + ppl_logevent(("Client requested a shell")); + chan_run_shell(s->mainchan_chan); + s->finished_setup = TRUE; + return TRUE; + + case SSH1_CMSG_EXEC_CMD: + if (s->finished_setup) + goto unexpected_setup_packet; + + cmd = get_string(pktin); + ppl_logevent(("Client sent command '%.*s'", PTRLEN_PRINTF(cmd))); + chan_run_command(s->mainchan_chan, cmd); + s->finished_setup = TRUE; + return TRUE; + + case SSH1_CMSG_REQUEST_COMPRESSION: + if (s->compressing) { + pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_SMSG_FAILURE); + pq_push(s->ppl.out_pq, pktout); + } else { + pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_SMSG_SUCCESS); + pq_push(s->ppl.out_pq, pktout); + /* Synchronous run of output formatting, to ensure that + * success packet is converted into wire format before we + * start compressing */ + ssh_bpp_handle_output(s->ppl.bpp); + /* And now ensure that the _next_ packet will be the first + * compressed one. */ + ssh1_bpp_start_compression(s->ppl.bpp); + s->compressing = TRUE; + } + + return TRUE; + + case SSH1_CMSG_REQUEST_PTY: + if (s->finished_setup) + goto unexpected_setup_packet; + { + ptrlen termtype = get_string(pktin); + unsigned height = get_uint32(pktin); + unsigned width = get_uint32(pktin); + unsigned pixwidth = get_uint32(pktin); + unsigned pixheight = get_uint32(pktin); + struct ssh_ttymodes modes = read_ttymodes_from_packet( + BinarySource_UPCAST(pktin), 1); + + if (get_err(pktin)) { + ppl_logevent(("Unable to decode pty request packet")); + success = FALSE; + } else if (!chan_allocate_pty( + s->mainchan_chan, termtype, width, height, + pixwidth, pixheight, modes)) { + ppl_logevent(("Unable to allocate a pty")); + success = FALSE; + } else { + success = TRUE; + } + } + + pktout = ssh_bpp_new_pktout( + s->ppl.bpp, (success ? SSH1_SMSG_SUCCESS : SSH1_SMSG_FAILURE)); + pq_push(s->ppl.out_pq, pktout); + return TRUE; + + case SSH1_CMSG_PORT_FORWARD_REQUEST: + if (s->finished_setup) + goto unexpected_setup_packet; + + listenport = toint(get_uint32(pktin)); + host = get_string(pktin); + port = toint(get_uint32(pktin)); + + ppl_logevent(("Client requested port %d forward to %.*s:%d", + listenport, PTRLEN_PRINTF(host), port)); + + host_str = mkstr(host); + success = portfwdmgr_listen( + s->portfwdmgr, NULL, listenport, host_str, port, s->conf); + sfree(host_str); + + pktout = ssh_bpp_new_pktout( + s->ppl.bpp, (success ? SSH1_SMSG_SUCCESS : SSH1_SMSG_FAILURE)); + pq_push(s->ppl.out_pq, pktout); + return TRUE; + + case SSH1_CMSG_X11_REQUEST_FORWARDING: + if (s->finished_setup) + goto unexpected_setup_packet; + + { + ptrlen authproto = get_string(pktin); + ptrlen authdata = get_string(pktin); + unsigned screen_number = 0; + if (s->remote_protoflags & SSH1_PROTOFLAG_SCREEN_NUMBER) + screen_number = get_uint32(pktin); + + success = chan_enable_x11_forwarding( + s->mainchan_chan, FALSE, authproto, authdata, screen_number); + } + + pktout = ssh_bpp_new_pktout( + s->ppl.bpp, (success ? SSH1_SMSG_SUCCESS : SSH1_SMSG_FAILURE)); + pq_push(s->ppl.out_pq, pktout); + return TRUE; + + case SSH1_CMSG_AGENT_REQUEST_FORWARDING: + if (s->finished_setup) + goto unexpected_setup_packet; + + success = chan_enable_agent_forwarding(s->mainchan_chan); + + pktout = ssh_bpp_new_pktout( + s->ppl.bpp, (success ? SSH1_SMSG_SUCCESS : SSH1_SMSG_FAILURE)); + pq_push(s->ppl.out_pq, pktout); + return TRUE; + + case SSH1_CMSG_STDIN_DATA: + data = get_string(pktin); + chan_send(s->mainchan_chan, FALSE, data.ptr, data.len); + return TRUE; + + case SSH1_CMSG_EOF: + chan_send_eof(s->mainchan_chan); + return TRUE; + + case SSH1_CMSG_WINDOW_SIZE: + return TRUE; + + case SSH1_MSG_PORT_OPEN: + remid = get_uint32(pktin); + host = get_string(pktin); + port = toint(get_uint32(pktin)); + + host_str = mkstr(host); + + ppl_logevent(("Received request to connect to port %s:%d", + host_str, port)); + c = snew(struct ssh1_channel); + c->connlayer = s; + err = portfwdmgr_connect( + s->portfwdmgr, &c->chan, host_str, port, + &c->sc, ADDRTYPE_UNSPEC); + + sfree(host_str); + + if (err) { + ppl_logevent(("Port open failed: %s", err)); + sfree(err); + ssh1_channel_free(c); + pktout = ssh_bpp_new_pktout( + s->ppl.bpp, SSH1_MSG_CHANNEL_OPEN_FAILURE); + put_uint32(pktout, remid); + pq_push(s->ppl.out_pq, pktout); + } else { + ssh1_channel_init(c); + c->remoteid = remid; + c->halfopen = FALSE; + pktout = ssh_bpp_new_pktout( + s->ppl.bpp, SSH1_MSG_CHANNEL_OPEN_CONFIRMATION); + put_uint32(pktout, c->remoteid); + put_uint32(pktout, c->localid); + pq_push(s->ppl.out_pq, pktout); + ppl_logevent(("Forwarded port opened successfully")); + } + + return TRUE; + + default: + return FALSE; + } + + unexpected_setup_packet: + ssh_proto_error(s->ppl.ssh, "Received unexpected setup packet after the " + "setup phase, type %d (%s)", pktin->type, + ssh1_pkt_type(pktin->type)); + /* FIXME: ensure caller copes with us just having freed the whole layer */ + return TRUE; +} + +SshChannel *ssh1_session_open(ConnectionLayer *cl, Channel *chan) +{ + assert(FALSE && "Should never be called in the server"); +} + +struct ssh_rportfwd *ssh1_rportfwd_alloc( + ConnectionLayer *cl, + const char *shost, int sport, const char *dhost, int dport, + int addressfamily, const char *log_description, PortFwdRecord *pfr, + ssh_sharing_connstate *share_ctx) +{ + assert(FALSE && "Should never be called in the server"); + return NULL; +} + +static int ssh1sesschan_write(SshChannel *sc, int is_stderr, + const void *data, int len) +{ + struct ssh1_connection_state *s = + container_of(sc, struct ssh1_connection_state, mainchan_sc); + PktOut *pktout; + + pktout = ssh_bpp_new_pktout( + s->ppl.bpp, + (is_stderr ? SSH1_SMSG_STDERR_DATA : SSH1_SMSG_STDOUT_DATA)); + put_string(pktout, data, len); + pq_push(s->ppl.out_pq, pktout); + + return 0; +} + +static void ssh1sesschan_write_eof(SshChannel *sc) +{ + /* SSH-1 can't represent server-side EOF */ + /* FIXME: some kind of check-termination system, whereby once this has been called _and_ we've had an exit status _and_ we've got no other channels open, we send the actual EXIT_STATUS message */ +} + +static void ssh1sesschan_initiate_close(SshChannel *sc, const char *err) +{ + /* SSH-1 relies on the client to close the connection in the end */ +} + +static void ssh1sesschan_send_exit_status(SshChannel *sc, int status) +{ + struct ssh1_connection_state *s = + container_of(sc, struct ssh1_connection_state, mainchan_sc); + PktOut *pktout; + + pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_SMSG_EXIT_STATUS); + put_uint32(pktout, status); + pq_push(s->ppl.out_pq, pktout); +} + +static void ssh1sesschan_send_exit_signal( + SshChannel *sc, ptrlen signame, int core_dumped, ptrlen msg) +{ + /* SSH-1 has no separate representation for signals */ + ssh1sesschan_send_exit_status(sc, 128); +} + +SshChannel *ssh1_serverside_x11_open( + ConnectionLayer *cl, Channel *chan, const SocketPeerInfo *pi) +{ + struct ssh1_connection_state *s = + container_of(cl, struct ssh1_connection_state, cl); + PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */ + struct ssh1_channel *c = snew(struct ssh1_channel); + PktOut *pktout; + + c->connlayer = s; + ssh1_channel_init(c); + c->halfopen = TRUE; + c->chan = chan; + + ppl_logevent(("Forwarding X11 connection to client")); + + pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_SMSG_X11_OPEN); + put_uint32(pktout, c->localid); + pq_push(s->ppl.out_pq, pktout); + + return &c->sc; +} + +SshChannel *ssh1_serverside_agent_open(ConnectionLayer *cl, Channel *chan) +{ + struct ssh1_connection_state *s = + container_of(cl, struct ssh1_connection_state, cl); + PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */ + struct ssh1_channel *c = snew(struct ssh1_channel); + PktOut *pktout; + + c->connlayer = s; + ssh1_channel_init(c); + c->halfopen = TRUE; + c->chan = chan; + + ppl_logevent(("Forwarding agent connection to client")); + + pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_SMSG_AGENT_OPEN); + put_uint32(pktout, c->localid); + pq_push(s->ppl.out_pq, pktout); + + return &c->sc; +} diff --git a/ssh1connection.c b/ssh1connection.c index d7c9144d..a64ccb3d 100644 --- a/ssh1connection.c +++ b/ssh1connection.c @@ -69,6 +69,8 @@ static const struct ConnectionLayerVtable ssh1_connlayer_vtable = { ssh1_rportfwd_remove, ssh1_lportfwd_open, ssh1_session_open, + ssh1_serverside_x11_open, + ssh1_serverside_agent_open, ssh1_add_x11_display, NULL /* add_sharing_x11_display */, NULL /* remove_sharing_x11_display */, @@ -212,12 +214,14 @@ static void ssh1_connection_free(PacketProtocolLayer *ppl) sfree(s); } -void ssh1_connection_set_local_protoflags(PacketProtocolLayer *ppl, int flags) +void ssh1_connection_set_protoflags(PacketProtocolLayer *ppl, + int local, int remote) { assert(ppl->vt == &ssh1_connection_vtable); struct ssh1_connection_state *s = container_of(ppl, struct ssh1_connection_state, ppl); - s->local_protoflags = flags; + s->local_protoflags = local; + s->remote_protoflags = remote; } static int ssh1_connection_filter_queue(struct ssh1_connection_state *s) diff --git a/ssh1connection.h b/ssh1connection.h index c55a002d..7d5194da 100644 --- a/ssh1connection.h +++ b/ssh1connection.h @@ -8,7 +8,7 @@ struct ssh1_connection_state { Ssh *ssh; Conf *conf; - int local_protoflags; + int local_protoflags, remote_protoflags; tree234 *channels; /* indexed by local id */ @@ -49,6 +49,8 @@ struct ssh1_connection_state { */ struct outstanding_succfail *succfail_head, *succfail_tail; + int compressing; /* used in server mode only */ + ConnectionLayer cl; PacketProtocolLayer ppl; }; @@ -105,6 +107,9 @@ struct ssh_rportfwd *ssh1_rportfwd_alloc( const char *shost, int sport, const char *dhost, int dport, int addressfamily, const char *log_description, PortFwdRecord *pfr, ssh_sharing_connstate *share_ctx); +SshChannel *ssh1_serverside_x11_open( + ConnectionLayer *cl, Channel *chan, const SocketPeerInfo *pi); +SshChannel *ssh1_serverside_agent_open(ConnectionLayer *cl, Channel *chan); void ssh1_connection_direction_specific_setup( struct ssh1_connection_state *s); diff --git a/ssh1login-server.c b/ssh1login-server.c new file mode 100644 index 00000000..26f8f730 --- /dev/null +++ b/ssh1login-server.c @@ -0,0 +1,376 @@ +/* + * Packet protocol layer for the SSH-1 login phase, from the server side. + */ + +#include + +#include "putty.h" +#include "ssh.h" +#include "sshbpp.h" +#include "sshppl.h" +#include "sshcr.h" +#include "sshserver.h" + +struct ssh1_login_server_state { + int crState; + + PacketProtocolLayer *successor_layer; + + int remote_protoflags; + int local_protoflags; + unsigned long supported_ciphers_mask, supported_auths_mask; + unsigned cipher_type; + + unsigned char cookie[8]; + unsigned char session_key[32]; + unsigned char session_id[16]; + char *username_str; + ptrlen username; + + struct RSAKey *servkey, *hostkey; + int servkey_generated_here; + Bignum sesskey; + + AuthPolicy *authpolicy; + unsigned ap_methods, current_method; + unsigned char auth_rsa_expected_response[16]; + struct RSAKey *authkey; + int auth_successful; + + PacketProtocolLayer ppl; +}; + +static void ssh1_login_server_free(PacketProtocolLayer *); +static void ssh1_login_server_process_queue(PacketProtocolLayer *); + +static int ssh1_login_server_get_specials( + PacketProtocolLayer *ppl, add_special_fn_t add_special, + void *ctx) { return FALSE; } +static void ssh1_login_server_special_cmd(PacketProtocolLayer *ppl, + SessionSpecialCode code, int arg) {} +static int ssh1_login_server_want_user_input( + PacketProtocolLayer *ppl) { return FALSE; } +static void ssh1_login_server_got_user_input(PacketProtocolLayer *ppl) {} +static void ssh1_login_server_reconfigure( + PacketProtocolLayer *ppl, Conf *conf) {} + +static const struct PacketProtocolLayerVtable ssh1_login_server_vtable = { + ssh1_login_server_free, + ssh1_login_server_process_queue, + ssh1_login_server_get_specials, + ssh1_login_server_special_cmd, + ssh1_login_server_want_user_input, + ssh1_login_server_got_user_input, + ssh1_login_server_reconfigure, + NULL /* no layer names in SSH-1 */, +}; + +static void no_progress(void *param, int action, int phase, int iprogress) {} + +PacketProtocolLayer *ssh1_login_server_new( + PacketProtocolLayer *successor_layer, struct RSAKey *hostkey, + AuthPolicy *authpolicy) +{ + struct ssh1_login_server_state *s = snew(struct ssh1_login_server_state); + memset(s, 0, sizeof(*s)); + s->ppl.vt = &ssh1_login_server_vtable; + + s->hostkey = hostkey; + s->authpolicy = authpolicy; + + s->successor_layer = successor_layer; + return &s->ppl; +} + +static void ssh1_login_server_free(PacketProtocolLayer *ppl) +{ + struct ssh1_login_server_state *s = + container_of(ppl, struct ssh1_login_server_state, ppl); + + if (s->successor_layer) + ssh_ppl_free(s->successor_layer); + + if (s->servkey_generated_here && s->servkey) { + freersakey(s->servkey); + sfree(s->servkey); + } + + smemclr(s->session_key, sizeof(s->session_key)); + sfree(s->username_str); + + sfree(s); +} + +static int ssh1_login_server_filter_queue(struct ssh1_login_server_state *s) +{ + return ssh1_common_filter_queue(&s->ppl); +} + +static PktIn *ssh1_login_server_pop(struct ssh1_login_server_state *s) +{ + if (ssh1_login_server_filter_queue(s)) + return NULL; + return pq_pop(s->ppl.in_pq); +} + +static void ssh1_login_server_process_queue(PacketProtocolLayer *ppl) +{ + struct ssh1_login_server_state *s = + container_of(ppl, struct ssh1_login_server_state, ppl); + PktIn *pktin; + PktOut *pktout; + int i; + + /* Filter centrally handled messages off the front of the queue on + * every entry to this coroutine, no matter where we're resuming + * from, even if we're _not_ looping on pq_pop. That way we can + * still proactively handle those messages even if we're waiting + * for a user response. */ + if (ssh1_login_server_filter_queue(s)) + return; + + crBegin(s->crState); + + if (!s->servkey) { + int server_key_bits = s->hostkey->bytes - 256; + if (server_key_bits < 512) + server_key_bits = s->hostkey->bytes + 256; + s->servkey = snew(struct RSAKey); + rsa_generate(s->servkey, server_key_bits, no_progress, NULL); + s->servkey->comment = NULL; + s->servkey_generated_here = TRUE; + } + + s->local_protoflags = SSH1_PROTOFLAGS_SUPPORTED; + /* FIXME: ability to configure this to a subset */ + s->supported_ciphers_mask = ((1U << SSH_CIPHER_3DES) | + (1U << SSH_CIPHER_BLOWFISH) | + (1U << SSH_CIPHER_DES)); + s->supported_auths_mask = 0; + s->ap_methods = auth_methods(s->authpolicy); + if (s->ap_methods & AUTHMETHOD_PASSWORD) + s->supported_auths_mask |= (1U << SSH1_AUTH_PASSWORD); + if (s->ap_methods & AUTHMETHOD_PUBLICKEY) + s->supported_auths_mask |= (1U << SSH1_AUTH_RSA); + /* FIXME: TIS, CCARD */ + + for (i = 0; i < 8; i++) + s->cookie[i] = random_byte(); + + pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_SMSG_PUBLIC_KEY); + put_data(pktout, s->cookie, 8); + rsa_ssh1_public_blob(BinarySink_UPCAST(pktout), + s->servkey, RSA_SSH1_EXPONENT_FIRST); + rsa_ssh1_public_blob(BinarySink_UPCAST(pktout), + s->hostkey, RSA_SSH1_EXPONENT_FIRST); + put_uint32(pktout, s->local_protoflags); + put_uint32(pktout, s->supported_ciphers_mask); + put_uint32(pktout, s->supported_auths_mask); + pq_push(s->ppl.out_pq, pktout); + + crMaybeWaitUntilV((pktin = ssh1_login_server_pop(s)) != NULL); + if (pktin->type != SSH1_CMSG_SESSION_KEY) { + ssh_proto_error(s->ppl.ssh, "Received unexpected packet in response" + " to initial public key packet, type %d (%s)", + pktin->type, ssh1_pkt_type(pktin->type)); + return; + } + + { + ptrlen client_cookie; + s->cipher_type = get_byte(pktin); + client_cookie = get_data(pktin, 8); + s->sesskey = get_mp_ssh1(pktin); + s->remote_protoflags = get_uint32(pktin); + + if (get_err(pktin)) { + ssh_proto_error(s->ppl.ssh, "Unable to parse session key packet"); + return; + } + if (!ptrlen_eq_ptrlen(client_cookie, make_ptrlen(s->cookie, 8))) { + ssh_proto_error(s->ppl.ssh, + "Client sent incorrect anti-spoofing cookie"); + return; + } + } + if (s->cipher_type >= 32 || + !((s->supported_ciphers_mask >> s->cipher_type) & 1)) { + ssh_proto_error(s->ppl.ssh, "Client selected an unsupported cipher"); + return; + } + + { + struct RSAKey *smaller, *larger; + strbuf *data = strbuf_new(); + + if (bignum_bitcount(s->hostkey->modulus) > + bignum_bitcount(s->servkey->modulus)) { + larger = s->hostkey; + smaller = s->servkey; + } else { + smaller = s->hostkey; + larger = s->servkey; + } + + if (rsa_ssh1_decrypt_pkcs1(s->sesskey, larger, data)) { + freebn(s->sesskey); + s->sesskey = bignum_from_bytes(data->u, data->len); + data->len = 0; + if (rsa_ssh1_decrypt_pkcs1(s->sesskey, smaller, data) && + data->len == sizeof(s->session_key)) { + memcpy(s->session_key, data->u, sizeof(s->session_key)); + freebn(s->sesskey); + s->sesskey = NULL; /* indicates success */ + } + } + + strbuf_free(data); + } + if (s->sesskey) { + ssh_proto_error(s->ppl.ssh, "Failed to decrypt session key"); + return; + } + + ssh1_compute_session_id(s->session_id, s->cookie, s->hostkey, s->servkey); + + for (i = 0; i < 16; i++) + s->session_key[i] ^= s->session_id[i]; + + { + const struct ssh1_cipheralg *cipher = + (s->cipher_type == SSH_CIPHER_BLOWFISH ? &ssh1_blowfish : + s->cipher_type == SSH_CIPHER_DES ? &ssh1_des : &ssh1_3des); + ssh1_bpp_new_cipher(s->ppl.bpp, cipher, s->session_key); + } + + pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_SMSG_SUCCESS); + pq_push(s->ppl.out_pq, pktout); + + crMaybeWaitUntilV((pktin = ssh1_login_server_pop(s)) != NULL); + if (pktin->type != SSH1_CMSG_USER) { + ssh_proto_error(s->ppl.ssh, "Received unexpected packet while " + "expecting username, type %d (%s)", + pktin->type, ssh1_pkt_type(pktin->type)); + return; + } + s->username = get_string(pktin); + s->username.ptr = s->username_str = mkstr(s->username); + ppl_logevent(("Received username '%.*s'", PTRLEN_PRINTF(s->username))); + + s->auth_successful = auth_none(s->authpolicy, s->username); + while (1) { + /* Signal failed authentication */ + pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_SMSG_FAILURE); + pq_push(s->ppl.out_pq, pktout); + + crMaybeWaitUntilV((pktin = ssh1_login_server_pop(s)) != NULL); + if (pktin->type == SSH1_CMSG_AUTH_PASSWORD) { + s->current_method = AUTHMETHOD_PASSWORD; + if (!(s->ap_methods & s->current_method)) + continue; + + ptrlen password = get_string(pktin); + + /* Tolerate historic traffic-analysis defence of NUL + + * garbage on the end of the binary password string */ + char *nul = memchr(password.ptr, '\0', password.len); + if (nul) + password.len = (const char *)nul - (const char *)password.ptr; + + if (auth_password(s->authpolicy, s->username, password)) + goto auth_success; + } else if (pktin->type == SSH1_CMSG_AUTH_RSA) { + s->current_method = AUTHMETHOD_PUBLICKEY; + if (!(s->ap_methods & s->current_method)) + continue; + + { + Bignum modulus = get_mp_ssh1(pktin); + s->authkey = auth_publickey_ssh1( + s->authpolicy, s->username, modulus); + freebn(modulus); + } + + if (!s->authkey) + continue; + + if (s->authkey->bytes < 32) { + ppl_logevent(("Auth key far too small")); + continue; + } + + { + unsigned char *rsabuf = + snewn(s->authkey->bytes, unsigned char); + struct MD5Context md5c; + + for (i = 0; i < 32; i++) + rsabuf[i] = random_byte(); + + MD5Init(&md5c); + put_data(&md5c, rsabuf, 32); + put_data(&md5c, s->session_id, 16); + MD5Final(s->auth_rsa_expected_response, &md5c); + + if (!rsa_ssh1_encrypt(rsabuf, 32, s->authkey)) { + sfree(rsabuf); + ppl_logevent(("Failed to encrypt auth challenge")); + continue; + } + + Bignum bn = bignum_from_bytes(rsabuf, s->authkey->bytes); + smemclr(rsabuf, s->authkey->bytes); + sfree(rsabuf); + + pktout = ssh_bpp_new_pktout( + s->ppl.bpp, SSH1_SMSG_AUTH_RSA_CHALLENGE); + put_mp_ssh1(pktout, bn); + pq_push(s->ppl.out_pq, pktout); + + freebn(bn); + } + + crMaybeWaitUntilV((pktin = ssh1_login_server_pop(s)) != NULL); + if (pktin->type != SSH1_CMSG_AUTH_RSA_RESPONSE) { + ssh_proto_error(s->ppl.ssh, "Received unexpected packet in " + "response to RSA auth challenge, type %d (%s)", + pktin->type, ssh1_pkt_type(pktin->type)); + return; + } + + { + ptrlen response = get_data(pktin, 16); + ptrlen expected = make_ptrlen( + s->auth_rsa_expected_response, 16); + if (!ptrlen_eq_ptrlen(response, expected)) { + ppl_logevent(("Wrong response to auth challenge")); + continue; + } + } + + goto auth_success; + } + } + + auth_success: + if (!auth_successful(s->authpolicy, s->username, s->current_method)) { + ssh_sw_abort(s->ppl.ssh, "Multiple authentications required but SSH-1" + " cannot perform them"); + return; + } + + /* Signal successful authentication */ + pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_SMSG_SUCCESS); + pq_push(s->ppl.out_pq, pktout); + + ssh1_connection_set_protoflags( + s->successor_layer, s->local_protoflags, s->remote_protoflags); + { + PacketProtocolLayer *successor = s->successor_layer; + s->successor_layer = NULL; /* avoid freeing it ourself */ + ssh_ppl_replace(&s->ppl, successor); + return; /* we've just freed s, so avoid even touching s->crState */ + } + + crFinishV; +} diff --git a/ssh1login.c b/ssh1login.c index 0010b288..1d5b92b9 100644 --- a/ssh1login.c +++ b/ssh1login.c @@ -1086,8 +1086,8 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl) } } - ssh1_connection_set_local_protoflags( - s->successor_layer, s->local_protoflags); + ssh1_connection_set_protoflags( + s->successor_layer, s->local_protoflags, s->remote_protoflags); { PacketProtocolLayer *successor = s->successor_layer; s->successor_layer = NULL; /* avoid freeing it ourself */ diff --git a/ssh2bpp.c b/ssh2bpp.c index 225fed28..f67b4ece 100644 --- a/ssh2bpp.c +++ b/ssh2bpp.c @@ -34,6 +34,7 @@ struct ssh2_bpp_state { ssh_decompressor *in_decomp; ssh_compressor *out_comp; + int is_server; int pending_newkeys; int pending_compression, seen_userauth_success; @@ -54,13 +55,14 @@ static const struct BinaryPacketProtocolVtable ssh2_bpp_vtable = { }; BinaryPacketProtocol *ssh2_bpp_new( - LogContext *logctx, struct DataTransferStats *stats) + LogContext *logctx, struct DataTransferStats *stats, int is_server) { struct ssh2_bpp_state *s = snew(struct ssh2_bpp_state); memset(s, 0, sizeof(*s)); s->bpp.vt = &ssh2_bpp_vtable; s->bpp.logctx = logctx; s->stats = stats; + s->is_server = is_server; ssh_bpp_common_setup(&s->bpp); return &s->bpp; } @@ -216,6 +218,10 @@ void ssh2_bpp_new_incoming_crypto( /* Clear the pending_newkeys flag, so that handle_input below will * start consuming the input data again. */ s->pending_newkeys = FALSE; + + /* And schedule a run of handle_input, in case there's already + * input data in the queue. */ + queue_idempotent_callback(&s->bpp.ic_in_raw); } int ssh2_bpp_rekey_inadvisable(BinaryPacketProtocol *bpp) @@ -227,6 +233,24 @@ int ssh2_bpp_rekey_inadvisable(BinaryPacketProtocol *bpp) return s->pending_compression; } +static void ssh2_bpp_enable_pending_compression(struct ssh2_bpp_state *s) +{ + BinaryPacketProtocol *bpp = &s->bpp; /* for bpp_logevent */ + + if (s->in.pending_compression) { + s->in_decomp = ssh_decompressor_new(s->in.pending_compression); + bpp_logevent(("Initialised delayed %s decompression", + ssh_decompressor_alg(s->in_decomp)->text_name)); + s->in.pending_compression = NULL; + } + if (s->out.pending_compression) { + s->out_comp = ssh_compressor_new(s->out.pending_compression); + bpp_logevent(("Initialised delayed %s compression", + ssh_compressor_alg(s->out_comp)->text_name)); + s->out.pending_compression = NULL; + } +} + #define BPP_READ(ptr, len) do \ { \ crMaybeWaitUntilV(s->bpp.input_eof || \ @@ -571,29 +595,14 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp) continue; } - if (type == SSH2_MSG_USERAUTH_SUCCESS) { + if (type == SSH2_MSG_USERAUTH_SUCCESS && !s->is_server) { /* * Another one: if we were configured with OpenSSH's * deferred compression which is triggered on receipt * of USERAUTH_SUCCESS, then this is the moment to * turn on compression. */ - if (s->in.pending_compression) { - s->in_decomp = - ssh_decompressor_new(s->in.pending_compression); - bpp_logevent(("Initialised delayed %s decompression", - ssh_decompressor_alg( - s->in_decomp)->text_name)); - s->in.pending_compression = NULL; - } - if (s->out.pending_compression) { - s->out_comp = - ssh_compressor_new(s->out.pending_compression); - bpp_logevent(("Initialised delayed %s compression", - ssh_compressor_alg( - s->out_comp)->text_name)); - s->out.pending_compression = NULL; - } + ssh2_bpp_enable_pending_compression(s); /* * Whether or not we were doing delayed compression in @@ -869,13 +878,15 @@ static void ssh2_bpp_handle_output(BinaryPacketProtocol *bpp) } while ((pkt = pq_pop(&s->bpp.out_pq)) != NULL) { - if (userauth_range(pkt->type)) + int type = pkt->type; + + if (userauth_range(type)) n_userauth--; ssh2_bpp_format_packet(s, pkt); ssh_free_pktout(pkt); - if (n_userauth == 0 && s->out.pending_compression) { + if (n_userauth == 0 && s->out.pending_compression && !s->is_server) { /* * This is the last userauth packet in the queue, so * unless our side decides to send another one in future, @@ -885,6 +896,8 @@ static void ssh2_bpp_handle_output(BinaryPacketProtocol *bpp) */ s->pending_compression = TRUE; return; + } else if (type == SSH2_MSG_USERAUTH_SUCCESS && s->is_server) { + ssh2_bpp_enable_pending_compression(s); } } } diff --git a/ssh2connection-client.c b/ssh2connection-client.c index 5df69fd8..65fc6bc2 100644 --- a/ssh2connection-client.c +++ b/ssh2connection-client.c @@ -301,6 +301,17 @@ SshChannel *ssh2_session_open(ConnectionLayer *cl, Channel *chan) return &c->sc; } +SshChannel *ssh2_serverside_x11_open( + ConnectionLayer *cl, Channel *chan, const SocketPeerInfo *pi) +{ + assert(FALSE && "Should never be called in the client"); +} + +SshChannel *ssh2_serverside_agent_open(ConnectionLayer *cl, Channel *chan) +{ + assert(FALSE && "Should never be called in the client"); +} + static void ssh2_channel_response( struct ssh2_channel *c, PktIn *pkt, void *ctx) { diff --git a/ssh2connection-server.c b/ssh2connection-server.c new file mode 100644 index 00000000..da4b60cf --- /dev/null +++ b/ssh2connection-server.c @@ -0,0 +1,290 @@ +/* + * Server-specific parts of the SSH-2 connection layer. + */ + +#include + +#include "putty.h" +#include "ssh.h" +#include "sshbpp.h" +#include "sshppl.h" +#include "sshchan.h" +#include "sshcr.h" +#include "ssh2connection.h" +#include "sshserver.h" + +static ChanopenResult chan_open_session( + struct ssh2_connection_state *s, SshChannel *sc) +{ + PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */ + + ppl_logevent(("Opened session channel")); + CHANOPEN_RETURN_SUCCESS(sesschan_new(sc, s->ppl.logctx)); +} + +static ChanopenResult chan_open_direct_tcpip( + struct ssh2_connection_state *s, SshChannel *sc, + ptrlen dstaddr, int dstport, ptrlen peeraddr, int peerport) +{ + PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */ + Channel *ch; + char *dstaddr_str, *err; + + dstaddr_str = mkstr(dstaddr); + + ppl_logevent(("Received request to connect to port %s:%d (from %.*s:%d)", + dstaddr_str, dstport, PTRLEN_PRINTF(peeraddr), peerport)); + err = portfwdmgr_connect( + s->portfwdmgr, &ch, dstaddr_str, dstport, sc, ADDRTYPE_UNSPEC); + + sfree(dstaddr_str); + + if (err != NULL) { + ppl_logevent(("Port open failed: %s", err)); + sfree(err); + CHANOPEN_RETURN_FAILURE( + SSH2_OPEN_CONNECT_FAILED, ("Connection failed")); + } + + ppl_logevent(("Port opened successfully")); + CHANOPEN_RETURN_SUCCESS(ch); +} + +ChanopenResult ssh2_connection_parse_channel_open( + struct ssh2_connection_state *s, ptrlen type, + PktIn *pktin, SshChannel *sc) +{ + if (ptrlen_eq_string(type, "session")) { + return chan_open_session(s, sc); + } else if (ptrlen_eq_string(type, "direct-tcpip")) { + ptrlen dstaddr = get_string(pktin); + int dstport = toint(get_uint32(pktin)); + ptrlen peeraddr = get_string(pktin); + int peerport = toint(get_uint32(pktin)); + return chan_open_direct_tcpip( + s, sc, dstaddr, dstport, peeraddr, peerport); + } else { + CHANOPEN_RETURN_FAILURE( + SSH2_OPEN_UNKNOWN_CHANNEL_TYPE, + ("Unsupported channel type requested")); + } +} + +int ssh2_connection_parse_global_request( + struct ssh2_connection_state *s, ptrlen type, PktIn *pktin) +{ + if (ptrlen_eq_string(type, "tcpip-forward")) { + char *host = mkstr(get_string(pktin)); + unsigned port = get_uint32(pktin); + /* In SSH-2, the host/port we listen on are the same host/port + * we want reported back to us when a connection comes in, + * because that's what we tell the client */ + int toret = portfwdmgr_listen( + s->portfwdmgr, host, port, host, port, s->conf); + sfree(host); + return toret; + } else if (ptrlen_eq_string(type, "cancel-tcpip-forward")) { + char *host = mkstr(get_string(pktin)); + unsigned port = get_uint32(pktin); + int toret = portfwdmgr_unlisten(s->portfwdmgr, host, port); + sfree(host); + return toret; + } else { + /* Unrecognised request. */ + return FALSE; + } +} + +PktOut *ssh2_portfwd_chanopen( + struct ssh2_connection_state *s, struct ssh2_channel *c, + const char *hostname, int port, + const char *description, const SocketPeerInfo *pi) +{ + PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */ + PktOut *pktout; + + /* + * In server mode, this function is called by portfwdmgr in + * response to PortListeners that were set up by calling + * portfwdmgr_listen, which means that the hostname and port + * parameters will identify the listening socket on which a + * connection just came in. + */ + + if (pi && pi->log_text) + ppl_logevent(("Forwarding connection to listening port %s:%d from %s", + hostname, port, pi->log_text)); + else + ppl_logevent(("Forwarding connection to listening port %s:%d", + hostname, port)); + + pktout = ssh2_chanopen_init(c, "forwarded-tcpip"); + put_stringz(pktout, hostname); + put_uint32(pktout, port); + put_stringz(pktout, (pi && pi->addr_text ? pi->addr_text : "0.0.0.0")); + put_uint32(pktout, (pi && pi->port >= 0 ? pi->port : 0)); + + return pktout; +} + +struct ssh_rportfwd *ssh2_rportfwd_alloc( + ConnectionLayer *cl, + const char *shost, int sport, const char *dhost, int dport, + int addressfamily, const char *log_description, PortFwdRecord *pfr, + ssh_sharing_connstate *share_ctx) +{ + assert(FALSE && "Should never be called in the server"); +} + +void ssh2_rportfwd_remove(ConnectionLayer *cl, struct ssh_rportfwd *rpf) +{ + assert(FALSE && "Should never be called in the server"); +} + +SshChannel *ssh2_session_open(ConnectionLayer *cl, Channel *chan) +{ + assert(FALSE && "Should never be called in the server"); +} + +SshChannel *ssh2_serverside_x11_open( + ConnectionLayer *cl, Channel *chan, const SocketPeerInfo *pi) +{ + struct ssh2_connection_state *s = + container_of(cl, struct ssh2_connection_state, cl); + PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */ + struct ssh2_channel *c = snew(struct ssh2_channel); + PktOut *pktout; + + c->connlayer = s; + ssh2_channel_init(c); + c->halfopen = TRUE; + c->chan = chan; + + ppl_logevent(("Forwarding X11 channel to client")); + + pktout = ssh2_chanopen_init(c, "x11"); + put_stringz(pktout, (pi && pi->addr_text ? pi->addr_text : "0.0.0.0")); + put_uint32(pktout, (pi && pi->port >= 0 ? pi->port : 0)); + pq_push(s->ppl.out_pq, pktout); + + return &c->sc; +} + +SshChannel *ssh2_serverside_agent_open(ConnectionLayer *cl, Channel *chan) +{ + struct ssh2_connection_state *s = + container_of(cl, struct ssh2_connection_state, cl); + PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */ + struct ssh2_channel *c = snew(struct ssh2_channel); + PktOut *pktout; + + c->connlayer = s; + ssh2_channel_init(c); + c->halfopen = TRUE; + c->chan = chan; + + ppl_logevent(("Forwarding SSH agent to client")); + + pktout = ssh2_chanopen_init(c, "auth-agent@openssh.com"); + pq_push(s->ppl.out_pq, pktout); + + return &c->sc; +} + +void ssh2channel_start_shell(SshChannel *sc, int want_reply) +{ + assert(FALSE && "Should never be called in the server"); +} + +void ssh2channel_start_command( + SshChannel *sc, int want_reply, const char *command) +{ + assert(FALSE && "Should never be called in the server"); +} + +int ssh2channel_start_subsystem( + SshChannel *sc, int want_reply, const char *subsystem) +{ + assert(FALSE && "Should never be called in the server"); +} + +void ssh2channel_send_exit_status(SshChannel *sc, int status) +{ + struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc); + struct ssh2_connection_state *s = c->connlayer; + + PktOut *pktout = ssh2_chanreq_init(c, "exit-status", NULL, NULL); + put_uint32(pktout, status); + + pq_push(s->ppl.out_pq, pktout); +} + +void ssh2channel_send_exit_signal( + SshChannel *sc, ptrlen signame, int core_dumped, ptrlen msg) +{ + struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc); + struct ssh2_connection_state *s = c->connlayer; + + PktOut *pktout = ssh2_chanreq_init(c, "exit-signal", NULL, NULL); + put_stringpl(pktout, signame); + put_bool(pktout, core_dumped); + put_stringpl(pktout, msg); + put_stringz(pktout, ""); /* language tag */ + + pq_push(s->ppl.out_pq, pktout); +} + +void ssh2channel_send_exit_signal_numeric( + SshChannel *sc, int signum, int core_dumped, ptrlen msg) +{ + struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc); + struct ssh2_connection_state *s = c->connlayer; + + PktOut *pktout = ssh2_chanreq_init(c, "exit-signal", NULL, NULL); + put_uint32(pktout, signum); + put_bool(pktout, core_dumped); + put_stringpl(pktout, msg); + put_stringz(pktout, ""); /* language tag */ + + pq_push(s->ppl.out_pq, pktout); +} + +void ssh2channel_request_x11_forwarding( + SshChannel *sc, int want_reply, const char *authproto, + const char *authdata, int screen_number, int oneshot) +{ + assert(FALSE && "Should never be called in the server"); +} + +void ssh2channel_request_agent_forwarding(SshChannel *sc, int want_reply) +{ + assert(FALSE && "Should never be called in the server"); +} + +void ssh2channel_request_pty( + SshChannel *sc, int want_reply, Conf *conf, int w, int h) +{ + assert(FALSE && "Should never be called in the server"); +} + +int ssh2channel_send_env_var( + SshChannel *sc, int want_reply, const char *var, const char *value) +{ + assert(FALSE && "Should never be called in the server"); +} + +int ssh2channel_send_serial_break(SshChannel *sc, int want_reply, int length) +{ + assert(FALSE && "Should never be called in the server"); +} + +int ssh2channel_send_signal( + SshChannel *sc, int want_reply, const char *signame) +{ + assert(FALSE && "Should never be called in the server"); +} + +void ssh2channel_send_terminal_size_change(SshChannel *sc, int w, int h) +{ + assert(FALSE && "Should never be called in the server"); +} diff --git a/ssh2connection.c b/ssh2connection.c index 9c27a715..fa079fec 100644 --- a/ssh2connection.c +++ b/ssh2connection.c @@ -69,6 +69,8 @@ static const struct ConnectionLayerVtable ssh2_connlayer_vtable = { ssh2_rportfwd_remove, ssh2_lportfwd_open, ssh2_session_open, + ssh2_serverside_x11_open, + ssh2_serverside_agent_open, ssh2_add_x11_display, ssh2_add_sharing_x11_display, ssh2_remove_sharing_x11_display, diff --git a/ssh2connection.h b/ssh2connection.h index 11e62419..a441127e 100644 --- a/ssh2connection.h +++ b/ssh2connection.h @@ -163,8 +163,10 @@ struct ssh_rportfwd *ssh2_rportfwd_alloc( ssh_sharing_connstate *share_ctx); void ssh2_rportfwd_remove( ConnectionLayer *cl, struct ssh_rportfwd *rpf); - SshChannel *ssh2_session_open(ConnectionLayer *cl, Channel *chan); +SshChannel *ssh2_serverside_x11_open( + ConnectionLayer *cl, Channel *chan, const SocketPeerInfo *pi); +SshChannel *ssh2_serverside_agent_open(ConnectionLayer *cl, Channel *chan); void ssh2channel_send_exit_status(SshChannel *c, int status); void ssh2channel_send_exit_signal( diff --git a/ssh2kex-server.c b/ssh2kex-server.c new file mode 100644 index 00000000..4b62d56d --- /dev/null +++ b/ssh2kex-server.c @@ -0,0 +1,289 @@ +/* + * Server side of key exchange for the SSH-2 transport protocol (RFC 4253). + */ + +#include + +#include "putty.h" +#include "ssh.h" +#include "sshbpp.h" +#include "sshppl.h" +#include "sshcr.h" +#include "storage.h" +#include "ssh2transport.h" + +void ssh2_transport_provide_hostkeys(PacketProtocolLayer *ppl, + ssh_key *const *hostkeys, int nhostkeys) +{ + struct ssh2_transport_state *s = + container_of(ppl, struct ssh2_transport_state, ppl); + + s->hostkeys = hostkeys; + s->nhostkeys = nhostkeys; +} + +static strbuf *finalise_and_sign_exhash(struct ssh2_transport_state *s) +{ + strbuf *sb; + ssh2transport_finalise_exhash(s); + sb = strbuf_new(); + ssh_key_sign(s->hkey, s->exchange_hash, s->kex_alg->hash->hlen, + BinarySink_UPCAST(sb)); + return sb; +} + +static void no_progress(void *param, int action, int phase, int iprogress) +{ +} + +void ssh2kex_coroutine(struct ssh2_transport_state *s) +{ + PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */ + PktIn *pktin; + PktOut *pktout; + + crBegin(s->crStateKex); + + { + int i; + for (i = 0; i < s->nhostkeys; i++) + if (ssh_key_alg(s->hostkeys[i]) == s->hostkey_alg) { + s->hkey = s->hostkeys[i]; + break; + } + assert(s->hkey); + } + + s->hostkeyblob->len = 0; + ssh_key_public_blob(s->hkey, BinarySink_UPCAST(s->hostkeyblob)); + s->hostkeydata = ptrlen_from_strbuf(s->hostkeyblob); + + put_stringpl(s->exhash, s->hostkeydata); + + if (s->kex_alg->main_type == KEXTYPE_DH) { + /* + * If we're doing Diffie-Hellman group exchange, start by + * waiting for the group request. + */ + if (dh_is_gex(s->kex_alg)) { + ppl_logevent(("Doing Diffie-Hellman group exchange")); + s->ppl.bpp->pls->kctx = SSH2_PKTCTX_DHGEX; + + crMaybeWaitUntilV((pktin = ssh2_transport_pop(s)) != NULL); + if (pktin->type != SSH2_MSG_KEX_DH_GEX_REQUEST && + pktin->type != SSH2_MSG_KEX_DH_GEX_REQUEST_OLD) { + ssh_proto_error(s->ppl.ssh, "Received unexpected packet when " + "expecting Diffie-Hellman group exchange " + "request, type %d (%s)", pktin->type, + ssh2_pkt_type(s->ppl.bpp->pls->kctx, + s->ppl.bpp->pls->actx, + pktin->type)); + return; + } + + if (pktin->type != SSH2_MSG_KEX_DH_GEX_REQUEST_OLD) { + s->dh_got_size_bounds = TRUE; + s->dh_min_size = get_uint32(pktin); + s->pbits = get_uint32(pktin); + s->dh_max_size = get_uint32(pktin); + } else { + s->dh_got_size_bounds = FALSE; + s->pbits = get_uint32(pktin); + } + + /* + * This is a hopeless strategy for making a secure DH + * group! It's good enough for testing a client against, + * but not for serious use. + */ + s->p = primegen(s->pbits, 2, 2, NULL, 1, no_progress, NULL, 1); + s->g = bignum_from_long(2); + s->dh_ctx = dh_setup_gex(s->p, s->g); + s->kex_init_value = SSH2_MSG_KEX_DH_GEX_INIT; + s->kex_reply_value = SSH2_MSG_KEX_DH_GEX_REPLY; + + pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH2_MSG_KEX_DH_GEX_GROUP); + put_mp_ssh2(pktout, s->p); + put_mp_ssh2(pktout, s->g); + pq_push(s->ppl.out_pq, pktout); + } else { + s->ppl.bpp->pls->kctx = SSH2_PKTCTX_DHGROUP; + s->dh_ctx = dh_setup_group(s->kex_alg); + s->kex_init_value = SSH2_MSG_KEXDH_INIT; + s->kex_reply_value = SSH2_MSG_KEXDH_REPLY; + ppl_logevent(("Using Diffie-Hellman with standard group \"%s\"", + s->kex_alg->groupname)); + } + + ppl_logevent(("Doing Diffie-Hellman key exchange with hash %s", + s->kex_alg->hash->text_name)); + + /* + * Generate e for Diffie-Hellman. + */ + s->e = dh_create_e(s->dh_ctx, s->nbits * 2); + + /* + * Wait to receive f. + */ + crMaybeWaitUntilV((pktin = ssh2_transport_pop(s)) != NULL); + if (pktin->type != s->kex_init_value) { + ssh_proto_error(s->ppl.ssh, "Received unexpected packet when " + "expecting Diffie-Hellman initial packet, " + "type %d (%s)", pktin->type, + ssh2_pkt_type(s->ppl.bpp->pls->kctx, + s->ppl.bpp->pls->actx, + pktin->type)); + return; + } + s->f = get_mp_ssh2(pktin); + if (get_err(pktin)) { + ssh_proto_error(s->ppl.ssh, + "Unable to parse Diffie-Hellman initial packet"); + return; + } + + { + const char *err = dh_validate_f(s->dh_ctx, s->f); + if (err) { + ssh_proto_error(s->ppl.ssh, "Diffie-Hellman initial packet " + "failed validation: %s", err); + return; + } + } + s->K = dh_find_K(s->dh_ctx, s->f); + + if (dh_is_gex(s->kex_alg)) { + if (s->dh_got_size_bounds) + put_uint32(s->exhash, s->dh_min_size); + put_uint32(s->exhash, s->pbits); + if (s->dh_got_size_bounds) + put_uint32(s->exhash, s->dh_max_size); + put_mp_ssh2(s->exhash, s->p); + put_mp_ssh2(s->exhash, s->g); + } + put_mp_ssh2(s->exhash, s->f); + put_mp_ssh2(s->exhash, s->e); + + pktout = ssh_bpp_new_pktout(s->ppl.bpp, s->kex_reply_value); + put_stringpl(pktout, s->hostkeydata); + put_mp_ssh2(pktout, s->e); + put_stringsb(pktout, finalise_and_sign_exhash(s)); + pq_push(s->ppl.out_pq, pktout); + + dh_cleanup(s->dh_ctx); + s->dh_ctx = NULL; + freebn(s->f); s->f = NULL; + if (dh_is_gex(s->kex_alg)) { + freebn(s->g); s->g = NULL; + freebn(s->p); s->p = NULL; + } + } else if (s->kex_alg->main_type == KEXTYPE_ECDH) { + ppl_logevent(("Doing ECDH key exchange with curve %s and hash %s", + ssh_ecdhkex_curve_textname(s->kex_alg), + s->kex_alg->hash->text_name)); + s->ppl.bpp->pls->kctx = SSH2_PKTCTX_ECDHKEX; + + s->ecdh_key = ssh_ecdhkex_newkey(s->kex_alg); + if (!s->ecdh_key) { + ssh_sw_abort(s->ppl.ssh, "Unable to generate key for ECDH"); + return; + } + + crMaybeWaitUntilV((pktin = ssh2_transport_pop(s)) != NULL); + if (pktin->type != SSH2_MSG_KEX_ECDH_INIT) { + ssh_proto_error(s->ppl.ssh, "Received unexpected packet when " + "expecting ECDH initial packet, type %d (%s)", + pktin->type, + ssh2_pkt_type(s->ppl.bpp->pls->kctx, + s->ppl.bpp->pls->actx, + pktin->type)); + return; + } + + { + ptrlen keydata = get_string(pktin); + put_stringpl(s->exhash, keydata); + + s->K = ssh_ecdhkex_getkey(s->ecdh_key, keydata.ptr, keydata.len); + if (!get_err(pktin) && !s->K) { + ssh_proto_error(s->ppl.ssh, "Received invalid elliptic curve " + "point in ECDH initial packet"); + return; + } + } + + pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH2_MSG_KEX_ECDH_REPLY); + put_stringpl(pktout, s->hostkeydata); + { + strbuf *pubpoint = strbuf_new(); + ssh_ecdhkex_getpublic(s->ecdh_key, BinarySink_UPCAST(pubpoint)); + put_string(s->exhash, pubpoint->u, pubpoint->len); + put_stringsb(pktout, pubpoint); + } + put_stringsb(pktout, finalise_and_sign_exhash(s)); + pq_push(s->ppl.out_pq, pktout); + + ssh_ecdhkex_freekey(s->ecdh_key); + s->ecdh_key = NULL; + } else if (s->kex_alg->main_type == KEXTYPE_GSS) { + ssh_sw_abort(s->ppl.ssh, "GSS key exchange not supported in server"); + } else { + assert(s->kex_alg->main_type == KEXTYPE_RSA); + ppl_logevent(("Doing RSA key exchange with hash %s", + s->kex_alg->hash->text_name)); + s->ppl.bpp->pls->kctx = SSH2_PKTCTX_RSAKEX; + + { + const struct ssh_rsa_kex_extra *extra = + (const struct ssh_rsa_kex_extra *)s->kex_alg->extra; + + s->rsa_kex_key = snew(struct RSAKey); + rsa_generate(s->rsa_kex_key, extra->minklen, no_progress, NULL); + s->rsa_kex_key->comment = NULL; + } + + pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH2_MSG_KEXRSA_PUBKEY); + put_stringpl(pktout, s->hostkeydata); + { + strbuf *pubblob = strbuf_new(); + ssh_key_public_blob(&s->rsa_kex_key->sshk, + BinarySink_UPCAST(pubblob)); + put_string(s->exhash, pubblob->u, pubblob->len); + put_stringsb(pktout, pubblob); + } + pq_push(s->ppl.out_pq, pktout); + + crMaybeWaitUntilV((pktin = ssh2_transport_pop(s)) != NULL); + if (pktin->type != SSH2_MSG_KEXRSA_SECRET) { + ssh_proto_error(s->ppl.ssh, "Received unexpected packet when " + "expecting RSA kex secret, type %d (%s)", + pktin->type, + ssh2_pkt_type(s->ppl.bpp->pls->kctx, + s->ppl.bpp->pls->actx, + pktin->type)); + return; + } + + { + ptrlen encrypted_secret = get_string(pktin); + put_stringpl(s->exhash, encrypted_secret); + s->K = ssh_rsakex_decrypt( + s->kex_alg->hash, encrypted_secret, s->rsa_kex_key); + } + + if (!s->K) { + ssh_proto_error(s->ppl.ssh, "Unable to decrypt RSA kex secret"); + return; + } + + ssh_rsakex_freekey(s->rsa_kex_key); + s->rsa_kex_key = NULL; + + pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH2_MSG_KEXRSA_DONE); + put_stringsb(pktout, finalise_and_sign_exhash(s)); + pq_push(s->ppl.out_pq, pktout); + } + + crFinishV; +} diff --git a/ssh2transport.c b/ssh2transport.c index 22960f01..7b04e5f7 100644 --- a/ssh2transport.c +++ b/ssh2transport.c @@ -108,8 +108,8 @@ PacketProtocolLayer *ssh2_transport_new( Conf *conf, const char *host, int port, const char *fullhostname, const char *client_greeting, const char *server_greeting, struct ssh_connection_shared_gss_state *shgss, - struct DataTransferStats *stats, - PacketProtocolLayer *higher_layer) + struct DataTransferStats *stats, PacketProtocolLayer *higher_layer, + int is_server) { struct ssh2_transport_state *s = snew(struct ssh2_transport_state); memset(s, 0, sizeof(*s)); @@ -123,6 +123,7 @@ PacketProtocolLayer *ssh2_transport_new( s->client_greeting = dupstr(client_greeting); s->server_greeting = dupstr(server_greeting); s->stats = stats; + s->hostkeyblob = strbuf_new(); pq_in_init(&s->pq_in_higher); pq_out_init(&s->pq_out_higher); @@ -142,8 +143,17 @@ PacketProtocolLayer *ssh2_transport_new( s->thc = ssh_transient_hostkey_cache_new(); s->gss_kex_used = FALSE; - s->client_kexinit = strbuf_new(); - s->server_kexinit = strbuf_new(); + s->outgoing_kexinit = strbuf_new(); + s->incoming_kexinit = strbuf_new(); + if (is_server) { + s->client_kexinit = s->incoming_kexinit; + s->server_kexinit = s->outgoing_kexinit; + s->out.mkkey_adjust = 1; + } else { + s->client_kexinit = s->outgoing_kexinit; + s->server_kexinit = s->incoming_kexinit; + s->in.mkkey_adjust = 1; + } ssh2_transport_set_max_data_size(s); @@ -184,8 +194,9 @@ static void ssh2_transport_free(PacketProtocolLayer *ppl) sfree(s->server_greeting); sfree(s->keystr); sfree(s->hostkey_str); + strbuf_free(s->hostkeyblob); sfree(s->fingerprint); - if (s->hkey) { + if (s->hkey && !s->hostkeys) { ssh_key_free(s->hkey); s->hkey = NULL; } @@ -201,8 +212,8 @@ static void ssh2_transport_free(PacketProtocolLayer *ppl) ssh_ecdhkex_freekey(s->ecdh_key); if (s->exhash) ssh_hash_free(s->exhash); - strbuf_free(s->client_kexinit); - strbuf_free(s->server_kexinit); + strbuf_free(s->outgoing_kexinit); + strbuf_free(s->incoming_kexinit); ssh_transient_hostkey_cache_free(s->thc); sfree(s); } @@ -395,6 +406,7 @@ static void ssh2_write_kexinit_lists( Conf *conf, int remote_bugs, const char *hk_host, int hk_port, const ssh_keyalg *hk_prev, ssh_transient_hostkey_cache *thc, + ssh_key *const *our_hostkeys, int our_nhostkeys, int first_time, int can_gssapi_keyex, int transient_hostkey_mode) { int i, j, k, warn; @@ -522,7 +534,18 @@ static void ssh2_write_kexinit_lists( } } /* List server host key algorithms. */ - if (first_time) { + if (our_hostkeys) { + /* + * In server mode, we just list the algorithms that match the + * host keys we actually have. + */ + for (i = 0; i < our_nhostkeys; i++) { + alg = ssh2_kexinit_addalg(kexlists[KEXLIST_HOSTKEY], + ssh_key_alg(our_hostkeys[i])->ssh_id); + alg->u.hk.hostkey = ssh_key_alg(our_hostkeys[i]); + alg->u.hk.warn = FALSE; + } + } else if (first_time) { /* * In the first key exchange, we list all the algorithms * we're prepared to cope with, but prefer those algorithms @@ -1016,28 +1039,29 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) * later. */ s->client_kexinit->len = 0; - put_byte(s->client_kexinit, SSH2_MSG_KEXINIT); + put_byte(s->outgoing_kexinit, SSH2_MSG_KEXINIT); { int i; for (i = 0; i < 16; i++) - put_byte(s->client_kexinit, (unsigned char) random_byte()); + put_byte(s->outgoing_kexinit, (unsigned char) random_byte()); } ssh2_write_kexinit_lists( - BinarySink_UPCAST(s->client_kexinit), s->kexlists, + BinarySink_UPCAST(s->outgoing_kexinit), s->kexlists, s->conf, s->ppl.remote_bugs, s->savedhost, s->savedport, s->hostkey_alg, s->thc, + s->hostkeys, s->nhostkeys, !s->got_session_id, s->can_gssapi_keyex, s->gss_kex_used && !s->need_gss_transient_hostkey); /* First KEX packet does _not_ follow, because we're not that brave. */ - put_bool(s->client_kexinit, FALSE); - put_uint32(s->client_kexinit, 0); /* reserved */ + put_bool(s->outgoing_kexinit, FALSE); + put_uint32(s->outgoing_kexinit, 0); /* reserved */ /* * Send our KEXINIT. */ pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH2_MSG_KEXINIT); - put_data(pktout, s->client_kexinit->u + 1, - s->client_kexinit->len - 1); /* omit initial packet type byte */ + put_data(pktout, s->outgoing_kexinit->u + 1, + s->outgoing_kexinit->len - 1); /* omit initial packet type byte */ pq_push(s->ppl.out_pq, pktout); /* @@ -1056,9 +1080,9 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) s->ppl.bpp->pls->actx, pktin->type)); return; } - s->server_kexinit->len = 0; - put_byte(s->server_kexinit, SSH2_MSG_KEXINIT); - put_data(s->server_kexinit, get_ptr(pktin), get_avail(pktin)); + s->incoming_kexinit->len = 0; + put_byte(s->incoming_kexinit, SSH2_MSG_KEXINIT); + put_data(s->incoming_kexinit, get_ptr(pktin), get_avail(pktin)); /* * Work through the two KEXINIT packets in parallel to find the @@ -1241,8 +1265,8 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) ssh_bpp_handle_output(s->ppl.bpp); /* - * We've sent client NEWKEYS, so create and initialise - * client-to-server session keys. + * We've sent outgoing NEWKEYS, so create and initialise outgoing + * session keys. */ { strbuf *cipher_key = strbuf_new(); @@ -1250,14 +1274,15 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) strbuf *mac_key = strbuf_new(); if (s->out.cipher) { - ssh2_mkkey(s, cipher_iv, s->K, s->exchange_hash, 'A', - s->out.cipher->blksize); - ssh2_mkkey(s, cipher_key, s->K, s->exchange_hash, 'C', + ssh2_mkkey(s, cipher_iv, s->K, s->exchange_hash, + 'A' + s->out.mkkey_adjust, s->out.cipher->blksize); + ssh2_mkkey(s, cipher_key, s->K, s->exchange_hash, + 'C' + s->out.mkkey_adjust, s->out.cipher->padded_keybytes); } if (s->out.mac) { - ssh2_mkkey(s, mac_key, s->K, s->exchange_hash, 'E', - s->out.mac->keylen); + ssh2_mkkey(s, mac_key, s->K, s->exchange_hash, + 'E' + s->out.mkkey_adjust, s->out.mac->keylen); } ssh2_bpp_new_outgoing_crypto( @@ -1296,8 +1321,8 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) s->stats->in.remaining = s->max_data_size; /* - * We've seen server NEWKEYS, so create and initialise - * server-to-client session keys. + * We've seen incoming NEWKEYS, so create and initialise + * incoming session keys. */ { strbuf *cipher_key = strbuf_new(); @@ -1305,14 +1330,15 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) strbuf *mac_key = strbuf_new(); if (s->in.cipher) { - ssh2_mkkey(s, cipher_iv, s->K, s->exchange_hash, 'B', - s->in.cipher->blksize); - ssh2_mkkey(s, cipher_key, s->K, s->exchange_hash, 'D', + ssh2_mkkey(s, cipher_iv, s->K, s->exchange_hash, + 'A' + s->in.mkkey_adjust, s->in.cipher->blksize); + ssh2_mkkey(s, cipher_key, s->K, s->exchange_hash, + 'C' + s->in.mkkey_adjust, s->in.cipher->padded_keybytes); } if (s->in.mac) { - ssh2_mkkey(s, mac_key, s->K, s->exchange_hash, 'F', - s->in.mac->keylen); + ssh2_mkkey(s, mac_key, s->K, s->exchange_hash, + 'E' + s->in.mkkey_adjust, s->in.mac->keylen); } ssh2_bpp_new_incoming_crypto( @@ -1364,14 +1390,43 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) * decided to initiate a rekey ourselves for some reason. */ if (!s->higher_layer_ok) { - pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH2_MSG_SERVICE_REQUEST); - put_stringz(pktout, s->higher_layer->vt->name); - pq_push(s->ppl.out_pq, pktout); - crMaybeWaitUntilV((pktin = ssh2_transport_pop(s)) != NULL); - if (pktin->type != SSH2_MSG_SERVICE_ACCEPT) { - ssh_sw_abort(s->ppl.ssh, "Server refused request to start " - "'%s' protocol", s->higher_layer->vt->name); - return; + if (!s->hostkeys) { + /* We're the client, so send SERVICE_REQUEST. */ + pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH2_MSG_SERVICE_REQUEST); + put_stringz(pktout, s->higher_layer->vt->name); + pq_push(s->ppl.out_pq, pktout); + crMaybeWaitUntilV((pktin = ssh2_transport_pop(s)) != NULL); + if (pktin->type != SSH2_MSG_SERVICE_ACCEPT) { + ssh_sw_abort(s->ppl.ssh, "Server refused request to start " + "'%s' protocol", s->higher_layer->vt->name); + return; + } + } else { + ptrlen service_name; + + /* We're the server, so expect SERVICE_REQUEST. */ + crMaybeWaitUntilV((pktin = ssh2_transport_pop(s)) != NULL); + if (pktin->type != SSH2_MSG_SERVICE_REQUEST) { + ssh_proto_error(s->ppl.ssh, "Received unexpected packet when " + "expecting SERVICE_REQUEST, type %d (%s)", + pktin->type, + ssh2_pkt_type(s->ppl.bpp->pls->kctx, + s->ppl.bpp->pls->actx, + pktin->type)); + return; + } + service_name = get_string(pktin); + if (!ptrlen_eq_string(service_name, s->higher_layer->vt->name)) { + ssh_proto_error(s->ppl.ssh, "Client requested service " + "'%.*s' when we only support '%s'", + PTRLEN_PRINTF(service_name), + s->higher_layer->vt->name); + return; + } + + pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH2_MSG_SERVICE_ACCEPT); + put_stringz(pktout, s->higher_layer->vt->name); + pq_push(s->ppl.out_pq, pktout); } s->higher_layer_ok = TRUE; diff --git a/ssh2transport.h b/ssh2transport.h index 924ef38d..a86b6ee1 100644 --- a/ssh2transport.h +++ b/ssh2transport.h @@ -108,6 +108,7 @@ typedef struct transport_direction { int etm_mode; const struct ssh_compression_alg *comp; int comp_delayed; + int mkkey_adjust; } transport_direction; struct ssh2_transport_state { @@ -131,6 +132,7 @@ struct ssh2_transport_state { char *hostkey_str; /* string representation, for easy checking in rekeys */ unsigned char session_id[SSH2_KEX_MAX_HASH_LEN]; int session_id_len; + int dh_min_size, dh_max_size, dh_got_size_bounds; struct dh_ctx *dh_ctx; ssh_hash *exhash; @@ -163,10 +165,12 @@ struct ssh2_transport_state { int nbits, pbits, warn_kex, warn_hk, warn_cscipher, warn_sccipher; Bignum p, g, e, f, K; - strbuf *client_kexinit, *server_kexinit; + strbuf *outgoing_kexinit, *incoming_kexinit; + strbuf *client_kexinit, *server_kexinit; /* aliases to the above */ int kex_init_value, kex_reply_value; transport_direction in, out; ptrlen hostkeydata, sigdata; + strbuf *hostkeyblob; char *keystr, *fingerprint; ssh_key *hkey; /* actual host key */ struct RSAKey *rsa_kex_key; /* for RSA kex */ @@ -203,6 +207,9 @@ struct ssh2_transport_state { */ int cross_certifying; + ssh_key *const *hostkeys; + int nhostkeys; + PacketProtocolLayer ppl; }; diff --git a/ssh2userauth-server.c b/ssh2userauth-server.c new file mode 100644 index 00000000..84f3d27c --- /dev/null +++ b/ssh2userauth-server.c @@ -0,0 +1,269 @@ +/* + * Packet protocol layer for the server side of the SSH-2 userauth + * protocol (RFC 4252). + */ + +#include + +#include "putty.h" +#include "ssh.h" +#include "sshbpp.h" +#include "sshppl.h" +#include "sshcr.h" +#include "sshserver.h" + +#ifndef NO_GSSAPI +#include "sshgssc.h" +#include "sshgss.h" +#endif + +struct ssh2_userauth_server_state { + int crState; + + PacketProtocolLayer *transport_layer, *successor_layer; + ptrlen session_id; + + AuthPolicy *authpolicy; + + ptrlen username, service, method; + unsigned methods, this_method; + int partial_success; + + PacketProtocolLayer ppl; +}; + +static void ssh2_userauth_server_free(PacketProtocolLayer *); +static void ssh2_userauth_server_process_queue(PacketProtocolLayer *); + +static const struct PacketProtocolLayerVtable ssh2_userauth_server_vtable = { + ssh2_userauth_server_free, + ssh2_userauth_server_process_queue, + NULL /* get_specials */, + NULL /* special_cmd */, + NULL /* want_user_input */, + NULL /* got_user_input */, + NULL /* reconfigure */, + "ssh-userauth", +}; + +PacketProtocolLayer *ssh2_userauth_server_new( + PacketProtocolLayer *successor_layer, AuthPolicy *authpolicy) +{ + struct ssh2_userauth_server_state *s = + snew(struct ssh2_userauth_server_state); + memset(s, 0, sizeof(*s)); + s->ppl.vt = &ssh2_userauth_server_vtable; + + s->successor_layer = successor_layer; + s->authpolicy = authpolicy; + + return &s->ppl; +} + +void ssh2_userauth_server_set_transport_layer(PacketProtocolLayer *userauth, + PacketProtocolLayer *transport) +{ + struct ssh2_userauth_server_state *s = + container_of(userauth, struct ssh2_userauth_server_state, ppl); + s->transport_layer = transport; +} + +static void ssh2_userauth_server_free(PacketProtocolLayer *ppl) +{ + struct ssh2_userauth_server_state *s = + container_of(ppl, struct ssh2_userauth_server_state, ppl); + + if (s->successor_layer) + ssh_ppl_free(s->successor_layer); + + sfree(s); +} + +static PktIn *ssh2_userauth_server_pop(struct ssh2_userauth_server_state *s) +{ + return pq_pop(s->ppl.in_pq); +} + +static void ssh2_userauth_server_add_session_id( + struct ssh2_userauth_server_state *s, strbuf *sigdata) +{ + if (s->ppl.remote_bugs & BUG_SSH2_PK_SESSIONID) { + put_data(sigdata, s->session_id.ptr, s->session_id.len); + } else { + put_stringpl(sigdata, s->session_id); + } +} + +static void ssh2_userauth_server_process_queue(PacketProtocolLayer *ppl) +{ + struct ssh2_userauth_server_state *s = + container_of(ppl, struct ssh2_userauth_server_state, ppl); + PktIn *pktin; + PktOut *pktout; + + crBegin(s->crState); + + s->session_id = ssh2_transport_get_session_id(s->transport_layer); + + while (1) { + crMaybeWaitUntilV((pktin = ssh2_userauth_server_pop(s)) != NULL); + if (pktin->type != SSH2_MSG_USERAUTH_REQUEST) { + ssh_proto_error(s->ppl.ssh, "Received unexpected packet when " + "expecting USERAUTH_REQUEST, type %d (%s)", + pktin->type, + ssh2_pkt_type(s->ppl.bpp->pls->kctx, + s->ppl.bpp->pls->actx, pktin->type)); + return; + } + + s->username = get_string(pktin); + s->service = get_string(pktin); + s->method = get_string(pktin); + + if (!ptrlen_eq_string(s->service, s->successor_layer->vt->name)) { + /* + * Unconditionally reject authentication for any service + * other than the one we're going to hand over to. + */ + pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH2_MSG_USERAUTH_FAILURE); + put_stringz(pktout, ""); + put_bool(pktout, FALSE); + pq_push(s->ppl.out_pq, pktout); + continue; + } + + s->methods = auth_methods(s->authpolicy); + s->partial_success = FALSE; + + if (ptrlen_eq_string(s->method, "none")) { + s->this_method = AUTHMETHOD_NONE; + if (!(s->methods & s->this_method)) + goto failure; + + if (!auth_none(s->authpolicy, s->username)) + goto failure; + } else if (ptrlen_eq_string(s->method, "password")) { + int changing; + ptrlen password; + + s->this_method = AUTHMETHOD_PASSWORD; + if (!(s->methods & s->this_method)) + goto failure; + + changing = get_bool(pktin); + if (changing) + goto failure; /* FIXME: not yet supported */ + + password = get_string(pktin); + + if (!auth_password(s->authpolicy, s->username, password)) + goto failure; + } else if (ptrlen_eq_string(s->method, "publickey")) { + int has_signature, success; + ptrlen algorithm, blob, signature; + const ssh_keyalg *keyalg; + ssh_key *key; + strbuf *sigdata; + + s->this_method = AUTHMETHOD_PUBLICKEY; + if (!(s->methods & s->this_method)) + goto failure; + + has_signature = get_bool(pktin); + algorithm = get_string(pktin); + blob = get_string(pktin); + + if (!auth_publickey(s->authpolicy, s->username, blob)) + goto failure; + + keyalg = find_pubkey_alg_len(algorithm); + if (!keyalg) + goto failure; + key = ssh_key_new_pub(keyalg, blob); + if (!key) + goto failure; + + if (!has_signature) { + ssh_key_free(key); + pktout = ssh_bpp_new_pktout( + s->ppl.bpp, SSH2_MSG_USERAUTH_PK_OK); + put_stringpl(pktout, algorithm); + put_stringpl(pktout, blob); + pq_push(s->ppl.out_pq, pktout); + continue; /* skip USERAUTH_{SUCCESS,FAILURE} epilogue */ + } + + sigdata = strbuf_new(); + ssh2_userauth_server_add_session_id(s, sigdata); + put_byte(sigdata, SSH2_MSG_USERAUTH_REQUEST); + put_stringpl(sigdata, s->username); + put_stringpl(sigdata, s->service); + put_stringpl(sigdata, s->method); + put_bool(sigdata, has_signature); + put_stringpl(sigdata, algorithm); + put_stringpl(sigdata, blob); + + signature = get_string(pktin); + success = ssh_key_verify(key, signature, + ptrlen_from_strbuf(sigdata)); + ssh_key_free(key); + strbuf_free(sigdata); + + if (!success) + goto failure; + } else { + goto failure; + } + + /* + * If we get here, we've successfully completed this + * authentication step. + */ + if (auth_successful(s->authpolicy, s->username, s->this_method)) { + /* + * ... and it was the last one, so we're completely done. + */ + pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH2_MSG_USERAUTH_SUCCESS); + pq_push(s->ppl.out_pq, pktout); + break; + } else { + /* + * ... but another is required, so fall through to + * generation of USERAUTH_FAILURE, having first refreshed + * the bit mask of available methods. + */ + s->methods = auth_methods(s->authpolicy); + } + s->partial_success = TRUE; + + failure: + pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH2_MSG_USERAUTH_FAILURE); + { + strbuf *list = strbuf_new(); + if (s->methods & AUTHMETHOD_NONE) + add_to_commasep(list, "none"); + if (s->methods & AUTHMETHOD_PASSWORD) + add_to_commasep(list, "password"); + if (s->methods & AUTHMETHOD_PUBLICKEY) + add_to_commasep(list, "publickey"); + put_stringsb(pktout, list); + } + put_bool(pktout, s->partial_success); + pq_push(s->ppl.out_pq, pktout); + } + + /* + * Finally, hand over to our successor layer, and return + * immediately without reaching the crFinishV: ssh_ppl_replace + * will have freed us, so crFinishV's zeroing-out of crState would + * be a use-after-free bug. + */ + { + PacketProtocolLayer *successor = s->successor_layer; + s->successor_layer = NULL; /* avoid freeing it ourself */ + ssh_ppl_replace(&s->ppl, successor); + return; /* we've just freed s, so avoid even touching s->crState */ + } + + crFinishV; +} diff --git a/ssh2userauth.c b/ssh2userauth.c index 1d526d02..7cbb425e 100644 --- a/ssh2userauth.c +++ b/ssh2userauth.c @@ -1,5 +1,6 @@ /* - * Packet protocol layer for the SSH-2 userauth protocol (RFC 4252). + * Packet protocol layer for the client side of the SSH-2 userauth + * protocol (RFC 4252). */ #include diff --git a/sshbpp.h b/sshbpp.h index 264c37c4..04c1f5ed 100644 --- a/sshbpp.h +++ b/sshbpp.h @@ -56,6 +56,10 @@ BinaryPacketProtocol *ssh1_bpp_new(LogContext *logctx); void ssh1_bpp_new_cipher(BinaryPacketProtocol *bpp, const struct ssh1_cipheralg *cipher, const void *session_key); +/* This is only called from outside the BPP in server mode; in client + * mode the BPP detects compression start time automatically by + * snooping message types */ +void ssh1_bpp_start_compression(BinaryPacketProtocol *bpp); /* Helper routine which does common BPP initialisation, e.g. setting * up in_pq and out_pq, and initialising input_consumer. */ @@ -99,7 +103,7 @@ struct DataTransferStats { ((stats)->direction.remaining -= (size), FALSE)) BinaryPacketProtocol *ssh2_bpp_new( - LogContext *logctx, struct DataTransferStats *stats); + LogContext *logctx, struct DataTransferStats *stats, int is_server); void ssh2_bpp_new_outgoing_crypto( BinaryPacketProtocol *bpp, const struct ssh2_cipheralg *cipher, const void *ckey, const void *iv, @@ -137,7 +141,7 @@ struct ssh_version_receiver { BinaryPacketProtocol *ssh_verstring_new( Conf *conf, LogContext *logctx, int bare_connection_mode, const char *protoversion, struct ssh_version_receiver *rcv, - const char *impl_name); + int server_mode, const char *impl_name); const char *ssh_verstring_get_remote(BinaryPacketProtocol *); const char *ssh_verstring_get_local(BinaryPacketProtocol *); int ssh_verstring_get_bugs(BinaryPacketProtocol *); diff --git a/sshppl.h b/sshppl.h index fa50d639..a44ba02c 100644 --- a/sshppl.h +++ b/sshppl.h @@ -96,8 +96,8 @@ PacketProtocolLayer *ssh2_transport_new( Conf *conf, const char *host, int port, const char *fullhostname, const char *client_greeting, const char *server_greeting, struct ssh_connection_shared_gss_state *shgss, - struct DataTransferStats *stats, - PacketProtocolLayer *higher_layer); + struct DataTransferStats *stats, PacketProtocolLayer *higher_layer, + int is_server); PacketProtocolLayer *ssh2_userauth_new( PacketProtocolLayer *successor_layer, const char *hostname, const char *fullhostname, @@ -135,7 +135,8 @@ ptrlen ssh2_transport_get_session_id(PacketProtocolLayer *ssh2_transport_ptr); void ssh2_transport_notify_auth_done(PacketProtocolLayer *ssh2_transport_ptr); /* Methods for ssh1login to pass protocol flags to ssh1connection */ -void ssh1_connection_set_local_protoflags(PacketProtocolLayer *ppl, int flags); +void ssh1_connection_set_protoflags( + PacketProtocolLayer *ppl, int local, int remote); /* Shared get_specials method between the two ssh1 layers */ int ssh1_common_get_specials(PacketProtocolLayer *, add_special_fn_t, void *); @@ -146,4 +147,8 @@ void ssh1_compute_session_id( unsigned char *session_id, const unsigned char *cookie, struct RSAKey *hostkey, struct RSAKey *servkey); +/* Method used by the SSH server */ +void ssh2_transport_provide_hostkeys(PacketProtocolLayer *ssh2_transport_ptr, + ssh_key *const *hostkeys, int nhostkeys); + #endif /* PUTTY_SSHPPL_H */ diff --git a/sshserver.c b/sshserver.c new file mode 100644 index 00000000..eaa22ca1 --- /dev/null +++ b/sshserver.c @@ -0,0 +1,464 @@ +/* + * Top-level code for SSH server implementation. + */ + +#include +#include + +#include "putty.h" +#include "ssh.h" +#include "sshbpp.h" +#include "sshppl.h" +#include "sshserver.h" +#ifndef NO_GSSAPI +#include "sshgssc.h" +#include "sshgss.h" +#endif + +struct Ssh { int dummy; }; + +typedef struct server server; +struct server { + bufchain in_raw, out_raw; + IdempotentCallback ic_out_raw; + + bufchain dummy_user_input; /* we never put anything on this */ + + PacketLogSettings pls; + LogContext *logctx; + struct DataTransferStats stats; + + int remote_bugs; + + Socket *socket; + Plug plug; + int conn_throttle_count; + int frozen; + + Conf *conf; + ssh_key *const *hostkeys; + int nhostkeys; + struct RSAKey *hostkey1; + AuthPolicy *authpolicy; + + Seat seat; + Ssh ssh; + struct ssh_version_receiver version_receiver; + + BinaryPacketProtocol *bpp; + PacketProtocolLayer *base_layer; + ConnectionLayer *cl; + + struct ssh_connection_shared_gss_state gss_state; +}; + +static void ssh_server_free_callback(void *vsrv); +static void server_got_ssh_version(struct ssh_version_receiver *rcv, + int major_version); +static void server_connect_bpp(server *srv); +static void server_bpp_output_raw_data_callback(void *vctx); + +void share_activate(ssh_sharing_state *sharestate, + const char *server_verstring) {} +void ssh_connshare_provide_connlayer(ssh_sharing_state *sharestate, + ConnectionLayer *cl) {} +int share_ndownstreams(ssh_sharing_state *sharestate) { return 0; } +void share_got_pkt_from_server(ssh_sharing_connstate *cs, int type, + const void *vpkt, int pktlen) {} +void share_setup_x11_channel(ssh_sharing_connstate *cs, share_channel *chan, + unsigned upstream_id, unsigned server_id, + unsigned server_currwin, unsigned server_maxpkt, + unsigned client_adjusted_window, + const char *peer_addr, int peer_port, int endian, + int protomajor, int protominor, + const void *initial_data, int initial_len) {} +Channel *agentf_new(SshChannel *c) { return NULL; } +int agent_exists(void) { return FALSE; } +void ssh_got_exitcode(Ssh *ssh, int exitcode) {} + +mainchan *mainchan_new( + PacketProtocolLayer *ppl, ConnectionLayer *cl, Conf *conf, + int term_width, int term_height, int is_simple, SshChannel **sc_out) +{ return NULL; } +void mainchan_get_specials( + mainchan *mc, add_special_fn_t add_special, void *ctx) {} +void mainchan_special_cmd(mainchan *mc, SessionSpecialCode code, int arg) {} +void mainchan_terminal_size(mainchan *mc, int width, int height) {} + +/* Seat functions to ensure we don't get choosy about crypto - as the + * server, it's not up to us to give user warnings */ +static int server_confirm_weak_crypto_primitive( + Seat *seat, const char *algtype, const char *algname, + void (*callback)(void *ctx, int result), void *ctx) { return 1; } +static int server_confirm_weak_cached_hostkey( + Seat *seat, const char *algname, const char *betteralgs, + void (*callback)(void *ctx, int result), void *ctx) { return 1; } + +static const SeatVtable server_seat_vt = { + nullseat_output, + nullseat_eof, + nullseat_get_userpass_input, + nullseat_notify_remote_exit, + nullseat_connection_fatal, + nullseat_update_specials_menu, + nullseat_get_ttymode, + nullseat_set_busy_status, + nullseat_verify_ssh_host_key, + server_confirm_weak_crypto_primitive, + server_confirm_weak_cached_hostkey, + nullseat_is_never_utf8, + nullseat_echoedit_update, + nullseat_get_x_display, + nullseat_get_windowid, + nullseat_get_window_pixel_size, +}; + +static void server_socket_log(Plug *plug, int type, SockAddr *addr, int port, + const char *error_msg, int error_code) +{ + /* server *srv = container_of(plug, server, plug); */ + /* FIXME */ +} + +static void server_closing(Plug *plug, const char *error_msg, int error_code, + int calling_back) +{ + server *srv = container_of(plug, server, plug); + if (error_msg) { + ssh_remote_error(&srv->ssh, "Network error: %s", error_msg); + } else if (srv->bpp) { + srv->bpp->input_eof = TRUE; + queue_idempotent_callback(&srv->bpp->ic_in_raw); + } +} + +static void server_receive(Plug *plug, int urgent, char *data, int len) +{ + server *srv = container_of(plug, server, plug); + + /* Log raw data, if we're in that mode. */ + if (srv->logctx) + log_packet(srv->logctx, PKT_INCOMING, -1, NULL, data, len, + 0, NULL, NULL, 0, NULL); + + bufchain_add(&srv->in_raw, data, len); + if (!srv->frozen && srv->bpp) + queue_idempotent_callback(&srv->bpp->ic_in_raw); +} + +static void server_sent(Plug *plug, int bufsize) +{ +#ifdef FIXME + server *srv = container_of(plug, server, plug); + + /* + * If the send backlog on the SSH socket itself clears, we should + * unthrottle the whole world if it was throttled. Also trigger an + * extra call to the consumer of the BPP's output, to try to send + * some more data off its bufchain. + */ + if (bufsize < SSH_MAX_BACKLOG) { + srv_throttle_all(srv, 0, bufsize); + queue_idempotent_callback(&srv->ic_out_raw); + } +#endif +} + +LogContext *ssh_get_logctx(Ssh *ssh) +{ + server *srv = container_of(ssh, server, ssh); + return srv->logctx; +} + +void ssh_throttle_conn(Ssh *ssh, int adjust) +{ + server *srv = container_of(ssh, server, ssh); + int old_count = srv->conn_throttle_count; + int frozen; + + srv->conn_throttle_count += adjust; + assert(srv->conn_throttle_count >= 0); + + if (srv->conn_throttle_count && !old_count) { + frozen = TRUE; + } else if (!srv->conn_throttle_count && old_count) { + frozen = FALSE; + } else { + return; /* don't change current frozen state */ + } + + srv->frozen = frozen; + + if (srv->socket) { + sk_set_frozen(srv->socket, frozen); + + /* + * Now process any SSH connection data that was stashed in our + * queue while we were frozen. + */ + queue_idempotent_callback(&srv->bpp->ic_in_raw); + } +} + +static const PlugVtable ssh_server_plugvt = { + server_socket_log, + server_closing, + server_receive, + server_sent, + NULL +}; + +Plug *ssh_server_plug( + Conf *conf, ssh_key *const *hostkeys, int nhostkeys, + struct RSAKey *hostkey1, AuthPolicy *authpolicy, LogPolicy *logpolicy) +{ + server *srv = snew(server); + + memset(srv, 0, sizeof(server)); + + srv->plug.vt = &ssh_server_plugvt; + srv->conf = conf_copy(conf); + srv->logctx = log_init(logpolicy, conf); + conf_set_int(srv->conf, CONF_ssh_no_shell, TRUE); + srv->nhostkeys = nhostkeys; + srv->hostkeys = hostkeys; + srv->hostkey1 = hostkey1; + srv->authpolicy = authpolicy; + + srv->seat.vt = &server_seat_vt; + + bufchain_init(&srv->in_raw); + bufchain_init(&srv->out_raw); + bufchain_init(&srv->dummy_user_input); + + /* FIXME: replace with sensible */ + srv->gss_state.libs = snew(struct ssh_gss_liblist); + srv->gss_state.libs->nlibraries = 0; + + return &srv->plug; +} + +void ssh_server_start(Plug *plug, Socket *socket) +{ + server *srv = container_of(plug, server, plug); + const char *our_protoversion; + + if (srv->hostkey1 && srv->nhostkeys) { + our_protoversion = "1.99"; /* offer both SSH-1 and SSH-2 */ + } else if (srv->hostkey1) { + our_protoversion = "1.5"; /* SSH-1 only */ + } else { + assert(srv->nhostkeys); + our_protoversion = "2.0"; /* SSH-2 only */ + } + + srv->socket = socket; + + srv->ic_out_raw.fn = server_bpp_output_raw_data_callback; + srv->ic_out_raw.ctx = srv; + srv->version_receiver.got_ssh_version = server_got_ssh_version; + srv->bpp = ssh_verstring_new( + srv->conf, srv->logctx, FALSE /* bare_connection */, + our_protoversion, &srv->version_receiver, + TRUE, "Uppity"); + server_connect_bpp(srv); + queue_idempotent_callback(&srv->bpp->ic_in_raw); +} + +static void ssh_server_free_callback(void *vsrv) +{ + server *srv = (server *)vsrv; + + bufchain_clear(&srv->in_raw); + bufchain_clear(&srv->out_raw); + bufchain_clear(&srv->dummy_user_input); + + sk_close(srv->socket); + + if (srv->bpp) + ssh_bpp_free(srv->bpp); + + delete_callbacks_for_context(srv); + + conf_free(srv->conf); + log_free(srv->logctx); + + sfree(srv->gss_state.libs); /* FIXME: replace with sensible */ + + sfree(srv); + + server_instance_terminated(); +} + +static void server_connect_bpp(server *srv) +{ + srv->bpp->ssh = &srv->ssh; + srv->bpp->in_raw = &srv->in_raw; + srv->bpp->out_raw = &srv->out_raw; + srv->bpp->out_raw->ic = &srv->ic_out_raw; + srv->bpp->pls = &srv->pls; + srv->bpp->logctx = srv->logctx; + srv->bpp->remote_bugs = srv->remote_bugs; + /* Servers don't really have a notion of 'unexpected' connection + * closure. The client is free to close if it likes. */ + srv->bpp->expect_close = TRUE; +} + +static void server_connect_ppl(server *srv, PacketProtocolLayer *ppl) +{ + ppl->bpp = srv->bpp; + ppl->user_input = &srv->dummy_user_input; + ppl->logctx = srv->logctx; + ppl->ssh = &srv->ssh; + ppl->seat = &srv->seat; + ppl->remote_bugs = srv->remote_bugs; +} + +static void server_bpp_output_raw_data_callback(void *vctx) +{ + server *srv = (server *)vctx; + + if (!srv->socket) + return; + + while (bufchain_size(&srv->out_raw) > 0) { + void *data; + int len, backlog; + + bufchain_prefix(&srv->out_raw, &data, &len); + + if (srv->logctx) + log_packet(srv->logctx, PKT_OUTGOING, -1, NULL, data, len, + 0, NULL, NULL, 0, NULL); + backlog = sk_write(srv->socket, data, len); + + bufchain_consume(&srv->out_raw, len); + + if (backlog > SSH_MAX_BACKLOG) { +#ifdef FIXME + ssh_throttle_all(ssh, 1, backlog); +#endif + return; + } + } + +#ifdef FIXME + if (ssh->pending_close) { + sk_close(ssh->s); + ssh->s = NULL; + } +#endif +} + +#define LOG_FORMATTED_MSG(logctx, fmt) do \ + { \ + va_list ap; \ + va_start(ap, fmt); \ + logeventvf(logctx, fmt, ap); \ + va_end(ap); \ + } while (0) + +void ssh_remote_error(Ssh *ssh, const char *fmt, ...) +{ + server *srv = container_of(ssh, server, ssh); + LOG_FORMATTED_MSG(srv->logctx, fmt); + queue_toplevel_callback(ssh_server_free_callback, srv); +} + +void ssh_remote_eof(Ssh *ssh, const char *fmt, ...) +{ + server *srv = container_of(ssh, server, ssh); + LOG_FORMATTED_MSG(srv->logctx, fmt); + queue_toplevel_callback(ssh_server_free_callback, srv); +} + +void ssh_proto_error(Ssh *ssh, const char *fmt, ...) +{ + server *srv = container_of(ssh, server, ssh); + LOG_FORMATTED_MSG(srv->logctx, fmt); + queue_toplevel_callback(ssh_server_free_callback, srv); +} + +void ssh_sw_abort(Ssh *ssh, const char *fmt, ...) +{ + server *srv = container_of(ssh, server, ssh); + LOG_FORMATTED_MSG(srv->logctx, fmt); + queue_toplevel_callback(ssh_server_free_callback, srv); +} + +void ssh_user_close(Ssh *ssh, const char *fmt, ...) +{ + server *srv = container_of(ssh, server, ssh); + LOG_FORMATTED_MSG(srv->logctx, fmt); + queue_toplevel_callback(ssh_server_free_callback, srv); +} + +static void server_got_ssh_version(struct ssh_version_receiver *rcv, + int major_version) +{ + server *srv = container_of(rcv, server, version_receiver); + BinaryPacketProtocol *old_bpp; + PacketProtocolLayer *connection_layer; + + old_bpp = srv->bpp; + srv->remote_bugs = ssh_verstring_get_bugs(old_bpp); + + if (major_version == 2) { + PacketProtocolLayer *userauth_layer, *transport_child_layer; + + srv->bpp = ssh2_bpp_new(srv->logctx, &srv->stats, TRUE); + server_connect_bpp(srv); + + connection_layer = ssh2_connection_new( + &srv->ssh, NULL, FALSE, srv->conf, + ssh_verstring_get_local(old_bpp), &srv->cl); + server_connect_ppl(srv, connection_layer); + + if (conf_get_int(srv->conf, CONF_ssh_no_userauth)) { + userauth_layer = NULL; + transport_child_layer = connection_layer; + } else { + userauth_layer = ssh2_userauth_server_new( + connection_layer, srv->authpolicy); + server_connect_ppl(srv, userauth_layer); + transport_child_layer = userauth_layer; + } + + srv->base_layer = ssh2_transport_new( + srv->conf, NULL, 0, NULL, + ssh_verstring_get_remote(old_bpp), + ssh_verstring_get_local(old_bpp), + &srv->gss_state, &srv->stats, transport_child_layer, TRUE); + ssh2_transport_provide_hostkeys( + srv->base_layer, srv->hostkeys, srv->nhostkeys); + if (userauth_layer) + ssh2_userauth_server_set_transport_layer( + userauth_layer, srv->base_layer); + server_connect_ppl(srv, srv->base_layer); + + } else { + srv->bpp = ssh1_bpp_new(srv->logctx); + server_connect_bpp(srv); + + connection_layer = ssh1_connection_new(&srv->ssh, srv->conf, &srv->cl); + server_connect_ppl(srv, connection_layer); + + srv->base_layer = ssh1_login_server_new( + connection_layer, srv->hostkey1, srv->authpolicy); + server_connect_ppl(srv, srv->base_layer); + } + + /* Connect the base layer - whichever it is - to the BPP, and set + * up its selfptr. */ + srv->base_layer->selfptr = &srv->base_layer; + ssh_ppl_setup_queues(srv->base_layer, &srv->bpp->in_pq, &srv->bpp->out_pq); + +#ifdef FIXME // we probably will want one of these, in the end + srv->pinger = pinger_new(srv->conf, &srv->backend); +#endif + + queue_idempotent_callback(&srv->bpp->ic_in_raw); + ssh_ppl_process_queue(srv->base_layer); + + ssh_bpp_free(old_bpp); +} diff --git a/sshserver.h b/sshserver.h new file mode 100644 index 00000000..e4d76df8 --- /dev/null +++ b/sshserver.h @@ -0,0 +1,65 @@ +typedef struct AuthPolicy AuthPolicy; + +Plug *ssh_server_plug( + Conf *conf, ssh_key *const *hostkeys, int nhostkeys, + struct RSAKey *hostkey1, AuthPolicy *authpolicy, LogPolicy *logpolicy); +void ssh_server_start(Plug *plug, Socket *socket); + +void server_instance_terminated(void); +void platform_logevent(const char *msg); + +#define AUTHMETHODS(X) \ + X(NONE) \ + X(PASSWORD) \ + X(PUBLICKEY) \ + /* end of list */ + +#define AUTHMETHOD_BIT_INDEX(name) AUTHMETHOD_BIT_INDEX_##name, +enum { AUTHMETHODS(AUTHMETHOD_BIT_INDEX) AUTHMETHOD_BIT_INDEX_dummy }; +#define AUTHMETHOD_BIT_VALUE(name) \ + AUTHMETHOD_##name = 1 << AUTHMETHOD_BIT_INDEX_##name, +enum { AUTHMETHODS(AUTHMETHOD_BIT_VALUE) AUTHMETHOD_BIT_VALUE_dummy }; + +unsigned auth_methods(AuthPolicy *); +int auth_none(AuthPolicy *, ptrlen username); +int auth_password(AuthPolicy *, ptrlen username, ptrlen password); +int auth_publickey(AuthPolicy *, ptrlen username, ptrlen public_blob); +/* auth_publickey_ssh1 must return the whole public key given the modulus, + * because the SSH-1 client never transmits the exponent over the wire. + * The key remains owned by the AuthPolicy. */ +struct RSAKey *auth_publickey_ssh1( + AuthPolicy *ap, ptrlen username, Bignum rsa_modulus); +/* auth_successful returns FALSE if further authentication is needed */ +int auth_successful(AuthPolicy *, ptrlen username, unsigned method); + +PacketProtocolLayer *ssh2_userauth_server_new( + PacketProtocolLayer *successor_layer, AuthPolicy *authpolicy); +void ssh2_userauth_server_set_transport_layer( + PacketProtocolLayer *userauth, PacketProtocolLayer *transport); + +PacketProtocolLayer *ssh1_login_server_new( + PacketProtocolLayer *successor_layer, struct RSAKey *hostkey, + AuthPolicy *authpolicy); + +Channel *sesschan_new(SshChannel *c, LogContext *logctx); + +Backend *pty_backend_create( + Seat *seat, LogContext *logctx, Conf *conf, char **argv, const char *cmd, + struct ssh_ttymodes ttymodes, int pipes_instead_of_pty); +ptrlen pty_backend_exit_signame(Backend *be, char **aux_msg); + +/* + * Establish a listening X server. Return value is the _number_ of + * Sockets that it established pointing at the given Plug. (0 + * indicates complete failure.) The socket pointers themselves are + * written into sockets[], up to a possible total of MAX_X11_SOCKETS. + * + * The supplied Conf has necessary environment variables written into + * it. (And is also used to open the port listeners, though that + * shouldn't affect anything.) + */ +#define MAX_X11_SOCKETS 2 +int platform_make_x11_server(Plug *plug, const char *progname, int mindisp, + const char *screen_number_suffix, + ptrlen authproto, ptrlen authdata, + Socket **sockets, Conf *conf); diff --git a/sshverstring.c b/sshverstring.c index f11c35ea..758c9e15 100644 --- a/sshverstring.c +++ b/sshverstring.c @@ -61,7 +61,7 @@ static int ssh_version_includes_v2(const char *ver); BinaryPacketProtocol *ssh_verstring_new( Conf *conf, LogContext *logctx, int bare_connection_mode, const char *protoversion, struct ssh_version_receiver *rcv, - const char *impl_name) + int server_mode, const char *impl_name) { struct ssh_verstring_state *s = snew(struct ssh_verstring_state); @@ -98,8 +98,10 @@ BinaryPacketProtocol *ssh_verstring_new( * We send our version string early if we can. But if it includes * SSH-1, we can't, because we have to take the other end into * account too (see below). + * + * In server mode, we do send early. */ - s->send_early = !ssh_version_includes_v1(protoversion); + s->send_early = server_mode || !ssh_version_includes_v1(protoversion); s->bpp.vt = &ssh_verstring_vtable; ssh_bpp_common_setup(&s->bpp); diff --git a/unix/uxserver.c b/unix/uxserver.c new file mode 100644 index 00000000..4c1ca982 --- /dev/null +++ b/unix/uxserver.c @@ -0,0 +1,529 @@ +/* + * SSH server for Unix: main program. + * + * ====================================================================== + * + * This server is NOT SECURE! + * + * DO NOT DEPLOY IT IN A HOSTILE-FACING ENVIRONMENT! + * + * Its purpose is to speak the server end of everything PuTTY speaks + * on the client side, so that I can test that I haven't broken PuTTY + * when I reorganise its code, even things like RSA key exchange or + * chained auth methods which it's hard to find a server that speaks + * at all. + * + * It has no interaction with the OS's authentication system: the + * authentications it will accept are configurable by command-line + * option, and once you authenticate, it will run the connection + * protocol - including all subprocesses and shells - under the same + * Unix user id you started it under. + * + * It really is only suitable for testing the actual SSH protocol. + * Don't use it for anything more serious! + * + * ====================================================================== + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifndef HAVE_NO_SYS_SELECT_H +#include +#endif + +#define PUTTY_DO_GLOBALS /* actually _define_ globals */ +#include "putty.h" +#include "ssh.h" +#include "sshserver.h" + +const char *const appname = "uppity"; + +void modalfatalbox(const char *p, ...) +{ + va_list ap; + fprintf(stderr, "FATAL ERROR: "); + va_start(ap, p); + vfprintf(stderr, p, ap); + va_end(ap); + fputc('\n', stderr); + exit(1); +} +void nonfatal(const char *p, ...) +{ + va_list ap; + fprintf(stderr, "ERROR: "); + va_start(ap, p); + vfprintf(stderr, p, ap); + va_end(ap); + fputc('\n', stderr); +} + +char *platform_default_s(const char *name) +{ + return NULL; +} + +int platform_default_i(const char *name, int def) +{ + return def; +} + +FontSpec *platform_default_fontspec(const char *name) +{ + return fontspec_new(""); +} + +Filename *platform_default_filename(const char *name) +{ + return filename_from_str(""); +} + +char *x_get_default(const char *key) +{ + return NULL; /* this is a stub */ +} + +/* + * Our selects are synchronous, so these functions are empty stubs. + */ +uxsel_id *uxsel_input_add(int fd, int rwx) { return NULL; } +void uxsel_input_remove(uxsel_id *id) { } + +void old_keyfile_warning(void) { } + +void timer_change_notify(unsigned long next) +{ +} + +char *platform_get_x_display(void) { return NULL; } + +static int verbose; + +static void log_to_stderr(const char *msg) +{ + /* + * FIXME: in multi-connection proper-socket mode, prefix this with + * a connection id of some kind. We'll surely pass this in to + * sshserver.c by way of constructing a distinct LogPolicy per + * instance and making its containing structure contain the id - + * but we'll also have to arrange for those LogPolicy structs to + * be freed when the server instance terminates. + * + * For now, though, we only have one server instance, so no need. + */ + + fputs(msg, stderr); + fputc('\n', stderr); + fflush(stderr); +} + +static void server_eventlog(LogPolicy *lp, const char *event) +{ + if (verbose) + log_to_stderr(event); +} + +static void server_logging_error(LogPolicy *lp, const char *event) +{ + log_to_stderr(event); /* unconditional */ +} + +static int server_askappend( + LogPolicy *lp, Filename *filename, + void (*callback)(void *ctx, int result), void *ctx) +{ + return 2; /* always overwrite (FIXME: could make this a cmdline option) */ +} + +static const LogPolicyVtable server_logpolicy_vt = { + server_eventlog, + server_askappend, + server_logging_error, +}; +LogPolicy server_logpolicy[1] = {{ &server_logpolicy_vt }}; + +struct AuthPolicy_ssh1_pubkey { + struct RSAKey key; + struct AuthPolicy_ssh1_pubkey *next; +}; +struct AuthPolicy_ssh2_pubkey { + ptrlen public_blob; + struct AuthPolicy_ssh2_pubkey *next; +}; + +struct AuthPolicy { + struct AuthPolicy_ssh1_pubkey *ssh1keys; + struct AuthPolicy_ssh2_pubkey *ssh2keys; +}; +unsigned auth_methods(AuthPolicy *ap) +{ + return AUTHMETHOD_PUBLICKEY | AUTHMETHOD_PASSWORD; +} +int auth_none(AuthPolicy *ap, ptrlen username) +{ + return FALSE; +} +int auth_password(AuthPolicy *ap, ptrlen username, ptrlen password) +{ + return ptrlen_eq_string(password, "weasel"); +} +int auth_publickey(AuthPolicy *ap, ptrlen username, ptrlen public_blob) +{ + struct AuthPolicy_ssh2_pubkey *iter; + for (iter = ap->ssh2keys; iter; iter = iter->next) { + if (ptrlen_eq_ptrlen(public_blob, iter->public_blob)) + return TRUE; + } + return FALSE; +} +struct RSAKey *auth_publickey_ssh1( + AuthPolicy *ap, ptrlen username, Bignum rsa_modulus) +{ + struct AuthPolicy_ssh1_pubkey *iter; + for (iter = ap->ssh1keys; iter; iter = iter->next) { + if (!bignum_cmp(rsa_modulus, iter->key.modulus)) + return &iter->key; + } + return NULL; +} +int auth_successful(AuthPolicy *ap, ptrlen username, unsigned method) +{ + return TRUE; +} + +static void show_help_and_exit(void) +{ + printf("usage: uppity [options]\n"); + printf("options: --hostkey KEY SSH host key (need at least one)\n"); + printf(" --userkey KEY public key" + " acceptable for user authentication\n"); + printf("also: uppity --help show this text\n"); + printf(" uppity --version show version information\n"); + exit(0); +} + +static void show_version_and_exit(void) +{ + char *buildinfo_text = buildinfo("\n"); + printf("uppity: %s\n%s\n", ver, buildinfo_text); + sfree(buildinfo_text); + exit(0); +} + +const int buildinfo_gtk_relevant = FALSE; + +static int finished = FALSE; +void server_instance_terminated(void) +{ + /* FIXME: change policy here if we're running in a listening loop */ + finished = TRUE; +} + +static int longoptarg(const char *arg, const char *expected, + const char **val, int *argcp, char ***argvp) +{ + int len = strlen(expected); + if (memcmp(arg, expected, len)) + return FALSE; + if (arg[len] == '=') { + *val = arg + len + 1; + return TRUE; + } else if (arg[len] == '\0') { + if (--*argcp > 0) { + *val = *++*argvp; + return TRUE; + } else { + fprintf(stderr, "uppity: option %s expects an argument\n", + expected); + exit(1); + } + } + return FALSE; +} + +int main(int argc, char **argv) +{ + int *fdlist; + int fd; + int i, fdcount, fdsize, fdstate; + unsigned long now; + + ssh_key **hostkeys = NULL; + int nhostkeys = 0, hostkeysize = 0; + struct RSAKey *hostkey1 = NULL; + + AuthPolicy ap; + + Conf *conf = conf_new(); + load_open_settings(NULL, conf); + + ap.ssh1keys = NULL; + ap.ssh2keys = NULL; + + while (--argc > 0) { + const char *arg = *++argv; + const char *val; + + if (!strcmp(arg, "--help")) { + show_help_and_exit(); + } else if (!strcmp(arg, "--version")) { + show_version_and_exit(); + } else if (!strcmp(arg, "--verbose") || !strcmp(arg, "-v")) { + verbose = TRUE; + } else if (longoptarg(arg, "--hostkey", &val, &argc, &argv)) { + Filename *keyfile; + int keytype; + const char *error; + + keyfile = filename_from_str(val); + keytype = key_type(keyfile); + + if (keytype == SSH_KEYTYPE_SSH2) { + struct ssh2_userkey *uk; + ssh_key *key; + uk = ssh2_load_userkey(keyfile, NULL, &error); + filename_free(keyfile); + if (!uk || !uk->key) { + fprintf(stderr, "uppity: unable to load host key '%s': " + "%s\n", val, error); + exit(1); + } + key = uk->key; + sfree(uk->comment); + sfree(uk); + + for (i = 0; i < nhostkeys; i++) + if (ssh_key_alg(hostkeys[i]) == ssh_key_alg(key)) { + fprintf(stderr, "uppity: host key '%s' duplicates key " + "type %s\n", val, ssh_key_alg(key)->ssh_id); + exit(1); + } + + if (nhostkeys >= hostkeysize) { + hostkeysize = nhostkeys * 5 / 4 + 16; + hostkeys = sresize(hostkeys, hostkeysize, ssh_key *); + } + hostkeys[nhostkeys++] = key; + } else if (keytype == SSH_KEYTYPE_SSH1) { + if (hostkey1) { + fprintf(stderr, "uppity: host key '%s' is a redundant " + "SSH-1 host key\n", val); + exit(1); + } + hostkey1 = snew(struct RSAKey); + if (!rsa_ssh1_loadkey(keyfile, hostkey1, NULL, &error)) { + fprintf(stderr, "uppity: unable to load host key '%s': " + "%s\n", val, error); + exit(1); + } + } else { + fprintf(stderr, "uppity: '%s' is not loadable as a " + "private key (%s)", val, key_type_to_str(keytype)); + exit(1); + } + } else if (longoptarg(arg, "--userkey", &val, &argc, &argv)) { + Filename *keyfile; + int keytype; + const char *error; + + keyfile = filename_from_str(val); + keytype = key_type(keyfile); + + if (keytype == SSH_KEYTYPE_SSH2_PUBLIC_RFC4716 || + keytype == SSH_KEYTYPE_SSH2_PUBLIC_OPENSSH) { + strbuf *sb = strbuf_new(); + struct AuthPolicy_ssh2_pubkey *node; + void *blob; + + if (!ssh2_userkey_loadpub(keyfile, NULL, BinarySink_UPCAST(sb), + NULL, &error)) { + fprintf(stderr, "uppity: unable to load user key '%s': " + "%s\n", val, error); + exit(1); + } + + node = snew_plus(struct AuthPolicy_ssh2_pubkey, sb->len); + blob = snew_plus_get_aux(node); + memcpy(blob, sb->u, sb->len); + node->public_blob = make_ptrlen(blob, sb->len); + + node->next = ap.ssh2keys; + ap.ssh2keys = node; + + strbuf_free(sb); + } else if (keytype == SSH_KEYTYPE_SSH1_PUBLIC) { + strbuf *sb = strbuf_new(); + BinarySource src[1]; + struct AuthPolicy_ssh1_pubkey *node; + + if (!rsa_ssh1_loadpub(keyfile, BinarySink_UPCAST(sb), + NULL, &error)) { + fprintf(stderr, "uppity: unable to load user key '%s': " + "%s\n", val, error); + exit(1); + } + + node = snew(struct AuthPolicy_ssh1_pubkey); + BinarySource_BARE_INIT(src, sb->u, sb->len); + get_rsa_ssh1_pub(src, &node->key, RSA_SSH1_EXPONENT_FIRST); + + node->next = ap.ssh1keys; + ap.ssh1keys = node; + + strbuf_free(sb); + } else { + fprintf(stderr, "uppity: '%s' is not loadable as a public key " + "(%s)\n", val, key_type_to_str(keytype)); + exit(1); + } + } else if (longoptarg(arg, "--sshlog", &val, &argc, &argv) || + longoptarg(arg, "-sshlog", &val, &argc, &argv)) { + Filename *logfile = filename_from_str(val); + conf_set_filename(conf, CONF_logfilename, logfile); + filename_free(logfile); + conf_set_int(conf, CONF_logtype, LGTYP_PACKETS); + conf_set_int(conf, CONF_logxfovr, LGXF_OVR); + } else if (longoptarg(arg, "--sshrawlog", &val, &argc, &argv) || + longoptarg(arg, "-sshrawlog", &val, &argc, &argv)) { + Filename *logfile = filename_from_str(val); + conf_set_filename(conf, CONF_logfilename, logfile); + filename_free(logfile); + conf_set_int(conf, CONF_logtype, LGTYP_SSHRAW); + conf_set_int(conf, CONF_logxfovr, LGXF_OVR); + } else { + fprintf(stderr, "uppity: unrecognised option '%s'\n", arg); + exit(1); + } + } + + if (nhostkeys == 0 && !hostkey1) { + fprintf(stderr, "uppity: specify at least one host key\n"); + exit(1); + } + + fdlist = NULL; + fdcount = fdsize = 0; + + random_ref(); + + /* + * Block SIGPIPE, so that we'll get EPIPE individually on + * particular network connections that go wrong. + */ + putty_signal(SIGPIPE, SIG_IGN); + + sk_init(); + uxsel_init(); + + { + Plug *plug = ssh_server_plug( + conf, hostkeys, nhostkeys, hostkey1, &ap, server_logpolicy); + ssh_server_start(plug, make_fd_socket(0, 1, -1, plug)); + } + + now = GETTICKCOUNT(); + + while (!finished) { + fd_set rset, wset, xset; + int maxfd; + int rwx; + int ret; + unsigned long next; + + FD_ZERO(&rset); + FD_ZERO(&wset); + FD_ZERO(&xset); + maxfd = 0; + + /* Count the currently active fds. */ + i = 0; + for (fd = first_fd(&fdstate, &rwx); fd >= 0; + fd = next_fd(&fdstate, &rwx)) i++; + + /* Expand the fdlist buffer if necessary. */ + if (i > fdsize) { + fdsize = i + 16; + fdlist = sresize(fdlist, fdsize, int); + } + + /* + * Add all currently open fds to the select sets, and store + * them in fdlist as well. + */ + fdcount = 0; + for (fd = first_fd(&fdstate, &rwx); fd >= 0; + fd = next_fd(&fdstate, &rwx)) { + fdlist[fdcount++] = fd; + if (rwx & 1) + FD_SET_MAX(fd, maxfd, rset); + if (rwx & 2) + FD_SET_MAX(fd, maxfd, wset); + if (rwx & 4) + FD_SET_MAX(fd, maxfd, xset); + } + + if (toplevel_callback_pending()) { + struct timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 0; + ret = select(maxfd, &rset, &wset, &xset, &tv); + } else if (run_timers(now, &next)) { + do { + unsigned long then; + long ticks; + struct timeval tv; + + then = now; + now = GETTICKCOUNT(); + if (now - then > next - then) + ticks = 0; + else + ticks = next - now; + tv.tv_sec = ticks / 1000; + tv.tv_usec = ticks % 1000 * 1000; + ret = select(maxfd, &rset, &wset, &xset, &tv); + if (ret == 0) + now = next; + else + now = GETTICKCOUNT(); + } while (ret < 0 && errno == EINTR); + } else { + ret = select(maxfd, &rset, &wset, &xset, NULL); + } + + if (ret < 0 && errno == EINTR) + continue; + + if (ret < 0) { + perror("select"); + exit(1); + } + + for (i = 0; i < fdcount; i++) { + fd = fdlist[i]; + /* + * We must process exceptional notifications before + * ordinary readability ones, or we may go straight + * past the urgent marker. + */ + if (FD_ISSET(fd, &xset)) + select_result(fd, 4); + if (FD_ISSET(fd, &rset)) + select_result(fd, 1); + if (FD_ISSET(fd, &wset)) + select_result(fd, 2); + } + + run_toplevel_callbacks(); + } +} From a081dd0a4ca0f3e99653e371f6ea14d0130a279e Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 20 Oct 2018 22:10:32 +0100 Subject: [PATCH 560/607] Add an SFTP server to the SSH server code. Unlike the traditional Unix SSH server organisation, the SFTP server is built into the same process as all the rest of the code. sesschan.c spots a subsystem request for "sftp", and responds to it by instantiating an SftpServer object and swapping out its own vtable for one that talks to it. (I rather like the idea of an object swapping its own vtable for a different one in the middle of its lifetime! This is one of those tricks that would be absurdly hard to implement in a 'proper' OO language, but when you're doing vtables by hand in C, it's no more difficult than any other piece of ordinary pointer manipulation. As long as the methods in both vtables expect the same physical structure layout, it doesn't cause a problem.) The SftpServer object doesn't deal directly with SFTP packet formats; it implements the SFTP server logic in a more abstract way, by having a vtable method for each SFTP request type with an appropriate parameter list. It sends its replies by calling methods in another vtable called SftpReplyBuilder, which in the normal case will write an SFTP reply packet to send back to the client. So SftpServer can focus more or less completely on the details of a particular filesystem API - and hence, the implementation I've got lives in the unix source directory, and works directly with file descriptors and struct stat and the like. (One purpose of this abstraction layer is that I may well want to write a second dummy implementation, for test-suite purposes, with completely controllable behaviour, and now I have a handy place to plug it in in place of the live filesystem.) In between sesschan's parsing of the byte stream into SFTP packets and the SftpServer object, there's a layer in the new file sftpserver.c which does the actual packet decoding and encoding: each request packet is passed to that, which pulls the fields out of the request packet and calls the appropriate method of SftpServer. It also provides the default SftpReplyBuilder which makes the output packet. I've moved some code out of the previous SFTP client implementation - basic packet construction code, and in particular the BinarySink/ BinarySource marshalling fuinction for fxp_attrs - into sftpcommon.c, so that the two directions can share as much as possible. --- Recipe | 6 +- configure.ac | 2 +- defs.h | 3 + psftp.c | 2 +- sesschan.c | 96 +++++- sftp.c | 130 +------- sftp.h | 214 +++++++++++- sftpcommon.c | 139 ++++++++ sftpserver.c | 278 ++++++++++++++++ ssh1connection-server.c | 2 +- ssh2connection-server.c | 11 +- ssh2connection.h | 2 + sshserver.c | 6 +- sshserver.h | 9 +- unix/uxserver.c | 5 +- unix/uxsftpserver.c | 708 ++++++++++++++++++++++++++++++++++++++++ 16 files changed, 1473 insertions(+), 140 deletions(-) create mode 100644 sftpcommon.c create mode 100644 sftpserver.c create mode 100644 unix/uxsftpserver.c diff --git a/Recipe b/Recipe index 72b899b6..309087d6 100644 --- a/Recipe +++ b/Recipe @@ -267,7 +267,7 @@ WINSSH = SSH winnoise wincapi winpgntc wingss winshare winnps winnpc UXSSH = SSH uxnoise uxagentc uxgss uxshare # SFTP implementation (pscp, psftp). -SFTP = sftp int64 logging cmdline +SFTP = sftp sftpcommon int64 logging cmdline # Miscellaneous objects appearing in all the utilities, or all the # network ones, or the Unix or Windows subsets of those in turn. @@ -283,7 +283,7 @@ UXMISC = MISCNET UXMISCCOMMON uxproxy # SSH server. SSHSERVER = SSHCOMMON sshserver settings be_none logging ssh2kex-server + ssh2userauth-server sshrsag sshprime ssh2connection-server - + sesschan int64 proxy cproxy ssh1login-server + + sesschan sftpcommon int64 sftpserver proxy cproxy ssh1login-server + ssh1connection-server # import.c and dependencies, for PuTTYgen-like utilities that have to @@ -377,7 +377,7 @@ testbn : [UT] testbn sshbn MISC version CONF tree234 uxmisc uxnogtk testbn : [C] testbn sshbn MISC version CONF tree234 winmisc LIBS uppity : [UT] uxserver SSHSERVER UXMISC uxsignal uxnoise uxgss uxnogtk - + uxpty ux_x11 uxagentsock + + uxpty uxsftpserver ux_x11 uxagentsock # ---------------------------------------------------------------------- # On Windows, provide a means of removing local test binaries that we diff --git a/configure.ac b/configure.ac index 2c6484ca..a09d6417 100644 --- a/configure.ac +++ b/configure.ac @@ -160,7 +160,7 @@ AC_CHECK_LIB(X11, XOpenDisplay, [GTK_LIBS="-lX11 $GTK_LIBS" AC_DEFINE([HAVE_LIBX11],[],[Define if libX11.a is available])]) -AC_CHECK_FUNCS([getaddrinfo posix_openpt ptsname setresuid strsignal updwtmpx]) +AC_CHECK_FUNCS([getaddrinfo posix_openpt ptsname setresuid strsignal updwtmpx fstatat dirfd]) AC_CHECK_DECLS([CLOCK_MONOTONIC], [], [], [[#include ]]) AC_SEARCH_LIBS([clock_gettime], [rt], [AC_DEFINE([HAVE_CLOCK_GETTIME],[],[Define if clock_gettime() is available])]) diff --git a/defs.h b/defs.h index ed934a13..bf257117 100644 --- a/defs.h +++ b/defs.h @@ -61,6 +61,9 @@ typedef struct Frontend Frontend; typedef struct Ssh Ssh; +typedef struct SftpServer SftpServer; +typedef struct SftpServerVtable SftpServerVtable; + typedef struct Channel Channel; typedef struct SshChannel SshChannel; typedef struct mainchan mainchan; diff --git a/psftp.c b/psftp.c index bee62b7d..8ccbb503 100644 --- a/psftp.c +++ b/psftp.c @@ -420,7 +420,7 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart) if (restart) { file = open_existing_wfile(outfname, NULL); } else { - file = open_new_file(outfname, GET_PERMISSIONS(attrs)); + file = open_new_file(outfname, GET_PERMISSIONS(attrs, -1)); } if (!file) { diff --git a/sesschan.c b/sesschan.c index 577c5feb..46116466 100644 --- a/sesschan.c +++ b/sesschan.c @@ -11,12 +11,14 @@ #include "ssh.h" #include "sshchan.h" #include "sshserver.h" +#include "sftp.h" typedef struct sesschan { SshChannel *c; LogContext *parent_logctx, *child_logctx; Conf *conf; + const SftpServerVtable *sftpserver_vt; LogPolicy logpolicy; Seat seat; @@ -39,6 +41,7 @@ typedef struct sesschan { Backend *backend; bufchain subsys_input; + SftpServer *sftpsrv; Channel chan; } sesschan; @@ -91,6 +94,35 @@ static const struct ChannelVtable sesschan_channelvt = { chan_no_request_response, }; +static int sftp_chan_send(Channel *chan, int is_stderr, const void *, int); +static void sftp_chan_send_eof(Channel *chan); +static char *sftp_log_close_msg(Channel *chan); + +static const struct ChannelVtable sftp_channelvt = { + sesschan_free, + chan_remotely_opened_confirmation, + chan_remotely_opened_failure, + sftp_chan_send, + sftp_chan_send_eof, + sesschan_set_input_wanted, + sftp_log_close_msg, + chan_default_want_close, + chan_no_exit_status, + chan_no_exit_signal, + chan_no_exit_signal_numeric, + chan_no_run_shell, + chan_no_run_command, + chan_no_run_subsystem, + chan_no_enable_x11_forwarding, + chan_no_enable_agent_forwarding, + chan_no_allocate_pty, + chan_no_set_env, + chan_no_send_break, + chan_no_send_signal, + chan_no_change_window_size, + chan_no_request_response, +}; + static void sesschan_eventlog(LogPolicy *lp, const char *event) {} static void sesschan_logging_error(LogPolicy *lp, const char *event) {} static int sesschan_askappend( @@ -128,7 +160,8 @@ static const SeatVtable sesschan_seat_vt = { sesschan_get_window_pixel_size, }; -Channel *sesschan_new(SshChannel *c, LogContext *logctx) +Channel *sesschan_new(SshChannel *c, LogContext *logctx, + const SftpServerVtable *sftpserver_vt) { sesschan *sess = snew(sesschan); memset(sess, 0, sizeof(sesschan)); @@ -150,6 +183,8 @@ Channel *sesschan_new(SshChannel *c, LogContext *logctx) sess->logpolicy.vt = &sesschan_logpolicy_vt; sess->child_logctx = log_init(&sess->logpolicy, sess->conf); + sess->sftpserver_vt = sftpserver_vt; + bufchain_init(&sess->subsys_input); return &sess->chan; @@ -165,6 +200,8 @@ static void sesschan_free(Channel *chan) if (sess->backend) backend_free(sess->backend); bufchain_clear(&sess->subsys_input); + if (sess->sftpsrv) + sftpsrv_free(sess->sftpsrv); for (i = 0; i < sess->n_x11_sockets; i++) sk_close(sess->x11_sockets[i]); if (sess->agentfwd_socket) @@ -236,6 +273,15 @@ int sesschan_run_command(Channel *chan, ptrlen command) int sesschan_run_subsystem(Channel *chan, ptrlen subsys) { + sesschan *sess = container_of(chan, sesschan, chan); + + if (ptrlen_eq_string(subsys, "sftp") && sess->sftpserver_vt) { + sess->sftpsrv = sftpsrv_new(sess->sftpserver_vt); + sess->chan.vt = &sftp_channelvt; + logevent(sess->parent_logctx, "Starting built-in SFTP subsystem"); + return TRUE; + } + return FALSE; } @@ -557,3 +603,51 @@ static int sesschan_get_window_pixel_size(Seat *seat, int *width, int *height) return TRUE; } + +/* ---------------------------------------------------------------------- + * Built-in SFTP subsystem. + */ + +static int sftp_chan_send(Channel *chan, int is_stderr, + const void *data, int length) +{ + sesschan *sess = container_of(chan, sesschan, chan); + + bufchain_add(&sess->subsys_input, data, length); + + while (bufchain_size(&sess->subsys_input) >= 4) { + char lenbuf[4]; + unsigned pktlen; + struct sftp_packet *pkt, *reply; + + bufchain_fetch(&sess->subsys_input, lenbuf, 4); + pktlen = GET_32BIT(lenbuf); + + if (bufchain_size(&sess->subsys_input) - 4 < pktlen) + break; /* wait for more data */ + + bufchain_consume(&sess->subsys_input, 4); + pkt = sftp_recv_prepare(pktlen); + bufchain_fetch_consume(&sess->subsys_input, pkt->data, pktlen); + sftp_recv_finish(pkt); + reply = sftp_handle_request(sess->sftpsrv, pkt); + sftp_pkt_free(pkt); + + sftp_send_prepare(reply); + sshfwd_write(sess->c, reply->data, reply->length); + sftp_pkt_free(reply); + } + + return 0; +} + +static void sftp_chan_send_eof(Channel *chan) +{ + sesschan *sess = container_of(chan, sesschan, chan); + sshfwd_write_eof(sess->c); +} + +static char *sftp_log_close_msg(Channel *chan) +{ + return dupstr("Session channel (SFTP) closed"); +} diff --git a/sftp.c b/sftp.c index 9aa4a7db..98b8a6e8 100644 --- a/sftp.c +++ b/sftp.c @@ -13,138 +13,24 @@ #include "tree234.h" #include "sftp.h" -struct sftp_packet { - char *data; - unsigned length, maxlen; - unsigned savedpos; - int type; - BinarySink_IMPLEMENTATION; - BinarySource_IMPLEMENTATION; -}; - static const char *fxp_error_message; static int fxp_errtype; static void fxp_internal_error(const char *msg); /* ---------------------------------------------------------------------- - * SFTP packet construction functions. - */ -static void sftp_pkt_BinarySink_write( - BinarySink *bs, const void *data, size_t length) -{ - struct sftp_packet *pkt = BinarySink_DOWNCAST(bs, struct sftp_packet); - unsigned newlen; - - assert(length <= 0xFFFFFFFFU - pkt->length); - - newlen = pkt->length + length; - if (pkt->maxlen < newlen) { - pkt->maxlen = newlen * 5 / 4 + 256; - pkt->data = sresize(pkt->data, pkt->maxlen, char); - } - - memcpy(pkt->data + pkt->length, data, length); - pkt->length = newlen; -} -static struct sftp_packet *sftp_pkt_init(int pkt_type) -{ - struct sftp_packet *pkt; - pkt = snew(struct sftp_packet); - pkt->data = NULL; - pkt->savedpos = -1; - pkt->length = 0; - pkt->maxlen = 0; - BinarySink_INIT(pkt, sftp_pkt_BinarySink_write); - put_uint32(pkt, 0); /* length field will be filled in later */ - put_byte(pkt, pkt_type); - return pkt; -} - -static void BinarySink_put_fxp_attrs(BinarySink *bs, struct fxp_attrs attrs) -{ - put_uint32(bs, attrs.flags); - if (attrs.flags & SSH_FILEXFER_ATTR_SIZE) - put_uint64(bs, attrs.size); - if (attrs.flags & SSH_FILEXFER_ATTR_UIDGID) { - put_uint32(bs, attrs.uid); - put_uint32(bs, attrs.gid); - } - if (attrs.flags & SSH_FILEXFER_ATTR_PERMISSIONS) { - put_uint32(bs, attrs.permissions); - } - if (attrs.flags & SSH_FILEXFER_ATTR_ACMODTIME) { - put_uint32(bs, attrs.atime); - put_uint32(bs, attrs.mtime); - } - if (attrs.flags & SSH_FILEXFER_ATTR_EXTENDED) { - /* - * We currently don't support sending any extended - * attributes. - */ - } -} - -static const struct fxp_attrs no_attrs = { 0 }; - -#define put_fxp_attrs(bs, attrs) \ - BinarySink_put_fxp_attrs(BinarySink_UPCAST(bs), attrs) - -/* ---------------------------------------------------------------------- - * SFTP packet decode functions. + * Client-specific parts of the send- and receive-packet system. */ -static int BinarySource_get_fxp_attrs(BinarySource *src, - struct fxp_attrs *attrs) -{ - attrs->flags = get_uint32(src); - if (attrs->flags & SSH_FILEXFER_ATTR_SIZE) - attrs->size = get_uint64(src); - if (attrs->flags & SSH_FILEXFER_ATTR_UIDGID) { - attrs->uid = get_uint32(src); - attrs->gid = get_uint32(src); - } - if (attrs->flags & SSH_FILEXFER_ATTR_PERMISSIONS) - attrs->permissions = get_uint32(src); - if (attrs->flags & SSH_FILEXFER_ATTR_ACMODTIME) { - attrs->atime = get_uint32(src); - attrs->mtime = get_uint32(src); - } - if (attrs->flags & SSH_FILEXFER_ATTR_EXTENDED) { - unsigned long count = get_uint32(src); - while (count--) { - /* - * We should try to analyse these, if we ever find one - * we recognise. - */ - get_string(src); - get_string(src); - } - } - return 1; -} - -#define get_fxp_attrs(bs, attrs) \ - BinarySource_get_fxp_attrs(BinarySource_UPCAST(bs), attrs) - -static void sftp_pkt_free(struct sftp_packet *pkt) -{ - if (pkt->data) - sfree(pkt->data); - sfree(pkt); -} - -/* ---------------------------------------------------------------------- - * Send and receive packet functions. - */ int sftp_send(struct sftp_packet *pkt) { int ret; - PUT_32BIT(pkt->data, pkt->length - 4); + sftp_send_prepare(pkt); ret = sftp_senddata(pkt->data, pkt->length); sftp_pkt_free(pkt); return ret; } + struct sftp_packet *sftp_recv(void) { struct sftp_packet *pkt; @@ -153,20 +39,14 @@ struct sftp_packet *sftp_recv(void) if (!sftp_recvdata(x, 4)) return NULL; - pkt = snew(struct sftp_packet); - pkt->savedpos = 0; - pkt->length = pkt->maxlen = GET_32BIT(x); - pkt->data = snewn(pkt->length, char); + pkt = sftp_recv_prepare(GET_32BIT(x)); if (!sftp_recvdata(pkt->data, pkt->length)) { sftp_pkt_free(pkt); return NULL; } - BinarySource_INIT(pkt, pkt->data, pkt->length); - pkt->type = get_byte(pkt); - - if (get_err(pkt)) { + if (!sftp_recv_finish(pkt)) { sftp_pkt_free(pkt); return NULL; } diff --git a/sftp.h b/sftp.h index 65c8a44d..636c42d6 100644 --- a/sftp.h +++ b/sftp.h @@ -86,6 +86,7 @@ struct fxp_attrs { unsigned long atime; unsigned long mtime; }; +extern const struct fxp_attrs no_attrs; /* * Copy between the possibly-unused permissions field in an fxp_attrs @@ -96,9 +97,9 @@ struct fxp_attrs { ((attrs).flags |= SSH_FILEXFER_ATTR_PERMISSIONS, \ (attrs).permissions = (perms)) : \ ((attrs).flags &= ~SSH_FILEXFER_ATTR_PERMISSIONS)) -#define GET_PERMISSIONS(attrs) \ +#define GET_PERMISSIONS(attrs, defaultperms) \ ((attrs).flags & SSH_FILEXFER_ATTR_PERMISSIONS ? \ - (attrs).permissions : -1) + (attrs).permissions : defaultperms) struct fxp_handle { char *hstring; @@ -116,7 +117,47 @@ struct fxp_names { }; struct sftp_request; -struct sftp_packet; + +/* + * Packet-manipulation functions. + */ + +struct sftp_packet { + char *data; + unsigned length, maxlen; + unsigned savedpos; + int type; + BinarySink_IMPLEMENTATION; + BinarySource_IMPLEMENTATION; +}; + +/* When sending a packet, create it with sftp_pkt_init, then add + * things to it by treating it as a BinarySink. When it's done, call + * sftp_send_prepare, and then pkt->data and pkt->length describe its + * wire format. */ +struct sftp_packet *sftp_pkt_init(int pkt_type); +void sftp_send_prepare(struct sftp_packet *pkt); + +/* When receiving a packet, create it with sftp_recv_prepare once you + * decode its length from the first 4 bytes of wire data. Then write + * that many bytes into pkt->data, and call sftp_recv_finish to set up + * the type code and BinarySource. */ +struct sftp_packet *sftp_recv_prepare(unsigned length); +int sftp_recv_finish(struct sftp_packet *pkt); + +/* Either kind of packet can be freed afterwards with sftp_pkt_free. */ +void sftp_pkt_free(struct sftp_packet *pkt); + +void BinarySink_put_fxp_attrs(BinarySink *bs, struct fxp_attrs attrs); +int BinarySource_get_fxp_attrs(BinarySource *src, struct fxp_attrs *attrs); +#define put_fxp_attrs(bs, attrs) \ + BinarySink_put_fxp_attrs(BinarySink_UPCAST(bs), attrs) +#define get_fxp_attrs(bs, attrs) \ + BinarySource_get_fxp_attrs(BinarySource_UPCAST(bs), attrs) + +/* + * Error handling. + */ const char *fxp_error(void); int fxp_error_type(void); @@ -269,3 +310,170 @@ int xfer_upload_gotpkt(struct fxp_xfer *xfer, struct sftp_packet *pktin); int xfer_done(struct fxp_xfer *xfer); void xfer_set_error(struct fxp_xfer *xfer); void xfer_cleanup(struct fxp_xfer *xfer); + +/* + * Vtable for the platform-specific filesystem implementation that + * answers requests in an SFTP server. + */ +typedef struct SftpReplyBuilder SftpReplyBuilder; +struct SftpServer { + const SftpServerVtable *vt; +}; +struct SftpServerVtable { + SftpServer *(*new)(const SftpServerVtable *vt); + void (*free)(SftpServer *srv); + + /* + * Handle actual filesystem requests. + * + * Each of these functions replies by calling an appropiate + * sftp_reply_foo() function on the given reply packet. + */ + + /* Should call fxp_reply_error or fxp_reply_simple_name */ + void (*realpath)(SftpServer *srv, SftpReplyBuilder *reply, + ptrlen path); + + /* Should call fxp_reply_error or fxp_reply_handle */ + void (*open)(SftpServer *srv, SftpReplyBuilder *reply, + ptrlen path, unsigned flags, struct fxp_attrs attrs); + + /* Should call fxp_reply_error or fxp_reply_handle */ + void (*opendir)(SftpServer *srv, SftpReplyBuilder *reply, + ptrlen path); + + /* Should call fxp_reply_error or fxp_reply_ok */ + void (*close)(SftpServer *srv, SftpReplyBuilder *reply, ptrlen handle); + + /* Should call fxp_reply_error or fxp_reply_ok */ + void (*mkdir)(SftpServer *srv, SftpReplyBuilder *reply, + ptrlen path, struct fxp_attrs attrs); + + /* Should call fxp_reply_error or fxp_reply_ok */ + void (*rmdir)(SftpServer *srv, SftpReplyBuilder *reply, ptrlen path); + + /* Should call fxp_reply_error or fxp_reply_ok */ + void (*remove)(SftpServer *srv, SftpReplyBuilder *reply, ptrlen path); + + /* Should call fxp_reply_error or fxp_reply_ok */ + void (*rename)(SftpServer *srv, SftpReplyBuilder *reply, + ptrlen srcpath, ptrlen dstpath); + + /* Should call fxp_reply_error or fxp_reply_attrs */ + void (*stat)(SftpServer *srv, SftpReplyBuilder *reply, ptrlen path, + int follow_symlinks); + + /* Should call fxp_reply_error or fxp_reply_attrs */ + void (*fstat)(SftpServer *srv, SftpReplyBuilder *reply, ptrlen handle); + + /* Should call fxp_reply_error or fxp_reply_ok */ + void (*setstat)(SftpServer *srv, SftpReplyBuilder *reply, + ptrlen path, struct fxp_attrs attrs); + + /* Should call fxp_reply_error or fxp_reply_ok */ + void (*fsetstat)(SftpServer *srv, SftpReplyBuilder *reply, + ptrlen handle, struct fxp_attrs attrs); + + /* Should call fxp_reply_error or fxp_reply_data */ + void (*read)(SftpServer *srv, SftpReplyBuilder *reply, + ptrlen handle, uint64 offset, unsigned length); + + /* Should call fxp_reply_error or fxp_reply_ok */ + void (*write)(SftpServer *srv, SftpReplyBuilder *reply, + ptrlen handle, uint64 offset, ptrlen data); + + /* Should call fxp_reply_error, or fxp_reply_name_count once and + * then fxp_reply_full_name that many times */ + void (*readdir)(SftpServer *srv, SftpReplyBuilder *reply, ptrlen handle, + int max_entries, int omit_longname); +}; + +#define sftpsrv_new(vt) \ + ((vt)->new(vt)) +#define sftpsrv_free(srv) \ + ((srv)->vt->free(srv)) +#define sftpsrv_realpath(srv, reply, path) \ + ((srv)->vt->realpath(srv, reply, path)) +#define sftpsrv_open(srv, reply, path, flags, attrs) \ + ((srv)->vt->open(srv, reply, path, flags, attrs)) +#define sftpsrv_opendir(srv, reply, path) \ + ((srv)->vt->opendir(srv, reply, path)) +#define sftpsrv_close(srv, reply, handle) \ + ((srv)->vt->close(srv, reply, handle)) +#define sftpsrv_mkdir(srv, reply, path, attrs) \ + ((srv)->vt->mkdir(srv, reply, path, attrs)) +#define sftpsrv_rmdir(srv, reply, path) \ + ((srv)->vt->rmdir(srv, reply, path)) +#define sftpsrv_remove(srv, reply, path) \ + ((srv)->vt->remove(srv, reply, path)) +#define sftpsrv_rename(srv, reply, srcpath, dstpath) \ + ((srv)->vt->rename(srv, reply, srcpath, dstpath)) +#define sftpsrv_stat(srv, reply, path, follow) \ + ((srv)->vt->stat(srv, reply, path, follow)) +#define sftpsrv_fstat(srv, reply, handle) \ + ((srv)->vt->fstat(srv, reply, handle)) +#define sftpsrv_setstat(srv, reply, path, attrs) \ + ((srv)->vt->setstat(srv, reply, path, attrs)) +#define sftpsrv_fsetstat(srv, reply, handle, attrs) \ + ((srv)->vt->fsetstat(srv, reply, handle, attrs)) +#define sftpsrv_read(srv, reply, handle, offset, length) \ + ((srv)->vt->read(srv, reply, handle, offset, length)) +#define sftpsrv_write(srv, reply, handle, offset, data) \ + ((srv)->vt->write(srv, reply, handle, offset, data)) +#define sftpsrv_readdir(srv, reply, handle, max, nolongname) \ + ((srv)->vt->readdir(srv, reply, handle, max, nolongname)) + +typedef struct SftpReplyBuilderVtable SftpReplyBuilderVtable; +struct SftpReplyBuilder { + const SftpReplyBuilderVtable *vt; +}; +struct SftpReplyBuilderVtable { + void (*reply_ok)(SftpReplyBuilder *reply); + void (*reply_error)(SftpReplyBuilder *reply, unsigned code, + const char *msg); + void (*reply_simple_name)(SftpReplyBuilder *reply, ptrlen name); + void (*reply_name_count)(SftpReplyBuilder *reply, unsigned count); + void (*reply_full_name)(SftpReplyBuilder *reply, ptrlen name, + ptrlen longname, struct fxp_attrs attrs); + void (*reply_handle)(SftpReplyBuilder *reply, ptrlen handle); + void (*reply_data)(SftpReplyBuilder *reply, ptrlen data); + void (*reply_attrs)(SftpReplyBuilder *reply, struct fxp_attrs attrs); +}; + +#define fxp_reply_ok(reply) \ + ((reply)->vt->reply_ok(reply)) +#define fxp_reply_error(reply, code, msg) \ + ((reply)->vt->reply_error(reply, code, msg)) +#define fxp_reply_simple_name(reply, name) \ + ((reply)->vt->reply_simple_name(reply, name)) +#define fxp_reply_name_count(reply, count) \ + ((reply)->vt->reply_name_count(reply, count)) +#define fxp_reply_full_name(reply, name, longname, attrs) \ + ((reply)->vt->reply_full_name(reply, name, longname, attrs)) +#define fxp_reply_handle(reply, handle) \ + ((reply)->vt->reply_handle(reply, handle)) +#define fxp_reply_data(reply, data) \ + ((reply)->vt->reply_data(reply, data)) +#define fxp_reply_attrs(reply, attrs) \ + ((reply)->vt->reply_attrs(reply, attrs)) + +/* + * The usual implementation of an SftpReplyBuilder, containing a + * 'struct sftp_packet' which is assumed to be already initialised + * before one of the above request methods is called. + */ +extern const struct SftpReplyBuilderVtable DefaultSftpReplyBuilder_vt; +typedef struct DefaultSftpReplyBuilder DefaultSftpReplyBuilder; +struct DefaultSftpReplyBuilder { + SftpReplyBuilder rb; + struct sftp_packet *pkt; +}; + +/* + * The top-level function that handles an SFTP request, given an + * implementation of the above SftpServer abstraction to do the actual + * filesystem work. It handles all the marshalling and unmarshalling + * of packets, and the copying of request ids into the responses. + */ +struct sftp_packet *sftp_handle_request( + SftpServer *srv, struct sftp_packet *request); diff --git a/sftpcommon.c b/sftpcommon.c new file mode 100644 index 00000000..5becf3ce --- /dev/null +++ b/sftpcommon.c @@ -0,0 +1,139 @@ +/* + * sftpcommon.c: SFTP code shared between client and server. + */ + +#include +#include +#include +#include +#include + +#include "misc.h" +#include "sftp.h" + +static void sftp_pkt_BinarySink_write( + BinarySink *bs, const void *data, size_t length) +{ + struct sftp_packet *pkt = BinarySink_DOWNCAST(bs, struct sftp_packet); + unsigned newlen; + + assert(length <= 0xFFFFFFFFU - pkt->length); + + newlen = pkt->length + length; + if (pkt->maxlen < newlen) { + pkt->maxlen = newlen * 5 / 4 + 256; + pkt->data = sresize(pkt->data, pkt->maxlen, char); + } + + memcpy(pkt->data + pkt->length, data, length); + pkt->length = newlen; +} + +struct sftp_packet *sftp_pkt_init(int type) +{ + struct sftp_packet *pkt; + pkt = snew(struct sftp_packet); + pkt->data = NULL; + pkt->savedpos = -1; + pkt->length = 0; + pkt->maxlen = 0; + pkt->type = type; + BinarySink_INIT(pkt, sftp_pkt_BinarySink_write); + put_uint32(pkt, 0); /* length field will be filled in later */ + put_byte(pkt, 0); /* so will the type field */ + return pkt; +} + +void BinarySink_put_fxp_attrs(BinarySink *bs, struct fxp_attrs attrs) +{ + put_uint32(bs, attrs.flags); + if (attrs.flags & SSH_FILEXFER_ATTR_SIZE) + put_uint64(bs, attrs.size); + if (attrs.flags & SSH_FILEXFER_ATTR_UIDGID) { + put_uint32(bs, attrs.uid); + put_uint32(bs, attrs.gid); + } + if (attrs.flags & SSH_FILEXFER_ATTR_PERMISSIONS) { + put_uint32(bs, attrs.permissions); + } + if (attrs.flags & SSH_FILEXFER_ATTR_ACMODTIME) { + put_uint32(bs, attrs.atime); + put_uint32(bs, attrs.mtime); + } + if (attrs.flags & SSH_FILEXFER_ATTR_EXTENDED) { + /* + * We currently don't support sending any extended + * attributes. + */ + } +} + +const struct fxp_attrs no_attrs = { 0 }; + +#define put_fxp_attrs(bs, attrs) \ + BinarySink_put_fxp_attrs(BinarySink_UPCAST(bs), attrs) + +int BinarySource_get_fxp_attrs(BinarySource *src, struct fxp_attrs *attrs) +{ + attrs->flags = get_uint32(src); + if (attrs->flags & SSH_FILEXFER_ATTR_SIZE) + attrs->size = get_uint64(src); + if (attrs->flags & SSH_FILEXFER_ATTR_UIDGID) { + attrs->uid = get_uint32(src); + attrs->gid = get_uint32(src); + } + if (attrs->flags & SSH_FILEXFER_ATTR_PERMISSIONS) + attrs->permissions = get_uint32(src); + if (attrs->flags & SSH_FILEXFER_ATTR_ACMODTIME) { + attrs->atime = get_uint32(src); + attrs->mtime = get_uint32(src); + } + if (attrs->flags & SSH_FILEXFER_ATTR_EXTENDED) { + unsigned long count = get_uint32(src); + while (count--) { + /* + * We should try to analyse these, if we ever find one + * we recognise. + */ + get_string(src); + get_string(src); + } + } + return 1; +} + +void sftp_pkt_free(struct sftp_packet *pkt) +{ + if (pkt->data) + sfree(pkt->data); + sfree(pkt); +} + +void sftp_send_prepare(struct sftp_packet *pkt) +{ + PUT_32BIT(pkt->data, pkt->length - 4); + if (pkt->length >= 5) { + /* Rewrite the type code, in case the caller changed its mind + * about pkt->type since calling sftp_pkt_init */ + pkt->data[4] = pkt->type; + } +} + +struct sftp_packet *sftp_recv_prepare(unsigned length) +{ + struct sftp_packet *pkt; + + pkt = snew(struct sftp_packet); + pkt->savedpos = 0; + pkt->length = pkt->maxlen = length; + pkt->data = snewn(pkt->length, char); + + return pkt; +} + +int sftp_recv_finish(struct sftp_packet *pkt) +{ + BinarySource_INIT(pkt, pkt->data, pkt->length); + pkt->type = get_byte(pkt); + return !get_err(pkt); +} diff --git a/sftpserver.c b/sftpserver.c new file mode 100644 index 00000000..4324137e --- /dev/null +++ b/sftpserver.c @@ -0,0 +1,278 @@ +/* + * Implement the centralised parts of the server side of SFTP. + */ + +#include +#include +#include + +#include "putty.h" +#include "ssh.h" +#include "sftp.h" + +struct sftp_packet *sftp_handle_request( + SftpServer *srv, struct sftp_packet *req) +{ + struct sftp_packet *reply; + unsigned id; + ptrlen path, dstpath, handle, data; + uint64 offset; + unsigned length; + struct fxp_attrs attrs; + DefaultSftpReplyBuilder dsrb; + SftpReplyBuilder *rb; + + if (req->type == SSH_FXP_INIT) { + /* + * Special case which doesn't have a request id at the start. + */ + reply = sftp_pkt_init(SSH_FXP_VERSION); + /* + * Since we support only the lowest protocol version, we don't + * need to take the min of this and the client's version, or + * even to bother reading the client version number out of the + * input packet. + */ + put_uint32(reply, SFTP_PROTO_VERSION); + return reply; + } + + /* + * Centralise the request id handling. We'll overwrite the type + * code of the output packet later. + */ + id = get_uint32(req); + reply = sftp_pkt_init(0); + put_uint32(reply, id); + + dsrb.rb.vt = &DefaultSftpReplyBuilder_vt; + dsrb.pkt = reply; + rb = &dsrb.rb; + + switch (req->type) { + case SSH_FXP_REALPATH: + path = get_string(req); + if (get_err(req)) + goto decode_error; + sftpsrv_realpath(srv, rb, path); + break; + + case SSH_FXP_OPEN: + path = get_string(req); + flags = get_uint32(req); + get_fxp_attrs(req, &attrs); + if (get_err(req)) + goto decode_error; + if ((flags & (SSH_FXF_READ|SSH_FXF_WRITE)) == 0) { + fxp_reply_error(rb, SSH_FX_BAD_MESSAGE, + "open without READ or WRITE flag"); + } else if ((flags & (SSH_FXF_CREAT|SSH_FXF_TRUNC)) == SSH_FXF_TRUNC) { + fxp_reply_error(rb, SSH_FX_BAD_MESSAGE, + "open with TRUNC but not CREAT"); + } else if ((flags & (SSH_FXF_CREAT|SSH_FXF_EXCL)) == SSH_FXF_EXCL) { + fxp_reply_error(rb, SSH_FX_BAD_MESSAGE, + "open with EXCL but not CREAT"); + } else { + sftpsrv_open(srv, rb, path, flags, attrs); + } + break; + + case SSH_FXP_OPENDIR: + path = get_string(req); + if (get_err(req)) + goto decode_error; + sftpsrv_opendir(srv, rb, path); + break; + + case SSH_FXP_CLOSE: + handle = get_string(req); + if (get_err(req)) + goto decode_error; + sftpsrv_close(srv, rb, handle); + break; + + case SSH_FXP_MKDIR: + path = get_string(req); + get_fxp_attrs(req, &attrs); + if (get_err(req)) + goto decode_error; + sftpsrv_mkdir(srv, rb, path, attrs); + break; + + case SSH_FXP_RMDIR: + path = get_string(req); + if (get_err(req)) + goto decode_error; + sftpsrv_rmdir(srv, rb, path); + break; + + case SSH_FXP_REMOVE: + path = get_string(req); + if (get_err(req)) + goto decode_error; + sftpsrv_remove(srv, rb, path); + break; + + case SSH_FXP_RENAME: + path = get_string(req); + dstpath = get_string(req); + if (get_err(req)) + goto decode_error; + sftpsrv_rename(srv, rb, path, dstpath); + break; + + case SSH_FXP_STAT: + path = get_string(req); + if (get_err(req)) + goto decode_error; + sftpsrv_stat(srv, rb, path, TRUE); + break; + + case SSH_FXP_LSTAT: + path = get_string(req); + if (get_err(req)) + goto decode_error; + sftpsrv_stat(srv, rb, path, FALSE); + break; + + case SSH_FXP_FSTAT: + handle = get_string(req); + if (get_err(req)) + goto decode_error; + sftpsrv_fstat(srv, rb, handle); + break; + + case SSH_FXP_SETSTAT: + path = get_string(req); + get_fxp_attrs(req, &attrs); + if (get_err(req)) + goto decode_error; + sftpsrv_setstat(srv, rb, path, attrs); + break; + + case SSH_FXP_FSETSTAT: + handle = get_string(req); + get_fxp_attrs(req, &attrs); + if (get_err(req)) + goto decode_error; + sftpsrv_fsetstat(srv, rb, handle, attrs); + break; + + case SSH_FXP_READ: + handle = get_string(req); + offset = get_uint64(req); + length = get_uint32(req); + if (get_err(req)) + goto decode_error; + sftpsrv_read(srv, rb, handle, offset, length); + break; + + case SSH_FXP_READDIR: + handle = get_string(req); + if (get_err(req)) + goto decode_error; + sftpsrv_readdir(srv, rb, handle, INT_MAX, FALSE); + break; + + case SSH_FXP_WRITE: + handle = get_string(req); + offset = get_uint64(req); + data = get_string(req); + if (get_err(req)) + goto decode_error; + sftpsrv_write(srv, rb, handle, offset, data); + break; + + default: + if (get_err(req)) + goto decode_error; + fxp_reply_error(rb, SSH_FX_OP_UNSUPPORTED, + "Unrecognised request type"); + break; + + decode_error: + fxp_reply_error(rb, SSH_FX_BAD_MESSAGE, "Unable to decode request"); + } + + return reply; +} + +static void default_reply_ok(SftpReplyBuilder *reply) +{ + DefaultSftpReplyBuilder *d = + container_of(reply, DefaultSftpReplyBuilder, rb); + d->pkt->type = SSH_FXP_STATUS; + put_uint32(d->pkt, SSH_FX_OK); + put_stringz(d->pkt, ""); +} + +static void default_reply_error( + SftpReplyBuilder *reply, unsigned code, const char *msg) +{ + DefaultSftpReplyBuilder *d = + container_of(reply, DefaultSftpReplyBuilder, rb); + d->pkt->type = SSH_FXP_STATUS; + put_uint32(d->pkt, code); + put_stringz(d->pkt, msg); +} + +static void default_reply_name_count(SftpReplyBuilder *reply, unsigned count) +{ + DefaultSftpReplyBuilder *d = + container_of(reply, DefaultSftpReplyBuilder, rb); + d->pkt->type = SSH_FXP_NAME; + put_uint32(d->pkt, count); +} + +static void default_reply_full_name(SftpReplyBuilder *reply, ptrlen name, + ptrlen longname, struct fxp_attrs attrs) +{ + DefaultSftpReplyBuilder *d = + container_of(reply, DefaultSftpReplyBuilder, rb); + d->pkt->type = SSH_FXP_NAME; + put_stringpl(d->pkt, name); + put_stringpl(d->pkt, longname); + put_fxp_attrs(d->pkt, attrs); +} + +static void default_reply_simple_name(SftpReplyBuilder *reply, ptrlen name) +{ + fxp_reply_name_count(reply, 1); + fxp_reply_full_name(reply, name, PTRLEN_LITERAL(""), no_attrs); +} + +static void default_reply_handle(SftpReplyBuilder *reply, ptrlen handle) +{ + DefaultSftpReplyBuilder *d = + container_of(reply, DefaultSftpReplyBuilder, rb); + d->pkt->type = SSH_FXP_HANDLE; + put_stringpl(d->pkt, handle); +} + +static void default_reply_data(SftpReplyBuilder *reply, ptrlen data) +{ + DefaultSftpReplyBuilder *d = + container_of(reply, DefaultSftpReplyBuilder, rb); + d->pkt->type = SSH_FXP_DATA; + put_stringpl(d->pkt, data); +} + +static void default_reply_attrs( + SftpReplyBuilder *reply, struct fxp_attrs attrs) +{ + DefaultSftpReplyBuilder *d = + container_of(reply, DefaultSftpReplyBuilder, rb); + d->pkt->type = SSH_FXP_ATTRS; + put_fxp_attrs(d->pkt, attrs); +} + +const struct SftpReplyBuilderVtable DefaultSftpReplyBuilder_vt = { + default_reply_ok, + default_reply_error, + default_reply_simple_name, + default_reply_name_count, + default_reply_full_name, + default_reply_handle, + default_reply_data, + default_reply_attrs, +}; diff --git a/ssh1connection-server.c b/ssh1connection-server.c index 01ea6f8d..330b9058 100644 --- a/ssh1connection-server.c +++ b/ssh1connection-server.c @@ -50,7 +50,7 @@ void ssh1_connection_direction_specific_setup( if (!s->mainchan_chan) { s->mainchan_sc.vt = &ssh1sesschan_vtable; s->mainchan_sc.cl = &s->cl; - s->mainchan_chan = sesschan_new(&s->mainchan_sc, s->ppl.logctx); + s->mainchan_chan = sesschan_new(&s->mainchan_sc, s->ppl.logctx, NULL); } } diff --git a/ssh2connection-server.c b/ssh2connection-server.c index da4b60cf..7691ffb1 100644 --- a/ssh2connection-server.c +++ b/ssh2connection-server.c @@ -13,13 +13,22 @@ #include "ssh2connection.h" #include "sshserver.h" +void ssh2connection_server_configure( + PacketProtocolLayer *ppl, const SftpServerVtable *sftpserver_vt) +{ + struct ssh2_connection_state *s = + container_of(ppl, struct ssh2_connection_state, ppl); + s->sftpserver_vt = sftpserver_vt; +} + static ChanopenResult chan_open_session( struct ssh2_connection_state *s, SshChannel *sc) { PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */ ppl_logevent(("Opened session channel")); - CHANOPEN_RETURN_SUCCESS(sesschan_new(sc, s->ppl.logctx)); + CHANOPEN_RETURN_SUCCESS(sesschan_new(sc, s->ppl.logctx, + s->sftpserver_vt)); } static ChanopenResult chan_open_direct_tcpip( diff --git a/ssh2connection.h b/ssh2connection.h index a441127e..058efb57 100644 --- a/ssh2connection.h +++ b/ssh2connection.h @@ -37,6 +37,8 @@ struct ssh2_connection_state { PortFwdManager *portfwdmgr; int portfwdmgr_configured; + const SftpServerVtable *sftpserver_vt; + /* * These store the list of global requests that we're waiting for * replies to. (REQUEST_FAILURE doesn't come with any indication diff --git a/sshserver.c b/sshserver.c index eaa22ca1..9c3963e1 100644 --- a/sshserver.c +++ b/sshserver.c @@ -40,6 +40,7 @@ struct server { int nhostkeys; struct RSAKey *hostkey1; AuthPolicy *authpolicy; + const SftpServerVtable *sftpserver_vt; Seat seat; Ssh ssh; @@ -210,7 +211,8 @@ static const PlugVtable ssh_server_plugvt = { Plug *ssh_server_plug( Conf *conf, ssh_key *const *hostkeys, int nhostkeys, - struct RSAKey *hostkey1, AuthPolicy *authpolicy, LogPolicy *logpolicy) + struct RSAKey *hostkey1, AuthPolicy *authpolicy, LogPolicy *logpolicy, + const SftpServerVtable *sftpserver_vt) { server *srv = snew(server); @@ -224,6 +226,7 @@ Plug *ssh_server_plug( srv->hostkeys = hostkeys; srv->hostkey1 = hostkey1; srv->authpolicy = authpolicy; + srv->sftpserver_vt = sftpserver_vt; srv->seat.vt = &server_seat_vt; @@ -412,6 +415,7 @@ static void server_got_ssh_version(struct ssh_version_receiver *rcv, connection_layer = ssh2_connection_new( &srv->ssh, NULL, FALSE, srv->conf, ssh_verstring_get_local(old_bpp), &srv->cl); + ssh2connection_server_configure(connection_layer, srv->sftpserver_vt); server_connect_ppl(srv, connection_layer); if (conf_get_int(srv->conf, CONF_ssh_no_userauth)) { diff --git a/sshserver.h b/sshserver.h index e4d76df8..fa0ee87e 100644 --- a/sshserver.h +++ b/sshserver.h @@ -2,7 +2,8 @@ typedef struct AuthPolicy AuthPolicy; Plug *ssh_server_plug( Conf *conf, ssh_key *const *hostkeys, int nhostkeys, - struct RSAKey *hostkey1, AuthPolicy *authpolicy, LogPolicy *logpolicy); + struct RSAKey *hostkey1, AuthPolicy *authpolicy, LogPolicy *logpolicy, + const SftpServerVtable *sftpserver_vt); void ssh_server_start(Plug *plug, Socket *socket); void server_instance_terminated(void); @@ -37,11 +38,15 @@ PacketProtocolLayer *ssh2_userauth_server_new( void ssh2_userauth_server_set_transport_layer( PacketProtocolLayer *userauth, PacketProtocolLayer *transport); +void ssh2connection_server_configure( + PacketProtocolLayer *ppl, const SftpServerVtable *sftpserver_vt); + PacketProtocolLayer *ssh1_login_server_new( PacketProtocolLayer *successor_layer, struct RSAKey *hostkey, AuthPolicy *authpolicy); -Channel *sesschan_new(SshChannel *c, LogContext *logctx); +Channel *sesschan_new(SshChannel *c, LogContext *logctx, + const SftpServerVtable *sftpserver_vt); Backend *pty_backend_create( Seat *seat, LogContext *logctx, Conf *conf, char **argv, const char *cmd, diff --git a/unix/uxserver.c b/unix/uxserver.c index 4c1ca982..b5e08404 100644 --- a/unix/uxserver.c +++ b/unix/uxserver.c @@ -251,6 +251,8 @@ static int longoptarg(const char *arg, const char *expected, return FALSE; } +extern const SftpServerVtable unix_live_sftpserver_vt; + int main(int argc, char **argv) { int *fdlist; @@ -427,7 +429,8 @@ int main(int argc, char **argv) { Plug *plug = ssh_server_plug( - conf, hostkeys, nhostkeys, hostkey1, &ap, server_logpolicy); + conf, hostkeys, nhostkeys, hostkey1, &ap, server_logpolicy, + &unix_live_sftpserver_vt); ssh_server_start(plug, make_fd_socket(0, 1, -1, plug)); } diff --git a/unix/uxsftpserver.c b/unix/uxsftpserver.c new file mode 100644 index 00000000..ddc84665 --- /dev/null +++ b/unix/uxsftpserver.c @@ -0,0 +1,708 @@ +/* + * Implement the SftpServer abstraction, in the 'live' form (i.e. + * really operating on the Unix filesystem). + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "putty.h" +#include "ssh.h" +#include "sftp.h" +#include "tree234.h" + +typedef struct UnixSftpServer UnixSftpServer; + +struct UnixSftpServer { + unsigned *fdseqs; + int *fdsopen; + int fdsize; + + tree234 *dirhandles; + int last_dirhandle_index; + + char handlekey[8]; + + SftpServer srv; +}; + +struct uss_dirhandle { + int index; + DIR *dp; +}; + +#define USS_DIRHANDLE_SEQ (0xFFFFFFFFU) + +static int uss_dirhandle_cmp(void *av, void *bv) +{ + struct uss_dirhandle *a = (struct uss_dirhandle *)av; + struct uss_dirhandle *b = (struct uss_dirhandle *)bv; + if (a->index < b->index) + return -1; + if (a->index > b->index) + return +1; + return 0; +} + +static SftpServer *uss_new(const SftpServerVtable *vt) +{ + int i; + UnixSftpServer *uss = snew(UnixSftpServer); + + memset(uss, 0, sizeof(UnixSftpServer)); + + uss->dirhandles = newtree234(uss_dirhandle_cmp); + uss->srv.vt = vt; + + for (i = 0; i < lenof(uss->handlekey); i++) + uss->handlekey[i] = random_byte(); + + return &uss->srv; +} + +static void uss_free(SftpServer *srv) +{ + UnixSftpServer *uss = container_of(srv, UnixSftpServer, srv); + struct uss_dirhandle *udh; + int i; + + for (i = 0; i < uss->fdsize; i++) + if (uss->fdsopen[i]) + close(i); + sfree(uss->fdseqs); + + while ((udh = delpos234(uss->dirhandles, 0)) != NULL) { + closedir(udh->dp); + sfree(udh); + } + + sfree(uss); +} + +static void uss_return_handle_raw( + UnixSftpServer *uss, SftpReplyBuilder *reply, int index, unsigned seq) +{ + unsigned char handlebuf[8]; + PUT_32BIT(handlebuf, index); + PUT_32BIT(handlebuf + 4, seq); + des_encrypt_xdmauth(uss->handlekey, handlebuf, 8); + fxp_reply_handle(reply, make_ptrlen(handlebuf, 8)); +} + +static int uss_decode_handle( + UnixSftpServer *uss, ptrlen handle, int *index, unsigned *seq) +{ + unsigned char handlebuf[8]; + + if (handle.len != 8) + return FALSE; + memcpy(handlebuf, handle.ptr, 8); + des_decrypt_xdmauth(uss->handlekey, handlebuf, 8); + *index = toint(GET_32BIT(handlebuf)); + *seq = GET_32BIT(handlebuf + 4); + return TRUE; +} + +static void uss_return_new_handle( + UnixSftpServer *uss, SftpReplyBuilder *reply, int fd) +{ + assert(fd >= 0); + if (fd >= uss->fdsize) { + int old_size = uss->fdsize; + uss->fdsize = fd * 5 / 4 + 32; + uss->fdseqs = sresize(uss->fdseqs, uss->fdsize, unsigned); + uss->fdsopen = sresize(uss->fdsopen, uss->fdsize, int); + while (old_size < uss->fdsize) { + uss->fdseqs[old_size] = 0; + uss->fdsopen[old_size] = FALSE; + old_size++; + } + } + assert(!uss->fdsopen[fd]); + uss->fdsopen[fd] = TRUE; + if (++uss->fdseqs[fd] == USS_DIRHANDLE_SEQ) + uss->fdseqs[fd] = 0; + uss_return_handle_raw(uss, reply, fd, uss->fdseqs[fd]); +} + +static int uss_try_lookup_fd(UnixSftpServer *uss, ptrlen handle) +{ + int fd; + unsigned seq; + if (!uss_decode_handle(uss, handle, &fd, &seq) || + fd < 0 || fd >= uss->fdsize || + !uss->fdsopen[fd] || uss->fdseqs[fd] != seq) + return -1; + + return fd; +} + +static int uss_lookup_fd(UnixSftpServer *uss, SftpReplyBuilder *reply, + ptrlen handle) +{ + int fd = uss_try_lookup_fd(uss, handle); + if (fd < 0) + fxp_reply_error(reply, SSH_FX_FAILURE, "invalid file handle"); + return fd; +} + +static void uss_return_new_dirhandle( + UnixSftpServer *uss, SftpReplyBuilder *reply, DIR *dp) +{ + struct uss_dirhandle *udh = snew(struct uss_dirhandle); + udh->index = uss->last_dirhandle_index++; + udh->dp = dp; + struct uss_dirhandle *added = add234(uss->dirhandles, udh); + assert(added == udh); + uss_return_handle_raw(uss, reply, udh->index, USS_DIRHANDLE_SEQ); +} + +static struct uss_dirhandle *uss_try_lookup_dirhandle( + UnixSftpServer *uss, ptrlen handle) +{ + struct uss_dirhandle key, *udh; + unsigned seq; + + if (!uss_decode_handle(uss, handle, &key.index, &seq) || + seq != USS_DIRHANDLE_SEQ || + (udh = find234(uss->dirhandles, &key, NULL)) == NULL) + return NULL; + + return udh; +} + +static struct uss_dirhandle *uss_lookup_dirhandle( + UnixSftpServer *uss, SftpReplyBuilder *reply, ptrlen handle) +{ + struct uss_dirhandle *udh = uss_try_lookup_dirhandle(uss, handle); + if (!udh) + fxp_reply_error(reply, SSH_FX_FAILURE, "invalid file handle"); + return udh; +} + +static void uss_error(UnixSftpServer *uss, SftpReplyBuilder *reply) +{ + unsigned code = SSH_FX_FAILURE; + switch (errno) { + case ENOENT: + code = SSH_FX_NO_SUCH_FILE; + break; + case EPERM: + code = SSH_FX_PERMISSION_DENIED; + break; + } + fxp_reply_error(reply, code, strerror(errno)); +} + +static void uss_realpath(SftpServer *srv, SftpReplyBuilder *reply, + ptrlen path) +{ + UnixSftpServer *uss = container_of(srv, UnixSftpServer, srv); + + char *inpath = mkstr(path); + char *outpath = realpath(inpath, NULL); + free(inpath); + + if (!outpath) { + uss_error(uss, reply); + } else { + fxp_reply_simple_name(reply, ptrlen_from_asciz(outpath)); + free(outpath); + } +} + +static void uss_open(SftpServer *srv, SftpReplyBuilder *reply, + ptrlen path, unsigned flags, struct fxp_attrs attrs) +{ + UnixSftpServer *uss = container_of(srv, UnixSftpServer, srv); + + int openflags = 0; + if (!((SSH_FXF_READ | SSH_FXF_WRITE) &~ flags)) + openflags |= O_RDWR; + else if (flags & SSH_FXF_WRITE) + openflags |= O_WRONLY; + else if (flags & SSH_FXF_READ) + openflags |= O_RDONLY; + if (flags & SSH_FXF_APPEND) + openflags |= O_APPEND; + if (flags & SSH_FXF_CREAT) + openflags |= O_CREAT; + if (flags & SSH_FXF_TRUNC) + openflags |= O_TRUNC; + if (flags & SSH_FXF_EXCL) + openflags |= O_EXCL; + + char *pathstr = mkstr(path); + int fd = open(pathstr, openflags, GET_PERMISSIONS(attrs, 0777)); + free(pathstr); + + if (fd < 0) { + uss_error(uss, reply); + } else { + uss_return_new_handle(uss, reply, fd); + } +} + +static void uss_opendir(SftpServer *srv, SftpReplyBuilder *reply, + ptrlen path) +{ + UnixSftpServer *uss = container_of(srv, UnixSftpServer, srv); + + char *pathstr = mkstr(path); + DIR *dp = opendir(pathstr); + free(pathstr); + + if (!dp) { + uss_error(uss, reply); + } else { + uss_return_new_dirhandle(uss, reply, dp); + } +} + +static void uss_close(SftpServer *srv, SftpReplyBuilder *reply, + ptrlen handle) +{ + UnixSftpServer *uss = container_of(srv, UnixSftpServer, srv); + int fd; + struct uss_dirhandle *udh; + + if ((udh = uss_try_lookup_dirhandle(uss, handle)) != NULL) { + closedir(udh->dp); + del234(uss->dirhandles, udh); + sfree(udh); + fxp_reply_ok(reply); + } else if ((fd = uss_lookup_fd(uss, reply, handle)) >= 0) { + close(fd); + assert(0 <= fd && fd <= uss->fdsize); + uss->fdsopen[fd] = FALSE; + fxp_reply_ok(reply); + } + /* if both failed, uss_lookup_fd will have filled in an error response */ +} + +static void uss_mkdir(SftpServer *srv, SftpReplyBuilder *reply, + ptrlen path, struct fxp_attrs attrs) +{ + UnixSftpServer *uss = container_of(srv, UnixSftpServer, srv); + + char *pathstr = mkstr(path); + int status = mkdir(pathstr, GET_PERMISSIONS(attrs, 0777)); + free(pathstr); + + if (status < 0) { + uss_error(uss, reply); + } else { + fxp_reply_ok(reply); + } +} + +static void uss_rmdir(SftpServer *srv, SftpReplyBuilder *reply, ptrlen path) +{ + UnixSftpServer *uss = container_of(srv, UnixSftpServer, srv); + + char *pathstr = mkstr(path); + int status = rmdir(pathstr); + free(pathstr); + + if (status < 0) { + uss_error(uss, reply); + } else { + fxp_reply_ok(reply); + } +} + +static void uss_remove(SftpServer *srv, SftpReplyBuilder *reply, + ptrlen path) +{ + UnixSftpServer *uss = container_of(srv, UnixSftpServer, srv); + + char *pathstr = mkstr(path); + int status = unlink(pathstr); + free(pathstr); + + if (status < 0) { + uss_error(uss, reply); + } else { + fxp_reply_ok(reply); + } +} + +static void uss_rename(SftpServer *srv, SftpReplyBuilder *reply, + ptrlen srcpath, ptrlen dstpath) +{ + UnixSftpServer *uss = container_of(srv, UnixSftpServer, srv); + + char *srcstr = mkstr(srcpath), *dststr = mkstr(dstpath); + int status = rename(srcstr, dststr); + free(srcstr); + free(dststr); + + if (status < 0) { + uss_error(uss, reply); + } else { + fxp_reply_ok(reply); + } +} + +static uint64 uint64_from_off_t(off_t off) +{ + return uint64_make((off >> 16) >> 16, (off & 0xFFFFFFFFU)); +} + +static struct fxp_attrs uss_translate_struct_stat(const struct stat *st) +{ + struct fxp_attrs attrs; + + attrs.flags = (SSH_FILEXFER_ATTR_SIZE | + SSH_FILEXFER_ATTR_PERMISSIONS | + SSH_FILEXFER_ATTR_UIDGID | + SSH_FILEXFER_ATTR_ACMODTIME); + + attrs.size = uint64_from_off_t(st->st_size); + attrs.permissions = st->st_mode; + attrs.uid = st->st_uid; + attrs.gid = st->st_gid; + attrs.atime = st->st_atime; + attrs.mtime = st->st_mtime; + + return attrs; +} + +static void uss_reply_struct_stat(SftpReplyBuilder *reply, + const struct stat *st) +{ + fxp_reply_attrs(reply, uss_translate_struct_stat(st)); +} + +static void uss_stat(SftpServer *srv, SftpReplyBuilder *reply, + ptrlen path, int follow_symlinks) +{ + UnixSftpServer *uss = container_of(srv, UnixSftpServer, srv); + struct stat st; + + char *pathstr = mkstr(path); + int status = (follow_symlinks ? stat : lstat) (pathstr, &st); + free(pathstr); + + if (status < 0) { + uss_error(uss, reply); + } else { + uss_reply_struct_stat(reply, &st); + } +} + +static void uss_fstat(SftpServer *srv, SftpReplyBuilder *reply, + ptrlen handle) +{ + UnixSftpServer *uss = container_of(srv, UnixSftpServer, srv); + struct stat st; + int fd; + + if ((fd = uss_lookup_fd(uss, reply, handle)) < 0) + return; + int status = fstat(fd, &st); + + if (status < 0) { + uss_error(uss, reply); + } else { + uss_reply_struct_stat(reply, &st); + } +} + +static off_t uint64_to_off_t(uint64 u) +{ + return ((((off_t)u.hi) << 16) << 16) | (off_t)u.lo; +} + +/* + * The guts of setstat and fsetstat, macroised so that they can call + * fchown(fd,...) or chown(path,...) depending on parameters. + */ +#define SETSTAT_GUTS(api_prefix, api_arg, attrs, success) do \ + { \ + if (attrs.flags & SSH_FILEXFER_ATTR_SIZE) \ + if (api_prefix(truncate)( \ + api_arg, uint64_to_off_t(attrs.size)) < 0) \ + success = FALSE; \ + if (attrs.flags & SSH_FILEXFER_ATTR_UIDGID) \ + if (api_prefix(chown)(api_arg, attrs.uid, attrs.gid) < 0) \ + success = FALSE; \ + if (attrs.flags & SSH_FILEXFER_ATTR_PERMISSIONS) \ + if (api_prefix(chmod)(api_arg, attrs.permissions) < 0) \ + success = FALSE; \ + if (attrs.flags & SSH_FILEXFER_ATTR_ACMODTIME) { \ + struct timeval tv[2]; \ + tv[0].tv_sec = attrs.atime; \ + tv[1].tv_sec = attrs.mtime; \ + tv[0].tv_usec = tv[1].tv_usec = 0; \ + if (api_prefix(utimes)(api_arg, tv) < 0) \ + success = FALSE; \ + } \ + } while (0) + +#define PATH_PREFIX(func) func +#define FD_PREFIX(func) f ## func + +static void uss_setstat(SftpServer *srv, SftpReplyBuilder *reply, + ptrlen path, struct fxp_attrs attrs) +{ + UnixSftpServer *uss = container_of(srv, UnixSftpServer, srv); + + char *pathstr = mkstr(path); + int success = TRUE; + SETSTAT_GUTS(PATH_PREFIX, pathstr, attrs, success); + free(pathstr); + + if (!success) { + uss_error(uss, reply); + } else { + fxp_reply_ok(reply); + } +} + +static void uss_fsetstat(SftpServer *srv, SftpReplyBuilder *reply, + ptrlen handle, struct fxp_attrs attrs) +{ + UnixSftpServer *uss = container_of(srv, UnixSftpServer, srv); + int fd; + + if ((fd = uss_lookup_fd(uss, reply, handle)) < 0) + return; + + int success = TRUE; + SETSTAT_GUTS(FD_PREFIX, fd, attrs, success); + + if (!success) { + uss_error(uss, reply); + } else { + fxp_reply_ok(reply); + } +} + +static void uss_read(SftpServer *srv, SftpReplyBuilder *reply, + ptrlen handle, uint64 offset, unsigned length) +{ + UnixSftpServer *uss = container_of(srv, UnixSftpServer, srv); + int fd; + char *buf; + + if ((fd = uss_lookup_fd(uss, reply, handle)) < 0) + return; + + if ((buf = malloc(length)) == NULL) { + /* A rare case in which I bother to check malloc failure, + * because in this case we can localise the problem easily by + * turning it into a failure response from this one sftp + * request */ + fxp_reply_error(reply, SSH_FX_FAILURE, + "Out of memory for read buffer"); + return; + } + + char *p = buf; + + int status = lseek(fd, uint64_to_off_t(offset), SEEK_SET); + if (status >= 0 || errno == ESPIPE) { + int seekable = (status >= 0); + while (length > 0) { + status = read(fd, p, length); + if (status <= 0) + break; + + unsigned bytes_read = status; + assert(bytes_read <= length); + length -= bytes_read; + p += bytes_read; + + if (!seekable) { + /* + * If the seek failed because the file is fundamentally + * not a seekable kind of thing, abandon this loop after + * one attempt, i.e. we just read whatever we could get + * and we don't mind returning a short buffer. + */ + } + } + } + + if (status < 0) { + uss_error(uss, reply); + } else if (p == buf) { + fxp_reply_error(reply, SSH_FX_EOF, "End of file"); + } else { + fxp_reply_data(reply, make_ptrlen(buf, p - buf)); + } + + free(buf); +} + +static void uss_write(SftpServer *srv, SftpReplyBuilder *reply, + ptrlen handle, uint64 offset, ptrlen data) +{ + UnixSftpServer *uss = container_of(srv, UnixSftpServer, srv); + int fd; + + if ((fd = uss_lookup_fd(uss, reply, handle)) < 0) + return; + + const char *p = data.ptr; + unsigned length = data.len; + + int status = lseek(fd, uint64_to_off_t(offset), SEEK_SET); + if (status >= 0 || errno == ESPIPE) { + + while (length > 0) { + status = write(fd, p, length); + assert(status != 0); + if (status < 0) + break; + + unsigned bytes_written = status; + assert(bytes_written <= length); + length -= bytes_written; + p += bytes_written; + } + } + + if (status < 0) { + uss_error(uss, reply); + } else { + fxp_reply_ok(reply); + } +} + +static void uss_readdir(SftpServer *srv, SftpReplyBuilder *reply, + ptrlen handle, int max_entries, int omit_longname) +{ + UnixSftpServer *uss = container_of(srv, UnixSftpServer, srv); + struct dirent *de; + struct uss_dirhandle *udh; + + if ((udh = uss_lookup_dirhandle(uss, reply, handle)) == NULL) + return; + + errno = 0; + de = readdir(udh->dp); + if (!de) { + if (errno == 0) { + fxp_reply_error(reply, SSH_FX_EOF, "End of directory"); + } else { + uss_error(uss, reply); + } + } else { + ptrlen longname = PTRLEN_LITERAL(""); + char *longnamebuf = NULL; + struct fxp_attrs attrs = no_attrs; + +#if defined HAVE_FSTATAT && defined HAVE_DIRFD + struct stat st; + if (!fstatat(dirfd(udh->dp), de->d_name, &st, AT_SYMLINK_NOFOLLOW)) { + char perms[11], sizebuf[32], *uidbuf = NULL, *gidbuf = NULL; + struct passwd *pwd; + struct group *grp; + const char *user, *group; + struct tm tm; + + attrs = uss_translate_struct_stat(&st); + + if (!omit_longname) { + + strcpy(perms, "----------"); + switch (st.st_mode & S_IFMT) { + case S_IFBLK: perms[0] = 'b'; break; + case S_IFCHR: perms[0] = 'c'; break; + case S_IFDIR: perms[0] = 'd'; break; + case S_IFIFO: perms[0] = 'p'; break; + case S_IFLNK: perms[0] = 'l'; break; + case S_IFSOCK: perms[0] = 's'; break; + } + if (st.st_mode & S_IRUSR) + perms[1] = 'r'; + if (st.st_mode & S_IWUSR) + perms[2] = 'w'; + if (st.st_mode & S_IXUSR) + perms[3] = (st.st_mode & S_ISUID ? 's' : 'x'); + else + perms[3] = (st.st_mode & S_ISUID ? 'S' : '-'); + if (st.st_mode & S_IRGRP) + perms[4] = 'r'; + if (st.st_mode & S_IWGRP) + perms[5] = 'w'; + if (st.st_mode & S_IXGRP) + perms[6] = (st.st_mode & S_ISGID ? 's' : 'x'); + else + perms[6] = (st.st_mode & S_ISGID ? 'S' : '-'); + if (st.st_mode & S_IROTH) + perms[7] = 'r'; + if (st.st_mode & S_IWOTH) + perms[8] = 'w'; + if (st.st_mode & S_IXOTH) + perms[9] = 'x'; + + if ((pwd = getpwuid(st.st_uid)) != NULL) + user = pwd->pw_name; + else + user = uidbuf = dupprintf("%u", (unsigned)st.st_uid); + if ((grp = getgrgid(st.st_gid)) != NULL) + group = grp->gr_name; + else + group = gidbuf = dupprintf("%u", (unsigned)st.st_gid); + + uint64_decimal(uint64_from_off_t(st.st_size), sizebuf); + + tm = *localtime(&st.st_mtime); + + longnamebuf = dupprintf( + "%s %3u %-8s %-8s %8s %.3s %2d %02d:%02d %s", + perms, (unsigned)st.st_nlink, user, group, sizebuf, + ("JanFebMarAprMayJunJulAugSepOctNovDec" + 3*tm.tm_mon), + tm.tm_mday, tm.tm_hour, tm.tm_min, de->d_name); + longname = ptrlen_from_asciz(longnamebuf); + + sfree(uidbuf); + sfree(gidbuf); + } + } +#endif + + /* FIXME: be able to return more than one, in which case we + * must also check max_entries */ + fxp_reply_name_count(reply, 1); + fxp_reply_full_name(reply, ptrlen_from_asciz(de->d_name), + longname, attrs); + + sfree(longnamebuf); + } +} + +const struct SftpServerVtable unix_live_sftpserver_vt = { + uss_new, + uss_free, + uss_realpath, + uss_open, + uss_opendir, + uss_close, + uss_mkdir, + uss_rmdir, + uss_remove, + uss_rename, + uss_stat, + uss_fstat, + uss_setstat, + uss_fsetstat, + uss_read, + uss_write, + uss_readdir, +}; From aa162bbca1bda79b9e100a60c09af04a70f223f5 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 21 Oct 2018 10:14:22 +0100 Subject: [PATCH 561/607] Close standard handles in watchdog subprocesses. Naturally, there's one really glaring goof I find out instants after 'git push'! If Pageant starts a watchdog subprocess which will wait until the main process terminates and then clean up the socket, then it had better not have that subprocess keep the standard I/O handles open, or else commands like eval $(pageant -X) won't terminate. I've applied the same fix in the X11 socket creation, though I think it's less critical there. --- unix/ux_x11.c | 5 +++++ unix/uxagentsock.c | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/unix/ux_x11.c b/unix/ux_x11.c index 91c95bbc..4df66d15 100644 --- a/unix/ux_x11.c +++ b/unix/ux_x11.c @@ -159,6 +159,11 @@ int platform_make_x11_server(Plug *plug, const char *progname, int mindisp, * we expect read() to return EOF as soon as * that process terminates. */ + + close(0); + close(1); + close(2); + setpgid(0, 0); close(cleanup_pipe[1]); close(authfd); diff --git a/unix/uxagentsock.c b/unix/uxagentsock.c index 90e701ff..3fbbb84f 100644 --- a/unix/uxagentsock.c +++ b/unix/uxagentsock.c @@ -62,6 +62,11 @@ Socket *platform_make_agent_socket( * we expect read() to return EOF as soon as * that process terminates. */ + + close(0); + close(1); + close(2); + setpgid(0, 0); close(cleanup_pipe[1]); while (read(cleanup_pipe[0], buf, sizeof(buf)) > 0); From aaa1bfbb57a627726e544a5cad67b4544d731e4a Mon Sep 17 00:00:00 2001 From: Pavel Kryukov Date: Wed, 11 Jul 2018 15:03:23 +0300 Subject: [PATCH 562/607] Makefile.vc: permit building for Windows on Arm. --- mkfiles.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkfiles.pl b/mkfiles.pl index 79ecf9d0..8e23b640 100755 --- a/mkfiles.pl +++ b/mkfiles.pl @@ -693,7 +693,7 @@ sub manpages { "# C compilation flags\n". "CFLAGS = /nologo /W3 /O1 " . (join " ", map {"-I$dirpfx$_"} @srcdirs) . - " /D_WINDOWS /D_WIN32_WINDOWS=0x500 /DWINVER=0x500 /D_CRT_SECURE_NO_WARNINGS\n". + " /D_WINDOWS /D_WIN32_WINDOWS=0x500 /DWINVER=0x500 /D_CRT_SECURE_NO_WARNINGS /D_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE\n". "LFLAGS = /incremental:no /dynamicbase /nxcompat\n". "RCFLAGS = ".(join " ", map {"-I$dirpfx$_"} @srcdirs). " -DWIN32 -D_WIN32 -DWINVER=0x0400\n". From a7c7ba0eb1a5669935024db13883b1ae2d9ff007 Mon Sep 17 00:00:00 2001 From: "Pavel I. Kryukov" Date: Sun, 21 Oct 2018 14:57:16 +0300 Subject: [PATCH 563/607] Add missing #ifndef OMIT_UTMP over pty_utmp_helper_pipe closing --- unix/uxpty.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/unix/uxpty.c b/unix/uxpty.c index d0fc2798..b3fe0f83 100644 --- a/unix/uxpty.c +++ b/unix/uxpty.c @@ -887,10 +887,12 @@ Backend *pty_backend_create( /* If somehow we've got a pty master already and don't * need it, throw it away! */ close(pty->master_fd); +#ifndef OMIT_UTMP if (pty_utmp_helper_pipe >= 0) { close(pty_utmp_helper_pipe); /* don't need this either */ pty_utmp_helper_pipe = -1; } +#endif } From fafb89889166d8b5834f3e3997300bb888c6322a Mon Sep 17 00:00:00 2001 From: "Pavel I. Kryukov" Date: Sun, 21 Oct 2018 14:58:34 +0300 Subject: [PATCH 564/607] uxserver.c: exit with 0 explicitly to make GCC 4 happy --- unix/uxserver.c | 1 + 1 file changed, 1 insertion(+) diff --git a/unix/uxserver.c b/unix/uxserver.c index b5e08404..61e30ce9 100644 --- a/unix/uxserver.c +++ b/unix/uxserver.c @@ -529,4 +529,5 @@ int main(int argc, char **argv) run_toplevel_callbacks(); } + exit(0); } From 1806b71241ccce5628a9a9090d5986075eaf9584 Mon Sep 17 00:00:00 2001 From: "Pavel I. Kryukov" Date: Sun, 21 Oct 2018 15:00:09 +0300 Subject: [PATCH 565/607] uxsftpserver.c: do not let Clang think we append integer to string --- unix/uxsftpserver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unix/uxsftpserver.c b/unix/uxsftpserver.c index ddc84665..9427a2e2 100644 --- a/unix/uxsftpserver.c +++ b/unix/uxsftpserver.c @@ -667,7 +667,7 @@ static void uss_readdir(SftpServer *srv, SftpReplyBuilder *reply, longnamebuf = dupprintf( "%s %3u %-8s %-8s %8s %.3s %2d %02d:%02d %s", perms, (unsigned)st.st_nlink, user, group, sizebuf, - ("JanFebMarAprMayJunJulAugSepOctNovDec" + 3*tm.tm_mon), + (&"JanFebMarAprMayJunJulAugSepOctNovDec"[3*tm.tm_mon]), tm.tm_mday, tm.tm_hour, tm.tm_min, de->d_name); longname = ptrlen_from_asciz(longnamebuf); From 5f03613614a86a32dfd50e393dedd5d041be6709 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Mon, 22 Oct 2018 20:17:47 +0100 Subject: [PATCH 566/607] Improve Uppity's online help and command-line errors. We now show the --help output if invoked with no arguments, and the help text also includes a big safety warning in the hope of stopping anyone from mistaking this for a _secure_ SSH server implementation. While I'm here, the errors now all use appname[] in place of constantly repeating the program name. (Not because I anticipate a change right now, but if nothing else, it makes things easier moving errors out into shared source files or between applications.) --- unix/uxserver.c | 85 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 55 insertions(+), 30 deletions(-) diff --git a/unix/uxserver.c b/unix/uxserver.c index 61e30ce9..2e68ca89 100644 --- a/unix/uxserver.c +++ b/unix/uxserver.c @@ -201,21 +201,32 @@ int auth_successful(AuthPolicy *ap, ptrlen username, unsigned method) return TRUE; } -static void show_help_and_exit(void) +static void safety_warning(FILE *fp) { - printf("usage: uppity [options]\n"); - printf("options: --hostkey KEY SSH host key (need at least one)\n"); - printf(" --userkey KEY public key" - " acceptable for user authentication\n"); - printf("also: uppity --help show this text\n"); - printf(" uppity --version show version information\n"); - exit(0); + fputs(" =================================================\n" + " THIS SSH SERVER IS NOT WRITTEN TO BE SECURE!\n" + " DO NOT DEPLOY IT IN A HOSTILE-FACING ENVIRONMENT!\n" + " =================================================\n", fp); +} + +static void show_help(FILE *fp) +{ + safety_warning(fp); + fputs("\n" + "usage: uppity [options]\n" + "options: --hostkey KEY SSH host key (need at least one)\n" + " --userkey KEY public key" + " acceptable for user authentication\n" + "also: uppity --help show this text\n" + " uppity --version show version information\n" + "\n", fp); + safety_warning(fp); } static void show_version_and_exit(void) { char *buildinfo_text = buildinfo("\n"); - printf("uppity: %s\n%s\n", ver, buildinfo_text); + printf("%s: %s\n%s\n", appname, ver, buildinfo_text); sfree(buildinfo_text); exit(0); } @@ -243,8 +254,8 @@ static int longoptarg(const char *arg, const char *expected, *val = *++*argvp; return TRUE; } else { - fprintf(stderr, "uppity: option %s expects an argument\n", - expected); + fprintf(stderr, "%s: option %s expects an argument\n", + appname, expected); exit(1); } } @@ -272,12 +283,24 @@ int main(int argc, char **argv) ap.ssh1keys = NULL; ap.ssh2keys = NULL; + if (argc <= 1) { + /* + * We're going to terminate with an error message below, + * because there are no host keys. But we'll display the help + * as additional standard-error output, if nothing else so + * that people see the giant safety warning. + */ + show_help(stderr); + fputc('\n', stderr); + } + while (--argc > 0) { const char *arg = *++argv; const char *val; if (!strcmp(arg, "--help")) { - show_help_and_exit(); + show_help(stdout); + exit(0); } else if (!strcmp(arg, "--version")) { show_version_and_exit(); } else if (!strcmp(arg, "--verbose") || !strcmp(arg, "-v")) { @@ -296,8 +319,8 @@ int main(int argc, char **argv) uk = ssh2_load_userkey(keyfile, NULL, &error); filename_free(keyfile); if (!uk || !uk->key) { - fprintf(stderr, "uppity: unable to load host key '%s': " - "%s\n", val, error); + fprintf(stderr, "%s: unable to load host key '%s': " + "%s\n", appname, val, error); exit(1); } key = uk->key; @@ -306,8 +329,9 @@ int main(int argc, char **argv) for (i = 0; i < nhostkeys; i++) if (ssh_key_alg(hostkeys[i]) == ssh_key_alg(key)) { - fprintf(stderr, "uppity: host key '%s' duplicates key " - "type %s\n", val, ssh_key_alg(key)->ssh_id); + fprintf(stderr, "%s: host key '%s' duplicates key " + "type %s\n", appname, val, + ssh_key_alg(key)->ssh_id); exit(1); } @@ -318,19 +342,20 @@ int main(int argc, char **argv) hostkeys[nhostkeys++] = key; } else if (keytype == SSH_KEYTYPE_SSH1) { if (hostkey1) { - fprintf(stderr, "uppity: host key '%s' is a redundant " - "SSH-1 host key\n", val); + fprintf(stderr, "%s: host key '%s' is a redundant " + "SSH-1 host key\n", appname, val); exit(1); } hostkey1 = snew(struct RSAKey); if (!rsa_ssh1_loadkey(keyfile, hostkey1, NULL, &error)) { - fprintf(stderr, "uppity: unable to load host key '%s': " - "%s\n", val, error); + fprintf(stderr, "%s: unable to load host key '%s': " + "%s\n", appname, val, error); exit(1); } } else { - fprintf(stderr, "uppity: '%s' is not loadable as a " - "private key (%s)", val, key_type_to_str(keytype)); + fprintf(stderr, "%s: '%s' is not loadable as a " + "private key (%s)", appname, val, + key_type_to_str(keytype)); exit(1); } } else if (longoptarg(arg, "--userkey", &val, &argc, &argv)) { @@ -349,8 +374,8 @@ int main(int argc, char **argv) if (!ssh2_userkey_loadpub(keyfile, NULL, BinarySink_UPCAST(sb), NULL, &error)) { - fprintf(stderr, "uppity: unable to load user key '%s': " - "%s\n", val, error); + fprintf(stderr, "%s: unable to load user key '%s': " + "%s\n", appname, val, error); exit(1); } @@ -370,8 +395,8 @@ int main(int argc, char **argv) if (!rsa_ssh1_loadpub(keyfile, BinarySink_UPCAST(sb), NULL, &error)) { - fprintf(stderr, "uppity: unable to load user key '%s': " - "%s\n", val, error); + fprintf(stderr, "%s: unable to load user key '%s': " + "%s\n", appname, val, error); exit(1); } @@ -384,8 +409,8 @@ int main(int argc, char **argv) strbuf_free(sb); } else { - fprintf(stderr, "uppity: '%s' is not loadable as a public key " - "(%s)\n", val, key_type_to_str(keytype)); + fprintf(stderr, "%s: '%s' is not loadable as a public key " + "(%s)\n", appname, val, key_type_to_str(keytype)); exit(1); } } else if (longoptarg(arg, "--sshlog", &val, &argc, &argv) || @@ -403,13 +428,13 @@ int main(int argc, char **argv) conf_set_int(conf, CONF_logtype, LGTYP_SSHRAW); conf_set_int(conf, CONF_logxfovr, LGXF_OVR); } else { - fprintf(stderr, "uppity: unrecognised option '%s'\n", arg); + fprintf(stderr, "%s: unrecognised option '%s'\n", appname, arg); exit(1); } } if (nhostkeys == 0 && !hostkey1) { - fprintf(stderr, "uppity: specify at least one host key\n"); + fprintf(stderr, "%s: specify at least one host key\n", appname); exit(1); } From c9e6118246fd0ded8adff97245bcef5df0616f87 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Mon, 22 Oct 2018 20:32:58 +0100 Subject: [PATCH 567/607] Uppity: add challenge-response auth methods. This adds the server side of the SSH-2 keyboard-interactive protocol, and the pair of very similar SSH-1 methods AUTH_TIS and AUTH_CCARD (which basically differ only in message numbers, and each involve a single challenge from the server and a response from the user). --- ssh1login-server.c | 46 +++++++++++++++++++++++- ssh2userauth-server.c | 81 +++++++++++++++++++++++++++++++++++++++++++ sshserver.h | 28 +++++++++++++++ unix/uxserver.c | 64 +++++++++++++++++++++++++++++++++- 4 files changed, 217 insertions(+), 2 deletions(-) diff --git a/ssh1login-server.c b/ssh1login-server.c index 26f8f730..359dcf98 100644 --- a/ssh1login-server.c +++ b/ssh1login-server.c @@ -152,7 +152,10 @@ static void ssh1_login_server_process_queue(PacketProtocolLayer *ppl) s->supported_auths_mask |= (1U << SSH1_AUTH_PASSWORD); if (s->ap_methods & AUTHMETHOD_PUBLICKEY) s->supported_auths_mask |= (1U << SSH1_AUTH_RSA); - /* FIXME: TIS, CCARD */ + if (s->ap_methods & AUTHMETHOD_TIS) + s->supported_auths_mask |= (1U << SSH1_AUTH_TIS); + if (s->ap_methods & AUTHMETHOD_CRYPTOCARD) + s->supported_auths_mask |= (1U << SSH1_AUTH_CCARD); for (i = 0; i < 8; i++) s->cookie[i] = random_byte(); @@ -349,6 +352,47 @@ static void ssh1_login_server_process_queue(PacketProtocolLayer *ppl) } goto auth_success; + } else if (pktin->type == SSH1_CMSG_AUTH_TIS || + pktin->type == SSH1_CMSG_AUTH_CCARD) { + char *challenge; + unsigned response_type; + ptrlen response; + + s->current_method = (pktin->type == SSH1_CMSG_AUTH_TIS ? + AUTHMETHOD_TIS : AUTHMETHOD_CRYPTOCARD); + if (!(s->ap_methods & s->current_method)) + continue; + + challenge = auth_ssh1int_challenge( + s->authpolicy, s->current_method, s->username); + if (!challenge) + continue; + pktout = ssh_bpp_new_pktout( + s->ppl.bpp, + (s->current_method == AUTHMETHOD_TIS ? + SSH1_SMSG_AUTH_TIS_CHALLENGE : + SSH1_SMSG_AUTH_CCARD_CHALLENGE)); + put_stringz(pktout, challenge); + pq_push(s->ppl.out_pq, pktout); + sfree(challenge); + + crMaybeWaitUntilV((pktin = ssh1_login_server_pop(s)) != NULL); + response_type = (s->current_method == AUTHMETHOD_TIS ? + SSH1_CMSG_AUTH_TIS_RESPONSE : + SSH1_CMSG_AUTH_CCARD_RESPONSE); + if (pktin->type != response_type) { + ssh_proto_error(s->ppl.ssh, "Received unexpected packet in " + "response to %s challenge, type %d (%s)", + (s->current_method == AUTHMETHOD_TIS ? + "TIS" : "CryptoCard"), + pktin->type, ssh1_pkt_type(pktin->type)); + return; + } + + response = get_string(pktin); + + if (auth_ssh1int_response(s->authpolicy, response)) + goto auth_success; } } diff --git a/ssh2userauth-server.c b/ssh2userauth-server.c index 84f3d27c..e642e3de 100644 --- a/ssh2userauth-server.c +++ b/ssh2userauth-server.c @@ -29,6 +29,8 @@ struct ssh2_userauth_server_state { unsigned methods, this_method; int partial_success; + AuthKbdInt *aki; + PacketProtocolLayer ppl; }; @@ -46,6 +48,21 @@ static const struct PacketProtocolLayerVtable ssh2_userauth_server_vtable = { "ssh-userauth", }; +static void free_auth_kbdint(AuthKbdInt *aki) +{ + int i; + + if (!aki) + return; + + sfree(aki->title); + sfree(aki->instruction); + for (i = 0; i < aki->nprompts; i++) + sfree(aki->prompts[i].prompt); + sfree(aki->prompts); + sfree(aki); +} + PacketProtocolLayer *ssh2_userauth_server_new( PacketProtocolLayer *successor_layer, AuthPolicy *authpolicy) { @@ -76,6 +93,8 @@ static void ssh2_userauth_server_free(PacketProtocolLayer *ppl) if (s->successor_layer) ssh_ppl_free(s->successor_layer); + free_auth_kbdint(s->aki); + sfree(s); } @@ -211,6 +230,66 @@ static void ssh2_userauth_server_process_queue(PacketProtocolLayer *ppl) if (!success) goto failure; + } else if (ptrlen_eq_string(s->method, "keyboard-interactive")) { + int i, ok; + unsigned n; + + s->this_method = AUTHMETHOD_KBDINT; + if (!(s->methods & s->this_method)) + goto failure; + + do { + s->aki = auth_kbdint_prompts(s->authpolicy, s->username); + if (!s->aki) + goto failure; + + pktout = ssh_bpp_new_pktout( + s->ppl.bpp, SSH2_MSG_USERAUTH_INFO_REQUEST); + put_stringz(pktout, s->aki->title); + put_stringz(pktout, s->aki->instruction); + put_stringz(pktout, ""); /* language tag */ + put_uint32(pktout, s->aki->nprompts); + for (i = 0; i < s->aki->nprompts; i++) { + put_stringz(pktout, s->aki->prompts[i].prompt); + put_bool(pktout, s->aki->prompts[i].echo); + } + pq_push(s->ppl.out_pq, pktout); + + crMaybeWaitUntilV( + (pktin = ssh2_userauth_server_pop(s)) != NULL); + if (pktin->type != SSH2_MSG_USERAUTH_INFO_RESPONSE) { + ssh_proto_error( + s->ppl.ssh, "Received unexpected packet when " + "expecting USERAUTH_INFO_RESPONSE, type %d (%s)", + pktin->type, + ssh2_pkt_type(s->ppl.bpp->pls->kctx, + s->ppl.bpp->pls->actx, pktin->type)); + return; + } + + n = get_uint32(pktin); + if (n != s->aki->nprompts) { + ssh_proto_error( + s->ppl.ssh, "Received %u keyboard-interactive " + "responses after sending %u prompts", + n, s->aki->nprompts); + return; + } + + { + ptrlen *responses = snewn(s->aki->nprompts, ptrlen); + for (i = 0; i < s->aki->nprompts; i++) + responses[i] = get_string(pktin); + ok = auth_kbdint_responses(s->authpolicy, responses); + sfree(responses); + } + + free_auth_kbdint(s->aki); + s->aki = NULL; + } while (ok == 0); + + if (ok <= 0) + goto failure; } else { goto failure; } @@ -246,6 +325,8 @@ static void ssh2_userauth_server_process_queue(PacketProtocolLayer *ppl) add_to_commasep(list, "password"); if (s->methods & AUTHMETHOD_PUBLICKEY) add_to_commasep(list, "publickey"); + if (s->methods & AUTHMETHOD_KBDINT) + add_to_commasep(list, "keyboard-interactive"); put_stringsb(pktout, list); } put_bool(pktout, s->partial_success); diff --git a/sshserver.h b/sshserver.h index fa0ee87e..7081d0cd 100644 --- a/sshserver.h +++ b/sshserver.h @@ -13,6 +13,9 @@ void platform_logevent(const char *msg); X(NONE) \ X(PASSWORD) \ X(PUBLICKEY) \ + X(KBDINT) \ + X(TIS) \ + X(CRYPTOCARD) \ /* end of list */ #define AUTHMETHOD_BIT_INDEX(name) AUTHMETHOD_BIT_INDEX_##name, @@ -21,6 +24,18 @@ enum { AUTHMETHODS(AUTHMETHOD_BIT_INDEX) AUTHMETHOD_BIT_INDEX_dummy }; AUTHMETHOD_##name = 1 << AUTHMETHOD_BIT_INDEX_##name, enum { AUTHMETHODS(AUTHMETHOD_BIT_VALUE) AUTHMETHOD_BIT_VALUE_dummy }; +typedef struct AuthKbdInt AuthKbdInt; +typedef struct AuthKbdIntPrompt AuthKbdIntPrompt; +struct AuthKbdInt { + char *title, *instruction; /* both need freeing */ + int nprompts; + AuthKbdIntPrompt *prompts; /* the array itself needs freeing */ +}; +struct AuthKbdIntPrompt { + char *prompt; /* needs freeing */ + int echo; +}; + unsigned auth_methods(AuthPolicy *); int auth_none(AuthPolicy *, ptrlen username); int auth_password(AuthPolicy *, ptrlen username, ptrlen password); @@ -28,6 +43,19 @@ int auth_publickey(AuthPolicy *, ptrlen username, ptrlen public_blob); /* auth_publickey_ssh1 must return the whole public key given the modulus, * because the SSH-1 client never transmits the exponent over the wire. * The key remains owned by the AuthPolicy. */ + +AuthKbdInt *auth_kbdint_prompts(AuthPolicy *, ptrlen username); +/* auth_kbdint_prompts returns NULL to trigger auth failure */ +int auth_kbdint_responses(AuthPolicy *, const ptrlen *responses); +/* auth_kbdint_responses returns >0 for success, <0 for failure, and 0 + * to indicate that we haven't decided yet and further prompts are + * coming */ + +/* The very similar SSH-1 TIS and CryptoCard methods are combined into + * a single API for AuthPolicy, which takes a method argument */ +char *auth_ssh1int_challenge(AuthPolicy *, unsigned method, ptrlen username); +int auth_ssh1int_response(AuthPolicy *, ptrlen response); + struct RSAKey *auth_publickey_ssh1( AuthPolicy *ap, ptrlen username, Bignum rsa_modulus); /* auth_successful returns FALSE if further authentication is needed */ diff --git a/unix/uxserver.c b/unix/uxserver.c index 2e68ca89..bbb26ef1 100644 --- a/unix/uxserver.c +++ b/unix/uxserver.c @@ -164,10 +164,12 @@ struct AuthPolicy_ssh2_pubkey { struct AuthPolicy { struct AuthPolicy_ssh1_pubkey *ssh1keys; struct AuthPolicy_ssh2_pubkey *ssh2keys; + int kbdint_state; }; unsigned auth_methods(AuthPolicy *ap) { - return AUTHMETHOD_PUBLICKEY | AUTHMETHOD_PASSWORD; + return (AUTHMETHOD_PUBLICKEY | AUTHMETHOD_PASSWORD | AUTHMETHOD_KBDINT | + AUTHMETHOD_TIS | AUTHMETHOD_CRYPTOCARD); } int auth_none(AuthPolicy *ap, ptrlen username) { @@ -196,6 +198,65 @@ struct RSAKey *auth_publickey_ssh1( } return NULL; } +AuthKbdInt *auth_kbdint_prompts(AuthPolicy *ap, ptrlen username) +{ + AuthKbdInt *aki = snew(AuthKbdInt); + + switch (ap->kbdint_state) { + case 0: + aki->title = dupstr("Initial double prompt"); + aki->instruction = + dupstr("First prompt should echo, second should not"); + aki->nprompts = 2; + aki->prompts = snewn(aki->nprompts, AuthKbdIntPrompt); + aki->prompts[0].prompt = dupstr("Echoey prompt: "); + aki->prompts[0].echo = TRUE; + aki->prompts[1].prompt = dupstr("Silent prompt: "); + aki->prompts[1].echo = FALSE; + return aki; + case 1: + aki->title = dupstr("Zero-prompt step"); + aki->instruction = dupstr("Shouldn't see any prompts this time"); + aki->nprompts = 0; + aki->prompts = NULL; + return aki; + default: + ap->kbdint_state = 0; + return NULL; + } +} +int auth_kbdint_responses(AuthPolicy *ap, const ptrlen *responses) +{ + switch (ap->kbdint_state) { + case 0: + if (ptrlen_eq_string(responses[0], "stoat") && + ptrlen_eq_string(responses[1], "weasel")) { + ap->kbdint_state++; + return 0; /* those are the expected responses */ + } else { + ap->kbdint_state = 0; + return -1; + } + break; + case 1: + return +1; /* succeed after the zero-prompt step */ + default: + ap->kbdint_state = 0; + return -1; + } +} +char *auth_ssh1int_challenge(AuthPolicy *ap, unsigned method, ptrlen username) +{ + /* FIXME: test returning a challenge string without \n, and ensure + * it gets printed as a prompt in its own right, without PuTTY + * making up a "Response: " prompt to follow it */ + return dupprintf("This is a dummy %s challenge!\n", + (method == AUTHMETHOD_TIS ? "TIS" : "CryptoCard")); +} +int auth_ssh1int_response(AuthPolicy *ap, ptrlen response) +{ + return ptrlen_eq_string(response, "otter"); +} int auth_successful(AuthPolicy *ap, ptrlen username, unsigned method) { return TRUE; @@ -280,6 +341,7 @@ int main(int argc, char **argv) Conf *conf = conf_new(); load_open_settings(NULL, conf); + ap.kbdint_state = 0; ap.ssh1keys = NULL; ap.ssh2keys = NULL; From 76a32c514c1f8be6f117f86f26aba93e13147086 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Mon, 22 Oct 2018 20:34:17 +0100 Subject: [PATCH 568/607] Fix two bugs in SSH-1 TIS and CryptoCard auth. Firstly, these protocols had a display heuristic - credited to OpenSSH in the comments - in which, if the challenge string contained a newline, it was supposed to be printed with "Response: " on the next line, whereas if it didn't, it would be taken as a prompt in its own right. In fact, I had got the sense of memchr backwards, so each behaviour was applying in the opposite case. Secondly, apparently I'd never before tested against a server that offered _both_ those methods, because when I tried it against Uppity just now, I found that the setup and challenge phases for both methods ran in immediate succession before prompting the user, which confused the server completely. This is exactly why I wanted to have a server implementation of everything PuTTY is supposed to speak the client side of! --- ssh1login.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/ssh1login.c b/ssh1login.c index 1d5b92b9..ae02b314 100644 --- a/ssh1login.c +++ b/ssh1login.c @@ -821,7 +821,7 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl) s->cur_prompt->to_server = TRUE; s->cur_prompt->name = dupstr("SSH TIS authentication"); /* Prompt heuristic comes from OpenSSH */ - if (memchr(challenge.ptr, '\n', challenge.len)) { + if (!memchr(challenge.ptr, '\n', challenge.len)) { instr_suf = dupstr(""); prompt = mkstr(challenge); } else { @@ -842,8 +842,7 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl) ssh1_pkt_type(pktin->type)); return; } - } - if (conf_get_int(s->conf, CONF_try_tis_auth) && + } else if (conf_get_int(s->conf, CONF_try_tis_auth) && (s->supported_auths_mask & (1 << SSH1_AUTH_CCARD)) && !s->ccard_auth_refused) { s->pwpkt_type = SSH1_CMSG_AUTH_CCARD_RESPONSE; @@ -871,7 +870,7 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl) s->cur_prompt->name = dupstr("SSH CryptoCard authentication"); s->cur_prompt->name_reqd = FALSE; /* Prompt heuristic comes from OpenSSH */ - if (memchr(challenge.ptr, '\n', challenge.len)) { + if (!memchr(challenge.ptr, '\n', challenge.len)) { instr_suf = dupstr(""); prompt = mkstr(challenge); } else { From cf8a421fa23bd22b29a3cb7edada4ce4b478a94f Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 21 Oct 2018 13:19:54 +0100 Subject: [PATCH 569/607] Add a missing const in uint64_from_decimal. --- int64.c | 2 +- int64.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/int64.c b/int64.c index b1c986ce..a6a98f31 100644 --- a/int64.c +++ b/int64.c @@ -116,7 +116,7 @@ uint64 uint64_shift_left(uint64 x, int shift) return x; } -uint64 uint64_from_decimal(char *str) +uint64 uint64_from_decimal(const char *str) { uint64 ret; ret.hi = ret.lo = 0; diff --git a/int64.h b/int64.h index 17122974..fb50fbaf 100644 --- a/int64.h +++ b/int64.h @@ -21,7 +21,7 @@ uint64 uint64_subtract(uint64 x, uint64 y); double uint64_to_double(uint64 x); uint64 uint64_shift_right(uint64 x, int shift); uint64 uint64_shift_left(uint64 x, int shift); -uint64 uint64_from_decimal(char *str); +uint64 uint64_from_decimal(const char *str); void BinarySink_put_uint64(BinarySink *, uint64); uint64 BinarySource_get_uint64(BinarySource *); From d1eb40950c7b34690287b0a8ef05169904f5678c Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Tue, 23 Oct 2018 18:02:35 +0100 Subject: [PATCH 570/607] wildcard.c: allow the matched string to be a ptrlen. The main wildcard matching code now doesn't depend on having a NUL terminator in the string to be matched; instead it works with a pair of pointers, one working along the string as we match, and the other identifying the end of the string, and tests that p < target_end before dereferencing p. User-facing entry points now allow you to pass either an ordinary ASCIZ const char * or a ptrlen, and set up target_end accordingly. For the moment, the _wildcard_ parameter still has to be an ordinary null-terminated string, but who knows, maybe that will have to change too at some later point. --- putty.h | 1 + wildcard.c | 33 +++++++++++++++++++++++---------- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/putty.h b/putty.h index aaf8d78c..b8350eb8 100644 --- a/putty.h +++ b/putty.h @@ -1679,6 +1679,7 @@ int agent_exists(void); * Exports from wildcard.c */ const char *wc_error(int value); +int wc_match_pl(const char *wildcard, ptrlen target); int wc_match(const char *wildcard, const char *target); int wc_unescape(char *output, const char *wildcard); diff --git a/wildcard.c b/wildcard.c index c1cb0b49..f480a19a 100644 --- a/wildcard.c +++ b/wildcard.c @@ -97,7 +97,8 @@ const char *wc_error(int value) * returns zero. If the wildcard fragment suffers a syntax error, * it returns <0 and the precise value indexes into wc_error. */ -static int wc_match_fragment(const char **fragment, const char **target) +static int wc_match_fragment(const char **fragment, const char **target, + const char *target_end) { const char *f, *t; @@ -107,7 +108,7 @@ static int wc_match_fragment(const char **fragment, const char **target) * The fragment terminates at either the end of the string, or * the first (unescaped) *. */ - while (*f && *f != '*' && *t) { + while (*f && *f != '*' && t < target_end) { /* * Extract one character from t, and one character's worth * of pattern from f, and step along both. Return 0 if they @@ -204,8 +205,10 @@ static int wc_match_fragment(const char **fragment, const char **target) * successful match, 0 for an unsuccessful match, and <0 for a * syntax error in the wildcard. */ -int wc_match(const char *wildcard, const char *target) +static int wc_match_inner( + const char *wildcard, const char *target, size_t target_len) { + const char *target_end = target + target_len; int ret; /* @@ -216,7 +219,7 @@ int wc_match(const char *wildcard, const char *target) * routine once and give up if it fails. */ if (*wildcard != '*') { - ret = wc_match_fragment(&wildcard, &target); + ret = wc_match_fragment(&wildcard, &target, target_end); if (ret <= 0) return ret; /* pass back failure or error alike */ } @@ -245,12 +248,12 @@ int wc_match(const char *wildcard, const char *target) while (*target) { const char *save_w = wildcard, *save_t = target; - ret = wc_match_fragment(&wildcard, &target); + ret = wc_match_fragment(&wildcard, &target, target_end); if (ret < 0) return ret; /* syntax error */ - if (ret > 0 && !*wildcard && *target) { + if (ret > 0 && !*wildcard && target != target_end) { /* * Final special case - literally. * @@ -272,9 +275,9 @@ int wc_match(const char *wildcard, const char *target) * (which is why we saved `wildcard'). Then we * return whatever that operation returns. */ - target = save_t + strlen(save_t) - (target - save_t); + target = target_end - (target - save_t); wildcard = save_w; - return wc_match_fragment(&wildcard, &target); + return wc_match_fragment(&wildcard, &target, target_end); } if (ret > 0) @@ -292,7 +295,17 @@ int wc_match(const char *wildcard, const char *target) * wildcard. Hence, we return 1 if and only if we are also * right at the end of the target. */ - return (*target ? 0 : 1); + return target == target_end; +} + +int wc_match(const char *wildcard, const char *target) +{ + return wc_match_inner(wildcard, target, strlen(target)); +} + +int wc_match_pl(const char *wildcard, ptrlen target) +{ + return wc_match_inner(wildcard, target.ptr, target.len); } /* @@ -439,7 +452,7 @@ int main(void) f = fragment_tests[i].wildcard; t = fragment_tests[i].target; eret = fragment_tests[i].expected_result; - aret = wc_match_fragment(&f, &t); + aret = wc_match_fragment(&f, &t, t + strlen(t)); if (aret != eret) { printf("failed test: /%s/ against /%s/ returned %d not %d\n", fragment_tests[i].wildcard, fragment_tests[i].target, From c31e3cd43764172f073fe6b5872f7e33616e7a7b Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Wed, 24 Oct 2018 19:14:13 +0100 Subject: [PATCH 571/607] Fix a couple of uninitialised variables. throttled_by_backlog is quite new, so it's not too surprising that I hadn't already noticed it wasn't initialised. But the failure to null out the final 'next' pointer in the callbacks list when it's rewritten as a result of delete_callbacks_for_context is a great deal older, so I'm a lot more puzzled about how it hasn't come up until now! --- callback.c | 1 + ssh2connection.c | 1 + 2 files changed, 2 insertions(+) diff --git a/callback.c b/callback.c index 0a05f624..09a5e49b 100644 --- a/callback.c +++ b/callback.c @@ -65,6 +65,7 @@ void delete_callbacks_for_context(void *ctx) cbhead = newhead; cbtail = newtail; + newtail->next = NULL; } void queue_toplevel_callback(toplevel_callback_fn_t fn, void *ctx) diff --git a/ssh2connection.c b/ssh2connection.c index fa079fec..b858a04c 100644 --- a/ssh2connection.c +++ b/ssh2connection.c @@ -1229,6 +1229,7 @@ void ssh2_channel_init(struct ssh2_channel *c) c->closes = 0; c->pending_eof = FALSE; c->throttling_conn = FALSE; + c->throttled_by_backlog = FALSE; c->sharectx = NULL; c->locwindow = c->locmaxwin = c->remlocwin = s->ssh_is_simple ? OUR_V2_BIGWIN : OUR_V2_WINSIZE; From 18d7998008f210b4b90118c0a982b9f7974a77f7 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Tue, 23 Oct 2018 18:05:58 +0100 Subject: [PATCH 572/607] pscp: extra security check in SCP mode. When you don't specify -r, we now check whether the server is sending a whole subdirectory in place of a single file, and abort if it does. Previously we'd accept the subdirectory download regardless. The new error message labels this as a security violation, just on the grounds that it involves the server doing something other than what the implicit contract suggested it ought to, but I don't think it's a really serious violation in the same sense as letting the server cd into ".." or overwrite files of arbitrary name would be. In this case it can only leave a downloaded thing in the specific place you already authorised it to put _some_ downloaded thing - it's just returned you a directory in place of a file. --- pscp.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pscp.c b/pscp.c index d7efd147..230d8c5e 100644 --- a/pscp.c +++ b/pscp.c @@ -1456,6 +1456,10 @@ int scp_get_sink_action(struct scp_sink_action *act) case 'C': case 'D': act->action = (action == 'C' ? SCP_SINK_FILE : SCP_SINK_DIR); + if (act->action == SCP_SINK_DIR && !recursive) { + bump("security violation: remote host attempted to create " + "a subdirectory in a non-recursive copy!"); + } break; default: bump("Protocol error: Expected control record"); From 8a60fdaa57e6e6691cfcf661152e151d63dd498b Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 20 Oct 2018 11:19:17 +0100 Subject: [PATCH 573/607] Provide Uppity with a built-in old-style scp server. Like the SFTP server, this is implemented in-process rather than by invoking a separate scp server binary. It also uses the internal SftpServer abstraction for access to the server's filesystem, which means that when (or if) I implement an alternative SftpServer implementing a dummy file system for test suite purposes, this scp server should automatically start using it too. As a bonus, the new scpserver.c contains a large comment documenting my understanding of the SCP protocol, which I previously didn't have even a de-facto or post-hoc spec for. I don't claim it's authoritative - it's all reverse-engineered from my own code and observing other implementations in action - but at least it'll make it easier to refresh my own memory of what's going on the next time I need to do something to either this code or PSCP. --- Recipe | 2 +- scpserver.c | 1407 +++++++++++++++++++++++++++++++++++++++++++++++++++ sesschan.c | 67 +++ sftp.h | 40 ++ 4 files changed, 1515 insertions(+), 1 deletion(-) create mode 100644 scpserver.c diff --git a/Recipe b/Recipe index 309087d6..ecdfcf33 100644 --- a/Recipe +++ b/Recipe @@ -284,7 +284,7 @@ UXMISC = MISCNET UXMISCCOMMON uxproxy SSHSERVER = SSHCOMMON sshserver settings be_none logging ssh2kex-server + ssh2userauth-server sshrsag sshprime ssh2connection-server + sesschan sftpcommon int64 sftpserver proxy cproxy ssh1login-server - + ssh1connection-server + + ssh1connection-server scpserver # import.c and dependencies, for PuTTYgen-like utilities that have to # load foreign key files. diff --git a/scpserver.c b/scpserver.c new file mode 100644 index 00000000..5e90103a --- /dev/null +++ b/scpserver.c @@ -0,0 +1,1407 @@ +/* + * Server side of the old-school SCP protocol. + */ + +#include +#include +#include + +#include "putty.h" +#include "ssh.h" +#include "sshcr.h" +#include "sshchan.h" +#include "sftp.h" + +/* + * I think it's worth actually documenting my understanding of what + * this protocol _is_, since I don't know of any other documentation + * of it anywhere. + * + * Format of data stream + * --------------------- + * + * The sending side of an SCP connection - the client, if you're + * uploading files, or the server if you're downloading - sends a data + * stream consisting of a sequence of 'commands', or header records, + * or whatever you want to call them, interleaved with file data. + * + * Each command starts with a letter indicating what type it is, and + * ends with a \n. + * + * The 'C' command introduces an actual file. It is followed by an + * octal file-permissions mask, then a space, then a decimal file + * size, then a space, then the file name up to the termating newline. + * For example, "C0644 12345 filename.txt\n" would be a plausible C + * command. + * + * After the 'C' command, the sending side will transmit exactly as + * many bytes of file data as specified by the size field in the + * header line, followed by a single zero byte. + * + * The 'D' command introduces a subdirectory. Its format is identical + * to 'C', including the size field, but the size field is sent as + * zero. + * + * After the 'D' command, all subsequent C and D commands are taken to + * indicate files that should be placed inside that subdirectory, + * until a terminating 'E' command. + * + * The 'E' command indicates the end of a subdirectory. It has no + * arguments at all (its format is always just "E\n"). After the E + * command, the receiver should revert to placing further downloaded + * files in whatever directory it was placing them before the + * subdirectory opened by the just-closed D. + * + * D and E commands match like parentheses: if you send, say, + * + * C0644 123 foo.txt ( followed by data ) + * D0755 0 subdir + * C0644 123 bar.txt ( followed by data ) + * D0755 0 subsubdir + * C0644 123 baz.txt ( followed by data ) + * E + * C0644 123 quux.txt ( followed by data ) + * E + * C0644 123 wibble.txt ( followed by data ) + * + * then foo.txt, subdir and wibble.txt go in the top-level destination + * directory; bar.txt, subsubdir and quux.txt go in 'subdir'; and + * baz.txt goes in 'subdir/subsubdir'. + * + * The sender terminates the data stream with EOF when it has no more + * files to send. I believe it is not _required_ for all D to be + * closed by an E before this happens - you can elide a trailing + * sequence of E commands without provoking an error message from the + * receiver. + * + * Finally, the 'T' command is sent immediately before a C or D. It is + * followed by four space-separated decimal integers giving an mtime + * and atime to be applied to the file or directory created by the + * following C or D command. The first two integers give the mtime, + * encoded as seconds and microseconds (respectively) since the Unix + * epoch; the next two give the atime, encoded similarly. So + * "T1540373455 0 1540373457 0\n" is an example of a valid T command. + * + * Acknowledgments + * --------------- + * + * The sending side waits for an ack from the receiving side before + * sending each command; before beginning to send the file data + * following a C command; and before sending the final EOF. + * + * (In particular, the receiving side is expected to send an initial + * ack before _anything_ is sent.) + * + * Normally an ack consists of a single zero byte. It's also allowable + * to send a byte with value 1 or 2 followed by a \n-terminated error + * message (where 1 means a non-fatal error and 2 means a fatal one). + * I have to suppose that sending an error message from client to + * server is of limited use, but apparently it's allowed. + * + * Initiation + * ---------- + * + * The protocol is begun by the client sending a command string to the + * server via the SSH-2 "exec" request (or the analogous + * SSH1_CMSG_EXEC_CMD), which indicates that this is an scp session + * rather than any other thing; specifies the direction of transfer; + * says what file(s) are to be sent by the server, or where the server + * should put files that the client is about to send; and a couple of + * other options. + * + * The command string takes the following form: + * + * Start with prefix "scp ", indicating that this is an SCP command at + * all. Otherwise it's a request to run some completely different + * command in the SSH session. + * + * Next the command can contain zero or more of the following options, + * each followed by a space: + * + * "-v" turns on verbose server diagnostics. Of course a server is not + * required to actually produce any, but this is an invitation for it + * to send any it might have available. Diagnostics are free-form, and + * sent as SSH standard-error extended data, so that they are separate + * from the actual data stream as described above. + * + * (Servers can send standard-error output anyway if they like, and in + * case of an actual error, they probably will with or without -v.) + * + * "-r" indicates recursive file transfer, i.e. potentially including + * subdirectories. For a download, this indicates that the client is + * willing to receive subdirectories (a D/E command pair bracketing + * further files and subdirs); without it, the server should only send + * C commands for individual files, followed by EOF. + * + * This flag must also be specified for a recursive upload, because I + * believe at least one server will reject D/E pairs sent by the + * client if the command didn't have -r in it. (Probably a consequence + * of sharing code between download and upload.) + * + * "-p" means preserve file times. In a download, this requests the + * server to send a T command before each C or D. I don't know whether + * any server will insist on having seen this option from the client + * before accepting T commands in an upload, but it is probably + * sensible to send it anyway. + * + * "-d", in an upload, means that the destination pathname (see below) + * is expected to be a directory, and that uploaded files (and + * subdirs) should be put inside it. Without -d, the semantics are + * that _if_ the destination exists and is a directory, then files + * will be put in it, whereas if it is not, then just a single file + * (or subdir) upload is expected, which will be placed at that exact + * pathname. + * + * In a download, I observe that clients tend to send -d if they are + * requesting multiple files or a wildcard, but as far as I know, + * servers ignore it. + * + * After all those optional options, there is a single mandatory + * option indicating the direction of transfer, which is either "-f" + * or "-t". "-f" indicates a download; "-t" indicates an upload. + * + * After that mandatory option, there is a single space, followed by + * the name(s) of files to transfer. + * + * This file name field is transmitted with NO QUOTING, in spite of + * the fact that a server will typically interpret it as a shell + * command. You'd think this couldn't possibly work, in the face of + * almost any filename with an interesting character in it - and you'd + * be right. Or rather (you might argue), it works 'as designed', but + * it's designed in a weird way, in that it's the user's + * responsibility to apply quoting on the client command line to get + * the filename through the shell that will decode things on the + * server side. + * + * But one effect of this is that if you issue a download command + * including a wildcard, say "scp -f somedir/foo*.txt", then the shell + * will expand the wildcard, and actually run the server-side scp + * program with multiple arguments, say "somedir/foo.txt + * somedir/quux.txt", leading to the download sending multiple C + * commands. This clearly _is_ intended: it's how a command such as + * 'scp server:somedir/foo*.txt destdir' can work at all. + * + * (You would think, given that, that it might also be legal to send + * multiple space-separated filenames in order to trigger a download + * of exactly those files. Given how scp is invoked in practice on a + * typical server, this would surely actually work, but my observation + * is that scp clients don't in fact try this - if you run OpenSSH's + * scp by saying 'scp server:foo server:bar destdir' then it will make + * two separate connections to the server for the two files, rather + * than sending a single space-separated remote command. PSCP won't + * even do that, and will make you do it in two separate runs.) + * + * So, some examples: + * + * - "scp -f filename.txt" + * + * Server should send a single C command (plus data) for that file. + * Client ought to ignore the filename in the C command, in favour + * of saving the file under the name implied by the user's command + * line. + * + * - "scp -f file*.txt" + * + * Server sends zero or more C commands, then EOF. Client will have + * been given a target directory to put them all in, and will name + * each one according to the name in the C command. + * + * (You'd like the client to validate the filenames against the + * wildcard it sent, to ensure a malicious server didn't try to + * overwrite some path like ".bashrc" when you thought you were + * downloading only normal text files. But wildcard semantics are + * chosen by the server, so this is essentially hopeless to do + * rigorously.) + * + * - "scp -f -r somedir" + * + * Assuming somedir is actually a directory, server sends a D/E + * pair, in between which are the contents of the directory + * (perhaps including further nested D/E pairs). Client probably + * ignores the name field of the outermost D + * + * - "scp -f -r some*wild*card*" + * + * Server sends multiple C or D-stuff-E, one for each top-level + * thing matching the wildcard, whether it's a file or a directory. + * + * - "scp -t -d some_dir" + * + * Client sends stuff, and server deposits each file at + * some_dir/. + * + * - "scp -t some_path_name" + * + * Client sends one C command, and server deposits it at + * some_path_name itself, or in some_path_name/, depending whether some_path_name was already a + * directory or not. + */ + +/* + * Here's a useful debugging aid: run over a binary file containing + * the complete contents of the sender's data stream (e.g. extracted + * by contrib/logparse.pl -d), it removes the file contents, leaving + * only the list of commands, so you can see what the server sent. + * + * perl -pe 'read ARGV,$x,1+$1 if/^C\S+ (\d+)/' + */ + +/* ---------------------------------------------------------------------- + * Shared system for receiving replies from the SftpServer, and + * putting them into a set of ordinary variables rather than + * marshalling them into actual SFTP reply packets that we'd only have + * to unmarshal again. + */ + +typedef struct ScpReplyReceiver ScpReplyReceiver; +struct ScpReplyReceiver { + int err; + unsigned code; + char *errmsg; + struct fxp_attrs attrs; + ptrlen name, handle, data; + + SftpReplyBuilder srb; +}; + +static void scp_reply_ok(SftpReplyBuilder *srb) +{ + ScpReplyReceiver *reply = container_of(srb, ScpReplyReceiver, srb); + reply->err = FALSE; +} + +static void scp_reply_error( + SftpReplyBuilder *srb, unsigned code, const char *msg) +{ + ScpReplyReceiver *reply = container_of(srb, ScpReplyReceiver, srb); + reply->err = TRUE; + reply->code = code; + sfree(reply->errmsg); + reply->errmsg = dupstr(msg); +} + +static void scp_reply_name_count(SftpReplyBuilder *srb, unsigned count) +{ + ScpReplyReceiver *reply = container_of(srb, ScpReplyReceiver, srb); + reply->err = FALSE; +} + +static void scp_reply_full_name( + SftpReplyBuilder *srb, ptrlen name, + ptrlen longname, struct fxp_attrs attrs) +{ + ScpReplyReceiver *reply = container_of(srb, ScpReplyReceiver, srb); + char *p; + reply->err = FALSE; + sfree((void *)reply->name.ptr); + reply->name.ptr = p = mkstr(name); + reply->name.len = name.len; + reply->attrs = attrs; +} + +static void scp_reply_simple_name(SftpReplyBuilder *srb, ptrlen name) +{ + ScpReplyReceiver *reply = container_of(srb, ScpReplyReceiver, srb); + reply->err = FALSE; +} + +static void scp_reply_handle(SftpReplyBuilder *srb, ptrlen handle) +{ + ScpReplyReceiver *reply = container_of(srb, ScpReplyReceiver, srb); + char *p; + reply->err = FALSE; + sfree((void *)reply->handle.ptr); + reply->handle.ptr = p = mkstr(handle); + reply->handle.len = handle.len; +} + +static void scp_reply_data(SftpReplyBuilder *srb, ptrlen data) +{ + ScpReplyReceiver *reply = container_of(srb, ScpReplyReceiver, srb); + char *p; + reply->err = FALSE; + sfree((void *)reply->data.ptr); + reply->data.ptr = p = mkstr(data); + reply->data.len = data.len; +} + +static void scp_reply_attrs( + SftpReplyBuilder *srb, struct fxp_attrs attrs) +{ + ScpReplyReceiver *reply = container_of(srb, ScpReplyReceiver, srb); + reply->err = FALSE; + reply->attrs = attrs; +} + +static const struct SftpReplyBuilderVtable ScpReplyReceiver_vt = { + scp_reply_ok, + scp_reply_error, + scp_reply_simple_name, + scp_reply_name_count, + scp_reply_full_name, + scp_reply_handle, + scp_reply_data, + scp_reply_attrs, +}; + +static void scp_reply_setup(ScpReplyReceiver *reply) +{ + memset(reply, 0, sizeof(*reply)); + reply->srb.vt = &ScpReplyReceiver_vt; +} + +static void scp_reply_cleanup(ScpReplyReceiver *reply) +{ + sfree(reply->errmsg); + sfree((void *)reply->name.ptr); + sfree((void *)reply->handle.ptr); + sfree((void *)reply->data.ptr); +} + +/* ---------------------------------------------------------------------- + * Source end of the SCP protocol. + */ + +#define SCP_MAX_BACKLOG 65536 + +typedef struct ScpSource ScpSource; +typedef struct ScpSourceStackEntry ScpSourceStackEntry; + +struct ScpSource { + SftpServer *sf; + + int acks, expect_newline, eof, throttled, finished; + + SshChannel *sc; + ScpSourceStackEntry *head; + int recursive; + int send_file_times; + + strbuf *pending_commands[3]; + int n_pending_commands; + + uint64 file_offset, file_size; + + ScpReplyReceiver reply; + + ScpServer scpserver; +}; + +typedef enum ScpSourceNodeType ScpSourceNodeType; +enum ScpSourceNodeType { SCP_ROOTPATH, SCP_NAME, SCP_READDIR, SCP_READFILE }; + +struct ScpSourceStackEntry { + ScpSourceStackEntry *next; + ScpSourceNodeType type; + ptrlen pathname, handle; + const char *wildcard; + struct fxp_attrs attrs; +}; + +static void scp_source_push(ScpSource *scp, ScpSourceNodeType type, + ptrlen pathname, ptrlen handle, + const struct fxp_attrs *attrs, const char *wc) +{ + size_t wc_len = wc ? strlen(wc)+1 : 0; + ScpSourceStackEntry *node = snew_plus( + ScpSourceStackEntry, pathname.len + handle.len + wc_len); + char *namebuf = snew_plus_get_aux(node); + memcpy(namebuf, pathname.ptr, pathname.len); + node->pathname = make_ptrlen(namebuf, pathname.len); + memcpy(namebuf + pathname.len, handle.ptr, handle.len); + node->handle = make_ptrlen(namebuf + pathname.len, handle.len); + if (wc) { + strcpy(namebuf + pathname.len + handle.len, wc); + node->wildcard = namebuf + pathname.len + handle.len; + } else { + node->wildcard = NULL; + } + node->attrs = attrs ? *attrs : no_attrs; + node->type = type; + node->next = scp->head; + scp->head = node; +} + +static char *scp_source_err_base(ScpSource *scp, const char *fmt, va_list ap) +{ + char *msg = dupvprintf(fmt, ap); + sshfwd_write_ext(scp->sc, TRUE, msg, strlen(msg)); + sshfwd_write_ext(scp->sc, TRUE, "\012", 1); + return msg; +} +static void scp_source_err(ScpSource *scp, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + sfree(scp_source_err_base(scp, fmt, ap)); + va_end(ap); +} +static void scp_source_abort(ScpSource *scp, const char *fmt, ...) +{ + va_list ap; + char *msg; + + va_start(ap, fmt); + msg = scp_source_err_base(scp, fmt, ap); + va_end(ap); + + sshfwd_send_exit_status(scp->sc, 1); + sshfwd_write_eof(scp->sc); + sshfwd_initiate_close(scp->sc, msg); + + scp->finished = TRUE; +} + +static void scp_source_push_name( + ScpSource *scp, ptrlen pathname, struct fxp_attrs attrs, const char *wc) +{ + if (!(attrs.flags & SSH_FILEXFER_ATTR_PERMISSIONS)) { + scp_source_err(scp, "unable to read file permissions for %.*s", + PTRLEN_PRINTF(pathname)); + return; + } + if (attrs.permissions & PERMS_DIRECTORY) { + if (!scp->recursive && !wc) { + scp_source_err(scp, "%.*s: is a directory", + PTRLEN_PRINTF(pathname)); + return; + } + } else { + if (!attrs.flags & SSH_FILEXFER_ATTR_SIZE) { + scp_source_err(scp, "unable to read file size for %.*s", + PTRLEN_PRINTF(pathname)); + return; + } + } + + scp_source_push(scp, SCP_NAME, pathname, PTRLEN_LITERAL(""), &attrs, wc); +} + +static void scp_source_free(ScpServer *s); +static int scp_source_send(ScpServer *s, const void *data, size_t length); +static void scp_source_eof(ScpServer *s); +static void scp_source_throttle(ScpServer *s, int throttled); + +static struct ScpServerVtable ScpSource_ScpServer_vt = { + scp_source_free, + scp_source_send, + scp_source_throttle, + scp_source_eof, +}; + +static ScpSource *scp_source_new( + SshChannel *sc, const SftpServerVtable *sftpserver_vt, ptrlen pathname) +{ + ScpSource *scp = snew(ScpSource); + memset(scp, 0, sizeof(*scp)); + + scp->scpserver.vt = &ScpSource_ScpServer_vt; + scp_reply_setup(&scp->reply); + scp->sc = sc; + scp->sf = sftpsrv_new(sftpserver_vt); + scp->n_pending_commands = 0; + + scp_source_push(scp, SCP_ROOTPATH, pathname, PTRLEN_LITERAL(""), + NULL, NULL); + + return scp; +} + +static void scp_source_free(ScpServer *s) +{ + ScpSource *scp = container_of(s, ScpSource, scpserver); + scp_reply_cleanup(&scp->reply); + while (scp->n_pending_commands > 0) + strbuf_free(scp->pending_commands[--scp->n_pending_commands]); + while (scp->head) { + ScpSourceStackEntry *node = scp->head; + scp->head = node->next; + sfree(node); + } + sfree(scp); +} + +static void scp_source_send_E(ScpSource *scp) +{ + strbuf *cmd; + + assert(scp->n_pending_commands == 0); + + scp->pending_commands[scp->n_pending_commands++] = cmd = strbuf_new(); + strbuf_catf(cmd, "E\012"); +} + +static void scp_source_send_CD( + ScpSource *scp, char cmdchar, + struct fxp_attrs attrs, uint64 size, ptrlen name) +{ + strbuf *cmd; + + assert(scp->n_pending_commands == 0); + + if (scp->send_file_times && (attrs.flags & SSH_FILEXFER_ATTR_ACMODTIME)) { + scp->pending_commands[scp->n_pending_commands++] = cmd = strbuf_new(); + /* Our SFTP-based filesystem API doesn't support microsecond times */ + strbuf_catf(cmd, "T%lu 0 %lu 0\012", attrs.mtime, attrs.atime); + } + + char sizebuf[32]; + uint64_decimal(size, sizebuf); + + const char *slash; + while ((slash = memchr(name.ptr, '/', name.len)) != NULL) + name = make_ptrlen( + slash+1, name.len - (slash+1 - (const char *)name.ptr)); + + scp->pending_commands[scp->n_pending_commands++] = cmd = strbuf_new(); + strbuf_catf(cmd, "%c%04o %s %.*s\012", cmdchar, + (unsigned)(attrs.permissions & 07777), + sizebuf, PTRLEN_PRINTF(name)); + + if (cmdchar == 'C') { + /* We'll also wait for an ack before sending the file data, + * which we record by saving a zero-length 'command' to be + * sent after the C. */ + scp->pending_commands[scp->n_pending_commands++] = cmd = strbuf_new(); + } +} + +static void scp_source_process_stack(ScpSource *scp); +static void scp_source_process_stack_cb(void *vscp) +{ + ScpSource *scp = (ScpSource *)vscp; + if (scp->finished) + return; /* this callback is out of date */ + scp_source_process_stack(scp); +} +static void scp_requeue(ScpSource *scp) +{ + queue_toplevel_callback(scp_source_process_stack_cb, scp); +} + +static void scp_source_process_stack(ScpSource *scp) +{ + if (scp->throttled) + return; + + while (scp->n_pending_commands > 0) { + /* Expect an ack, and consume it */ + if (scp->eof) { + scp_source_abort( + scp, "scp: received client EOF, abandoning transfer"); + return; + } + if (scp->acks == 0) + return; + scp->acks--; + + /* + * Now send the actual command (unless it was the phony + * zero-length one that indicates our need for an ack before + * beginning to send file data). + */ + + if (scp->pending_commands[0]->len) + sshfwd_write(scp->sc, scp->pending_commands[0]->s, + scp->pending_commands[0]->len); + + strbuf_free(scp->pending_commands[0]); + scp->n_pending_commands--; + if (scp->n_pending_commands > 0) { + /* + * We still have at least one pending command to send, so + * move up the queue. + * + * (We do that with a bodgy memmove, because there are at + * most a bounded number of commands ever pending at once, + * so no need to worry about quadratic time.) + */ + memmove(scp->pending_commands, scp->pending_commands+1, + scp->n_pending_commands * sizeof(*scp->pending_commands)); + } + } + + /* + * Mostly, we start by waiting for an ack byte from the receiver. + */ + if (scp->head && scp->head->type == SCP_READFILE && + uint64_compare(scp->file_offset, uint64_make(0, 0)) != 0) { + /* + * Exception: if we're already in the middle of transferring a + * file, we'll be called back here because the channel backlog + * has cleared; we don't need to wait for an ack. + */ + } else if (scp->head && scp->head->type == SCP_ROOTPATH) { + /* + * Another exception: the initial action node that makes us + * stat the root path. We'll translate it into an SCP_NAME, + * and _that_ will require an ack. + */ + ScpSourceStackEntry *node = scp->head; + scp->head = node->next; + + /* + * Start by checking if there's a wildcard involved in the + * root path. + */ + char *rootpath_str = mkstr(node->pathname); + char *rootpath_unesc = snewn(1+node->pathname.len, char); + ptrlen pathname; + const char *wildcard; + + if (wc_unescape(rootpath_unesc, rootpath_str)) { + /* + * We successfully removed instances of the escape + * character used in our wildcard syntax, without + * encountering any actual wildcard chars - i.e. this is + * not a wildcard, just a single file. The simple case. + */ + pathname = ptrlen_from_asciz(rootpath_str); + wildcard = NULL; + } else { + /* + * This is a wildcard. Separate it into a directory name + * (which we enforce mustn't contain wc characters, for + * simplicity) and a wildcard to match leaf names. + */ + char *last_slash = strrchr(rootpath_str, '/'); + + if (last_slash) { + wildcard = last_slash + 1; + *last_slash = '\0'; + if (!wc_unescape(rootpath_unesc, rootpath_str)) { + scp_source_abort(scp, "scp: wildcards in path components " + "before the file name not supported"); + sfree(rootpath_str); + sfree(rootpath_unesc); + return; + } + + pathname = ptrlen_from_asciz(rootpath_unesc); + } else { + pathname = PTRLEN_LITERAL("."); + wildcard = rootpath_str; + } + } + + /* + * Now we know what directory we're scanning, and what + * wildcard (if any) we're using to match the filenames we get + * back. + */ + sftpsrv_stat(scp->sf, &scp->reply.srb, pathname, TRUE); + if (scp->reply.err) { + scp_source_abort( + scp, "%.*s: unable to access: %s", + PTRLEN_PRINTF(pathname), scp->reply.errmsg); + sfree(rootpath_str); + sfree(rootpath_unesc); + sfree(node); + return; + } + + scp_source_push_name(scp, pathname, scp->reply.attrs, wildcard); + + sfree(rootpath_str); + sfree(rootpath_unesc); + sfree(node); + scp_requeue(scp); + return; + } else { + } + + if (scp->head && scp->head->type == SCP_READFILE) { + /* + * Transfer file data if our backlog hasn't filled up. + */ + int backlog; + uint64 remaining = + uint64_subtract(scp->file_size, scp->file_offset); + uint64 limit = uint64_make(0, 4096); + if (uint64_compare(remaining, limit) < 0) + limit = remaining; + if (limit.lo > 0) { + sftpsrv_read(scp->sf, &scp->reply.srb, scp->head->handle, + scp->file_offset, limit.lo); + if (scp->reply.err) { + scp_source_abort( + scp, "%.*s: unable to read: %s", + PTRLEN_PRINTF(scp->head->pathname), scp->reply.errmsg); + return; + } + + backlog = sshfwd_write( + scp->sc, scp->reply.data.ptr, scp->reply.data.len); + scp->file_offset = uint64_add( + scp->file_offset, uint64_make(0, scp->reply.data.len)); + + if (backlog < SCP_MAX_BACKLOG) + scp_requeue(scp); + return; + } + + /* + * If we're done, send a terminating zero byte, close our file + * handle, and pop the stack. + */ + sshfwd_write(scp->sc, "\0", 1); + sftpsrv_close(scp->sf, &scp->reply.srb, scp->head->handle); + ScpSourceStackEntry *node = scp->head; + scp->head = node->next; + sfree(node); + scp_requeue(scp); + return; + } + + /* + * If our queue is actually empty, send outgoing EOF. + */ + if (!scp->head) { + sshfwd_send_exit_status(scp->sc, 0); + sshfwd_write_eof(scp->sc); + sshfwd_initiate_close(scp->sc, NULL); + scp->finished = TRUE; + return; + } + + /* + * Otherwise, handle a command. + */ + ScpSourceStackEntry *node = scp->head; + scp->head = node->next; + + if (node->type == SCP_READDIR) { + sftpsrv_readdir(scp->sf, &scp->reply.srb, node->handle, 1, TRUE); + if (scp->reply.err) { + if (scp->reply.code != SSH_FX_EOF) + scp_source_err(scp, "%.*s: unable to list directory: %s", + PTRLEN_PRINTF(node->pathname), + scp->reply.errmsg); + sftpsrv_close(scp->sf, &scp->reply.srb, node->handle); + + if (!node->wildcard) { + /* + * Send 'pop stack' or 'end of directory' command, + * unless this was the topmost READDIR in a + * wildcard-based retrieval (in which case we didn't + * send a D command to start, so an E now would have + * no stack entry to pop). + */ + scp_source_send_E(scp); + } + } else if (ptrlen_eq_string(scp->reply.name, ".") || + ptrlen_eq_string(scp->reply.name, "..") || + (node->wildcard && + !wc_match_pl(node->wildcard, scp->reply.name))) { + /* Skip special directory names . and .., and anything + * that doesn't match our wildcard (if we have one). */ + scp->head = node; /* put back the unfinished READDIR */ + node = NULL; /* and prevent it being freed */ + } else { + ptrlen subpath; + subpath.len = node->pathname.len + 1 + scp->reply.name.len; + char *subpath_space = snewn(subpath.len, char); + subpath.ptr = subpath_space; + memcpy(subpath_space, node->pathname.ptr, node->pathname.len); + subpath_space[node->pathname.len] = '/'; + memcpy(subpath_space + node->pathname.len + 1, + scp->reply.name.ptr, scp->reply.name.len); + + scp->head = node; /* put back the unfinished READDIR */ + node = NULL; /* and prevent it being freed */ + scp_source_push_name(scp, subpath, scp->reply.attrs, NULL); + + sfree(subpath_space); + } + } else if (node->attrs.permissions & PERMS_DIRECTORY) { + assert(scp->recursive || node->wildcard); + + if (!node->wildcard) + scp_source_send_CD(scp, 'D', node->attrs, + uint64_make(0, 0), node->pathname); + sftpsrv_opendir(scp->sf, &scp->reply.srb, node->pathname); + if (scp->reply.err) { + scp_source_err( + scp, "%.*s: unable to access: %s", + PTRLEN_PRINTF(node->pathname), scp->reply.errmsg); + + if (!node->wildcard) { + /* Send 'pop stack' or 'end of directory' command. */ + scp_source_send_E(scp); + } + } else { + scp_source_push( + scp, SCP_READDIR, node->pathname, + scp->reply.handle, NULL, node->wildcard); + } + } else { + sftpsrv_open(scp->sf, &scp->reply.srb, + node->pathname, SSH_FXF_READ, no_attrs); + if (scp->reply.err) { + scp_source_err( + scp, "%.*s: unable to open: %s", + PTRLEN_PRINTF(node->pathname), scp->reply.errmsg); + scp_requeue(scp); + return; + } + sftpsrv_fstat(scp->sf, &scp->reply.srb, scp->reply.handle); + if (scp->reply.err) { + scp_source_err( + scp, "%.*s: unable to stat: %s", + PTRLEN_PRINTF(node->pathname), scp->reply.errmsg); + sftpsrv_close(scp->sf, &scp->reply.srb, scp->reply.handle); + scp_requeue(scp); + return; + } + scp->file_offset = uint64_make(0, 0); + scp->file_size = scp->reply.attrs.size; + scp_source_send_CD(scp, 'C', node->attrs, + scp->file_size, node->pathname); + scp_source_push( + scp, SCP_READFILE, node->pathname, scp->reply.handle, NULL, NULL); + } + sfree(node); + scp_requeue(scp); +} + +static int scp_source_send(ScpServer *s, const void *vdata, size_t length) +{ + ScpSource *scp = container_of(s, ScpSource, scpserver); + const char *data = (const char *)vdata; + size_t i; + + if (scp->finished) + return 0; + + for (i = 0; i < length; i++) { + if (scp->expect_newline) { + if (data[i] == '\012') { + /* End of an error message following a 1 byte */ + scp->expect_newline = FALSE; + scp->acks++; + } + } else { + switch (data[i]) { + case 0: /* ordinary ack */ + scp->acks++; + break; + case 1: /* non-fatal error; consume it */ + scp->expect_newline = TRUE; + break; + case 2: + scp_source_abort( + scp, "terminating on fatal error from client"); + return 0; + default: + scp_source_abort( + scp, "unrecognised response code from client"); + return 0; + } + } + } + + scp_source_process_stack(scp); + + return 0; +} + +static void scp_source_throttle(ScpServer *s, int throttled) +{ + ScpSource *scp = container_of(s, ScpSource, scpserver); + + if (scp->finished) + return; + + scp->throttled = throttled; + if (!throttled) + scp_source_process_stack(scp); +} + +static void scp_source_eof(ScpServer *s) +{ + ScpSource *scp = container_of(s, ScpSource, scpserver); + + if (scp->finished) + return; + + scp->eof = TRUE; + scp_source_process_stack(scp); +} + +/* ---------------------------------------------------------------------- + * Sink end of the SCP protocol. + */ + +typedef struct ScpSink ScpSink; +typedef struct ScpSinkStackEntry ScpSinkStackEntry; + +struct ScpSink { + SftpServer *sf; + + SshChannel *sc; + ScpSinkStackEntry *head; + + uint64 file_offset, file_size; + unsigned long atime, mtime; + int got_file_times; + + bufchain data; + int input_eof; + strbuf *command; + char command_chr; + + strbuf *filename_sb; + ptrlen filename; + struct fxp_attrs attrs; + + char *errmsg; + + int crState; + + ScpReplyReceiver reply; + + ScpServer scpserver; +}; + +struct ScpSinkStackEntry { + ScpSinkStackEntry *next; + ptrlen destpath; + + /* + * If isdir is TRUE, then destpath identifies a directory that the + * files we receive should be created inside. If it's FALSE, then + * it identifies the exact pathname the next file we receive + * should be created _as_ - regardless of the filename in the 'C' + * command. + */ + int isdir; +}; + +static void scp_sink_push(ScpSink *scp, ptrlen pathname, int isdir) +{ + ScpSinkStackEntry *node = snew_plus(ScpSinkStackEntry, pathname.len); + char *p = snew_plus_get_aux(node); + + node->destpath.ptr = p; + node->destpath.len = pathname.len; + memcpy(p, pathname.ptr, pathname.len); + node->isdir = isdir; + + node->next = scp->head; + scp->head = node; +} + +static void scp_sink_pop(ScpSink *scp) +{ + ScpSinkStackEntry *node = scp->head; + scp->head = node->next; + sfree(node); +} + +static void scp_sink_free(ScpServer *s); +static int scp_sink_send(ScpServer *s, const void *data, size_t length); +static void scp_sink_eof(ScpServer *s); +static void scp_sink_throttle(ScpServer *s, int throttled) {} + +static struct ScpServerVtable ScpSink_ScpServer_vt = { + scp_sink_free, + scp_sink_send, + scp_sink_throttle, + scp_sink_eof, +}; + +static void scp_sink_coroutine(ScpSink *scp); +static void scp_sink_start_callback(void *vscp) +{ + scp_sink_coroutine((ScpSink *)vscp); +} + +static ScpSink *scp_sink_new( + SshChannel *sc, const SftpServerVtable *sftpserver_vt, ptrlen pathname, + int pathname_is_definitely_dir) +{ + ScpSink *scp = snew(ScpSink); + memset(scp, 0, sizeof(*scp)); + + scp->scpserver.vt = &ScpSink_ScpServer_vt; + scp_reply_setup(&scp->reply); + scp->sc = sc; + scp->sf = sftpsrv_new(sftpserver_vt); + bufchain_init(&scp->data); + scp->command = strbuf_new(); + scp->filename_sb = strbuf_new(); + + if (!pathname_is_definitely_dir) { + /* + * If our root pathname is not already expected to be a + * directory because of the -d option in the command line, + * test it ourself to see whether it is or not. + */ + sftpsrv_stat(scp->sf, &scp->reply.srb, pathname, TRUE); + if (!scp->reply.err && + (scp->reply.attrs.flags & SSH_FILEXFER_ATTR_PERMISSIONS) && + (scp->reply.attrs.permissions & PERMS_DIRECTORY)) + pathname_is_definitely_dir = TRUE; + } + scp_sink_push(scp, pathname, pathname_is_definitely_dir); + + queue_toplevel_callback(scp_sink_start_callback, scp); + + return scp; +} + +static void scp_sink_free(ScpServer *s) +{ + ScpSink *scp = container_of(s, ScpSink, scpserver); + + scp_reply_cleanup(&scp->reply); + bufchain_clear(&scp->data); + strbuf_free(scp->command); + strbuf_free(scp->filename_sb); + while (scp->head) + scp_sink_pop(scp); + sfree(scp->errmsg); + + delete_callbacks_for_context(scp); + + sfree(scp); +} + +static void scp_sink_coroutine(ScpSink *scp) +{ + crBegin(scp->crState); + + while (1) { + /* + * Send an ack, and read a command. + */ + sshfwd_write(scp->sc, "\0", 1); + scp->command->len = 0; + while (1) { + crMaybeWaitUntilV(scp->input_eof || bufchain_size(&scp->data) > 0); + if (scp->input_eof) + goto done; + + void *vdata; + int len; + const char *cdata, *newline; + + bufchain_prefix(&scp->data, &vdata, &len); + cdata = vdata; + newline = memchr(cdata, '\012', len); + if (newline) + len = (int)(newline+1 - cdata); + put_data(scp->command, cdata, len); + bufchain_consume(&scp->data, len); + + if (newline) + break; + } + + /* + * Parse the command. + */ + scp->command->len--; /* chomp the newline */ + scp->command_chr = scp->command->len > 0 ? scp->command->s[0] : '\0'; + if (scp->command_chr == 'T') { + unsigned long dummy1, dummy2; + if (sscanf(scp->command->s, "T%lu %lu %lu %lu", + &scp->mtime, &dummy1, &scp->atime, &dummy2) != 4) + goto parse_error; + scp->got_file_times = TRUE; + } else if (scp->command_chr == 'C' || scp->command_chr == 'D') { + /* + * Common handling of the start of this case, because the + * messages are parsed similarly. We diverge later. + */ + const char *q, *p = scp->command->s + 1; /* skip the 'C' */ + + scp->attrs.flags = SSH_FILEXFER_ATTR_PERMISSIONS; + scp->attrs.permissions = 0; + while (*p >= '0' && *p <= '7') { + scp->attrs.permissions = + scp->attrs.permissions * 8 + (*p - '0'); + p++; + } + if (*p != ' ') + goto parse_error; + p++; + + q = p; + while (*p >= '0' && *p <= '9') + p++; + if (*p != ' ') + goto parse_error; + p++; + scp->file_size = uint64_from_decimal(q); + + ptrlen leafname = make_ptrlen( + p, scp->command->len - (p - scp->command->s)); + scp->filename_sb->len = 0; + put_data(scp->filename_sb, scp->head->destpath.ptr, + scp->head->destpath.len); + if (scp->head->isdir) { + if (scp->filename_sb->len > 0 && + scp->filename_sb->s[scp->filename_sb->len-1] + != '/') + put_byte(scp->filename_sb, '/'); + put_data(scp->filename_sb, leafname.ptr, leafname.len); + } + scp->filename = ptrlen_from_strbuf(scp->filename_sb); + + if (scp->got_file_times) { + scp->attrs.mtime = scp->mtime; + scp->attrs.atime = scp->atime; + scp->attrs.flags |= SSH_FILEXFER_ATTR_ACMODTIME; + } + scp->got_file_times = FALSE; + + if (scp->command_chr == 'D') { + sftpsrv_mkdir(scp->sf, &scp->reply.srb, + scp->filename, scp->attrs); + + if (scp->reply.err) { + scp->errmsg = dupprintf( + "'%.*s': unable to create directory: %s", + PTRLEN_PRINTF(scp->filename), scp->reply.errmsg); + goto done; + } + + scp_sink_push(scp, scp->filename, TRUE); + } else { + sftpsrv_open(scp->sf, &scp->reply.srb, scp->filename, + SSH_FXF_WRITE | SSH_FXF_CREAT | SSH_FXF_TRUNC, + scp->attrs); + if (scp->reply.err) { + scp->errmsg = dupprintf( + "'%.*s': unable to open file: %s", + PTRLEN_PRINTF(scp->filename), scp->reply.errmsg); + goto done; + } + + /* + * Now send an ack, and read the file data. + */ + sshfwd_write(scp->sc, "\0", 1); + scp->file_offset = uint64_make(0, 0); + while (uint64_compare(scp->file_offset, scp->file_size) < 0) { + void *vdata; + int len; + uint64 this_len, remaining; + + crMaybeWaitUntilV( + scp->input_eof || bufchain_size(&scp->data) > 0); + if (scp->input_eof) { + sftpsrv_close(scp->sf, &scp->reply.srb, + scp->reply.handle); + goto done; + } + + bufchain_prefix(&scp->data, &vdata, &len); + this_len = uint64_make(0, len); + remaining = uint64_subtract( + scp->file_size, scp->file_offset); + if (uint64_compare(this_len, remaining) > 0) + this_len = remaining; + sftpsrv_write(scp->sf, &scp->reply.srb, + scp->reply.handle, scp->file_offset, + make_ptrlen(vdata, this_len.lo)); + if (scp->reply.err) { + scp->errmsg = dupprintf( + "'%.*s': unable to write to file: %s", + PTRLEN_PRINTF(scp->filename), scp->reply.errmsg); + goto done; + } + bufchain_consume(&scp->data, this_len.lo); + scp->file_offset = uint64_add(scp->file_offset, this_len); + } + + /* + * Wait for the trailing NUL byte. + */ + crMaybeWaitUntilV( + scp->input_eof || bufchain_size(&scp->data) > 0); + if (scp->input_eof) { + sftpsrv_close(scp->sf, &scp->reply.srb, + scp->reply.handle); + goto done; + } + bufchain_consume(&scp->data, 1); + } + } else if (scp->command_chr == 'E') { + if (!scp->head) { + scp->errmsg = dupstr("received E command without matching D"); + goto done; + } + scp_sink_pop(scp); + scp->got_file_times = FALSE; + } else { + ptrlen cmd_pl; + + /* + * Also come here if any of the above cases run into + * parsing difficulties. + */ + parse_error: + cmd_pl = ptrlen_from_strbuf(scp->command); + scp->errmsg = dupprintf("unrecognised scp command '%.*s'", + PTRLEN_PRINTF(cmd_pl)); + goto done; + } + } + + done: + if (scp->errmsg) { + sshfwd_write_ext(scp->sc, TRUE, scp->errmsg, strlen(scp->errmsg)); + sshfwd_write_ext(scp->sc, TRUE, "\012", 1); + sshfwd_send_exit_status(scp->sc, 1); + } else { + sshfwd_send_exit_status(scp->sc, 0); + } + sshfwd_write_eof(scp->sc); + sshfwd_initiate_close(scp->sc, scp->errmsg); + while (1) crReturnV; + + crFinishV; +} + +static int scp_sink_send(ScpServer *s, const void *data, size_t length) +{ + ScpSink *scp = container_of(s, ScpSink, scpserver); + + if (!scp->input_eof) { + bufchain_add(&scp->data, data, length); + scp_sink_coroutine(scp); + } + return 0; +} + +static void scp_sink_eof(ScpServer *s) +{ + ScpSink *scp = container_of(s, ScpSink, scpserver); + + scp->input_eof = TRUE; + scp_sink_coroutine(scp); +} + +/* ---------------------------------------------------------------------- + * Top-level error handler, instantiated in the case where the user + * sent a command starting with "scp " that we couldn't make sense of. + */ + +typedef struct ScpError ScpError; + +struct ScpError { + SshChannel *sc; + char *message; + ScpServer scpserver; +}; + +static void scp_error_free(ScpServer *s); + +static int scp_error_send(ScpServer *s, const void *data, size_t length) +{ return 0; } +static void scp_error_eof(ScpServer *s) {} +static void scp_error_throttle(ScpServer *s, int throttled) {} + +static struct ScpServerVtable ScpError_ScpServer_vt = { + scp_error_free, + scp_error_send, + scp_error_throttle, + scp_error_eof, +}; + +static void scp_error_send_message_cb(void *vscp) +{ + ScpError *scp = (ScpError *)vscp; + sshfwd_write_ext(scp->sc, TRUE, scp->message, strlen(scp->message)); + sshfwd_write_ext(scp->sc, TRUE, "\n", 1); + sshfwd_send_exit_status(scp->sc, 1); + sshfwd_write_eof(scp->sc); + sshfwd_initiate_close(scp->sc, scp->message); +} + +static ScpError *scp_error_new(SshChannel *sc, const char *fmt, ...) +{ + va_list ap; + ScpError *scp = snew(ScpError); + + memset(scp, 0, sizeof(*scp)); + + scp->scpserver.vt = &ScpError_ScpServer_vt; + scp->sc = sc; + + va_start(ap, fmt); + scp->message = dupvprintf(fmt, ap); + va_end(ap); + + queue_toplevel_callback(scp_error_send_message_cb, scp); + + return scp; +} + +static void scp_error_free(ScpServer *s) +{ + ScpError *scp = container_of(s, ScpError, scpserver); + + sfree(scp->message); + + delete_callbacks_for_context(scp); + + sfree(scp); +} + +/* ---------------------------------------------------------------------- + * Top-level entry point, which parses a command sent from the SSH + * client, and if it recognises it as an scp command, instantiates an + * appropriate ScpServer implementation and returns it. + */ + +ScpServer *scp_recognise_exec( + SshChannel *sc, const SftpServerVtable *sftpserver_vt, ptrlen command) +{ + int recursive = FALSE, preserve = FALSE; + int targetshouldbedirectory = FALSE; + ptrlen command_orig = command; + + if (!ptrlen_startswith(command, PTRLEN_LITERAL("scp "), &command)) + return NULL; + + while (1) { + if (ptrlen_startswith(command, PTRLEN_LITERAL("-v "), &command)) { + /* Enable verbose mode in the server, which we ignore */ + continue; + } + if (ptrlen_startswith(command, PTRLEN_LITERAL("-r "), &command)) { + recursive = TRUE; + continue; + } + if (ptrlen_startswith(command, PTRLEN_LITERAL("-p "), &command)) { + preserve = TRUE; + continue; + } + if (ptrlen_startswith(command, PTRLEN_LITERAL("-d "), &command)) { + targetshouldbedirectory = TRUE; + continue; + } + break; + } + + if (ptrlen_startswith(command, PTRLEN_LITERAL("-t "), &command)) { + ScpSink *scp = scp_sink_new(sc, sftpserver_vt, command, + targetshouldbedirectory); + return &scp->scpserver; + } else if (ptrlen_startswith(command, PTRLEN_LITERAL("-f "), &command)) { + ScpSource *scp = scp_source_new(sc, sftpserver_vt, command); + scp->recursive = recursive; + scp->send_file_times = preserve; + return &scp->scpserver; + } else { + ScpError *scp = scp_error_new( + sc, "Unable to parse scp command: '%.*s'", + PTRLEN_PRINTF(command_orig)); + return &scp->scpserver; + } +} diff --git a/sesschan.c b/sesschan.c index 46116466..9a1c6c44 100644 --- a/sesschan.c +++ b/sesschan.c @@ -42,6 +42,7 @@ typedef struct sesschan { bufchain subsys_input; SftpServer *sftpsrv; + ScpServer *scpsrv; Channel chan; } sesschan; @@ -123,6 +124,36 @@ static const struct ChannelVtable sftp_channelvt = { chan_no_request_response, }; +static int scp_chan_send(Channel *chan, int is_stderr, const void *, int); +static void scp_chan_send_eof(Channel *chan); +static void scp_set_input_wanted(Channel *chan, int wanted); +static char *scp_log_close_msg(Channel *chan); + +static const struct ChannelVtable scp_channelvt = { + sesschan_free, + chan_remotely_opened_confirmation, + chan_remotely_opened_failure, + scp_chan_send, + scp_chan_send_eof, + scp_set_input_wanted, + scp_log_close_msg, + chan_default_want_close, + chan_no_exit_status, + chan_no_exit_signal, + chan_no_exit_signal_numeric, + chan_no_run_shell, + chan_no_run_command, + chan_no_run_subsystem, + chan_no_enable_x11_forwarding, + chan_no_enable_agent_forwarding, + chan_no_allocate_pty, + chan_no_set_env, + chan_no_send_break, + chan_no_send_signal, + chan_no_change_window_size, + chan_no_request_response, +}; + static void sesschan_eventlog(LogPolicy *lp, const char *event) {} static void sesschan_logging_error(LogPolicy *lp, const char *event) {} static int sesschan_askappend( @@ -264,6 +295,14 @@ int sesschan_run_command(Channel *chan, ptrlen command) if (sess->backend) return FALSE; + /* FIXME: make this possible to configure off */ + if ((sess->scpsrv = scp_recognise_exec(sess->c, sess->sftpserver_vt, + command)) != NULL) { + sess->chan.vt = &scp_channelvt; + logevent(sess->parent_logctx, "Starting built-in SCP server"); + return TRUE; + } + char *command_str = mkstr(command); sesschan_start_backend(sess, command_str); sfree(command_str); @@ -651,3 +690,31 @@ static char *sftp_log_close_msg(Channel *chan) { return dupstr("Session channel (SFTP) closed"); } + +/* ---------------------------------------------------------------------- + * Built-in SCP subsystem. + */ + +static int scp_chan_send(Channel *chan, int is_stderr, + const void *data, int length) +{ + sesschan *sess = container_of(chan, sesschan, chan); + return scp_send(sess->scpsrv, data, length); +} + +static void scp_chan_send_eof(Channel *chan) +{ + sesschan *sess = container_of(chan, sesschan, chan); + scp_eof(sess->scpsrv); +} + +static char *scp_log_close_msg(Channel *chan) +{ + return dupstr("Session channel (SCP) closed"); +} + +static void scp_set_input_wanted(Channel *chan, int wanted) +{ + sesschan *sess = container_of(chan, sesschan, chan); + scp_throttle(sess->scpsrv, !wanted); +} diff --git a/sftp.h b/sftp.h index 636c42d6..8bbb7f7b 100644 --- a/sftp.h +++ b/sftp.h @@ -56,6 +56,8 @@ #define SFTP_PROTO_VERSION 3 +#define PERMS_DIRECTORY 040000 + /* * External references. The sftp client module sftp.c expects to be * able to get at these functions. @@ -477,3 +479,41 @@ struct DefaultSftpReplyBuilder { */ struct sftp_packet *sftp_handle_request( SftpServer *srv, struct sftp_packet *request); + +/* ---------------------------------------------------------------------- + * Not exactly SFTP-related, but here's a system that implements an + * old-fashioned SCP server module, given an SftpServer vtable to use + * as its underlying filesystem access. + */ + +typedef struct ScpServer ScpServer; +typedef struct ScpServerVtable ScpServerVtable; +struct ScpServer { + const struct ScpServerVtable *vt; +}; +struct ScpServerVtable { + void (*free)(ScpServer *s); + + int (*send)(ScpServer *s, const void *data, size_t length); + void (*throttle)(ScpServer *s, int throttled); + void (*eof)(ScpServer *s); +}; + +#define scp_free(s) ((s)->vt->free(s)) +#define scp_send(s, data, len) ((s)->vt->send(s, data, len)) +#define scp_throttle(s, th) ((s)->vt->throttle(s, th)) +#define scp_eof(s) ((s)->vt->eof(s)) + +/* + * Create an ScpServer by calling this function, giving it the command + * you received from the SSH client to execute. If that command is + * recognised as an scp command, it will construct an ScpServer object + * and return it; otherwise, it will return NULL, and you should + * execute the command in whatever way you normally would. + * + * The ScpServer will generate output for the client by writing it to + * the provided SshChannel using sshfwd_write; you pass it input using + * the send method in its own vtable. + */ +ScpServer *scp_recognise_exec( + SshChannel *sc, const SftpServerVtable *sftpserver_vt, ptrlen command); From f789251ee495a05068589db15719ce5bd11d27f0 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Thu, 25 Oct 2018 18:33:56 +0100 Subject: [PATCH 574/607] Fix a couple of benign compile warnings. A function containing assert(FALSE && "Should never be called") doesn't _really_ need to return a value, but it makes compilers happier if it pretends to. --- ssh2connection-client.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ssh2connection-client.c b/ssh2connection-client.c index 65fc6bc2..dbccf42a 100644 --- a/ssh2connection-client.c +++ b/ssh2connection-client.c @@ -305,11 +305,13 @@ SshChannel *ssh2_serverside_x11_open( ConnectionLayer *cl, Channel *chan, const SocketPeerInfo *pi) { assert(FALSE && "Should never be called in the client"); + return 0; /* placate optimiser */ } SshChannel *ssh2_serverside_agent_open(ConnectionLayer *cl, Channel *chan) { assert(FALSE && "Should never be called in the client"); + return 0; /* placate optimiser */ } static void ssh2_channel_response( From 6714fcddc626f88373dbaf02af182f3236ca2109 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Thu, 25 Oct 2018 18:34:19 +0100 Subject: [PATCH 575/607] Fix a newly introduced segfault in callback.c. Colin Harrison points out that commit c31e3cd43 was less cautious than it should have been: when delete_callbacks_for_context nulls out the 'next' pointer in the new tail element of the callbacks list, it should only do so if there _is_ a new tail element. If the list has just become empty, that won't work very well! --- callback.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/callback.c b/callback.c index 09a5e49b..6a888e89 100644 --- a/callback.c +++ b/callback.c @@ -65,7 +65,8 @@ void delete_callbacks_for_context(void *ctx) cbhead = newhead; cbtail = newtail; - newtail->next = NULL; + if (newtail) + newtail->next = NULL; } void queue_toplevel_callback(toplevel_callback_fn_t fn, void *ctx) From 291c1b07f22ecaccdedf2bfe4a0923673eb8f14b Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Thu, 25 Oct 2018 18:34:39 +0100 Subject: [PATCH 576/607] Remove unused and bit-rotted scroll optimisation. In the very old days, when PuTTY was new and computers were slow, I tried to implement a feature where scrolling the window would be implemented using a fast rectangle-copy GDI operation, rather than an expensive character-by-character redraw of all the changed areas. It never quite worked right, and I ended up conditioning it out on Windows, and never even tried to implement it on GTK. It's now been sitting around unused for so long that I think it's no longer worth keeping in the code at all - if I tried to put it back in, it surely wouldn't even compile, and would need rewriting from scratch anyway. Disturbingly, it looks as if I _tried_ to re-enable it at one point, in that there was a '#define OPTIMISE_IS_SCROLL 1' in putty.h - but that never had any effect, because the macro name is misspelled. All the #ifdefs are for 'OPTIMISE_SCROLL', without the 'IS'. So despite appearances, it really _has_ been conditioned out all along! --- putty.h | 4 -- terminal.c | 122 ++--------------------------------------------- terminal.h | 13 ----- windows/window.c | 21 -------- 4 files changed, 5 insertions(+), 155 deletions(-) diff --git a/putty.h b/putty.h index b8350eb8..da6a175e 100644 --- a/putty.h +++ b/putty.h @@ -1020,9 +1020,6 @@ void do_text(Context, int, int, wchar_t *, int, unsigned long, int, void do_cursor(Context, int, int, wchar_t *, int, unsigned long, int, truecolour); int char_width(Context ctx, int uc); -#ifdef OPTIMISE_SCROLL -void do_scroll(Context, int, int, int); -#endif void set_title(Frontend *frontend, char *); void set_icon(Frontend *frontend, char *); void set_sbar(Frontend *frontend, int, int, int); @@ -1043,7 +1040,6 @@ void modalfatalbox(const char *, ...); void do_beep(Frontend *frontend, int); void sys_cursor(Frontend *frontend, int x, int y); void frontend_request_paste(Frontend *frontend, int clipboard); -#define OPTIMISE_IS_SCROLL 1 void set_iconic(Frontend *frontend, int iconic); void move_window(Frontend *frontend, int x, int y); diff --git a/terminal.c b/terminal.c index 621d81de..01fd8da0 100644 --- a/terminal.c +++ b/terminal.c @@ -101,7 +101,7 @@ static void resizeline(Terminal *, termline *, int); static termline *lineptr(Terminal *, int, int, int); static void unlineptr(termline *); static void check_line_size(Terminal *, termline *); -static void do_paint(Terminal *, Context, int); +static void do_paint(Terminal *, Context); static void erase_lots(Terminal *, int, int, int); static int find_last_nonempty_line(Terminal *, tree234 *); static void swap_screen(Terminal *, int, int, int); @@ -110,9 +110,6 @@ static void deselect(Terminal *); static void term_print_finish(Terminal *); static void scroll(Terminal *, int, int, int, int); static void parse_optionalrgb(optionalrgb *out, unsigned *values); -#ifdef OPTIMISE_SCROLL -static void scroll_display(Terminal *, int, int, int); -#endif /* OPTIMISE_SCROLL */ static termline *newline(Terminal *term, int cols, int bce) { @@ -1366,7 +1363,7 @@ void term_update(Terminal *term) if (need_sbar_update) update_sbar(term); - do_paint(term, ctx, TRUE); + do_paint(term, ctx); sys_cursor(term->frontend, term->curs.x, term->curs.y - term->disptop); free_ctx(ctx); } @@ -1686,9 +1683,6 @@ Terminal *term_init(Conf *myconf, struct unicode_data *ucsdata, term->rows = term->cols = -1; power_on(term, TRUE); term->beephead = term->beeptail = NULL; -#ifdef OPTIMISE_SCROLL - term->scrollhead = term->scrolltail = NULL; -#endif /* OPTIMISE_SCROLL */ term->nbeeps = 0; term->lastbeep = FALSE; term->beep_overloaded = FALSE; @@ -2126,18 +2120,10 @@ static void scroll(Terminal *term, int topline, int botline, int lines, int sb) { termline *line; int i, seltop, scrollwinsize; -#ifdef OPTIMISE_SCROLL - int olddisptop, shift; -#endif /* OPTIMISE_SCROLL */ if (topline != 0 || term->alt_which != 0) sb = FALSE; -#ifdef OPTIMISE_SCROLL - olddisptop = term->disptop; - shift = lines; -#endif /* OPTIMISE_SCROLL */ - scrollwinsize = botline - topline + 1; if (lines < 0) { @@ -2258,81 +2244,8 @@ static void scroll(Terminal *term, int topline, int botline, int lines, int sb) } } } -#ifdef OPTIMISE_SCROLL - shift += term->disptop - olddisptop; - if (shift < term->rows && shift > -term->rows && shift != 0) - scroll_display(term, topline, botline, shift); -#endif /* OPTIMISE_SCROLL */ -} - -#ifdef OPTIMISE_SCROLL -/* - * Add a scroll of a region on the screen into the pending scroll list. - * `lines' is +ve for scrolling forward, -ve for backward. - * - * If the scroll is on the same area as the last scroll in the list, - * merge them. - */ -static void save_scroll(Terminal *term, int topline, int botline, int lines) -{ - struct scrollregion *newscroll; - if (term->scrolltail && - term->scrolltail->topline == topline && - term->scrolltail->botline == botline) { - term->scrolltail->lines += lines; - } else { - newscroll = snew(struct scrollregion); - newscroll->topline = topline; - newscroll->botline = botline; - newscroll->lines = lines; - newscroll->next = NULL; - - if (!term->scrollhead) - term->scrollhead = newscroll; - else - term->scrolltail->next = newscroll; - term->scrolltail = newscroll; - } } -/* - * Scroll the physical display, and our conception of it in disptext. - */ -static void scroll_display(Terminal *term, int topline, int botline, int lines) -{ - int distance, nlines, i, j; - - distance = lines > 0 ? lines : -lines; - nlines = botline - topline + 1 - distance; - if (lines > 0) { - for (i = 0; i < nlines; i++) - for (j = 0; j < term->cols; j++) - copy_termchar(term->disptext[i], j, - term->disptext[i+distance]->chars+j); - if (term->dispcursy >= 0 && - term->dispcursy >= topline + distance && - term->dispcursy < topline + distance + nlines) - term->dispcursy -= distance; - for (i = 0; i < distance; i++) - for (j = 0; j < term->cols; j++) - term->disptext[nlines+i]->chars[j].attr |= ATTR_INVALID; - } else { - for (i = nlines; i-- ;) - for (j = 0; j < term->cols; j++) - copy_termchar(term->disptext[i+distance], j, - term->disptext[i]->chars+j); - if (term->dispcursy >= 0 && - term->dispcursy >= topline && - term->dispcursy < topline + nlines) - term->dispcursy += distance; - for (i = 0; i < distance; i++) - for (j = 0; j < term->cols; j++) - term->disptext[i]->chars[j].attr |= ATTR_INVALID; - } - save_scroll(term, topline, botline, lines); -} -#endif /* OPTIMISE_SCROLL */ - /* * Move the cursor to a given position, clipping at boundaries. We * may or may not want to clip at the scroll margin: marg_clip is 0 @@ -5109,19 +5022,15 @@ static termchar *term_bidi_line(Terminal *term, struct termline *ldata, } /* - * Given a context, update the window. Out of paranoia, we don't - * allow WM_PAINT responses to do scrolling optimisations. + * Given a context, update the window. */ -static void do_paint(Terminal *term, Context ctx, int may_optimise) +static void do_paint(Terminal *term, Context ctx) { int i, j, our_curs_y, our_curs_x; int rv, cursor; pos scrpos; wchar_t *ch; int chlen; -#ifdef OPTIMISE_SCROLL - struct scrollregion *sr; -#endif /* OPTIMISE_SCROLL */ termchar *newline; chlen = 1024; @@ -5201,18 +5110,6 @@ static void do_paint(Terminal *term, Context ctx, int may_optimise) } term->dispcursx = term->dispcursy = -1; -#ifdef OPTIMISE_SCROLL - /* Do scrolls */ - sr = term->scrollhead; - while (sr) { - struct scrollregion *next = sr->next; - do_scroll(ctx, sr->topline, sr->botline, sr->lines); - sfree(sr); - sr = next; - } - term->scrollhead = term->scrolltail = NULL; -#endif /* OPTIMISE_SCROLL */ - /* The normal screen data */ for (i = 0; i < term->rows; i++) { termline *ldata; @@ -5574,7 +5471,7 @@ void term_paint(Terminal *term, Context ctx, } if (immediately) { - do_paint (term, ctx, FALSE); + do_paint (term, ctx); } else { term_schedule_update(term); } @@ -5590,10 +5487,6 @@ void term_paint(Terminal *term, Context ctx, void term_scroll(Terminal *term, int rel, int where) { int sbtop = -sblines(term); -#ifdef OPTIMISE_SCROLL - int olddisptop = term->disptop; - int shift; -#endif /* OPTIMISE_SCROLL */ term->disptop = (rel < 0 ? 0 : rel > 0 ? sbtop : term->disptop) + where; if (term->disptop < sbtop) @@ -5601,11 +5494,6 @@ void term_scroll(Terminal *term, int rel, int where) if (term->disptop > 0) term->disptop = 0; update_sbar(term); -#ifdef OPTIMISE_SCROLL - shift = (term->disptop - olddisptop); - if (shift < term->rows && shift > -term->rows) - scroll_display(term, 0, term->rows - 1, shift); -#endif /* OPTIMISE_SCROLL */ term_update(term); } diff --git a/terminal.h b/terminal.h index be3c589f..5129149c 100644 --- a/terminal.h +++ b/terminal.h @@ -20,15 +20,6 @@ typedef struct { int y, x; } pos; -#ifdef OPTIMISE_SCROLL -struct scrollregion { - struct scrollregion *next; - int topline; /* Top line of scroll region. */ - int botline; /* Bottom line of scroll region. */ - int lines; /* Number of lines to scroll by - +ve is forwards. */ -}; -#endif /* OPTIMISE_SCROLL */ - typedef struct termchar termchar; typedef struct termline termline; @@ -98,10 +89,6 @@ struct terminal_tag { #define TTYPE termchar #define TSIZE (sizeof(TTYPE)) -#ifdef OPTIMISE_SCROLL - struct scrollregion *scrollhead, *scrolltail; -#endif /* OPTIMISE_SCROLL */ - int default_attr, curr_attr, save_attr; truecolour curr_truecolour, save_truecolour; termchar basic_erase_char, erase_char; diff --git a/windows/window.c b/windows/window.c index d3047b25..613c1fdc 100644 --- a/windows/window.c +++ b/windows/window.c @@ -5514,27 +5514,6 @@ void frontend_request_paste(Frontend *frontend, int clipboard) hwnd, 0, &in_threadid); } -#if 0 -/* - * Move `lines' lines from position `from' to position `to' in the - * window. - */ -void optimised_move(Frontend *frontend, int to, int from, int lines) -{ - RECT r; - int min, max; - - min = (to < from ? to : from); - max = to + from - min; - - r.left = offset_width; - r.right = offset_width + term->cols * font_width; - r.top = offset_height + min * font_height; - r.bottom = offset_height + (max + lines) * font_height; - ScrollWindow(hwnd, 0, (to - from) * font_height, &r, &r); -} -#endif - /* * Print a modal (Really Bad) message box and perform a fatal exit. */ From 64f8f68a3434e883bb672f5e484e72845765da4d Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Thu, 25 Oct 2018 18:44:04 +0100 Subject: [PATCH 577/607] Remove the 'Frontend' type and replace it with a vtable. After the recent Seat and LogContext revamps, _nearly_ all the remaining uses of the type 'Frontend' were in terminal.c, which needs all sorts of interactions with the GUI window the terminal lives in, from the obvious (actually drawing text on the window, reading and writing the clipboard) to the obscure (minimising, maximising and moving the window in response to particular escape sequences). All of those functions are now provided by an abstraction called TermWin. The few remaining uses of Frontend after _that_ are internal to a particular platform directory, so as to spread the implementation of that particular kind of Frontend between multiple source files; so I've renamed all of those so that they take a more specifically named type that refers to the particular implementation rather than the general abstraction. So now the name 'Frontend' no longer exists in the code base at all, and everywhere one used to be used, it's completely clear whether it was operating in one of Frontend's three abstract roles (and if so, which), or whether it was specific to a particular implementation. Another type that's disappeared is 'Context', which used to be a typedef defined to something different on each platform, describing whatever short-lived resources were necessary to draw on the terminal window: the front end would provide a ready-made one when calling term_paint, and the terminal could request one with get_ctx/free_ctx if it wanted to do proactive window updates. Now that drawing context lives inside the TermWin itself, because there was never any need to have two of those contexts live at the same time. (Another minor API change is that the window-title functions - both reading and writing - have had a missing 'const' added to their char * parameters / return values.) I don't expect this change to enable any particularly interesting new functionality (in particular, I have no plans that need more than one implementation of TermWin in the same application). But it completes the tidying-up that began with the Seat and LogContext rework. --- defs.h | 3 +- fuzzterm.c | 105 +++++--- putty.h | 165 +++++++++--- terminal.c | 165 ++++++------ terminal.h | 2 +- unix/gtkapp.c | 4 +- unix/gtkmain.c | 2 +- unix/gtkwin.c | 630 ++++++++++++++++++++++++--------------------- unix/unix.h | 8 +- windows/windlg.c | 2 +- windows/window.c | 317 +++++++++++++++-------- windows/winstuff.h | 4 +- 12 files changed, 839 insertions(+), 568 deletions(-) diff --git a/defs.h b/defs.h index bf257117..74aca8b1 100644 --- a/defs.h +++ b/defs.h @@ -57,7 +57,8 @@ typedef struct LogPolicyVtable LogPolicyVtable; typedef struct Seat Seat; typedef struct SeatVtable SeatVtable; -typedef struct Frontend Frontend; +typedef struct TermWin TermWin; +typedef struct TermWinVtable TermWinVtable; typedef struct Ssh Ssh; diff --git a/fuzzterm.c b/fuzzterm.c index 32608d9f..d6a8337f 100644 --- a/fuzzterm.c +++ b/fuzzterm.c @@ -9,6 +9,8 @@ /* For Unix in particular, but harmless if this main() is reused elsewhere */ const int buildinfo_gtk_relevant = FALSE; +static const TermWinVtable fuzz_termwin_vt; + int main(int argc, char **argv) { char blk[512]; @@ -16,6 +18,9 @@ int main(int argc, char **argv) Terminal *term; Conf *conf; struct unicode_data ucsdata; + TermWin termwin; + + termwin.vt = &fuzz_termwin_vt; conf = conf_new(); do_defaults(NULL, conf); @@ -23,7 +28,7 @@ int main(int argc, char **argv) conf_get_int(conf, CONF_utf8_override), CS_NONE, conf_get_int(conf, CONF_vtmode)); - term = term_init(conf, &ucsdata, NULL); + term = term_init(conf, &ucsdata, &termwin); term_size(term, 24, 80, 10000); term->ldisc = NULL; /* Tell american fuzzy lop that this is a good place to fork. */ @@ -39,10 +44,10 @@ int main(int argc, char **argv) } /* functions required by terminal.c */ - -void request_resize(Frontend *frontend, int x, int y) { } -void do_text(Context ctx, int x, int y, wchar_t * text, int len, - unsigned long attr, int lattr, truecolour tc) +static int fuzz_setup_draw_ctx(TermWin *tw) { return TRUE; } +static void fuzz_draw_text( + TermWin *tw, int x, int y, wchar_t *text, int len, + unsigned long attr, int lattr, truecolour tc) { int i; @@ -52,8 +57,9 @@ void do_text(Context ctx, int x, int y, wchar_t * text, int len, } printf("\n"); } -void do_cursor(Context ctx, int x, int y, wchar_t * text, int len, - unsigned long attr, int lattr, truecolour tc) +static void fuzz_draw_cursor( + TermWin *tw, int x, int y, wchar_t *text, int len, + unsigned long attr, int lattr, truecolour tc) { int i; @@ -63,38 +69,69 @@ void do_cursor(Context ctx, int x, int y, wchar_t * text, int len, } printf("\n"); } -int char_width(Context ctx, int uc) { return 1; } -void set_title(Frontend *frontend, char *t) { } -void set_icon(Frontend *frontend, char *t) { } -void set_sbar(Frontend *frontend, int a, int b, int c) { } +static int fuzz_char_width(TermWin *tw, int uc) { return 1; } +static void fuzz_free_draw_ctx(TermWin *tw) {} +static void fuzz_set_cursor_pos(TermWin *tw, int x, int y) {} +static void fuzz_set_raw_mouse_mode(TermWin *tw, int enable) {} +static void fuzz_set_scrollbar(TermWin *tw, int total, int start, int page) {} +static void fuzz_bell(TermWin *tw, int mode) {} +static void fuzz_clip_write( + TermWin *tw, int clipboard, wchar_t *text, int *attrs, + truecolour *colours, int len, int must_deselect) {} +static void fuzz_clip_request_paste(TermWin *tw, int clipboard) {} +static void fuzz_refresh(TermWin *tw) {} +static void fuzz_request_resize(TermWin *tw, int w, int h) {} +static void fuzz_set_title(TermWin *tw, const char *title) {} +static void fuzz_set_icon_title(TermWin *tw, const char *icontitle) {} +static void fuzz_set_minimised(TermWin *tw, int minimised) {} +static int fuzz_is_minimised(TermWin *tw) { return FALSE; } +static void fuzz_set_maximised(TermWin *tw, int maximised) {} +static void fuzz_move(TermWin *tw, int x, int y) {} +static void fuzz_set_zorder(TermWin *tw, int top) {} +static int fuzz_palette_get(TermWin *tw, int n, int *r, int *g, int *b) +{ return FALSE; } +static void fuzz_palette_set(TermWin *tw, int n, int r, int g, int b) {} +static void fuzz_palette_reset(TermWin *tw) {} +static void fuzz_get_pos(TermWin *tw, int *x, int *y) { *x = *y = 0; } +static void fuzz_get_pixels(TermWin *tw, int *x, int *y) { *x = *y = 0; } +static const char *fuzz_get_title(TermWin *tw, int icon) { return "moo"; } +static int fuzz_is_utf8(TermWin *tw) { return TRUE; } + +static const TermWinVtable fuzz_termwin_vt = { + fuzz_setup_draw_ctx, + fuzz_draw_text, + fuzz_draw_cursor, + fuzz_char_width, + fuzz_free_draw_ctx, + fuzz_set_cursor_pos, + fuzz_set_raw_mouse_mode, + fuzz_set_scrollbar, + fuzz_bell, + fuzz_clip_write, + fuzz_clip_request_paste, + fuzz_refresh, + fuzz_request_resize, + fuzz_set_title, + fuzz_set_icon_title, + fuzz_set_minimised, + fuzz_is_minimised, + fuzz_set_maximised, + fuzz_move, + fuzz_set_zorder, + fuzz_palette_get, + fuzz_palette_set, + fuzz_palette_reset, + fuzz_get_pos, + fuzz_get_pixels, + fuzz_get_title, + fuzz_is_utf8, +}; void ldisc_send(Ldisc *ldisc, const void *buf, int len, int interactive) {} void ldisc_echoedit_update(Ldisc *ldisc) {} -Context get_ctx(Frontend *frontend) { return NULL; } -void free_ctx(Context ctx) { } -void palette_set(Frontend *frontend, int a, int b, int c, int d) { } -void palette_reset(Frontend *frontend) { } -int palette_get(Frontend *frontend, int n, int *r, int *g, int *b) {return FALSE;} -void write_clip(Frontend *frontend, int clipboard, - wchar_t *a, int *b, truecolour *c, int d, int e) { } -void set_raw_mouse_mode(Frontend *frontend, int m) { } -void frontend_request_paste(Frontend *frontend, int clipboard) { } -void do_beep(Frontend *frontend, int a) { } -void sys_cursor(Frontend *frontend, int x, int y) { } void modalfatalbox(const char *fmt, ...) { exit(0); } void nonfatal(const char *fmt, ...) { } -void set_iconic(Frontend *frontend, int iconic) { } -void move_window(Frontend *frontend, int x, int y) { } -void set_zorder(Frontend *frontend, int top) { } -void refresh_window(Frontend *frontend) { } -void set_zoomed(Frontend *frontend, int zoomed) { } -int is_iconic(Frontend *frontend) { return 0; } -void get_window_pos(Frontend *frontend, int *x, int *y) { *x = 0; *y = 0; } -void get_window_pixels(Frontend *frontend, int *x, int *y) { *x = 0; *y = 0; } -char *get_window_title(Frontend *frontend, int icon) { return "moo"; } -int frontend_is_utf8(Frontend *frontend) { return TRUE; } - /* needed by timing.c */ void timer_change_notify(unsigned long next) { } @@ -173,5 +210,3 @@ char *x_get_default(const char *key) { return NULL; /* this is a stub */ } - - diff --git a/putty.h b/putty.h index da6a175e..010935a7 100644 --- a/putty.h +++ b/putty.h @@ -1012,46 +1012,139 @@ int console_confirm_weak_cached_hostkey( int filexfer_get_userpass_input(Seat *seat, prompts_t *p, bufchain *input); /* - * Exports from the front end. + * Data type 'TermWin', which is a vtable encapsulating all the + * functionality that Terminal expects from its containing terminal + * window. + */ +struct TermWin { + const struct TermWinVtable *vt; +}; +struct TermWinVtable { + /* + * All functions listed here between setup_draw_ctx and + * free_draw_ctx expect to be _called_ between them too, so that + * the TermWin has a drawing context currently available. + * + * (Yes, even char_width, because e.g. the Windows implementation + * of TermWin handles it by loading the currently configured font + * into the HDC and doing a GDI query.) + */ + int (*setup_draw_ctx)(TermWin *); + /* Draw text in the window, during a painting operation */ + void (*draw_text)(TermWin *, int x, int y, wchar_t *text, int len, + unsigned long attrs, int line_attrs, truecolour tc); + /* Draw the visible cursor. Expects you to have called do_text + * first (because it might just draw an underline over a character + * presumed to exist already), but also expects you to pass in all + * the details of the character under the cursor (because it might + * redraw it in different colours). */ + void (*draw_cursor)(TermWin *, int x, int y, wchar_t *text, int len, + unsigned long attrs, int line_attrs, truecolour tc); + int (*char_width)(TermWin *, int uc); + void (*free_draw_ctx)(TermWin *); + + void (*set_cursor_pos)(TermWin *, int x, int y); + + void (*set_raw_mouse_mode)(TermWin *, int enable); + + void (*set_scrollbar)(TermWin *, int total, int start, int page); + + void (*bell)(TermWin *, int mode); + + void (*clip_write)(TermWin *, int clipboard, wchar_t *text, int *attrs, + truecolour *colours, int len, int must_deselect); + void (*clip_request_paste)(TermWin *, int clipboard); + + void (*refresh)(TermWin *); + + void (*request_resize)(TermWin *, int w, int h); + + void (*set_title)(TermWin *, const char *title); + void (*set_icon_title)(TermWin *, const char *icontitle); + /* set_minimised and set_maximised are assumed to set two + * independent settings, rather than a single three-way + * {min,normal,max} switch. The idea is that when you un-minimise + * the window it remembers whether to go back to normal or + * maximised. */ + void (*set_minimised)(TermWin *, int minimised); + int (*is_minimised)(TermWin *); + void (*set_maximised)(TermWin *, int maximised); + void (*move)(TermWin *, int x, int y); + void (*set_zorder)(TermWin *, int top); + + int (*palette_get)(TermWin *, int n, int *r, int *g, int *b); + void (*palette_set)(TermWin *, int n, int r, int g, int b); + void (*palette_reset)(TermWin *); + + void (*get_pos)(TermWin *, int *x, int *y); + void (*get_pixels)(TermWin *, int *x, int *y); + const char *(*get_title)(TermWin *, int icon); + int (*is_utf8)(TermWin *); +}; + +#define win_setup_draw_ctx(win) \ + ((win)->vt->setup_draw_ctx(win)) +#define win_draw_text(win, x, y, text, len, attrs, lattrs, tc) \ + ((win)->vt->draw_text(win, x, y, text, len, attrs, lattrs, tc)) +#define win_draw_cursor(win, x, y, text, len, attrs, lattrs, tc) \ + ((win)->vt->draw_cursor(win, x, y, text, len, attrs, lattrs, tc)) +#define win_char_width(win, uc) \ + ((win)->vt->char_width(win, uc)) +#define win_free_draw_ctx(win) \ + ((win)->vt->free_draw_ctx(win)) +#define win_set_cursor_pos(win, x, y) \ + ((win)->vt->set_cursor_pos(win, x, y)) +#define win_set_raw_mouse_mode(win, enable) \ + ((win)->vt->set_raw_mouse_mode(win, enable)) +#define win_set_scrollbar(win, total, start, page) \ + ((win)->vt->set_scrollbar(win, total, start, page)) +#define win_bell(win, mode) \ + ((win)->vt->bell(win, mode)) +#define win_clip_write(win, clipboard, text, attrs, colours, len, desel) \ + ((win)->vt->clip_write(win, clipboard, text, attrs, colours, len, desel)) +#define win_clip_request_paste(win, clipboard) \ + ((win)->vt->clip_request_paste(win, clipboard)) +#define win_refresh(win) \ + ((win)->vt->refresh(win)) +#define win_request_resize(win, w, h) \ + ((win)->vt->request_resize(win, w, h)) +#define win_set_title(win, title) \ + ((win)->vt->set_title(win, title)) +#define win_set_icon_title(win, ititle) \ + ((win)->vt->set_icon_title(win, ititle)) +#define win_set_minimised(win, minimised) \ + ((win)->vt->set_minimised(win, minimised)) +#define win_is_minimised(win) \ + ((win)->vt->is_minimised(win)) +#define win_set_maximised(win, maximised) \ + ((win)->vt->set_maximised(win, maximised)) +#define win_move(win, x, y) \ + ((win)->vt->move(win, x, y)) +#define win_set_zorder(win, top) \ + ((win)->vt->set_zorder(win, top)) +#define win_palette_get(win, n, r, g, b) \ + ((win)->vt->palette_get(win, n, r, g, b)) +#define win_palette_set(win, n, r, g, b) \ + ((win)->vt->palette_set(win, n, r, g, b)) +#define win_palette_reset(win) \ + ((win)->vt->palette_reset(win)) +#define win_get_pos(win, x, y) \ + ((win)->vt->get_pos(win, x, y)) +#define win_get_pixels(win, x, y) \ + ((win)->vt->get_pixels(win, x, y)) +#define win_get_title(win, icon) \ + ((win)->vt->get_title(win, icon)) +#define win_is_utf8(win) \ + ((win)->vt->is_utf8(win)) + +/* + * Global functions not specific to a connection instance. */ -void request_resize(Frontend *frontend, int, int); -void do_text(Context, int, int, wchar_t *, int, unsigned long, int, - truecolour); -void do_cursor(Context, int, int, wchar_t *, int, unsigned long, int, - truecolour); -int char_width(Context ctx, int uc); -void set_title(Frontend *frontend, char *); -void set_icon(Frontend *frontend, char *); -void set_sbar(Frontend *frontend, int, int, int); -Context get_ctx(Frontend *frontend); -void free_ctx(Context); -void palette_set(Frontend *frontend, int, int, int, int); -void palette_reset(Frontend *frontend); -int palette_get(Frontend *frontend, int n, int *r, int *g, int *b); -void write_clip(Frontend *frontend, int clipboard, wchar_t *, int *, - truecolour *, int, int); -void optimised_move(Frontend *frontend, int, int, int); -void set_raw_mouse_mode(Frontend *frontend, int); void nonfatal(const char *, ...); void modalfatalbox(const char *, ...); #ifdef macintosh #pragma noreturn(modalfatalbox) #endif -void do_beep(Frontend *frontend, int); -void sys_cursor(Frontend *frontend, int x, int y); -void frontend_request_paste(Frontend *frontend, int clipboard); - -void set_iconic(Frontend *frontend, int iconic); -void move_window(Frontend *frontend, int x, int y); -void set_zorder(Frontend *frontend, int top); -void refresh_window(Frontend *frontend); -void set_zoomed(Frontend *frontend, int zoomed); -int is_iconic(Frontend *frontend); -void get_window_pos(Frontend *frontend, int *x, int *y); -void get_window_pixels(Frontend *frontend, int *x, int *y); -char *get_window_title(Frontend *frontend, int icon); -int frontend_is_utf8(Frontend *frontend); - void cleanup_exit(int); /* @@ -1407,10 +1500,10 @@ FontSpec *platform_default_fontspec(const char *name); * Exports from terminal.c. */ -Terminal *term_init(Conf *, struct unicode_data *, Frontend *); +Terminal *term_init(Conf *, struct unicode_data *, TermWin *); void term_free(Terminal *); void term_size(Terminal *, int, int, int); -void term_paint(Terminal *, Context, int, int, int, int, int); +void term_paint(Terminal *, int, int, int, int, int); void term_scroll(Terminal *, int, int); void term_scroll_to_selection(Terminal *, int); void term_pwron(Terminal *, int); diff --git a/terminal.c b/terminal.c index 01fd8da0..6708c61a 100644 --- a/terminal.c +++ b/terminal.c @@ -101,7 +101,7 @@ static void resizeline(Terminal *, termline *, int); static termline *lineptr(Terminal *, int, int, int); static void unlineptr(termline *); static void check_line_size(Terminal *, termline *); -static void do_paint(Terminal *, Context); +static void do_paint(Terminal *); static void erase_lots(Terminal *, int, int, int); static int find_last_nonempty_line(Terminal *, tree234 *); static void swap_screen(Terminal *, int, int, int); @@ -1317,7 +1317,7 @@ static void power_on(Terminal *term, int clear) term->xterm_mouse = 0; term->xterm_extended_mouse = 0; term->urxvt_extended_mouse = 0; - set_raw_mouse_mode(term->frontend, FALSE); + win_set_raw_mouse_mode(term->win, FALSE); term->bracketed_paste = FALSE; { int i; @@ -1348,12 +1348,9 @@ static void power_on(Terminal *term, int clear) */ void term_update(Terminal *term) { - Context ctx; - term->window_update_pending = FALSE; - ctx = get_ctx(term->frontend); - if (ctx) { + if (win_setup_draw_ctx(term->win)) { int need_sbar_update = term->seen_disp_event; if (term->seen_disp_event && term->scroll_on_disp) { term->disptop = 0; /* return to main screen */ @@ -1363,9 +1360,10 @@ void term_update(Terminal *term) if (need_sbar_update) update_sbar(term); - do_paint(term, ctx); - sys_cursor(term->frontend, term->curs.x, term->curs.y - term->disptop); - free_ctx(ctx); + do_paint(term); + win_set_cursor_pos( + term->win, term->curs.x, term->curs.y - term->disptop); + win_free_draw_ctx(term->win); } } @@ -1568,7 +1566,7 @@ void term_reconfig(Terminal *term, Conf *conf) swap_screen(term, 0, FALSE, FALSE); if (conf_get_int(term->conf, CONF_no_mouse_rep)) { term->xterm_mouse = 0; - set_raw_mouse_mode(term->frontend, 0); + win_set_raw_mouse_mode(term->win, 0); } if (conf_get_int(term->conf, CONF_no_remote_charset)) { term->cset_attr[0] = term->cset_attr[1] = CSET_ASCII; @@ -1635,8 +1633,7 @@ const optionalrgb optionalrgb_none = {0, 0, 0, 0}; /* * Initialise the terminal. */ -Terminal *term_init(Conf *myconf, struct unicode_data *ucsdata, - Frontend *frontend) +Terminal *term_init(Conf *myconf, struct unicode_data *ucsdata, TermWin *win) { Terminal *term; @@ -1645,7 +1642,7 @@ Terminal *term_init(Conf *myconf, struct unicode_data *ucsdata, * that need it. */ term = snew(Terminal); - term->frontend = frontend; + term->win = win; term->ucsdata = ucsdata; term->conf = conf_copy(myconf); term->logctx = NULL; @@ -1712,8 +1709,8 @@ Terminal *term_init(Conf *myconf, struct unicode_data *ucsdata, term->last_selected_attr = NULL; term->last_selected_tc = NULL; term->last_selected_len = 0; - /* frontends will typically extend these with clipboard ids they - * know about */ + /* TermWin implementations will typically extend these with + * clipboard ids they know about */ term->mouse_select_clipboards[0] = CLIP_LOCAL; term->n_mouse_select_clipboards = 1; term->mouse_paste_clipboard = CLIP_NULL; @@ -2097,8 +2094,8 @@ static void swap_screen(Terminal *term, int which, int reset, int keep_cur_pos) static void update_sbar(Terminal *term) { int nscroll = sblines(term); - set_sbar(term->frontend, nscroll + term->rows, - nscroll + term->disptop, term->rows); + win_set_scrollbar(term->win, nscroll + term->rows, + nscroll + term->disptop, term->rows); } /* @@ -2533,7 +2530,7 @@ static void toggle_mode(Terminal *term, int mode, int query, int state) case 3: /* DECCOLM: 80/132 columns */ deselect(term); if (!term->no_remote_resize) - request_resize(term->frontend, state ? 132 : 80, term->rows); + win_request_resize(term->win, state ? 132 : 80, term->rows); term->reset_132 = state; term->alt_t = term->marg_t = 0; term->alt_b = term->marg_b = term->rows - 1; @@ -2585,11 +2582,11 @@ static void toggle_mode(Terminal *term, int mode, int query, int state) break; case 1000: /* xterm mouse 1 (normal) */ term->xterm_mouse = state ? 1 : 0; - set_raw_mouse_mode(term->frontend, state); + win_set_raw_mouse_mode(term->win, state); break; case 1002: /* xterm mouse 2 (inc. button drags) */ term->xterm_mouse = state ? 2 : 0; - set_raw_mouse_mode(term->frontend, state); + win_set_raw_mouse_mode(term->win, state); break; case 1006: /* xterm extended mouse */ term->xterm_extended_mouse = state ? 1 : 0; @@ -2659,20 +2656,20 @@ static void do_osc(Terminal *term) case 0: case 1: if (!term->no_remote_wintitle) - set_icon(term->frontend, term->osc_string); + win_set_icon_title(term->win, term->osc_string); if (term->esc_args[0] == 1) break; /* fall through: parameter 0 means set both */ case 2: case 21: if (!term->no_remote_wintitle) - set_title(term->frontend, term->osc_string); + win_set_title(term->win, term->osc_string); break; case 4: if (term->ldisc && !strcmp(term->osc_string, "?")) { int r, g, b; - if (palette_get(term->frontend, toint(term->esc_args[1]), - &r, &g, &b)) { + if (win_palette_get(term->win, toint(term->esc_args[1]), + &r, &g, &b)) { char *reply_buf = dupprintf( "\033]4;%u;rgb:%04x/%04x/%04x\007", term->esc_args[1], @@ -3182,7 +3179,7 @@ static void term_out(Terminal *term) * Perform an actual beep if we're not overloaded. */ if (!term->bellovl || !term->beep_overloaded) { - do_beep(term->frontend, term->beep); + win_bell(term->win, term->beep); if (term->beep == BELL_VISUAL) { term_schedule_vbell(term, FALSE, 0); @@ -3383,7 +3380,7 @@ static void term_out(Terminal *term) ldisc_echoedit_update(term->ldisc); if (term->reset_132) { if (!term->no_remote_resize) - request_resize(term->frontend, 80, term->rows); + win_request_resize(term->win, 80, term->rows); term->reset_132 = 0; } if (term->scroll_on_disp) @@ -4027,8 +4024,8 @@ static void term_out(Terminal *term) term->esc_args[0] >= 24)) { compatibility(VT340TEXT); if (!term->no_remote_resize) - request_resize(term->frontend, term->cols, - def(term->esc_args[0], 24)); + win_request_resize(term->win, term->cols, + def(term->esc_args[0], 24)); deselect(term); } else if (term->esc_nargs >= 1 && term->esc_args[0] >= 1 && @@ -4040,17 +4037,17 @@ static void term_out(Terminal *term) char buf[80]; const char *p; case 1: - set_iconic(term->frontend, FALSE); + win_set_minimised(term->win, FALSE); break; case 2: - set_iconic(term->frontend, TRUE); + win_set_minimised(term->win, TRUE); break; case 3: if (term->esc_nargs >= 3) { if (!term->no_remote_resize) - move_window(term->frontend, - def(term->esc_args[1], 0), - def(term->esc_args[2], 0)); + win_move(term->win, + def(term->esc_args[1], 0), + def(term->esc_args[2], 0)); } break; case 4: @@ -4061,38 +4058,41 @@ static void term_out(Terminal *term) break; case 5: /* move to top */ - set_zorder(term->frontend, TRUE); + win_set_zorder(term->win, TRUE); break; case 6: /* move to bottom */ - set_zorder(term->frontend, FALSE); + win_set_zorder(term->win, FALSE); break; case 7: - refresh_window(term->frontend); + win_refresh(term->win); break; case 8: if (term->esc_nargs >= 3) { if (!term->no_remote_resize) - request_resize(term->frontend, - def(term->esc_args[2], term->conf_width), - def(term->esc_args[1], term->conf_height)); + win_request_resize( + term->win, + def(term->esc_args[2], + term->conf_width), + def(term->esc_args[1], + term->conf_height)); } break; case 9: if (term->esc_nargs >= 2) - set_zoomed(term->frontend, - term->esc_args[1] ? - TRUE : FALSE); + win_set_maximised( + term->win, + term->esc_args[1] ? TRUE : FALSE); break; case 11: if (term->ldisc) ldisc_send(term->ldisc, - is_iconic(term->frontend) ? + win_is_minimised(term->win) ? "\033[2t" : "\033[1t", 4, 0); break; case 13: if (term->ldisc) { - get_window_pos(term->frontend, &x, &y); + win_get_pos(term->win, &x, &y); len = sprintf(buf, "\033[3;%u;%ut", (unsigned)x, (unsigned)y); @@ -4101,7 +4101,7 @@ static void term_out(Terminal *term) break; case 14: if (term->ldisc) { - get_window_pixels(term->frontend, &x, &y); + win_get_pixels(term->win, &x, &y); len = sprintf(buf, "\033[4;%d;%dt", y, x); ldisc_send(term->ldisc, buf, len, 0); } @@ -4134,7 +4134,7 @@ static void term_out(Terminal *term) if (term->ldisc && term->remote_qtitle_action != TITLE_NONE) { if(term->remote_qtitle_action == TITLE_REAL) - p = get_window_title(term->frontend, TRUE); + p = win_get_title(term->win, TRUE); else p = EMPTY_WINDOW_TITLE; len = strlen(p); @@ -4148,7 +4148,7 @@ static void term_out(Terminal *term) if (term->ldisc && term->remote_qtitle_action != TITLE_NONE) { if(term->remote_qtitle_action == TITLE_REAL) - p = get_window_title(term->frontend, FALSE); + p = win_get_title(term->win, FALSE); else p = EMPTY_WINDOW_TITLE; len = strlen(p); @@ -4187,9 +4187,9 @@ static void term_out(Terminal *term) compatibility(VT420); if (term->esc_nargs == 1 && term->esc_args[0] > 0) { if (!term->no_remote_resize) - request_resize(term->frontend, term->cols, - def(term->esc_args[0], - term->conf_height)); + win_request_resize(term->win, term->cols, + def(term->esc_args[0], + term->conf_height)); deselect(term); } break; @@ -4202,10 +4202,10 @@ static void term_out(Terminal *term) compatibility(VT340TEXT); if (term->esc_nargs <= 1) { if (!term->no_remote_resize) - request_resize(term->frontend, - def(term->esc_args[0], - term->conf_width), - term->rows); + win_request_resize( + term->win, + def(term->esc_args[0], term->conf_width), + term->rows); deselect(term); } break; @@ -4413,9 +4413,9 @@ static void term_out(Terminal *term) if (!has_compat(VT420) && has_compat(VT100)) { if (!term->no_remote_resize) { if (term->reset_132) - request_resize(132, 24); + win_request_resize(term->win, 132, 24); else - request_resize(80, 24); + win_request_resize(term->win, 80, 24); } } #endif @@ -4430,7 +4430,7 @@ static void term_out(Terminal *term) term->osc_strlen = 0; break; case 'R': /* Linux palette reset */ - palette_reset(term->frontend); + win_palette_reset(term->win); term_invalidate(term); term->termstate = TOPLEVEL; break; @@ -4528,10 +4528,11 @@ static void term_out(Terminal *term) } term->osc_string[term->osc_strlen++] = val; if (term->osc_strlen >= 7) { - palette_set(term->frontend, term->osc_string[0], - term->osc_string[1] * 16 + term->osc_string[2], - term->osc_string[3] * 16 + term->osc_string[4], - term->osc_string[5] * 16 + term->osc_string[6]); + win_palette_set( + term->win, term->osc_string[0], + term->osc_string[1] * 16 + term->osc_string[2], + term->osc_string[3] * 16 + term->osc_string[4], + term->osc_string[5] * 16 + term->osc_string[6]); term_invalidate(term); term->termstate = TOPLEVEL; } @@ -5024,7 +5025,7 @@ static termchar *term_bidi_line(Terminal *term, struct termline *ldata, /* * Given a context, update the window. */ -static void do_paint(Terminal *term, Context ctx) +static void do_paint(Terminal *term) { int i, j, our_curs_y, our_curs_x; int rv, cursor; @@ -5209,7 +5210,8 @@ static void do_paint(Terminal *term, Context ctx) if (tchar != term->disptext[i]->chars[j].chr || tattr != (term->disptext[i]->chars[j].attr &~ (ATTR_NARROW | DATTR_MASK))) { - if ((tattr & ATTR_WIDE) == 0 && char_width(ctx, tchar) == 2) + if ((tattr & ATTR_WIDE) == 0 && + win_char_width(term->win, tchar) == 2) tattr |= ATTR_NARROW; } else if (term->disptext[i]->chars[j].attr & ATTR_NARROW) tattr |= ATTR_NARROW; @@ -5324,10 +5326,11 @@ static void do_paint(Terminal *term, Context ctx) if (break_run) { if ((dirty_run || last_run_dirty) && ccount > 0) { - do_text(ctx, start, i, ch, ccount, attr, ldata->lattr, tc); + win_draw_text(term->win, start, i, ch, ccount, + attr, ldata->lattr, tc); if (attr & (TATTR_ACTCURS | TATTR_PASCURS)) - do_cursor(ctx, start, i, ch, ccount, attr, - ldata->lattr, tc); + win_draw_cursor(term->win, start, i, ch, ccount, attr, + ldata->lattr, tc); } start = j; ccount = 0; @@ -5423,9 +5426,11 @@ static void do_paint(Terminal *term, Context ctx) } } if (dirty_run && ccount > 0) { - do_text(ctx, start, i, ch, ccount, attr, ldata->lattr, tc); + win_draw_text(term->win, start, i, ch, ccount, + attr, ldata->lattr, tc); if (attr & (TATTR_ACTCURS | TATTR_PASCURS)) - do_cursor(ctx, start, i, ch, ccount, attr, ldata->lattr, tc); + win_draw_cursor(term->win, start, i, ch, ccount, + attr, ldata->lattr, tc); } unlineptr(ldata); @@ -5452,7 +5457,7 @@ void term_invalidate(Terminal *term) /* * Paint the window in response to a WM_PAINT message. */ -void term_paint(Terminal *term, Context ctx, +void term_paint(Terminal *term, int left, int top, int right, int bottom, int immediately) { int i, j; @@ -5471,7 +5476,7 @@ void term_paint(Terminal *term, Context ctx, } if (immediately) { - do_paint (term, ctx); + do_paint(term); } else { term_schedule_update(term); } @@ -5722,9 +5727,9 @@ static void clipme(Terminal *term, pos top, pos bottom, int rect, int desel, if (clipboards[i] == CLIP_LOCAL) { clip_local = TRUE; } else if (clipboards[i] != CLIP_NULL) { - write_clip(term->frontend, clipboards[i], - buf.textbuf, buf.attrbuf, buf.tcbuf, buf.bufpos, - desel); + win_clip_write( + term->win, clipboards[i], buf.textbuf, buf.attrbuf, + buf.tcbuf, buf.bufpos, desel); } } if (clip_local) { @@ -5767,12 +5772,10 @@ void term_request_copy(Terminal *term, const int *clipboards, int n_clipboards) for (i = 0; i < n_clipboards; i++) { assert(clipboards[i] != CLIP_LOCAL); if (clipboards[i] != CLIP_NULL) { - write_clip(term->frontend, clipboards[i], - term->last_selected_text, - term->last_selected_attr, - term->last_selected_tc, - term->last_selected_len, - FALSE); + win_clip_write(term->win, clipboards[i], + term->last_selected_text, term->last_selected_attr, + term->last_selected_tc, term->last_selected_len, + FALSE); } } } @@ -5787,7 +5790,7 @@ void term_request_paste(Terminal *term, int clipboard) queue_toplevel_callback(paste_from_clip_local, term); break; default: - frontend_request_paste(term->frontend, clipboard); + win_clip_request_paste(term->win, clipboard); break; } } @@ -6582,7 +6585,7 @@ char *term_get_ttymode(Terminal *term, const char *mode) if (strcmp(mode, "ERASE") == 0) { val = term->bksp_is_delete ? "^?" : "^H"; } else if (strcmp(mode, "IUTF8") == 0) { - val = frontend_is_utf8(term->frontend) ? "yes" : "no"; + val = win_is_utf8(term->win) ? "yes" : "no"; } /* FIXME: perhaps we should set ONLCR based on lfhascr as well? */ /* FIXME: or ECHO and friends based on local echo state? */ diff --git a/terminal.h b/terminal.h index 5129149c..b63d42e9 100644 --- a/terminal.h +++ b/terminal.h @@ -218,7 +218,7 @@ struct terminal_tag { Ldisc *ldisc; - Frontend *frontend; + TermWin *win; LogContext *logctx; diff --git a/unix/gtkapp.c b/unix/gtkapp.c index f79e5e9a..2629e684 100644 --- a/unix/gtkapp.c +++ b/unix/gtkapp.c @@ -99,7 +99,7 @@ int main(int argc, char **argv) fprintf(stderr, "GtkApplication frontend doesn't work pre-GTK3\n"); return 1; } -GtkWidget *make_gtk_toplevel_window(Frontend *frontend) { return NULL; } +GtkWidget *make_gtk_toplevel_window(GtkFrontend *frontend) { return NULL; } void launch_duplicate_session(Conf *conf) {} void launch_new_session(void) {} void launch_saved_session(const char *str) {} @@ -204,7 +204,7 @@ WIN_ACTION_LIST(WIN_ACTION_ENTRY) }; static GtkApplication *app; -GtkWidget *make_gtk_toplevel_window(Frontend *frontend) +GtkWidget *make_gtk_toplevel_window(GtkFrontend *frontend) { GtkWidget *win = gtk_application_window_new(app); g_action_map_add_action_entries(G_ACTION_MAP(win), diff --git a/unix/gtkmain.c b/unix/gtkmain.c index a97f7415..8829dbfa 100644 --- a/unix/gtkmain.c +++ b/unix/gtkmain.c @@ -549,7 +549,7 @@ int do_cmdline(int argc, char **argv, int do_everything, Conf *conf) return err; } -GtkWidget *make_gtk_toplevel_window(Frontend *frontend) +GtkWidget *make_gtk_toplevel_window(GtkFrontend *frontend) { return gtk_window_new(GTK_WINDOW_TOPLEVEL); } diff --git a/unix/gtkwin.c b/unix/gtkwin.c index c364afe2..0868d2fd 100644 --- a/unix/gtkwin.c +++ b/unix/gtkwin.c @@ -76,7 +76,7 @@ struct clipboard_data_instance { #endif struct clipboard_state { - Frontend *inst; + GtkFrontend *inst; int clipboard; GdkAtom atom; #ifdef JUST_USE_GTK_CLIPBOARD_UTF8 @@ -88,7 +88,7 @@ struct clipboard_state { #endif }; -struct Frontend { +struct GtkFrontend { GtkWidget *window, *area, *sbar; gboolean sbar_visible; gboolean drawing_area_got_size, drawing_area_realised; @@ -143,7 +143,7 @@ struct Frontend { struct clipboard_state clipstates[N_CLIPBOARDS]; #ifdef JUST_USE_GTK_CLIPBOARD_UTF8 /* Remember all clipboard_data_instance structures currently - * associated with this gui_data, in case they're still around + * associated with this GtkFrontend, in case they're still around * when it gets destroyed */ struct clipboard_data_instance cdi_headtail; #endif @@ -180,12 +180,14 @@ struct Frontend { #ifdef OSX_META_KEY_CONFIG int system_mod_mask; #endif + unifont_drawctx uctx; Seat seat; + TermWin termwin; LogPolicy logpolicy; }; -static void cache_conf_values(Frontend *inst) +static void cache_conf_values(GtkFrontend *inst) { inst->bold_style = conf_get_int(inst->conf, CONF_bold_style); inst->window_border = conf_get_int(inst->conf, CONF_window_border); @@ -202,33 +204,28 @@ static void cache_conf_values(Frontend *inst) #endif } -struct draw_ctx { - Frontend *inst; - unifont_drawctx uctx; -}; - static int send_raw_mouse; -static void start_backend(Frontend *inst); +static void start_backend(GtkFrontend *inst); static void exit_callback(void *vinst); -static void destroy_inst_connection(Frontend *inst); -static void delete_inst(Frontend *inst); +static void destroy_inst_connection(GtkFrontend *inst); +static void delete_inst(GtkFrontend *inst); static void post_fatal_message_box_toplevel(void *vctx) { - Frontend *inst = (Frontend *)vctx; + GtkFrontend *inst = (GtkFrontend *)vctx; gtk_widget_destroy(inst->window); } static void post_fatal_message_box(void *vctx, int result) { - Frontend *inst = (Frontend *)vctx; + GtkFrontend *inst = (GtkFrontend *)vctx; unregister_dialog(&inst->seat, DIALOG_SLOT_CONNECTION_FATAL); queue_toplevel_callback(post_fatal_message_box_toplevel, inst); } static void common_connfatal_message_box( - Frontend *inst, const char *msg, post_dialog_fn_t postfn) + GtkFrontend *inst, const char *msg, post_dialog_fn_t postfn) { char *title = dupcat(appname, " Fatal Error", NULL); GtkWidget *dialog = create_message_box( @@ -239,26 +236,26 @@ static void common_connfatal_message_box( sfree(title); } -void fatal_message_box(Frontend *inst, const char *msg) +void fatal_message_box(GtkFrontend *inst, const char *msg) { common_connfatal_message_box(inst, msg, post_fatal_message_box); } static void connection_fatal_callback(void *vctx) { - Frontend *inst = (Frontend *)vctx; + GtkFrontend *inst = (GtkFrontend *)vctx; destroy_inst_connection(inst); } static void post_nonfatal_message_box(void *vctx, int result) { - Frontend *inst = (Frontend *)vctx; + GtkFrontend *inst = (GtkFrontend *)vctx; unregister_dialog(&inst->seat, DIALOG_SLOT_CONNECTION_FATAL); } static void gtk_seat_connection_fatal(Seat *seat, const char *msg) { - Frontend *inst = container_of(seat, Frontend, seat); + GtkFrontend *inst = container_of(seat, GtkFrontend, seat); if (conf_get_int(inst->conf, CONF_close_on_exit) == FORCE_ON) { fatal_message_box(inst, msg); } else { @@ -306,27 +303,27 @@ int platform_default_i(const char *name, int def) static char *gtk_seat_get_ttymode(Seat *seat, const char *mode) { - Frontend *inst = container_of(seat, Frontend, seat); + GtkFrontend *inst = container_of(seat, GtkFrontend, seat); return term_get_ttymode(inst->term, mode); } static int gtk_seat_output(Seat *seat, int is_stderr, const void *data, int len) { - Frontend *inst = container_of(seat, Frontend, seat); + GtkFrontend *inst = container_of(seat, GtkFrontend, seat); return term_data(inst->term, is_stderr, data, len); } static int gtk_seat_eof(Seat *seat) { - /* Frontend *inst = container_of(seat, Frontend, seat); */ + /* GtkFrontend *inst = container_of(seat, GtkFrontend, seat); */ return TRUE; /* do respond to incoming EOF with outgoing */ } static int gtk_seat_get_userpass_input(Seat *seat, prompts_t *p, bufchain *input) { - Frontend *inst = container_of(seat, Frontend, seat); + GtkFrontend *inst = container_of(seat, GtkFrontend, seat); int ret; ret = cmdline_get_passwd_input(p); if (ret == -1) @@ -336,14 +333,14 @@ static int gtk_seat_get_userpass_input(Seat *seat, prompts_t *p, static int gtk_seat_is_utf8(Seat *seat) { - Frontend *inst = container_of(seat, Frontend, seat); - return frontend_is_utf8(inst); + GtkFrontend *inst = container_of(seat, GtkFrontend, seat); + return win_is_utf8(&inst->termwin); } static int gtk_seat_get_window_pixel_size(Seat *seat, int *w, int *h) { - Frontend *inst = container_of(seat, Frontend, seat); - get_window_pixels(inst, w, h); + GtkFrontend *inst = container_of(seat, GtkFrontend, seat); + win_get_pixels(&inst->termwin, w, h); return TRUE; } @@ -380,20 +377,20 @@ static const SeatVtable gtk_seat_vt = { static void gtk_eventlog(LogPolicy *lp, const char *string) { - Frontend *inst = container_of(lp, Frontend, logpolicy); + GtkFrontend *inst = container_of(lp, GtkFrontend, logpolicy); logevent_dlg(inst->eventlogstuff, string); } static int gtk_askappend(LogPolicy *lp, Filename *filename, void (*callback)(void *ctx, int result), void *ctx) { - Frontend *inst = container_of(lp, Frontend, logpolicy); + GtkFrontend *inst = container_of(lp, GtkFrontend, logpolicy); return gtkdlg_askappend(&inst->seat, filename, callback, ctx); } static void gtk_logging_error(LogPolicy *lp, const char *event) { - Frontend *inst = container_of(lp, Frontend, logpolicy); + GtkFrontend *inst = container_of(lp, GtkFrontend, logpolicy); /* Send 'can't open log file' errors to the terminal window. * (Marked as stderr, although terminal.c won't care.) */ @@ -433,7 +430,7 @@ static Mouse_Button translate_button(Mouse_Button button) */ GtkWidget *gtk_seat_get_window(Seat *seat) { - Frontend *inst = container_of(seat, Frontend, seat); + GtkFrontend *inst = container_of(seat, GtkFrontend, seat); return inst->window; } @@ -444,18 +441,18 @@ GtkWidget *gtk_seat_get_window(Seat *seat) */ void register_dialog(Seat *seat, enum DialogSlot slot, GtkWidget *dialog) { - Frontend *inst; + GtkFrontend *inst; assert(seat->vt == >k_seat_vt); - inst = container_of(seat, Frontend, seat); + inst = container_of(seat, GtkFrontend, seat); assert(slot < DIALOG_SLOT_LIMIT); assert(!inst->dialogs[slot]); inst->dialogs[slot] = dialog; } void unregister_dialog(Seat *seat, enum DialogSlot slot) { - Frontend *inst; + GtkFrontend *inst; assert(seat->vt == >k_seat_vt); - inst = container_of(seat, Frontend, seat); + inst = container_of(seat, GtkFrontend, seat); assert(slot < DIALOG_SLOT_LIMIT); assert(inst->dialogs[slot]); inst->dialogs[slot] = NULL; @@ -465,13 +462,14 @@ void unregister_dialog(Seat *seat, enum DialogSlot slot) * Minimise or restore the window in response to a server-side * request. */ -void set_iconic(Frontend *inst, int iconic) +static void gtkwin_set_minimised(TermWin *tw, int minimised) { /* * GTK 1.2 doesn't know how to do this. */ #if GTK_CHECK_VERSION(2,0,0) - if (iconic) + GtkFrontend *inst = container_of(tw, GtkFrontend, termwin); + if (minimised) gtk_window_iconify(GTK_WINDOW(inst->window)); else gtk_window_deiconify(GTK_WINDOW(inst->window)); @@ -481,8 +479,9 @@ void set_iconic(Frontend *inst, int iconic) /* * Move the window in response to a server-side request. */ -void move_window(Frontend *inst, int x, int y) +static void gtkwin_move(TermWin *tw, int x, int y) { + GtkFrontend *inst = container_of(tw, GtkFrontend, termwin); /* * I assume that when the GTK version of this call is available * we should use it. Not sure how it differs from the GDK one, @@ -501,8 +500,9 @@ void move_window(Frontend *inst, int x, int y) * Move the window to the top or bottom of the z-order in response * to a server-side request. */ -void set_zorder(Frontend *inst, int top) +static void gtkwin_set_zorder(TermWin *tw, int top) { + GtkFrontend *inst = container_of(tw, GtkFrontend, termwin); if (top) gdk_window_raise(gtk_widget_get_window(inst->window)); else @@ -512,8 +512,9 @@ void set_zorder(Frontend *inst, int top) /* * Refresh the window in response to a server-side request. */ -void refresh_window(Frontend *inst) +static void gtkwin_refresh(TermWin *tw) { + GtkFrontend *inst = container_of(tw, GtkFrontend, termwin); term_invalidate(inst->term); } @@ -521,13 +522,14 @@ void refresh_window(Frontend *inst) * Maximise or restore the window in response to a server-side * request. */ -void set_zoomed(Frontend *inst, int zoomed) +static void gtkwin_set_maximised(TermWin *tw, int maximised) { /* * GTK 1.2 doesn't know how to do this. */ #if GTK_CHECK_VERSION(2,0,0) - if (zoomed) + GtkFrontend *inst = container_of(tw, GtkFrontend, termwin); + if (maximised) gtk_window_maximize(GTK_WINDOW(inst->window)); else gtk_window_unmaximize(GTK_WINDOW(inst->window)); @@ -535,18 +537,20 @@ void set_zoomed(Frontend *inst, int zoomed) } /* - * Report whether the window is iconic, for terminal reports. + * Report whether the window is minimised, for terminal reports. */ -int is_iconic(Frontend *inst) +static int gtkwin_is_minimised(TermWin *tw) { + GtkFrontend *inst = container_of(tw, GtkFrontend, termwin); return !gdk_window_is_viewable(gtk_widget_get_window(inst->window)); } /* * Report the window's position, for terminal reports. */ -void get_window_pos(Frontend *inst, int *x, int *y) +static void gtkwin_get_pos(TermWin *tw, int *x, int *y) { + GtkFrontend *inst = container_of(tw, GtkFrontend, termwin); /* * I assume that when the GTK version of this call is available * we should use it. Not sure how it differs from the GDK one, @@ -562,8 +566,9 @@ void get_window_pos(Frontend *inst, int *x, int *y) /* * Report the window's pixel size, for terminal reports. */ -void get_window_pixels(Frontend *inst, int *x, int *y) +static void gtkwin_get_pixels(TermWin *tw, int *x, int *y) { + GtkFrontend *inst = container_of(tw, GtkFrontend, termwin); /* * I assume that when the GTK version of this call is available * we should use it. Not sure how it differs from the GDK one, @@ -582,7 +587,7 @@ void get_window_pixels(Frontend *inst, int *x, int *y) * raise it, so that the user realises they've already been asked this * question. */ -static int find_and_raise_dialog(Frontend *inst, enum DialogSlot slot) +static int find_and_raise_dialog(GtkFrontend *inst, enum DialogSlot slot) { GtkWidget *dialog = inst->dialogs[slot]; if (!dialog) @@ -598,14 +603,15 @@ static int find_and_raise_dialog(Frontend *inst, enum DialogSlot slot) /* * Return the window or icon title. */ -char *get_window_title(Frontend *inst, int icon) +static const char *gtkwin_get_title(TermWin *tw, int icon) { + GtkFrontend *inst = container_of(tw, GtkFrontend, termwin); return icon ? inst->icontitle : inst->wintitle; } static void warn_on_close_callback(void *vctx, int result) { - Frontend *inst = (Frontend *)vctx; + GtkFrontend *inst = (GtkFrontend *)vctx; unregister_dialog(&inst->seat, DIALOG_SLOT_WARN_ON_CLOSE); if (result) gtk_widget_destroy(inst->window); @@ -621,7 +627,7 @@ static void warn_on_close_callback(void *vctx, int result) * handler need not do anything', i.e. 'suppress default handler', * i.e. 'do not close the window'.) */ -gint delete_window(GtkWidget *widget, GdkEvent *event, Frontend *inst) +gint delete_window(GtkWidget *widget, GdkEvent *event, GtkFrontend *inst) { if (!inst->exited && conf_get_int(inst->conf, CONF_warn_on_close)) { /* @@ -644,7 +650,7 @@ gint delete_window(GtkWidget *widget, GdkEvent *event, Frontend *inst) return FALSE; } -static void update_mouseptr(Frontend *inst) +static void update_mouseptr(GtkFrontend *inst) { switch (inst->busy_status) { case BUSY_NOT: @@ -670,7 +676,7 @@ static void update_mouseptr(Frontend *inst) } } -static void show_mouseptr(Frontend *inst, int show) +static void show_mouseptr(GtkFrontend *inst, int show) { if (!conf_get_int(inst->conf, CONF_hide_mouseptr)) show = 1; @@ -678,9 +684,9 @@ static void show_mouseptr(Frontend *inst, int show) update_mouseptr(inst); } -static void draw_backing_rect(Frontend *inst); +static void draw_backing_rect(GtkFrontend *inst); -static void drawing_area_setup(Frontend *inst, int width, int height) +static void drawing_area_setup(GtkFrontend *inst, int width, int height) { int w, h, new_scale, need_size = 0; @@ -769,7 +775,7 @@ static void drawing_area_setup(Frontend *inst, int width, int height) #endif } -static void drawing_area_setup_simple(Frontend *inst) +static void drawing_area_setup_simple(GtkFrontend *inst) { /* * Wrapper on drawing_area_setup which fetches the width and @@ -786,7 +792,7 @@ static void drawing_area_setup_simple(Frontend *inst) drawing_area_setup(inst, alloc.width, alloc.height); } -static void area_realised(GtkWidget *widget, Frontend *inst) +static void area_realised(GtkWidget *widget, GtkFrontend *inst) { inst->drawing_area_realised = TRUE; if (inst->drawing_area_realised && inst->drawing_area_got_size && @@ -795,7 +801,7 @@ static void area_realised(GtkWidget *widget, Frontend *inst) } static void area_size_allocate( - GtkWidget *widget, GdkRectangle *alloc, Frontend *inst) + GtkWidget *widget, GdkRectangle *alloc, GtkFrontend *inst) { inst->drawing_area_got_size = TRUE; if (inst->drawing_area_realised && inst->drawing_area_got_size) @@ -803,7 +809,7 @@ static void area_size_allocate( } #if GTK_CHECK_VERSION(3,10,0) -static void area_check_scale(Frontend *inst) +static void area_check_scale(GtkFrontend *inst) { if (!inst->drawing_area_setup_needed && inst->scale != gtk_widget_get_scale_factor(inst->area)) { @@ -820,32 +826,32 @@ static void area_check_scale(Frontend *inst) static gboolean area_configured( GtkWidget *widget, GdkEventConfigure *event, gpointer data) { - Frontend *inst = (Frontend *)data; + GtkFrontend *inst = (GtkFrontend *)data; area_check_scale(inst); return FALSE; } #endif #ifdef DRAW_TEXT_CAIRO -static void cairo_setup_dctx(struct draw_ctx *dctx) +static void cairo_setup_draw_ctx(GtkFrontend *inst) { - cairo_get_matrix(dctx->uctx.u.cairo.cr, - &dctx->uctx.u.cairo.origmatrix); - cairo_set_line_width(dctx->uctx.u.cairo.cr, 1.0); - cairo_set_line_cap(dctx->uctx.u.cairo.cr, CAIRO_LINE_CAP_SQUARE); - cairo_set_line_join(dctx->uctx.u.cairo.cr, CAIRO_LINE_JOIN_MITER); + cairo_get_matrix(inst->uctx.u.cairo.cr, + &inst->uctx.u.cairo.origmatrix); + cairo_set_line_width(inst->uctx.u.cairo.cr, 1.0); + cairo_set_line_cap(inst->uctx.u.cairo.cr, CAIRO_LINE_CAP_SQUARE); + cairo_set_line_join(inst->uctx.u.cairo.cr, CAIRO_LINE_JOIN_MITER); /* This antialiasing setting appears to be ignored for Pango * font rendering but honoured for stroking and filling paths; * I don't quite understand the logic of that, but I won't * complain since it's exactly what I happen to want */ - cairo_set_antialias(dctx->uctx.u.cairo.cr, CAIRO_ANTIALIAS_NONE); + cairo_set_antialias(inst->uctx.u.cairo.cr, CAIRO_ANTIALIAS_NONE); } #endif #if GTK_CHECK_VERSION(3,0,0) static gint draw_area(GtkWidget *widget, cairo_t *cr, gpointer data) { - Frontend *inst = (Frontend *)data; + GtkFrontend *inst = (GtkFrontend *)data; #if GTK_CHECK_VERSION(3,10,0) /* @@ -908,7 +914,7 @@ static gint draw_area(GtkWidget *widget, cairo_t *cr, gpointer data) #else gint expose_area(GtkWidget *widget, GdkEventExpose *event, gpointer data) { - Frontend *inst = (Frontend *)data; + GtkFrontend *inst = (GtkFrontend *)data; #ifndef NO_BACKING_PIXMAPS /* @@ -958,12 +964,12 @@ char *dup_keyval_name(guint keyval) } #endif -static void change_font_size(Frontend *inst, int increment); -static void key_pressed(Frontend *inst); +static void change_font_size(GtkFrontend *inst, int increment); +static void key_pressed(GtkFrontend *inst); gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) { - Frontend *inst = (Frontend *)data; + GtkFrontend *inst = (GtkFrontend *)data; char output[256]; wchar_t ucsoutput[2]; int ucsval, start, end, special, output_charset, use_ucsoutput; @@ -2200,7 +2206,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) #if GTK_CHECK_VERSION(2,0,0) void input_method_commit_event(GtkIMContext *imc, gchar *str, gpointer data) { - Frontend *inst = (Frontend *)data; + GtkFrontend *inst = (GtkFrontend *)data; #ifdef KEY_EVENT_DIAGNOSTICS char *string_string = dupstr(""); @@ -2228,7 +2234,7 @@ void input_method_commit_event(GtkIMContext *imc, gchar *str, gpointer data) #define SCROLL_INCREMENT_LINES 5 #if GTK_CHECK_VERSION(3,4,0) -gboolean scroll_internal(Frontend *inst, gdouble delta, guint state, +gboolean scroll_internal(GtkFrontend *inst, gdouble delta, guint state, gdouble ex, gdouble ey) { int shift, ctrl, alt, x, y, raw_mouse_mode; @@ -2280,7 +2286,7 @@ gboolean scroll_internal(Frontend *inst, gdouble delta, guint state, } #endif -static gboolean button_internal(Frontend *inst, GdkEventButton *event) +static gboolean button_internal(GtkFrontend *inst, GdkEventButton *event) { int shift, ctrl, alt, x, y, button, act, raw_mouse_mode; @@ -2353,7 +2359,7 @@ static gboolean button_internal(Frontend *inst, GdkEventButton *event) gboolean button_event(GtkWidget *widget, GdkEventButton *event, gpointer data) { - Frontend *inst = (Frontend *)data; + GtkFrontend *inst = (GtkFrontend *)data; return button_internal(inst, event); } @@ -2365,7 +2371,7 @@ gboolean button_event(GtkWidget *widget, GdkEventButton *event, gpointer data) */ gboolean scroll_event(GtkWidget *widget, GdkEventScroll *event, gpointer data) { - Frontend *inst = (Frontend *)data; + GtkFrontend *inst = (GtkFrontend *)data; #if GTK_CHECK_VERSION(3,4,0) gdouble dx, dy; @@ -2406,7 +2412,7 @@ gboolean scroll_event(GtkWidget *widget, GdkEventScroll *event, gpointer data) gint motion_event(GtkWidget *widget, GdkEventMotion *event, gpointer data) { - Frontend *inst = (Frontend *)data; + GtkFrontend *inst = (GtkFrontend *)data; int shift, ctrl, alt, x, y, button; /* Remember the timestamp. */ @@ -2435,7 +2441,7 @@ gint motion_event(GtkWidget *widget, GdkEventMotion *event, gpointer data) return TRUE; } -static void key_pressed(Frontend *inst) +static void key_pressed(GtkFrontend *inst) { /* * If our child process has exited but not closed, terminate on @@ -2456,7 +2462,7 @@ static void key_pressed(Frontend *inst) static void exit_callback(void *vctx) { - Frontend *inst = (Frontend *)vctx; + GtkFrontend *inst = (GtkFrontend *)vctx; int exitcode, close_on_exit; if (!inst->exited && @@ -2473,11 +2479,11 @@ static void exit_callback(void *vctx) static void gtk_seat_notify_remote_exit(Seat *seat) { - Frontend *inst = container_of(seat, Frontend, seat); + GtkFrontend *inst = container_of(seat, GtkFrontend, seat); queue_toplevel_callback(exit_callback, inst); } -static void destroy_inst_connection(Frontend *inst) +static void destroy_inst_connection(GtkFrontend *inst) { inst->exited = TRUE; if (inst->ldisc) { @@ -2496,7 +2502,7 @@ static void destroy_inst_connection(Frontend *inst) } } -static void delete_inst(Frontend *inst) +static void delete_inst(GtkFrontend *inst) { int dialog_slot; for (dialog_slot = 0; dialog_slot < DIALOG_SLOT_LIMIT; dialog_slot++) { @@ -2559,7 +2565,7 @@ static void delete_inst(Frontend *inst) void destroy(GtkWidget *widget, gpointer data) { - Frontend *inst = (Frontend *)data; + GtkFrontend *inst = (GtkFrontend *)data; inst->window = NULL; delete_inst(inst); session_window_closed(); @@ -2567,7 +2573,7 @@ void destroy(GtkWidget *widget, gpointer data) gint focus_event(GtkWidget *widget, GdkEventFocus *event, gpointer data) { - Frontend *inst = (Frontend *)data; + GtkFrontend *inst = (GtkFrontend *)data; term_set_focus(inst->term, event->in); term_update(inst->term); show_mouseptr(inst, 1); @@ -2576,7 +2582,7 @@ gint focus_event(GtkWidget *widget, GdkEventFocus *event, gpointer data) static void gtk_seat_set_busy_status(Seat *seat, BusyStatus status) { - Frontend *inst = container_of(seat, Frontend, seat); + GtkFrontend *inst = container_of(seat, GtkFrontend, seat); inst->busy_status = status; update_mouseptr(inst); } @@ -2584,21 +2590,24 @@ static void gtk_seat_set_busy_status(Seat *seat, BusyStatus status) /* * set or clear the "raw mouse message" mode */ -void set_raw_mouse_mode(Frontend *inst, int activate) +static void gtkwin_set_raw_mouse_mode(TermWin *tw, int activate) { + GtkFrontend *inst = container_of(tw, GtkFrontend, termwin); activate = activate && !conf_get_int(inst->conf, CONF_no_mouse_rep); send_raw_mouse = activate; update_mouseptr(inst); } #if GTK_CHECK_VERSION(2,0,0) -static void compute_whole_window_size(Frontend *inst, +static void compute_whole_window_size(GtkFrontend *inst, int wchars, int hchars, int *wpix, int *hpix); #endif -void request_resize(Frontend *inst, int w, int h) +static void gtkwin_request_resize(TermWin *tw, int w, int h) { + GtkFrontend *inst = container_of(tw, GtkFrontend, termwin); + #if !GTK_CHECK_VERSION(3,0,0) int large_x, large_y; @@ -2684,7 +2693,7 @@ void request_resize(Frontend *inst, int w, int h) } -static void real_palette_set(Frontend *inst, int n, int r, int g, int b) +static void real_palette_set(GtkFrontend *inst, int n, int r, int g, int b) { inst->cols[n].red = r * 0x0101; inst->cols[n].green = g * 0x0101; @@ -2738,7 +2747,7 @@ void set_gtk_widget_background(GtkWidget *widget, const GdkColor *col) #endif } -void set_window_background(Frontend *inst) +void set_window_background(GtkFrontend *inst) { if (inst->area) set_gtk_widget_background(GTK_WIDGET(inst->area), &inst->cols[258]); @@ -2746,8 +2755,9 @@ void set_window_background(Frontend *inst) set_gtk_widget_background(GTK_WIDGET(inst->window), &inst->cols[258]); } -void palette_set(Frontend *inst, int n, int r, int g, int b) +static void gtkwin_palette_set(TermWin *tw, int n, int r, int g, int b) { + GtkFrontend *inst = container_of(tw, GtkFrontend, termwin); if (n >= 16) n += 256 - 16; if (n >= NALLCOLOURS) @@ -2762,8 +2772,9 @@ void palette_set(Frontend *inst, int n, int r, int g, int b) } } -int palette_get(Frontend *inst, int n, int *r, int *g, int *b) +static int gtkwin_palette_get(TermWin *tw, int n, int *r, int *g, int *b) { + GtkFrontend *inst = container_of(tw, GtkFrontend, termwin); if (n < 0 || n >= NALLCOLOURS) return FALSE; *r = inst->cols[n].red >> 8; @@ -2772,8 +2783,9 @@ int palette_get(Frontend *inst, int n, int *r, int *g, int *b) return TRUE; } -void palette_reset(Frontend *inst) +static void gtkwin_palette_reset(TermWin *tw) { + GtkFrontend *inst = container_of(tw, GtkFrontend, termwin); /* This maps colour indices in inst->conf to those used in inst->cols. */ static const int ww[] = { 256, 257, 258, 259, 260, 261, @@ -2841,7 +2853,7 @@ void palette_reset(Frontend *inst) } static struct clipboard_state *clipboard_from_atom( - Frontend *inst, GdkAtom atom) + GtkFrontend *inst, GdkAtom atom) { int i; @@ -2863,7 +2875,7 @@ static struct clipboard_state *clipboard_from_atom( * formats it feels like. */ -void set_clipboard_atom(Frontend *inst, int clipboard, GdkAtom atom) +void set_clipboard_atom(GtkFrontend *inst, int clipboard, GdkAtom atom) { struct clipboard_state *state = &inst->clipstates[clipboard]; @@ -2880,7 +2892,7 @@ void set_clipboard_atom(Frontend *inst, int clipboard, GdkAtom atom) } } -int init_clipboard(Frontend *inst) +int init_clipboard(GtkFrontend *inst) { set_clipboard_atom(inst, CLIP_PRIMARY, GDK_SELECTION_PRIMARY); set_clipboard_atom(inst, CLIP_CLIPBOARD, clipboard_atom); @@ -2918,10 +2930,11 @@ static void clipboard_clear(GtkClipboard *clipboard, gpointer data) sfree(cdi); } -void write_clip(Frontend *inst, int clipboard, - wchar_t *data, int *attr, truecolour *truecolour, int len, - int must_deselect) +static void gtkwin_clip_write( + TermWin *tw, int clipboard, wchar_t *data, int *attr, + truecolour *truecolour, int len, int must_deselect) { + GtkFrontend *inst = container_of(tw, GtkFrontend, termwin); struct clipboard_state *state = &inst->clipstates[clipboard]; struct clipboard_data_instance *cdi; @@ -2978,7 +2991,7 @@ void write_clip(Frontend *inst, int clipboard, static void clipboard_text_received(GtkClipboard *clipboard, const gchar *text, gpointer data) { - Frontend *inst = (Frontend *)data; + GtkFrontend *inst = (GtkFrontend *)data; wchar_t *paste; int paste_len; int length; @@ -2996,8 +3009,9 @@ static void clipboard_text_received(GtkClipboard *clipboard, sfree(paste); } -void frontend_request_paste(Frontend *inst, int clipboard) +static void gtkwin_clip_request_paste(TermWin *tw, int clipboard) { + GtkFrontend *inst = container_of(tw, GtkFrontend, termwin); struct clipboard_state *state = &inst->clipstates[clipboard]; if (!state->gtkclipboard) @@ -3030,7 +3044,7 @@ void frontend_request_paste(Frontend *inst, int clipboard) */ /* Store the data in a cut-buffer. */ -static void store_cutbuffer(Frontend *inst, char *ptr, int len) +static void store_cutbuffer(GtkFrontend *inst, char *ptr, int len) { #ifndef NOT_X_WINDOWS if (inst->disp) { @@ -3044,7 +3058,7 @@ static void store_cutbuffer(Frontend *inst, char *ptr, int len) /* Retrieve data from a cut-buffer. * Returned data needs to be freed with XFree(). */ -static char *retrieve_cutbuffer(Frontend *inst, int *nbytes) +static char *retrieve_cutbuffer(GtkFrontend *inst, int *nbytes) { #ifndef NOT_X_WINDOWS char *ptr; @@ -3064,10 +3078,11 @@ static char *retrieve_cutbuffer(Frontend *inst, int *nbytes) #endif } -void write_clip(Frontend *inst, int clipboard, - wchar_t *data, int *attr, truecolour *truecolour, int len, - int must_deselect) +static void gtkwin_clip_write( + TermWin *tw, int clipboard, wchar_t *data, int *attr, + truecolour *truecolour, int len, int must_deselect) { + GtkFrontend *inst = container_of(tw, GtkFrontend, termwin); struct clipboard_state *state = &inst->clipstates[clipboard]; if (state->pasteout_data) @@ -3169,7 +3184,7 @@ void write_clip(Frontend *inst, int clipboard, static void selection_get(GtkWidget *widget, GtkSelectionData *seldata, guint info, guint time_stamp, gpointer data) { - Frontend *inst = (Frontend *)data; + GtkFrontend *inst = (GtkFrontend *)data; GdkAtom target = gtk_selection_data_get_target(seldata); struct clipboard_state *state = clipboard_from_atom( inst, gtk_selection_data_get_selection(seldata)); @@ -3194,7 +3209,7 @@ static void selection_get(GtkWidget *widget, GtkSelectionData *seldata, static gint selection_clear(GtkWidget *widget, GdkEventSelection *seldata, gpointer data) { - Frontend *inst = (Frontend *)data; + GtkFrontend *inst = (GtkFrontend *)data; struct clipboard_state *state = clipboard_from_atom( inst, seldata->selection); @@ -3217,8 +3232,9 @@ static gint selection_clear(GtkWidget *widget, GdkEventSelection *seldata, return TRUE; } -void frontend_request_paste(Frontend *inst, int clipboard) +static void gtkwin_clip_request_paste(TermWin *tw, int clipboard) { + GtkFrontend *inst = container_of(tw, GtkFrontend, termwin); struct clipboard_state *state = &inst->clipstates[clipboard]; /* @@ -3251,7 +3267,7 @@ void frontend_request_paste(Frontend *inst, int clipboard) static void selection_received(GtkWidget *widget, GtkSelectionData *seldata, guint time, gpointer data) { - Frontend *inst = (Frontend *)data; + GtkFrontend *inst = (GtkFrontend *)data; char *text; int length; #ifndef NOT_X_WINDOWS @@ -3373,7 +3389,7 @@ static void selection_received(GtkWidget *widget, GtkSelectionData *seldata, #endif } -static void init_one_clipboard(Frontend *inst, int clipboard) +static void init_one_clipboard(GtkFrontend *inst, int clipboard) { struct clipboard_state *state = &inst->clipstates[clipboard]; @@ -3381,7 +3397,7 @@ static void init_one_clipboard(Frontend *inst, int clipboard) state->clipboard = clipboard; } -void set_clipboard_atom(Frontend *inst, int clipboard, GdkAtom atom) +void set_clipboard_atom(GtkFrontend *inst, int clipboard, GdkAtom atom) { struct clipboard_state *state = &inst->clipstates[clipboard]; @@ -3391,7 +3407,7 @@ void set_clipboard_atom(Frontend *inst, int clipboard, GdkAtom atom) state->atom = atom; } -void init_clipboard(Frontend *inst) +void init_clipboard(GtkFrontend *inst) { #ifndef NOT_X_WINDOWS /* @@ -3447,7 +3463,7 @@ void init_clipboard(Frontend *inst) #endif /* JUST_USE_GTK_CLIPBOARD_UTF8 */ -static void set_window_titles(Frontend *inst) +static void set_window_titles(GtkFrontend *inst) { /* * We must always call set_icon_name after calling set_title, @@ -3460,21 +3476,23 @@ static void set_window_titles(Frontend *inst) inst->icontitle); } -void set_title(Frontend *inst, char *title) +static void gtkwin_set_title(TermWin *tw, const char *title) { + GtkFrontend *inst = container_of(tw, GtkFrontend, termwin); sfree(inst->wintitle); inst->wintitle = dupstr(title); set_window_titles(inst); } -void set_icon(Frontend *inst, char *title) +static void gtkwin_set_icon_title(TermWin *tw, const char *title) { + GtkFrontend *inst = container_of(tw, GtkFrontend, termwin); sfree(inst->icontitle); inst->icontitle = dupstr(title); set_window_titles(inst); } -void set_title_and_icon(Frontend *inst, char *title, char *icon) +void set_title_and_icon(GtkFrontend *inst, char *title, char *icon) { sfree(inst->wintitle); inst->wintitle = dupstr(title); @@ -3483,8 +3501,9 @@ void set_title_and_icon(Frontend *inst, char *title, char *icon) set_window_titles(inst); } -void set_sbar(Frontend *inst, int total, int start, int page) +static void gtkwin_set_scrollbar(TermWin *tw, int total, int start, int page) { + GtkFrontend *inst = container_of(tw, GtkFrontend, termwin); if (!conf_get_int(inst->conf, CONF_scrollbar)) return; inst->ignore_sbar = TRUE; @@ -3500,7 +3519,7 @@ void set_sbar(Frontend *inst, int total, int start, int page) inst->ignore_sbar = FALSE; } -void scrollbar_moved(GtkAdjustment *adj, Frontend *inst) +void scrollbar_moved(GtkAdjustment *adj, GtkFrontend *inst) { if (!conf_get_int(inst->conf, CONF_scrollbar)) return; @@ -3508,7 +3527,7 @@ void scrollbar_moved(GtkAdjustment *adj, Frontend *inst) term_scroll(inst->term, 1, (int)gtk_adjustment_get_value(adj)); } -static void show_scrollbar(Frontend *inst, gboolean visible) +static void show_scrollbar(GtkFrontend *inst, gboolean visible) { inst->sbar_visible = visible; if (visible) @@ -3517,7 +3536,7 @@ static void show_scrollbar(Frontend *inst, gboolean visible) gtk_widget_hide(inst->sbar); } -void sys_cursor(Frontend *frontend, int x, int y) +static void gtkwin_set_cursor_pos(TermWin *tw, int x, int y) { /* * This is meaningless under X. @@ -3530,13 +3549,14 @@ void sys_cursor(Frontend *frontend, int x, int y) * may want to perform additional actions on any kind of bell (for * example, taskbar flashing in Windows). */ -void do_beep(Frontend *frontend, int mode) +static void gtkwin_bell(TermWin *tw, int mode) { + /* GtkFrontend *inst = container_of(tw, GtkFrontend, termwin); */ if (mode == BELL_DEFAULT) gdk_display_beep(gdk_display_get_default()); } -int char_width(Context ctx, int uc) +static int gtkwin_char_width(TermWin *tw, int uc) { /* * In this front end, double-width characters are handled using a @@ -3545,66 +3565,63 @@ int char_width(Context ctx, int uc) return 1; } -Context get_ctx(Frontend *inst) +static int gtkwin_setup_draw_ctx(TermWin *tw) { - struct draw_ctx *dctx; + GtkFrontend *inst = container_of(tw, GtkFrontend, termwin); if (!gtk_widget_get_window(inst->area)) - return NULL; + return FALSE; - dctx = snew(struct draw_ctx); - dctx->inst = inst; - dctx->uctx.type = inst->drawtype; + inst->uctx.type = inst->drawtype; #ifdef DRAW_TEXT_GDK - if (dctx->uctx.type == DRAWTYPE_GDK) { + if (inst->uctx.type == DRAWTYPE_GDK) { /* If we're doing GDK-based drawing, then we also expect * inst->pixmap to exist. */ - dctx->uctx.u.gdk.target = inst->pixmap; - dctx->uctx.u.gdk.gc = gdk_gc_new(gtk_widget_get_window(inst->area)); + inst->uctx.u.gdk.target = inst->pixmap; + inst->uctx.u.gdk.gc = gdk_gc_new(gtk_widget_get_window(inst->area)); } #endif #ifdef DRAW_TEXT_CAIRO - if (dctx->uctx.type == DRAWTYPE_CAIRO) { - dctx->uctx.u.cairo.widget = GTK_WIDGET(inst->area); + if (inst->uctx.type == DRAWTYPE_CAIRO) { + inst->uctx.u.cairo.widget = GTK_WIDGET(inst->area); /* If we're doing Cairo drawing, we expect inst->surface to * exist, and we draw to that first, regardless of whether we * subsequently copy the results to inst->pixmap. */ - dctx->uctx.u.cairo.cr = cairo_create(inst->surface); - cairo_scale(dctx->uctx.u.cairo.cr, inst->scale, inst->scale); - cairo_setup_dctx(dctx); + inst->uctx.u.cairo.cr = cairo_create(inst->surface); + cairo_scale(inst->uctx.u.cairo.cr, inst->scale, inst->scale); + cairo_setup_draw_ctx(inst); } #endif - return dctx; + return TRUE; } -void free_ctx(Context dctx) +static void gtkwin_free_draw_ctx(TermWin *tw) { - /* Frontend *inst = dctx->inst; */ + GtkFrontend *inst = container_of(tw, GtkFrontend, termwin); #ifdef DRAW_TEXT_GDK - if (dctx->uctx.type == DRAWTYPE_GDK) { - gdk_gc_unref(dctx->uctx.u.gdk.gc); + if (inst->uctx.type == DRAWTYPE_GDK) { + gdk_gc_unref(inst->uctx.u.gdk.gc); } #endif #ifdef DRAW_TEXT_CAIRO - if (dctx->uctx.type == DRAWTYPE_CAIRO) { - cairo_destroy(dctx->uctx.u.cairo.cr); + if (inst->uctx.type == DRAWTYPE_CAIRO) { + cairo_destroy(inst->uctx.u.cairo.cr); } #endif - sfree(dctx); } -static void draw_update(struct draw_ctx *dctx, int x, int y, int w, int h) +static void draw_update(GtkFrontend *inst, int x, int y, int w, int h) { #if defined DRAW_TEXT_CAIRO && !defined NO_BACKING_PIXMAPS - if (dctx->uctx.type == DRAWTYPE_CAIRO) { + if (inst->uctx.type == DRAWTYPE_CAIRO) { /* * If inst->surface and inst->pixmap both exist, then we've * just drawn new content to the former which we must copy to * the latter. */ - cairo_t *cr = gdk_cairo_create(dctx->inst->pixmap); - cairo_set_source_surface(cr, dctx->inst->surface, 0, 0); + cairo_t *cr = gdk_cairo_create(inst->pixmap); + cairo_set_source_surface(cr, inst->surface, 0, 0); cairo_rectangle(cr, x, y, w, h); cairo_fill(cr); cairo_destroy(cr); @@ -3620,7 +3637,7 @@ static void draw_update(struct draw_ctx *dctx, int x, int y, int w, int h) * Amazingly, this one API call is actually valid in all versions * of GTK :-) */ - gtk_widget_queue_draw_area(dctx->inst->area, x, y, w, h); + gtk_widget_queue_draw_area(inst->area, x, y, w, h); } #ifdef DRAW_TEXT_CAIRO @@ -3634,41 +3651,40 @@ static void cairo_set_source_rgb_dim(cairo_t *cr, double r, double g, double b, } #endif -static void draw_set_colour(struct draw_ctx *dctx, int col, int dim) +static void draw_set_colour(GtkFrontend *inst, int col, int dim) { #ifdef DRAW_TEXT_GDK - if (dctx->uctx.type == DRAWTYPE_GDK) { + if (inst->uctx.type == DRAWTYPE_GDK) { if (dim) { #if GTK_CHECK_VERSION(2,0,0) GdkColor color; - color.red = dctx->inst->cols[col].red * 2 / 3; - color.green = dctx->inst->cols[col].green * 2 / 3; - color.blue = dctx->inst->cols[col].blue * 2 / 3; - gdk_gc_set_rgb_fg_color(dctx->uctx.u.gdk.gc, &color); + color.red = inst->cols[col].red * 2 / 3; + color.green = inst->cols[col].green * 2 / 3; + color.blue = inst->cols[col].blue * 2 / 3; + gdk_gc_set_rgb_fg_color(inst->uctx.u.gdk.gc, &color); #else /* Poor GTK1 fallback */ - gdk_gc_set_foreground(dctx->uctx.u.gdk.gc, &dctx->inst->cols[col]); + gdk_gc_set_foreground(inst->uctx.u.gdk.gc, &inst->cols[col]); #endif } else { - gdk_gc_set_foreground(dctx->uctx.u.gdk.gc, &dctx->inst->cols[col]); + gdk_gc_set_foreground(inst->uctx.u.gdk.gc, &inst->cols[col]); } } #endif #ifdef DRAW_TEXT_CAIRO - if (dctx->uctx.type == DRAWTYPE_CAIRO) { - cairo_set_source_rgb_dim(dctx->uctx.u.cairo.cr, - dctx->inst->cols[col].red / 65535.0, - dctx->inst->cols[col].green / 65535.0, - dctx->inst->cols[col].blue / 65535.0, dim); + if (inst->uctx.type == DRAWTYPE_CAIRO) { + cairo_set_source_rgb_dim(inst->uctx.u.cairo.cr, + inst->cols[col].red / 65535.0, + inst->cols[col].green / 65535.0, + inst->cols[col].blue / 65535.0, dim); } #endif } -static void draw_set_colour_rgb(struct draw_ctx *dctx, optionalrgb orgb, - int dim) +static void draw_set_colour_rgb(GtkFrontend *inst, optionalrgb orgb, int dim) { #ifdef DRAW_TEXT_GDK - if (dctx->uctx.type == DRAWTYPE_GDK) { + if (inst->uctx.type == DRAWTYPE_GDK) { #if GTK_CHECK_VERSION(2,0,0) GdkColor color; color.red = orgb.r * 256; @@ -3679,50 +3695,50 @@ static void draw_set_colour_rgb(struct draw_ctx *dctx, optionalrgb orgb, color.green = color.green * 2 / 3; color.blue = color.blue * 2 / 3; } - gdk_gc_set_rgb_fg_color(dctx->uctx.u.gdk.gc, &color); + gdk_gc_set_rgb_fg_color(inst->uctx.u.gdk.gc, &color); #else /* Poor GTK1 fallback */ - gdk_gc_set_foreground(dctx->uctx.u.gdk.gc, &dctx->inst->cols[256]); + gdk_gc_set_foreground(inst->uctx.u.gdk.gc, &inst->cols[256]); #endif } #endif #ifdef DRAW_TEXT_CAIRO - if (dctx->uctx.type == DRAWTYPE_CAIRO) { - cairo_set_source_rgb_dim(dctx->uctx.u.cairo.cr, orgb.r / 255.0, + if (inst->uctx.type == DRAWTYPE_CAIRO) { + cairo_set_source_rgb_dim(inst->uctx.u.cairo.cr, orgb.r / 255.0, orgb.g / 255.0, orgb.b / 255.0, dim); } #endif } -static void draw_rectangle(struct draw_ctx *dctx, int filled, +static void draw_rectangle(GtkFrontend *inst, int filled, int x, int y, int w, int h) { #ifdef DRAW_TEXT_GDK - if (dctx->uctx.type == DRAWTYPE_GDK) { - gdk_draw_rectangle(dctx->uctx.u.gdk.target, dctx->uctx.u.gdk.gc, + if (inst->uctx.type == DRAWTYPE_GDK) { + gdk_draw_rectangle(inst->uctx.u.gdk.target, inst->uctx.u.gdk.gc, filled, x, y, w, h); } #endif #ifdef DRAW_TEXT_CAIRO - if (dctx->uctx.type == DRAWTYPE_CAIRO) { - cairo_new_path(dctx->uctx.u.cairo.cr); + if (inst->uctx.type == DRAWTYPE_CAIRO) { + cairo_new_path(inst->uctx.u.cairo.cr); if (filled) { - cairo_rectangle(dctx->uctx.u.cairo.cr, x, y, w, h); - cairo_fill(dctx->uctx.u.cairo.cr); + cairo_rectangle(inst->uctx.u.cairo.cr, x, y, w, h); + cairo_fill(inst->uctx.u.cairo.cr); } else { - cairo_rectangle(dctx->uctx.u.cairo.cr, + cairo_rectangle(inst->uctx.u.cairo.cr, x + 0.5, y + 0.5, w, h); - cairo_close_path(dctx->uctx.u.cairo.cr); - cairo_stroke(dctx->uctx.u.cairo.cr); + cairo_close_path(inst->uctx.u.cairo.cr); + cairo_stroke(inst->uctx.u.cairo.cr); } } #endif } -static void draw_clip(struct draw_ctx *dctx, int x, int y, int w, int h) +static void draw_clip(GtkFrontend *inst, int x, int y, int w, int h) { #ifdef DRAW_TEXT_GDK - if (dctx->uctx.type == DRAWTYPE_GDK) { + if (inst->uctx.type == DRAWTYPE_GDK) { GdkRectangle r; r.x = x; @@ -3730,59 +3746,59 @@ static void draw_clip(struct draw_ctx *dctx, int x, int y, int w, int h) r.width = w; r.height = h; - gdk_gc_set_clip_rectangle(dctx->uctx.u.gdk.gc, &r); + gdk_gc_set_clip_rectangle(inst->uctx.u.gdk.gc, &r); } #endif #ifdef DRAW_TEXT_CAIRO - if (dctx->uctx.type == DRAWTYPE_CAIRO) { - cairo_reset_clip(dctx->uctx.u.cairo.cr); - cairo_new_path(dctx->uctx.u.cairo.cr); - cairo_rectangle(dctx->uctx.u.cairo.cr, x, y, w, h); - cairo_clip(dctx->uctx.u.cairo.cr); + if (inst->uctx.type == DRAWTYPE_CAIRO) { + cairo_reset_clip(inst->uctx.u.cairo.cr); + cairo_new_path(inst->uctx.u.cairo.cr); + cairo_rectangle(inst->uctx.u.cairo.cr, x, y, w, h); + cairo_clip(inst->uctx.u.cairo.cr); } #endif } -static void draw_point(struct draw_ctx *dctx, int x, int y) +static void draw_point(GtkFrontend *inst, int x, int y) { #ifdef DRAW_TEXT_GDK - if (dctx->uctx.type == DRAWTYPE_GDK) { - gdk_draw_point(dctx->uctx.u.gdk.target, dctx->uctx.u.gdk.gc, x, y); + if (inst->uctx.type == DRAWTYPE_GDK) { + gdk_draw_point(inst->uctx.u.gdk.target, inst->uctx.u.gdk.gc, x, y); } #endif #ifdef DRAW_TEXT_CAIRO - if (dctx->uctx.type == DRAWTYPE_CAIRO) { - cairo_new_path(dctx->uctx.u.cairo.cr); - cairo_rectangle(dctx->uctx.u.cairo.cr, x, y, 1, 1); - cairo_fill(dctx->uctx.u.cairo.cr); + if (inst->uctx.type == DRAWTYPE_CAIRO) { + cairo_new_path(inst->uctx.u.cairo.cr); + cairo_rectangle(inst->uctx.u.cairo.cr, x, y, 1, 1); + cairo_fill(inst->uctx.u.cairo.cr); } #endif } -static void draw_line(struct draw_ctx *dctx, int x0, int y0, int x1, int y1) +static void draw_line(GtkFrontend *inst, int x0, int y0, int x1, int y1) { #ifdef DRAW_TEXT_GDK - if (dctx->uctx.type == DRAWTYPE_GDK) { - gdk_draw_line(dctx->uctx.u.gdk.target, dctx->uctx.u.gdk.gc, + if (inst->uctx.type == DRAWTYPE_GDK) { + gdk_draw_line(inst->uctx.u.gdk.target, inst->uctx.u.gdk.gc, x0, y0, x1, y1); } #endif #ifdef DRAW_TEXT_CAIRO - if (dctx->uctx.type == DRAWTYPE_CAIRO) { - cairo_new_path(dctx->uctx.u.cairo.cr); - cairo_move_to(dctx->uctx.u.cairo.cr, x0 + 0.5, y0 + 0.5); - cairo_line_to(dctx->uctx.u.cairo.cr, x1 + 0.5, y1 + 0.5); - cairo_stroke(dctx->uctx.u.cairo.cr); + if (inst->uctx.type == DRAWTYPE_CAIRO) { + cairo_new_path(inst->uctx.u.cairo.cr); + cairo_move_to(inst->uctx.u.cairo.cr, x0 + 0.5, y0 + 0.5); + cairo_line_to(inst->uctx.u.cairo.cr, x1 + 0.5, y1 + 0.5); + cairo_stroke(inst->uctx.u.cairo.cr); } #endif } -static void draw_stretch_before(struct draw_ctx *dctx, int x, int y, +static void draw_stretch_before(GtkFrontend *inst, int x, int y, int w, int wdouble, int h, int hdouble, int hbothalf) { #ifdef DRAW_TEXT_CAIRO - if (dctx->uctx.type == DRAWTYPE_CAIRO) { + if (inst->uctx.type == DRAWTYPE_CAIRO) { cairo_matrix_t matrix; matrix.xy = 0; @@ -3807,18 +3823,18 @@ static void draw_stretch_before(struct draw_ctx *dctx, int x, int y, matrix.yy = 1; matrix.y0 = 0; } - cairo_transform(dctx->uctx.u.cairo.cr, &matrix); + cairo_transform(inst->uctx.u.cairo.cr, &matrix); } #endif } -static void draw_stretch_after(struct draw_ctx *dctx, int x, int y, +static void draw_stretch_after(GtkFrontend *inst, int x, int y, int w, int wdouble, int h, int hdouble, int hbothalf) { #ifdef DRAW_TEXT_GDK #ifndef NO_BACKING_PIXMAPS - if (dctx->uctx.type == DRAWTYPE_GDK) { + if (inst->uctx.type == DRAWTYPE_GDK) { /* * I can't find any plausible StretchBlt equivalent in the X * server, so I'm going to do this the slow and painful way. @@ -3830,9 +3846,9 @@ static void draw_stretch_after(struct draw_ctx *dctx, int x, int y, int i; if (wdouble) { for (i = 0; i < w; i++) { - gdk_draw_pixmap(dctx->uctx.u.gdk.target, - dctx->uctx.u.gdk.gc, - dctx->uctx.u.gdk.target, + gdk_draw_pixmap(inst->uctx.u.gdk.target, + inst->uctx.u.gdk.gc, + inst->uctx.u.gdk.target, x + 2*i, y, x + 2*i+1, y, w - i, h); @@ -3848,9 +3864,9 @@ static void draw_stretch_after(struct draw_ctx *dctx, int x, int y, else dt = 1, db = 0; for (i = 0; i < h; i += 2) { - gdk_draw_pixmap(dctx->uctx.u.gdk.target, - dctx->uctx.u.gdk.gc, - dctx->uctx.u.gdk.target, + gdk_draw_pixmap(inst->uctx.u.gdk.target, + inst->uctx.u.gdk.gc, + inst->uctx.u.gdk.target, x, y + dt*i + db, x, y + dt*(i+1), w, h-i-1); @@ -3862,27 +3878,26 @@ static void draw_stretch_after(struct draw_ctx *dctx, int x, int y, #endif #endif /* DRAW_TEXT_GDK */ #ifdef DRAW_TEXT_CAIRO - if (dctx->uctx.type == DRAWTYPE_CAIRO) { - cairo_set_matrix(dctx->uctx.u.cairo.cr, - &dctx->uctx.u.cairo.origmatrix); + if (inst->uctx.type == DRAWTYPE_CAIRO) { + cairo_set_matrix(inst->uctx.u.cairo.cr, + &inst->uctx.u.cairo.origmatrix); } #endif } -static void draw_backing_rect(Frontend *inst) +static void draw_backing_rect(GtkFrontend *inst) { int w, h; - struct draw_ctx *dctx = get_ctx(inst); - if (!dctx) + if (!win_setup_draw_ctx(&inst->termwin)) return; w = inst->width * inst->font_width + 2*inst->window_border; h = inst->height * inst->font_height + 2*inst->window_border; - draw_set_colour(dctx, 258, FALSE); - draw_rectangle(dctx, 1, 0, 0, w, h); - draw_update(dctx, 0, 0, w, h); - free_ctx(dctx); + draw_set_colour(inst, 258, FALSE); + draw_rectangle(inst, 1, 0, 0, w, h); + draw_update(inst, 0, 0, w, h); + win_free_draw_ctx(&inst->termwin); } /* @@ -3891,10 +3906,10 @@ static void draw_backing_rect(Frontend *inst) * * We are allowed to fiddle with the contents of `text'. */ -void do_text_internal(Context dctx, int x, int y, wchar_t *text, int len, - unsigned long attr, int lattr, truecolour truecolour) +static void do_text_internal( + GtkFrontend *inst, int x, int y, wchar_t *text, int len, + unsigned long attr, int lattr, truecolour truecolour) { - Frontend *inst = dctx->inst; int ncombining; int nfg, nbg, t, fontid, shadow, rlen, widefactor, bold; int monochrome = @@ -3980,14 +3995,14 @@ void do_text_internal(Context dctx, int x, int y, wchar_t *text, int len, } else rlen = len; - draw_clip(dctx, + draw_clip(inst, x*inst->font_width+inst->window_border, y*inst->font_height+inst->window_border, rlen*widefactor*inst->font_width, inst->font_height); if ((lattr & LATTR_MODE) != LATTR_NORM) { - draw_stretch_before(dctx, + draw_stretch_before(inst, x*inst->font_width+inst->window_border, y*inst->font_height+inst->window_border, rlen*widefactor*inst->font_width, TRUE, @@ -3997,28 +4012,28 @@ void do_text_internal(Context dctx, int x, int y, wchar_t *text, int len, } if (truecolour.bg.enabled) - draw_set_colour_rgb(dctx, truecolour.bg, attr & ATTR_DIM); + draw_set_colour_rgb(inst, truecolour.bg, attr & ATTR_DIM); else - draw_set_colour(dctx, nbg, attr & ATTR_DIM); - draw_rectangle(dctx, TRUE, + draw_set_colour(inst, nbg, attr & ATTR_DIM); + draw_rectangle(inst, TRUE, x*inst->font_width+inst->window_border, y*inst->font_height+inst->window_border, rlen*widefactor*inst->font_width, inst->font_height); if (truecolour.fg.enabled) - draw_set_colour_rgb(dctx, truecolour.fg, attr & ATTR_DIM); + draw_set_colour_rgb(inst, truecolour.fg, attr & ATTR_DIM); else - draw_set_colour(dctx, nfg, attr & ATTR_DIM); + draw_set_colour(inst, nfg, attr & ATTR_DIM); if (ncombining > 1) { assert(len == 1); - unifont_draw_combining(&dctx->uctx, inst->fonts[fontid], + unifont_draw_combining(&inst->uctx, inst->fonts[fontid], x*inst->font_width+inst->window_border, (y*inst->font_height+inst->window_border+ inst->fonts[0]->ascent), text, ncombining, widefactor > 1, bold, inst->font_width); } else { - unifont_draw_text(&dctx->uctx, inst->fonts[fontid], + unifont_draw_text(&inst->uctx, inst->fonts[fontid], x*inst->font_width+inst->window_border, (y*inst->font_height+inst->window_border+ inst->fonts[0]->ascent), @@ -4030,14 +4045,14 @@ void do_text_internal(Context dctx, int x, int y, wchar_t *text, int len, int uheight = inst->fonts[0]->ascent + 1; if (uheight >= inst->font_height) uheight = inst->font_height - 1; - draw_line(dctx, x*inst->font_width+inst->window_border, + draw_line(inst, x*inst->font_width+inst->window_border, y*inst->font_height + uheight + inst->window_border, (x+len)*widefactor*inst->font_width-1+inst->window_border, y*inst->font_height + uheight + inst->window_border); } if ((lattr & LATTR_MODE) != LATTR_NORM) { - draw_stretch_after(dctx, + draw_stretch_after(inst, x*inst->font_width+inst->window_border, y*inst->font_height+inst->window_border, rlen*widefactor*inst->font_width, TRUE, @@ -4047,13 +4062,14 @@ void do_text_internal(Context dctx, int x, int y, wchar_t *text, int len, } } -void do_text(Context dctx, int x, int y, wchar_t *text, int len, - unsigned long attr, int lattr, truecolour truecolour) +static void gtkwin_draw_text( + TermWin *tw, int x, int y, wchar_t *text, int len, + unsigned long attr, int lattr, truecolour truecolour) { - Frontend *inst = dctx->inst; + GtkFrontend *inst = container_of(tw, GtkFrontend, termwin); int widefactor; - do_text_internal(dctx, x, y, text, len, attr, lattr, truecolour); + do_text_internal(inst, x, y, text, len, attr, lattr, truecolour); if (attr & ATTR_WIDE) { widefactor = 2; @@ -4070,17 +4086,17 @@ void do_text(Context dctx, int x, int y, wchar_t *text, int len, len *= 2; } - draw_update(dctx, + draw_update(inst, x*inst->font_width+inst->window_border, y*inst->font_height+inst->window_border, len*widefactor*inst->font_width, inst->font_height); } -void do_cursor(Context dctx, int x, int y, wchar_t *text, int len, - unsigned long attr, int lattr, truecolour truecolour) +static void gtkwin_draw_cursor( + TermWin *tw, int x, int y, wchar_t *text, int len, + unsigned long attr, int lattr, truecolour truecolour) { - Frontend *inst = dctx->inst; - + GtkFrontend *inst = container_of(tw, GtkFrontend, termwin); int active, passive, widefactor; if (attr & TATTR_PASCURS) { @@ -4093,7 +4109,7 @@ void do_cursor(Context dctx, int x, int y, wchar_t *text, int len, active = 1; } else active = 0; - do_text_internal(dctx, x, y, text, len, attr, lattr, truecolour); + do_text_internal(inst, x, y, text, len, attr, lattr, truecolour); if (attr & TATTR_COMBINING) len = 1; @@ -4120,8 +4136,8 @@ void do_cursor(Context dctx, int x, int y, wchar_t *text, int len, * if it's passive. */ if (passive) { - draw_set_colour(dctx, 261, FALSE); - draw_rectangle(dctx, FALSE, + draw_set_colour(inst, 261, FALSE); + draw_rectangle(inst, FALSE, x*inst->font_width+inst->window_border, y*inst->font_height+inst->window_border, len*widefactor*inst->font_width-1, @@ -4159,22 +4175,22 @@ void do_cursor(Context dctx, int x, int y, wchar_t *text, int len, length = inst->font_height; } - draw_set_colour(dctx, 261, FALSE); + draw_set_colour(inst, 261, FALSE); if (passive) { for (i = 0; i < length; i++) { if (i % 2 == 0) { - draw_point(dctx, startx, starty); + draw_point(inst, startx, starty); } startx += dx; starty += dy; } } else if (active) { - draw_line(dctx, startx, starty, + draw_line(inst, startx, starty, startx + (length-1) * dx, starty + (length-1) * dy); } /* else no cursor (e.g., blinked off) */ } - draw_update(dctx, + draw_update(inst, x*inst->font_width+inst->window_border, y*inst->font_height+inst->window_border, len*widefactor*inst->font_width, inst->font_height); @@ -4191,7 +4207,7 @@ void do_cursor(Context dctx, int x, int y, wchar_t *text, int len, #endif } -GdkCursor *make_mouse_ptr(Frontend *inst, int cursor_val) +GdkCursor *make_mouse_ptr(GtkFrontend *inst, int cursor_val) { if (cursor_val == -1) { #if GTK_CHECK_VERSION(2,16,0) @@ -4236,7 +4252,7 @@ static const char *gtk_seat_get_x_display(Seat *seat) #ifndef NOT_X_WINDOWS static int gtk_seat_get_windowid(Seat *seat, long *id) { - Frontend *inst = container_of(seat, Frontend, seat); + GtkFrontend *inst = container_of(seat, GtkFrontend, seat); GdkWindow *window = gtk_widget_get_window(inst->area); if (!GDK_IS_X11_WINDOW(window)) return FALSE; @@ -4245,12 +4261,13 @@ static int gtk_seat_get_windowid(Seat *seat, long *id) } #endif -int frontend_is_utf8(Frontend *inst) +static int gtkwin_is_utf8(TermWin *tw) { + GtkFrontend *inst = container_of(tw, GtkFrontend, termwin); return inst->ucsdata.line_codepage == CS_UTF8; } -char *setup_fonts_ucs(Frontend *inst) +char *setup_fonts_ucs(GtkFrontend *inst) { int shadowbold = conf_get_int(inst->conf, CONF_shadowbold); int shadowboldoffset = conf_get_int(inst->conf, CONF_shadowboldoffset); @@ -4353,7 +4370,7 @@ static void find_app_menu_bar(GtkWidget *widget, gpointer data) } #endif -static void compute_geom_hints(Frontend *inst, GdkGeometry *geom) +static void compute_geom_hints(GtkFrontend *inst, GdkGeometry *geom) { /* * Unused fields in geom. @@ -4454,7 +4471,7 @@ static void compute_geom_hints(Frontend *inst, GdkGeometry *geom) #endif } -void set_geom_hints(Frontend *inst) +void set_geom_hints(GtkFrontend *inst) { GdkGeometry geom; gint flags = GDK_HINT_MIN_SIZE | GDK_HINT_BASE_SIZE | GDK_HINT_RESIZE_INC; @@ -4468,7 +4485,7 @@ void set_geom_hints(Frontend *inst) } #if GTK_CHECK_VERSION(2,0,0) -static void compute_whole_window_size(Frontend *inst, +static void compute_whole_window_size(GtkFrontend *inst, int wchars, int hchars, int *wpix, int *hpix) { @@ -4481,13 +4498,13 @@ static void compute_whole_window_size(Frontend *inst, void clear_scrollback_menuitem(GtkMenuItem *item, gpointer data) { - Frontend *inst = (Frontend *)data; + GtkFrontend *inst = (GtkFrontend *)data; term_clrsb(inst->term); } void reset_terminal_menuitem(GtkMenuItem *item, gpointer data) { - Frontend *inst = (Frontend *)data; + GtkFrontend *inst = (GtkFrontend *)data; term_pwron(inst->term, TRUE); if (inst->ldisc) ldisc_echoedit_update(inst->ldisc); @@ -4495,27 +4512,27 @@ void reset_terminal_menuitem(GtkMenuItem *item, gpointer data) void copy_clipboard_menuitem(GtkMenuItem *item, gpointer data) { - Frontend *inst = (Frontend *)data; + GtkFrontend *inst = (GtkFrontend *)data; static const int clips[] = { MENU_CLIPBOARD }; term_request_copy(inst->term, clips, lenof(clips)); } void paste_clipboard_menuitem(GtkMenuItem *item, gpointer data) { - Frontend *inst = (Frontend *)data; + GtkFrontend *inst = (GtkFrontend *)data; term_request_paste(inst->term, MENU_CLIPBOARD); } void copy_all_menuitem(GtkMenuItem *item, gpointer data) { - Frontend *inst = (Frontend *)data; + GtkFrontend *inst = (GtkFrontend *)data; static const int clips[] = { COPYALL_CLIPBOARDS }; term_copyall(inst->term, clips, lenof(clips)); } void special_menuitem(GtkMenuItem *item, gpointer data) { - Frontend *inst = (Frontend *)data; + GtkFrontend *inst = (GtkFrontend *)data; SessionSpecial *sc = g_object_get_data(G_OBJECT(item), "user-data"); if (inst->backend) @@ -4524,17 +4541,17 @@ void special_menuitem(GtkMenuItem *item, gpointer data) void about_menuitem(GtkMenuItem *item, gpointer data) { - Frontend *inst = (Frontend *)data; + GtkFrontend *inst = (GtkFrontend *)data; about_box(inst->window); } void event_log_menuitem(GtkMenuItem *item, gpointer data) { - Frontend *inst = (Frontend *)data; + GtkFrontend *inst = (GtkFrontend *)data; showeventlog(inst->eventlogstuff, inst->window); } -void setup_clipboards(Frontend *inst, Terminal *term, Conf *conf) +void setup_clipboards(GtkFrontend *inst, Terminal *term, Conf *conf) { assert(term->mouse_select_clipboards[0] == CLIP_LOCAL); @@ -4596,7 +4613,7 @@ void setup_clipboards(Frontend *inst, Terminal *term, Conf *conf) } struct after_change_settings_dialog_ctx { - Frontend *inst; + GtkFrontend *inst; Conf *newconf; }; @@ -4604,7 +4621,7 @@ static void after_change_settings_dialog(void *vctx, int retval); void change_settings_menuitem(GtkMenuItem *item, gpointer data) { - Frontend *inst = (Frontend *)data; + GtkFrontend *inst = (GtkFrontend *)data; struct after_change_settings_dialog_ctx *ctx; GtkWidget *dialog; char *title; @@ -4637,7 +4654,7 @@ static void after_change_settings_dialog(void *vctx, int retval) }; struct after_change_settings_dialog_ctx ctx = *(struct after_change_settings_dialog_ctx *)vctx; - Frontend *inst = ctx.inst; + GtkFrontend *inst = ctx.inst; Conf *oldconf = inst->conf, *newconf = ctx.newconf; int i, j, need_size; @@ -4730,7 +4747,8 @@ static void after_change_settings_dialog(void *vctx, int retval) */ if (strcmp(conf_get_str(oldconf, CONF_wintitle), conf_get_str(newconf, CONF_wintitle))) - set_title(inst, conf_get_str(newconf, CONF_wintitle)); + win_set_title(&inst->termwin, + conf_get_str(newconf, CONF_wintitle)); set_window_titles(inst); /* @@ -4782,8 +4800,9 @@ static void after_change_settings_dialog(void *vctx, int retval) conf_get_int(newconf, CONF_window_border) || need_size) { set_geom_hints(inst); - request_resize(inst, conf_get_int(newconf, CONF_width), - conf_get_int(newconf, CONF_height)); + win_request_resize(&inst->termwin, + conf_get_int(newconf, CONF_width), + conf_get_int(newconf, CONF_height)); } else { /* * The above will have caused a call to term_size() for @@ -4812,7 +4831,7 @@ static void after_change_settings_dialog(void *vctx, int retval) } } -static void change_font_size(Frontend *inst, int increment) +static void change_font_size(GtkFrontend *inst, int increment) { static const int conf_keys[lenof(inst->fonts)] = { CONF_font, CONF_boldfont, CONF_widefont, CONF_wideboldfont, @@ -4856,8 +4875,8 @@ static void change_font_size(Frontend *inst, int increment) } set_geom_hints(inst); - request_resize(inst, conf_get_int(inst->conf, CONF_width), - conf_get_int(inst->conf, CONF_height)); + win_request_resize(&inst->termwin, conf_get_int(inst->conf, CONF_width), + conf_get_int(inst->conf, CONF_height)); term_invalidate(inst->term); gtk_widget_queue_draw(inst->area); @@ -4875,7 +4894,7 @@ static void change_font_size(Frontend *inst, int increment) void dup_session_menuitem(GtkMenuItem *item, gpointer gdata) { - Frontend *inst = (Frontend *)gdata; + GtkFrontend *inst = (GtkFrontend *)gdata; launch_duplicate_session(inst->conf); } @@ -4887,7 +4906,7 @@ void new_session_menuitem(GtkMenuItem *item, gpointer data) void restart_session_menuitem(GtkMenuItem *item, gpointer data) { - Frontend *inst = (Frontend *)data; + GtkFrontend *inst = (GtkFrontend *)data; if (!inst->backend) { logevent(inst->logctx, "----- Session restarted -----"); @@ -4911,9 +4930,9 @@ void saved_session_freedata(GtkMenuItem *item, gpointer data) sfree(str); } -void app_menu_action(Frontend *frontend, enum MenuAction action) +void app_menu_action(GtkFrontend *frontend, enum MenuAction action) { - Frontend *inst = (Frontend *)frontend; + GtkFrontend *inst = (GtkFrontend *)frontend; switch (action) { case MA_COPY: copy_clipboard_menuitem(NULL, inst); @@ -4947,7 +4966,7 @@ void app_menu_action(Frontend *frontend, enum MenuAction action) static void update_savedsess_menu(GtkMenuItem *menuitem, gpointer data) { - Frontend *inst = (Frontend *)data; + GtkFrontend *inst = (GtkFrontend *)data; struct sesslist sesslist; int i; @@ -5020,7 +5039,7 @@ static void free_special_cmd(gpointer data) { sfree(data); } static void gtk_seat_update_specials_menu(Seat *seat) { - Frontend *inst = container_of(seat, Frontend, seat); + GtkFrontend *inst = container_of(seat, GtkFrontend, seat); const SessionSpecial *specials; if (inst->backend) @@ -5086,7 +5105,7 @@ static void gtk_seat_update_specials_menu(Seat *seat) } } -static void start_backend(Frontend *inst) +static void start_backend(GtkFrontend *inst) { const struct BackendVtable *vt; char *realhost; @@ -5156,16 +5175,46 @@ static void get_monitor_geometry(GtkWidget *widget, GdkRectangle *geometry) } #endif +static const TermWinVtable gtk_termwin_vt = { + gtkwin_setup_draw_ctx, + gtkwin_draw_text, + gtkwin_draw_cursor, + gtkwin_char_width, + gtkwin_free_draw_ctx, + gtkwin_set_cursor_pos, + gtkwin_set_raw_mouse_mode, + gtkwin_set_scrollbar, + gtkwin_bell, + gtkwin_clip_write, + gtkwin_clip_request_paste, + gtkwin_refresh, + gtkwin_request_resize, + gtkwin_set_title, + gtkwin_set_icon_title, + gtkwin_set_minimised, + gtkwin_is_minimised, + gtkwin_set_maximised, + gtkwin_move, + gtkwin_set_zorder, + gtkwin_palette_get, + gtkwin_palette_set, + gtkwin_palette_reset, + gtkwin_get_pos, + gtkwin_get_pixels, + gtkwin_get_title, + gtkwin_is_utf8, +}; + void new_session_window(Conf *conf, const char *geometry_string) { - Frontend *inst; + GtkFrontend *inst; prepare_session(conf); /* * Create an instance structure and initialise to zeroes */ - inst = snew(Frontend); + inst = snew(GtkFrontend); memset(inst, 0, sizeof(*inst)); #ifdef JUST_USE_GTK_CLIPBOARD_UTF8 inst->cdi_headtail.next = inst->cdi_headtail.prev = &inst->cdi_headtail; @@ -5180,6 +5229,7 @@ void new_session_window(Conf *conf, const char *geometry_string) #endif inst->drawing_area_setup_needed = TRUE; + inst->termwin.vt = >k_termwin_vt; inst->seat.vt = >k_seat_vt; inst->logpolicy.vt = >k_logpolicy_vt; @@ -5264,7 +5314,7 @@ void new_session_window(Conf *conf, const char *geometry_string) /* * Set up the colour map. */ - palette_reset(inst); + win_palette_reset(&inst->termwin); inst->width = conf_get_int(inst->conf, CONF_width); inst->height = conf_get_int(inst->conf, CONF_height); @@ -5499,7 +5549,7 @@ void new_session_window(Conf *conf, const char *geometry_string) inst->eventlogstuff = eventlogstuff_new(); - inst->term = term_init(inst->conf, &inst->ucsdata, inst); + inst->term = term_init(inst->conf, &inst->ucsdata, &inst->termwin); setup_clipboards(inst, inst->term, inst->conf); inst->logctx = log_init(&inst->logpolicy, inst->conf); term_provide_logctx(inst->term, inst->logctx); diff --git a/unix/unix.h b/unix/unix.h index 521c5a87..11f9b51d 100644 --- a/unix/unix.h +++ b/unix/unix.h @@ -65,8 +65,6 @@ struct FontSpec { }; struct FontSpec *fontspec_new(const char *name); -typedef struct draw_ctx *Context; - extern const struct BackendVtable pty_backend; #define BROKEN_PIPE_ERROR_CODE EPIPE /* used in sshshare.c */ @@ -158,7 +156,7 @@ unsigned long getticks(void); #endif /* The per-session frontend structure managed by gtkwin.c */ -struct gui_data; +typedef struct GtkFrontend GtkFrontend; /* Callback when a dialog box finishes, and a no-op implementation of it */ typedef void (*post_dialog_fn_t)(void *ctx, int result); @@ -175,7 +173,7 @@ void launch_saved_session(const char *str); void session_window_closed(void); void window_setup_error(const char *errmsg); #ifdef MAY_REFER_TO_GTK_IN_HEADERS -GtkWidget *make_gtk_toplevel_window(Frontend *frontend); +GtkWidget *make_gtk_toplevel_window(GtkFrontend *frontend); #endif const struct BackendVtable *select_backend(Conf *conf); @@ -189,7 +187,7 @@ enum MenuAction { MA_RESTART_SESSION, MA_CHANGE_SETTINGS, MA_CLEAR_SCROLLBACK, MA_RESET_TERMINAL, MA_EVENT_LOG }; -void app_menu_action(Frontend *frontend, enum MenuAction); +void app_menu_action(GtkFrontend *frontend, enum MenuAction); /* Things gtkdlg.c needs from pterm.c */ #ifdef MAY_REFER_TO_GTK_IN_HEADERS diff --git a/windows/windlg.c b/windows/windlg.c index 6dd8bf98..6dae33f9 100644 --- a/windows/windlg.c +++ b/windows/windlg.c @@ -156,7 +156,7 @@ static INT_PTR CALLBACK LogProc(HWND hwnd, UINT msg, memcpy(p, sel_nl, sizeof(sel_nl)); p += sizeof(sel_nl); } - write_aclip(NULL, CLIP_SYSTEM, clipdata, size, TRUE); + write_aclip(CLIP_SYSTEM, clipdata, size, TRUE); sfree(clipdata); } sfree(selitems); diff --git a/windows/window.c b/windows/window.c index 613c1fdc..5a6ddb7a 100644 --- a/windows/window.c +++ b/windows/window.c @@ -227,17 +227,87 @@ static UINT wm_mousewheel = WM_MOUSEWHEEL; (((wch) >= 0x180B && (wch) <= 0x180D) || /* MONGOLIAN FREE VARIATION SELECTOR */ \ ((wch) >= 0xFE00 && (wch) <= 0xFE0F)) /* VARIATION SELECTOR 1-16 */ +static int wintw_setup_draw_ctx(TermWin *); +static void wintw_draw_text(TermWin *, int x, int y, wchar_t *text, int len, + unsigned long attrs, int lattrs, truecolour tc); +static void wintw_draw_cursor(TermWin *, int x, int y, wchar_t *text, int len, + unsigned long attrs, int lattrs, truecolour tc); +static int wintw_char_width(TermWin *, int uc); +static void wintw_free_draw_ctx(TermWin *); +static void wintw_set_cursor_pos(TermWin *, int x, int y); +static void wintw_set_raw_mouse_mode(TermWin *, int enable); +static void wintw_set_scrollbar(TermWin *, int total, int start, int page); +static void wintw_bell(TermWin *, int mode); +static void wintw_clip_write( + TermWin *, int clipboard, wchar_t *text, int *attrs, + truecolour *colours, int len, int must_deselect); +static void wintw_clip_request_paste(TermWin *, int clipboard); +static void wintw_refresh(TermWin *); +static void wintw_request_resize(TermWin *, int w, int h); +static void wintw_set_title(TermWin *, const char *title); +static void wintw_set_icon_title(TermWin *, const char *icontitle); +static void wintw_set_minimised(TermWin *, int minimised); +static int wintw_is_minimised(TermWin *); +static void wintw_set_maximised(TermWin *, int maximised); +static void wintw_move(TermWin *, int x, int y); +static void wintw_set_zorder(TermWin *, int top); +static int wintw_palette_get(TermWin *, int n, int *r, int *g, int *b); +static void wintw_palette_set(TermWin *, int n, int r, int g, int b); +static void wintw_palette_reset(TermWin *); +static void wintw_get_pos(TermWin *, int *x, int *y); +static void wintw_get_pixels(TermWin *, int *x, int *y); +static const char *wintw_get_title(TermWin *, int icon); +static int wintw_is_utf8(TermWin *); + +static const TermWinVtable windows_termwin_vt = { + wintw_setup_draw_ctx, + wintw_draw_text, + wintw_draw_cursor, + wintw_char_width, + wintw_free_draw_ctx, + wintw_set_cursor_pos, + wintw_set_raw_mouse_mode, + wintw_set_scrollbar, + wintw_bell, + wintw_clip_write, + wintw_clip_request_paste, + wintw_refresh, + wintw_request_resize, + wintw_set_title, + wintw_set_icon_title, + wintw_set_minimised, + wintw_is_minimised, + wintw_set_maximised, + wintw_move, + wintw_set_zorder, + wintw_palette_get, + wintw_palette_set, + wintw_palette_reset, + wintw_get_pos, + wintw_get_pixels, + wintw_get_title, + wintw_is_utf8, +}; + +static TermWin wintw[1]; +static HDC wintw_hdc; + const int share_can_be_downstream = TRUE; const int share_can_be_upstream = TRUE; -int frontend_is_utf8(Frontend *frontend) +static int is_utf8(void) { return ucsdata.line_codepage == CP_UTF8; } +static int wintw_is_utf8(TermWin *tw) +{ + return is_utf8(); +} + static int win_seat_is_utf8(Seat *seat) { - return frontend_is_utf8(NULL); + return is_utf8(); } char *win_seat_get_ttymode(Seat *seat, const char *mode) @@ -247,7 +317,7 @@ char *win_seat_get_ttymode(Seat *seat, const char *mode) int win_seat_get_window_pixel_size(Seat *seat, int *x, int *y) { - get_window_pixels(NULL, x, y); + win_get_pixels(wintw, x, y); return TRUE; } @@ -322,8 +392,8 @@ static void start_backend(void) title = msg; } sfree(realhost); - set_title(NULL, title); - set_icon(NULL, title); + win_set_title(wintw, title); + win_set_icon_title(wintw, title); /* * Connect the terminal to the backend for resize purposes. @@ -356,8 +426,8 @@ static void close_session(void *ignored_context) session_closed = TRUE; sprintf(morestuff, "%.70s (inactive)", appname); - set_icon(NULL, morestuff); - set_title(NULL, morestuff); + win_set_icon_title(wintw, morestuff); + win_set_title(wintw, morestuff); if (ldisc) { ldisc_free(ldisc); @@ -667,7 +737,8 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) * which will call schedule_timer(), which will in turn call * timer_change_notify() which will expect hwnd to exist.) */ - term = term_init(conf, &ucsdata, NULL); + wintw->vt = &windows_termwin_vt; + term = term_init(conf, &ucsdata, wintw); setup_clipboards(term, conf); logctx = log_init(default_logpolicy, conf); term_provide_logctx(term, logctx); @@ -1095,7 +1166,7 @@ static void win_seat_set_busy_status(Seat *seat, BusyStatus status) /* * set or clear the "raw mouse message" mode */ -void set_raw_mouse_mode(Frontend *frontend, int activate) +static void wintw_set_raw_mouse_mode(TermWin *tw, int activate) { activate = activate && !conf_get_int(conf, CONF_no_mouse_rep); send_raw_mouse = activate; @@ -1651,7 +1722,7 @@ static void deinit_fonts(void) } } -void request_resize(Frontend *frontend, int w, int h) +static void wintw_request_resize(TermWin *tw, int w, int h) { int width, height; @@ -2046,6 +2117,28 @@ static void conf_cache_data(void) static const int clips_system[] = { CLIP_SYSTEM }; +static HDC make_hdc(void) +{ + HDC hdc; + + if (!hwnd) + return NULL; + + hdc = GetDC(hwnd); + if (!hdc) + return NULL; + + SelectPalette(hdc, pal, FALSE); + return hdc; +} + +static void free_hdc(HDC hdc) +{ + assert(hwnd); + SelectPalette(hdc, GetStockObject(DEFAULT_PALETTE), FALSE); + ReleaseDC(hwnd, hdc); +} + static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { @@ -2348,7 +2441,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, init_lvl = 2; } - set_title(NULL, conf_get_str(conf, CONF_wintitle)); + win_set_title(wintw, conf_get_str(conf, CONF_wintitle)); if (IsIconic(hwnd)) { SetWindowText(hwnd, conf_get_int(conf, CONF_win_name_always) ? @@ -2671,12 +2764,15 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, * current terminal appearance so that WM_PAINT becomes * completely trivial. However, this should do for now. */ - term_paint(term, hdc, + assert(!wintw_hdc); + wintw_hdc = hdc; + term_paint(term, (p.rcPaint.left-offset_width)/font_width, (p.rcPaint.top-offset_height)/font_height, (p.rcPaint.right-offset_width-1)/font_width, (p.rcPaint.bottom-offset_height-1)/font_height, !term->window_update_pending); + wintw_hdc = NULL; if (p.fErase || p.rcPaint.left < offset_width || @@ -3043,21 +3139,21 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, break; case WM_PALETTECHANGED: if ((HWND) wParam != hwnd && pal != NULL) { - HDC hdc = get_ctx(NULL); + HDC hdc = make_hdc(); if (hdc) { if (RealizePalette(hdc) > 0) UpdateColors(hdc); - free_ctx(hdc); + free_hdc(hdc); } } break; case WM_QUERYNEWPALETTE: if (pal != NULL) { - HDC hdc = get_ctx(NULL); + HDC hdc = make_hdc(); if (hdc) { if (RealizePalette(hdc) > 0) UpdateColors(hdc); - free_ctx(hdc); + free_hdc(hdc); return TRUE; } } @@ -3308,7 +3404,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, * helper software tracks the system caret, so we should arrange to * have one.) */ -void sys_cursor(Frontend *frontend, int x, int y) +static void wintw_set_cursor_pos(TermWin *tw, int x, int y) { int cx, cy; @@ -3362,12 +3458,12 @@ static void sys_cursor_update(void) * * We are allowed to fiddle with the contents of `text'. */ -void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, - unsigned long attr, int lattr, truecolour truecolour) +static void do_text_internal( + int x, int y, wchar_t *text, int len, + unsigned long attr, int lattr, truecolour truecolour) { COLORREF fg, bg, t; int nfg, nbg, nfont; - HDC hdc = ctx; RECT line_box; int force_manual_underline = 0; int fnt_width, char_width; @@ -3513,13 +3609,13 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, GetBValue(fg) * 2 / 3); } - SelectObject(hdc, fonts[nfont]); - SetTextColor(hdc, fg); - SetBkColor(hdc, bg); + SelectObject(wintw_hdc, fonts[nfont]); + SetTextColor(wintw_hdc, fg); + SetBkColor(wintw_hdc, bg); if (attr & TATTR_COMBINING) - SetBkMode(hdc, TRANSPARENT); + SetBkMode(wintw_hdc, TRANSPARENT); else - SetBkMode(hdc, OPAQUE); + SetBkMode(wintw_hdc, OPAQUE); line_box.left = x; line_box.top = y; line_box.right = x + char_width * len; @@ -3556,7 +3652,7 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, * generally reasonable results. */ xoffset = char_width / 2; - SetTextAlign(hdc, TA_TOP | TA_CENTER | TA_NOUPDATECP); + SetTextAlign(wintw_hdc, TA_TOP | TA_CENTER | TA_NOUPDATECP); lpDx_maybe = NULL; maxlen = 1; } else { @@ -3565,7 +3661,7 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, * in the normal way. */ xoffset = 0; - SetTextAlign(hdc, TA_TOP | TA_LEFT | TA_NOUPDATECP); + SetTextAlign(wintw_hdc, TA_TOP | TA_LEFT | TA_NOUPDATECP); lpDx_maybe = lpDx; maxlen = len; } @@ -3652,14 +3748,14 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, if (nlen <= 0) return; /* Eeek! */ - ExtTextOutW(hdc, x + xoffset, + ExtTextOutW(wintw_hdc, x + xoffset, y - font_height * (lattr == LATTR_BOT) + text_adjust, ETO_CLIPPED | (opaque ? ETO_OPAQUE : 0), &line_box, uni_buf, nlen, lpDx_maybe); if (bold_font_mode == BOLD_SHADOW && (attr & ATTR_BOLD)) { - SetBkMode(hdc, TRANSPARENT); - ExtTextOutW(hdc, x + xoffset - 1, + SetBkMode(wintw_hdc, TRANSPARENT); + ExtTextOutW(wintw_hdc, x + xoffset - 1, y - font_height * (lattr == LATTR_BOT) + text_adjust, ETO_CLIPPED, &line_box, uni_buf, nlen, lpDx_maybe); @@ -3678,12 +3774,12 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, for (i = 0; i < len; i++) directbuf[i] = text[i] & 0xFF; - ExtTextOut(hdc, x + xoffset, + ExtTextOut(wintw_hdc, x + xoffset, y - font_height * (lattr == LATTR_BOT) + text_adjust, ETO_CLIPPED | (opaque ? ETO_OPAQUE : 0), &line_box, directbuf, len, lpDx_maybe); if (bold_font_mode == BOLD_SHADOW && (attr & ATTR_BOLD)) { - SetBkMode(hdc, TRANSPARENT); + SetBkMode(wintw_hdc, TRANSPARENT); /* GRR: This draws the character outside its box and * can leave 'droppings' even with the clip box! I @@ -3694,7 +3790,7 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, * or -1 for this shift depending on if the leftmost * column is blank... */ - ExtTextOut(hdc, x + xoffset - 1, + ExtTextOut(wintw_hdc, x + xoffset - 1, y - font_height * (lattr == LATTR_BOT) + text_adjust, ETO_CLIPPED, &line_box, directbuf, len, lpDx_maybe); @@ -3715,15 +3811,15 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, wbuf[i] = text[i]; /* print Glyphs as they are, without Windows' Shaping*/ - general_textout(hdc, x + xoffset, + general_textout(wintw_hdc, x + xoffset, y - font_height * (lattr==LATTR_BOT) + text_adjust, &line_box, wbuf, len, lpDx, opaque && !(attr & TATTR_COMBINING)); /* And the shadow bold hack. */ if (bold_font_mode == BOLD_SHADOW && (attr & ATTR_BOLD)) { - SetBkMode(hdc, TRANSPARENT); - ExtTextOutW(hdc, x + xoffset - 1, + SetBkMode(wintw_hdc, TRANSPARENT); + ExtTextOutW(wintw_hdc, x + xoffset - 1, y - font_height * (lattr == LATTR_BOT) + text_adjust, ETO_CLIPPED, &line_box, wbuf, len, lpDx_maybe); @@ -3734,7 +3830,7 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, * If we're looping round again, stop erasing the background * rectangle. */ - SetBkMode(hdc, TRANSPARENT); + SetBkMode(wintw_hdc, TRANSPARENT); opaque = FALSE; } if (lattr != LATTR_TOP && (force_manual_underline || @@ -3745,10 +3841,10 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, if (lattr == LATTR_BOT) dec = dec * 2 - font_height; - oldpen = SelectObject(hdc, CreatePen(PS_SOLID, 0, fg)); - MoveToEx(hdc, line_box.left, line_box.top + dec, NULL); - LineTo(hdc, line_box.right, line_box.top + dec); - oldpen = SelectObject(hdc, oldpen); + oldpen = SelectObject(wintw_hdc, CreatePen(PS_SOLID, 0, fg)); + MoveToEx(wintw_hdc, line_box.left, line_box.top + dec, NULL); + LineTo(wintw_hdc, line_box.right, line_box.top + dec); + oldpen = SelectObject(wintw_hdc, oldpen); DeleteObject(oldpen); } } @@ -3756,8 +3852,9 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, /* * Wrapper that handles combining characters. */ -void do_text(Context ctx, int x, int y, wchar_t *text, int len, - unsigned long attr, int lattr, truecolour truecolour) +static void wintw_draw_text( + TermWin *tw, int x, int y, wchar_t *text, int len, + unsigned long attr, int lattr, truecolour truecolour) { if (attr & TATTR_COMBINING) { unsigned long a = 0; @@ -3767,13 +3864,13 @@ void do_text(Context ctx, int x, int y, wchar_t *text, int len, len0 = 2; if (len-len0 >= 1 && IS_LOW_VARSEL(text[len0])) { attr &= ~TATTR_COMBINING; - do_text_internal(ctx, x, y, text, len0+1, attr, lattr, truecolour); + do_text_internal(x, y, text, len0+1, attr, lattr, truecolour); text += len0+1; len -= len0+1; a = TATTR_COMBINING; } else if (len-len0 >= 2 && IS_HIGH_VARSEL(text[len0], text[len0+1])) { attr &= ~TATTR_COMBINING; - do_text_internal(ctx, x, y, text, len0+2, attr, lattr, truecolour); + do_text_internal(x, y, text, len0+2, attr, lattr, truecolour); text += len0+2; len -= len0+2; a = TATTR_COMBINING; @@ -3783,33 +3880,32 @@ void do_text(Context ctx, int x, int y, wchar_t *text, int len, while (len--) { if (len >= 1 && IS_SURROGATE_PAIR(text[0], text[1])) { - do_text_internal(ctx, x, y, text, 2, attr | a, lattr, truecolour); + do_text_internal(x, y, text, 2, attr | a, lattr, truecolour); len--; text++; } else - do_text_internal(ctx, x, y, text, 1, attr | a, lattr, truecolour); + do_text_internal(x, y, text, 1, attr | a, lattr, truecolour); text++; a = TATTR_COMBINING; } } else - do_text_internal(ctx, x, y, text, len, attr, lattr, truecolour); + do_text_internal(x, y, text, len, attr, lattr, truecolour); } -void do_cursor(Context ctx, int x, int y, wchar_t *text, int len, - unsigned long attr, int lattr, truecolour truecolour) +static void wintw_draw_cursor( + TermWin *tw, int x, int y, wchar_t *text, int len, + unsigned long attr, int lattr, truecolour truecolour) { - int fnt_width; int char_width; - HDC hdc = ctx; int ctype = cursor_type; lattr &= LATTR_MODE; if ((attr & TATTR_ACTCURS) && (ctype == 0 || term->big_cursor)) { if (*text != UCSWIDE) { - do_text(ctx, x, y, text, len, attr, lattr, truecolour); + win_draw_text(tw, x, y, text, len, attr, lattr, truecolour); return; } ctype = 2; @@ -3831,9 +3927,9 @@ void do_cursor(Context ctx, int x, int y, wchar_t *text, int len, pts[2].x = pts[3].x = x + char_width - 1; pts[0].y = pts[3].y = pts[4].y = y; pts[1].y = pts[2].y = y + font_height - 1; - oldpen = SelectObject(hdc, CreatePen(PS_SOLID, 0, colours[261])); - Polyline(hdc, pts, 5); - oldpen = SelectObject(hdc, oldpen); + oldpen = SelectObject(wintw_hdc, CreatePen(PS_SOLID, 0, colours[261])); + Polyline(wintw_hdc, pts, 5); + oldpen = SelectObject(wintw_hdc, oldpen); DeleteObject(oldpen); } else if ((attr & (TATTR_ACTCURS | TATTR_PASCURS)) && ctype != 0) { int startx, starty, dx, dy, length, i; @@ -3856,15 +3952,15 @@ void do_cursor(Context ctx, int x, int y, wchar_t *text, int len, if (attr & TATTR_ACTCURS) { HPEN oldpen; oldpen = - SelectObject(hdc, CreatePen(PS_SOLID, 0, colours[261])); - MoveToEx(hdc, startx, starty, NULL); - LineTo(hdc, startx + dx * length, starty + dy * length); - oldpen = SelectObject(hdc, oldpen); + SelectObject(wintw_hdc, CreatePen(PS_SOLID, 0, colours[261])); + MoveToEx(wintw_hdc, startx, starty, NULL); + LineTo(wintw_hdc, startx + dx * length, starty + dy * length); + oldpen = SelectObject(wintw_hdc, oldpen); DeleteObject(oldpen); } else { for (i = 0; i < length; i++) { if (i % 2 == 0) { - SetPixel(hdc, startx, starty, colours[261]); + SetPixel(wintw_hdc, startx, starty, colours[261]); } startx += dx; starty += dy; @@ -3875,8 +3971,8 @@ void do_cursor(Context ctx, int x, int y, wchar_t *text, int len, /* This function gets the actual width of a character in the normal font. */ -int char_width(Context ctx, int uc) { - HDC hdc = ctx; +static int wintw_char_width(TermWin *tw, int uc) +{ int ibuf = 0; /* If the font max is the same as the font ave width then this @@ -3903,26 +3999,28 @@ int char_width(Context ctx, int uc) { return 1; if ( (uc & CSET_MASK) == CSET_ACP ) { - SelectObject(hdc, fonts[FONT_NORMAL]); + SelectObject(wintw_hdc, fonts[FONT_NORMAL]); } else if ( (uc & CSET_MASK) == CSET_OEMCP ) { another_font(FONT_OEM); if (!fonts[FONT_OEM]) return 0; - SelectObject(hdc, fonts[FONT_OEM]); + SelectObject(wintw_hdc, fonts[FONT_OEM]); } else return 0; - if ( GetCharWidth32(hdc, uc&~CSET_MASK, uc&~CSET_MASK, &ibuf) != 1 && - GetCharWidth(hdc, uc&~CSET_MASK, uc&~CSET_MASK, &ibuf) != 1) + if (GetCharWidth32(wintw_hdc, uc & ~CSET_MASK, + uc & ~CSET_MASK, &ibuf) != 1 && + GetCharWidth(wintw_hdc, uc & ~CSET_MASK, + uc & ~CSET_MASK, &ibuf) != 1) return 0; } else { /* Speedup, I know of no font where ascii is the wrong width */ if (uc >= ' ' && uc <= '~') return 1; - SelectObject(hdc, fonts[FONT_NORMAL]); - if ( GetCharWidth32W(hdc, uc, uc, &ibuf) == 1 ) + SelectObject(wintw_hdc, fonts[FONT_NORMAL]); + if (GetCharWidth32W(wintw_hdc, uc, uc, &ibuf) == 1) /* Okay that one worked */ ; - else if ( GetCharWidthW(hdc, uc, uc, &ibuf) == 1 ) + else if (GetCharWidthW(wintw_hdc, uc, uc, &ibuf) == 1) /* This should work on 9x too, but it's "less accurate" */ ; else return 0; @@ -4844,7 +4942,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, return -1; } -void set_title(Frontend *frontend, char *title) +static void wintw_set_title(TermWin *tw, const char *title) { sfree(window_name); window_name = snewn(1 + strlen(title), char); @@ -4853,7 +4951,7 @@ void set_title(Frontend *frontend, char *title) SetWindowText(hwnd, title); } -void set_icon(Frontend *frontend, char *title) +static void wintw_set_icon_title(TermWin *tw, const char *title) { sfree(icon_name); icon_name = snewn(1 + strlen(title), char); @@ -4862,7 +4960,7 @@ void set_icon(Frontend *frontend, char *title) SetWindowText(hwnd, title); } -void set_sbar(Frontend *frontend, int total, int start, int page) +static void wintw_set_scrollbar(TermWin *tw, int total, int start, int page) { SCROLLINFO si; @@ -4880,22 +4978,18 @@ void set_sbar(Frontend *frontend, int total, int start, int page) SetScrollInfo(hwnd, SB_VERT, &si, TRUE); } -Context get_ctx(Frontend *frontend) +static int wintw_setup_draw_ctx(TermWin *tw) { - HDC hdc; - if (hwnd) { - hdc = GetDC(hwnd); - if (hdc && pal) - SelectPalette(hdc, pal, FALSE); - return hdc; - } else - return NULL; + assert(!wintw_hdc); + wintw_hdc = make_hdc(); + return wintw_hdc != NULL; } -void free_ctx(Context ctx) +static void wintw_free_draw_ctx(TermWin *tw) { - SelectPalette(ctx, GetStockObject(DEFAULT_PALETTE), FALSE); - ReleaseDC(hwnd, ctx); + assert(wintw_hdc); + free_hdc(wintw_hdc); + wintw_hdc = NULL; } static void real_palette_set(int n, int r, int g, int b) @@ -4910,7 +5004,7 @@ static void real_palette_set(int n, int r, int g, int b) } } -int palette_get(Frontend *frontend, int n, int *r, int *g, int *b) +static int wintw_palette_get(TermWin *tw, int n, int *r, int *g, int *b) { if (n < 0 || n >= NALLCOLOURS) return FALSE; @@ -4920,7 +5014,7 @@ int palette_get(Frontend *frontend, int n, int *r, int *g, int *b) return TRUE; } -void palette_set(Frontend *frontend, int n, int r, int g, int b) +static void wintw_palette_set(TermWin *tw, int n, int r, int g, int b) { if (n >= 16) n += 256 - 16; @@ -4928,10 +5022,10 @@ void palette_set(Frontend *frontend, int n, int r, int g, int b) return; real_palette_set(n, r, g, b); if (pal) { - HDC hdc = get_ctx(frontend); + HDC hdc = make_hdc(); UnrealizeObject(pal); RealizePalette(hdc); - free_ctx(hdc); + free_hdc(hdc); } else { if (n == (ATTR_DEFBG>>ATTR_BGSHIFT)) /* If Default Background changes, we need to ensure any @@ -4941,7 +5035,7 @@ void palette_set(Frontend *frontend, int n, int r, int g, int b) } } -void palette_reset(Frontend *frontend) +static void wintw_palette_reset(TermWin *tw) { int i; @@ -4960,9 +5054,9 @@ void palette_reset(Frontend *frontend) if (pal) { HDC hdc; SetPaletteEntries(pal, 0, NALLCOLOURS, logpal->palPalEntry); - hdc = get_ctx(frontend); + hdc = make_hdc(); RealizePalette(hdc); - free_ctx(hdc); + free_hdc(hdc); } else { /* Default Background may have changed. Ensure any space between * text area and window border is redrawn. */ @@ -4970,8 +5064,7 @@ void palette_reset(Frontend *frontend) } } -void write_aclip(Frontend *frontend, int clipboard, - char *data, int len, int must_deselect) +void write_aclip(int clipboard, char *data, int len, int must_deselect) { HGLOBAL clipdata; void *lock; @@ -5018,9 +5111,9 @@ int cmpCOLORREF(void *va, void *vb) /* * Note: unlike write_aclip() this will not append a nul. */ -void write_clip(Frontend *frontend, int clipboard, - wchar_t *data, int *attr, truecolour *truecolour, int len, - int must_deselect) +static void wintw_clip_write( + TermWin *tw, int clipboard, wchar_t *data, int *attr, + truecolour *truecolour, int len, int must_deselect) { HGLOBAL clipdata, clipdata2, clipdata3; int len2; @@ -5489,7 +5582,7 @@ static void process_clipdata(HGLOBAL clipdata, int unicode) sfree(clipboard_contents); } -void frontend_request_paste(Frontend *frontend, int clipboard) +static void wintw_clip_request_paste(TermWin *tw, int clipboard) { assert(clipboard == CLIP_SYSTEM); @@ -5628,7 +5721,7 @@ static void flash_window(int mode) /* * Beep. */ -void do_beep(Frontend *frontend, int mode) +static void wintw_bell(TermWin *tw, int mode) { if (mode == BELL_DEFAULT) { /* @@ -5690,13 +5783,13 @@ void do_beep(Frontend *frontend, int mode) * Minimise or restore the window in response to a server-side * request. */ -void set_iconic(Frontend *frontend, int iconic) +static void wintw_set_minimised(TermWin *tw, int minimised) { if (IsIconic(hwnd)) { - if (!iconic) + if (!minimised) ShowWindow(hwnd, SW_RESTORE); } else { - if (iconic) + if (minimised) ShowWindow(hwnd, SW_MINIMIZE); } } @@ -5704,7 +5797,7 @@ void set_iconic(Frontend *frontend, int iconic) /* * Move the window in response to a server-side request. */ -void move_window(Frontend *frontend, int x, int y) +static void wintw_move(TermWin *tw, int x, int y) { int resize_action = conf_get_int(conf, CONF_resize_action); if (resize_action == RESIZE_DISABLED || @@ -5719,7 +5812,7 @@ void move_window(Frontend *frontend, int x, int y) * Move the window to the top or bottom of the z-order in response * to a server-side request. */ -void set_zorder(Frontend *frontend, int top) +static void wintw_set_zorder(TermWin *tw, int top) { if (conf_get_int(conf, CONF_alwaysontop)) return; /* ignore */ @@ -5730,7 +5823,7 @@ void set_zorder(Frontend *frontend, int top) /* * Refresh the window in response to a server-side request. */ -void refresh_window(Frontend *frontend) +static void wintw_refresh(TermWin *tw) { InvalidateRect(hwnd, NULL, TRUE); } @@ -5739,13 +5832,13 @@ void refresh_window(Frontend *frontend) * Maximise or restore the window in response to a server-side * request. */ -void set_zoomed(Frontend *frontend, int zoomed) +static void wintw_set_maximised(TermWin *tw, int maximised) { if (IsZoomed(hwnd)) { - if (!zoomed) + if (!maximised) ShowWindow(hwnd, SW_RESTORE); } else { - if (zoomed) + if (maximised) ShowWindow(hwnd, SW_MAXIMIZE); } } @@ -5753,7 +5846,7 @@ void set_zoomed(Frontend *frontend, int zoomed) /* * Report whether the window is iconic, for terminal reports. */ -int is_iconic(Frontend *frontend) +static int wintw_is_minimised(TermWin *tw) { return IsIconic(hwnd); } @@ -5761,7 +5854,7 @@ int is_iconic(Frontend *frontend) /* * Report the window's position, for terminal reports. */ -void get_window_pos(Frontend *frontend, int *x, int *y) +static void wintw_get_pos(TermWin *tw, int *x, int *y) { RECT r; GetWindowRect(hwnd, &r); @@ -5772,7 +5865,7 @@ void get_window_pos(Frontend *frontend, int *x, int *y) /* * Report the window's pixel size, for terminal reports. */ -void get_window_pixels(Frontend *frontend, int *x, int *y) +static void wintw_get_pixels(TermWin *tw, int *x, int *y) { RECT r; GetWindowRect(hwnd, &r); @@ -5783,7 +5876,7 @@ void get_window_pixels(Frontend *frontend, int *x, int *y) /* * Return the window or icon title. */ -char *get_window_title(Frontend *frontend, int icon) +static const char *wintw_get_title(TermWin *tw, int icon) { return icon ? icon_name : window_name; } diff --git a/windows/winstuff.h b/windows/winstuff.h index 3708e2e6..0a55be89 100644 --- a/windows/winstuff.h +++ b/windows/winstuff.h @@ -195,8 +195,6 @@ struct FontSpec *fontspec_new(const char *name, #define DEFAULT_CODEPAGE CP_ACP #define USES_VTLINE_HACK -typedef HDC Context; - #ifndef NO_GSSAPI /* * GSS-API stuff @@ -261,7 +259,7 @@ int win_seat_confirm_weak_cached_hostkey( * which takes the data string in the system code page instead of * Unicode. */ -void write_aclip(Frontend *frontend, int clipboard, char *, int, int); +void write_aclip(int clipboard, char *, int, int); #define WM_NETEVENT (WM_APP + 5) From 6750eb73ab645fbd64866b6905cc3f563177a3b7 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Fri, 26 Oct 2018 23:05:53 +0100 Subject: [PATCH 578/607] Fix build failure on GTK 2. In the TermWin revamp, I forgot to make sure I'd changed all the ifdef branches for different major versions of GTK. --- unix/gtkwin.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unix/gtkwin.c b/unix/gtkwin.c index 0868d2fd..d56c1ee5 100644 --- a/unix/gtkwin.c +++ b/unix/gtkwin.c @@ -2635,7 +2635,7 @@ static void gtkwin_request_resize(TermWin *tw, int w, int h) * bogus size request which guarantees to be bigger than the * current size of the drawing area. */ - get_window_pixels(inst, &large_x, &large_y); + win_get_pixels(&inst->termwin, &large_x, &large_y); large_x += 32; large_y += 32; From ab89fd7847b1670cf9eae2b91d4535f71e9c290c Mon Sep 17 00:00:00 2001 From: Pavel Kryukov Date: Fri, 26 Oct 2018 17:37:32 +0300 Subject: [PATCH 579/607] scpserver.c: add missing brackets around mask checks --- scpserver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scpserver.c b/scpserver.c index 5e90103a..74efc579 100644 --- a/scpserver.c +++ b/scpserver.c @@ -469,7 +469,7 @@ static void scp_source_push_name( return; } } else { - if (!attrs.flags & SSH_FILEXFER_ATTR_SIZE) { + if (!(attrs.flags & SSH_FILEXFER_ATTR_SIZE)) { scp_source_err(scp, "unable to read file size for %.*s", PTRLEN_PRINTF(pathname)); return; From 730af28b996cce2118b8cd4d11988dbe155f347e Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 28 Oct 2018 09:14:53 +0000 Subject: [PATCH 580/607] Stop using deprecated gtk_container_set_focus_chain(). In GTK 2, this function was a new and convenient way to override the order in which the Tab key cycled through the sub-widgets of a container, replacing the more verbose mechanism in GTK 1 where you had to provide a custom implementation of the "focus" method in GtkContainerClass. GTK 3.24 has now deprecated gtk_container_set_focus_chain(), apparently on the grounds that that old system is what they think you _ought_ to be doing. So I've abandoned set_focus_chain completely, and switched back to doing it by a custom focus method for _all_ versions of GTK, with the only slight wrinkle being that between GTK 1 and 2 the method in question moved from GtkContainer to GtkWidget (my guess is so that an individual non-container widget can still have multiple separately focusable UI components). --- unix/gtkcols.c | 72 +++++++++++++++++++++++------------------------- unix/gtkcompat.h | 5 ++++ 2 files changed, 39 insertions(+), 38 deletions(-) diff --git a/unix/gtkcols.c b/unix/gtkcols.c index ef060d63..60e39441 100644 --- a/unix/gtkcols.c +++ b/unix/gtkcols.c @@ -6,6 +6,18 @@ #include "gtkcompat.h" #include "gtkcols.h" +#if GTK_CHECK_VERSION(2,0,0) +/* The "focus" method lives in GtkWidget from GTK 2 onwards, but it + * was in GtkContainer in GTK 1 */ +#define FOCUS_METHOD_SUPERCLASS GtkWidget +#define FOCUS_METHOD_LOCATION widget_class /* used in columns_init */ +#define CHILD_FOCUS(cont, dir) gtk_widget_child_focus(GTK_WIDGET(cont), dir) +#else +#define FOCUS_METHOD_SUPERCLASS GtkContainer +#define FOCUS_METHOD_LOCATION container_class +#define CHILD_FOCUS(cont, dir) gtk_container_focus(GTK_CONTAINER(cont), dir) +#endif + static void columns_init(Columns *cols); static void columns_class_init(ColumnsClass *klass); #if !GTK_CHECK_VERSION(2,0,0) @@ -23,9 +35,8 @@ static void columns_base_add(GtkContainer *container, GtkWidget *widget); static void columns_remove(GtkContainer *container, GtkWidget *widget); static void columns_forall(GtkContainer *container, gboolean include_internals, GtkCallback callback, gpointer callback_data); -#if !GTK_CHECK_VERSION(2,0,0) -static gint columns_focus(GtkContainer *container, GtkDirectionType dir); -#endif +static gint columns_focus(FOCUS_METHOD_SUPERCLASS *container, + GtkDirectionType dir); static GType columns_child_type(GtkContainer *container); #if GTK_CHECK_VERSION(3,0,0) static void columns_get_preferred_width(GtkWidget *widget, @@ -93,10 +104,8 @@ GType columns_get_type(void) } #endif -#if !GTK_CHECK_VERSION(2,0,0) -static gint (*columns_inherited_focus)(GtkContainer *container, +static gint (*columns_inherited_focus)(FOCUS_METHOD_SUPERCLASS *container, GtkDirectionType direction); -#endif static void columns_class_init(ColumnsClass *klass) { @@ -139,12 +148,11 @@ static void columns_class_init(ColumnsClass *klass) container_class->remove = columns_remove; container_class->forall = columns_forall; container_class->child_type = columns_child_type; -#if !GTK_CHECK_VERSION(2,0,0) + /* Save the previous value of this method. */ if (!columns_inherited_focus) - columns_inherited_focus = container_class->focus; - container_class->focus = columns_focus; -#endif + columns_inherited_focus = FOCUS_METHOD_LOCATION->focus; + FOCUS_METHOD_LOCATION->focus = columns_focus; } static void columns_init(Columns *cols) @@ -362,9 +370,6 @@ static void columns_remove(GtkContainer *container, GtkWidget *widget) cols->taborder = g_list_remove_link(cols->taborder, children); g_list_free(children); -#if GTK_CHECK_VERSION(2,0,0) - gtk_container_set_focus_chain(container, cols->taborder); -#endif break; } } @@ -463,10 +468,6 @@ void columns_add(Columns *cols, GtkWidget *child, gtk_widget_set_parent(child, GTK_WIDGET(cols)); -#if GTK_CHECK_VERSION(2,0,0) - gtk_container_set_focus_chain(GTK_CONTAINER(cols), cols->taborder); -#endif - if (gtk_widget_get_realized(GTK_WIDGET(cols))) gtk_widget_realize(child); @@ -548,38 +549,34 @@ void columns_taborder_last(Columns *cols, GtkWidget *widget) cols->taborder = g_list_remove_link(cols->taborder, children); g_list_free(children); cols->taborder = g_list_append(cols->taborder, widget); -#if GTK_CHECK_VERSION(2,0,0) - gtk_container_set_focus_chain(GTK_CONTAINER(cols), cols->taborder); -#endif break; } } -#if !GTK_CHECK_VERSION(2,0,0) /* * Override GtkContainer's focus movement so the user can * explicitly specify the tab order. */ -static gint columns_focus(GtkContainer *container, GtkDirectionType dir) +static gint columns_focus(FOCUS_METHOD_SUPERCLASS *super, GtkDirectionType dir) { Columns *cols; GList *pos; GtkWidget *focuschild; - g_return_val_if_fail(container != NULL, FALSE); - g_return_val_if_fail(IS_COLUMNS(container), FALSE); + g_return_val_if_fail(super != NULL, FALSE); + g_return_val_if_fail(IS_COLUMNS(super), FALSE); - cols = COLUMNS(container); + cols = COLUMNS(super); - if (!GTK_WIDGET_DRAWABLE(cols) || - !GTK_WIDGET_IS_SENSITIVE(cols)) + if (!gtk_widget_is_drawable(GTK_WIDGET(cols)) || + !gtk_widget_is_sensitive(GTK_WIDGET(cols))) return FALSE; - if (!GTK_WIDGET_CAN_FOCUS(container) && + if (!gtk_widget_get_can_focus(GTK_WIDGET(cols)) && (dir == GTK_DIR_TAB_FORWARD || dir == GTK_DIR_TAB_BACKWARD)) { - focuschild = container->focus_child; - gtk_container_set_focus_child(container, NULL); + focuschild = gtk_container_get_focus_child(GTK_CONTAINER(cols)); + gtk_container_set_focus_child(GTK_CONTAINER(cols), NULL); if (dir == GTK_DIR_TAB_FORWARD) pos = cols->taborder; @@ -592,18 +589,18 @@ static gint columns_focus(GtkContainer *container, GtkDirectionType dir) if (focuschild) { if (focuschild == child) { focuschild = NULL; /* now we can start looking in here */ - if (GTK_WIDGET_DRAWABLE(child) && + if (gtk_widget_is_drawable(child) && GTK_IS_CONTAINER(child) && - !GTK_WIDGET_HAS_FOCUS(child)) { - if (gtk_container_focus(GTK_CONTAINER(child), dir)) + !gtk_widget_has_focus(child)) { + if (CHILD_FOCUS(child, dir)) return TRUE; } } - } else if (GTK_WIDGET_DRAWABLE(child)) { + } else if (gtk_widget_is_drawable(child)) { if (GTK_IS_CONTAINER(child)) { - if (gtk_container_focus(GTK_CONTAINER(child), dir)) + if (CHILD_FOCUS(child, dir)) return TRUE; - } else if (GTK_WIDGET_CAN_FOCUS(child)) { + } else if (gtk_widget_get_can_focus(child)) { gtk_widget_grab_focus(child); return TRUE; } @@ -617,9 +614,8 @@ static gint columns_focus(GtkContainer *container, GtkDirectionType dir) return FALSE; } else - return columns_inherited_focus(container, dir); + return columns_inherited_focus(super, dir); } -#endif /* * Underlying parts of the layout algorithm, to compute the Columns diff --git a/unix/gtkcompat.h b/unix/gtkcompat.h index 03947a79..fe070720 100644 --- a/unix/gtkcompat.h +++ b/unix/gtkcompat.h @@ -53,6 +53,7 @@ #define gtk_widget_get_parent(w) ((w)->parent) #define gtk_widget_set_allocation(w, a) ((w)->allocation = *(a)) #define gtk_container_get_border_width(c) ((c)->border_width) +#define gtk_container_get_focus_child(c) ((c)->focus_child) #define gtk_bin_get_child(b) ((b)->child) #define gtk_color_selection_dialog_get_color_selection(cs) ((cs)->colorsel) #define gtk_selection_data_get_target(sd) ((sd)->target) @@ -79,6 +80,10 @@ #define gtk_widget_get_mapped(w) GTK_WIDGET_MAPPED(w) #define gtk_widget_get_realized(w) GTK_WIDGET_REALIZED(w) #define gtk_widget_get_state(w) GTK_WIDGET_STATE(w) +#define gtk_widget_get_can_focus(w) GTK_WIDGET_CAN_FOCUS(w) +#define gtk_widget_is_drawable(w) GTK_WIDGET_DRAWABLE(w) +#define gtk_widget_is_sensitive(w) GTK_WIDGET_IS_SENSITIVE(w) +#define gtk_widget_has_focus(w) GTK_WIDGET_HAS_FOCUS(w) /* This is a bit of a bodge because it relies on us only calling this * macro as GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), so under From 23e98b0afb7284faac564c22a5595ebdcd983607 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Mon, 29 Oct 2018 07:23:32 +0000 Subject: [PATCH 581/607] Uppity: support SSH-2 password change request. This is the first time I've _ever_ been able to test that feature of the client userauth code personally, and pleasingly, it seems to work fine. --- ssh1login-server.c | 2 +- ssh2userauth-server.c | 24 +++++++++++++++++++----- sshserver.h | 7 ++++++- unix/uxserver.c | 31 +++++++++++++++++++++++++++++-- 4 files changed, 55 insertions(+), 9 deletions(-) diff --git a/ssh1login-server.c b/ssh1login-server.c index 359dcf98..4e3f5a92 100644 --- a/ssh1login-server.c +++ b/ssh1login-server.c @@ -280,7 +280,7 @@ static void ssh1_login_server_process_queue(PacketProtocolLayer *ppl) if (nul) password.len = (const char *)nul - (const char *)password.ptr; - if (auth_password(s->authpolicy, s->username, password)) + if (auth_password(s->authpolicy, s->username, password, NULL)) goto auth_success; } else if (pktin->type == SSH1_CMSG_AUTH_RSA) { s->current_method = AUTHMETHOD_PUBLICKEY; diff --git a/ssh2userauth-server.c b/ssh2userauth-server.c index e642e3de..224097ad 100644 --- a/ssh2userauth-server.c +++ b/ssh2userauth-server.c @@ -163,20 +163,34 @@ static void ssh2_userauth_server_process_queue(PacketProtocolLayer *ppl) goto failure; } else if (ptrlen_eq_string(s->method, "password")) { int changing; - ptrlen password; + ptrlen password, new_password, *new_password_ptr; s->this_method = AUTHMETHOD_PASSWORD; if (!(s->methods & s->this_method)) goto failure; changing = get_bool(pktin); - if (changing) - goto failure; /* FIXME: not yet supported */ - password = get_string(pktin); - if (!auth_password(s->authpolicy, s->username, password)) + if (changing) { + new_password = get_string(pktin); + new_password_ptr = &new_password; + } else { + new_password_ptr = NULL; + } + + int result = auth_password(s->authpolicy, s->username, + password, new_password_ptr); + if (result == 2) { + pktout = ssh_bpp_new_pktout( + s->ppl.bpp, SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ); + put_stringz(pktout, "Please change your password"); + put_stringz(pktout, ""); /* language tag */ + pq_push(s->ppl.out_pq, pktout); + continue; /* skip USERAUTH_{SUCCESS,FAILURE} epilogue */ + } else if (result != 1) { goto failure; + } } else if (ptrlen_eq_string(s->method, "publickey")) { int has_signature, success; ptrlen algorithm, blob, signature; diff --git a/sshserver.h b/sshserver.h index 7081d0cd..846c40c5 100644 --- a/sshserver.h +++ b/sshserver.h @@ -38,7 +38,12 @@ struct AuthKbdIntPrompt { unsigned auth_methods(AuthPolicy *); int auth_none(AuthPolicy *, ptrlen username); -int auth_password(AuthPolicy *, ptrlen username, ptrlen password); + +int auth_password(AuthPolicy *, ptrlen username, ptrlen password, + ptrlen *opt_new_password); +/* auth_password returns 1 for 'accepted', 0 for 'rejected', and 2 for + * 'ok but now you need to change your password' */ + int auth_publickey(AuthPolicy *, ptrlen username, ptrlen public_blob); /* auth_publickey_ssh1 must return the whole public key given the modulus, * because the SSH-1 client never transmits the exponent over the wire. diff --git a/unix/uxserver.c b/unix/uxserver.c index bbb26ef1..dbf5815a 100644 --- a/unix/uxserver.c +++ b/unix/uxserver.c @@ -175,9 +175,36 @@ int auth_none(AuthPolicy *ap, ptrlen username) { return FALSE; } -int auth_password(AuthPolicy *ap, ptrlen username, ptrlen password) +int auth_password(AuthPolicy *ap, ptrlen username, ptrlen password, + ptrlen *new_password_opt) { - return ptrlen_eq_string(password, "weasel"); + const char *PHONY_GOOD_PASSWORD = "weasel"; + const char *PHONY_BAD_PASSWORD = "ferret"; + + if (!new_password_opt) { + /* Accept login with our preconfigured good password */ + if (ptrlen_eq_string(password, PHONY_GOOD_PASSWORD)) + return 1; + /* Don't outright reject the bad password, but insist on a change */ + if (ptrlen_eq_string(password, PHONY_BAD_PASSWORD)) + return 2; + /* Reject anything else */ + return 0; + } else { + /* In a password-change request, expect the bad password as input */ + if (!ptrlen_eq_string(password, PHONY_BAD_PASSWORD)) + return 0; + /* Accept a request to change it to the good password */ + if (ptrlen_eq_string(*new_password_opt, PHONY_GOOD_PASSWORD)) + return 1; + /* Outright reject a request to change it to the same password + * as it already 'was' */ + if (ptrlen_eq_string(*new_password_opt, PHONY_BAD_PASSWORD)) + return 0; + /* Anything else, pretend the new pw wasn't good enough, and + * re-request a change */ + return 2; + } } int auth_publickey(AuthPolicy *ap, ptrlen username, ptrlen public_blob) { From 1d459fc725dc303f9bbeb9f893d9eb735b2a5e96 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Mon, 29 Oct 2018 07:23:32 +0000 Subject: [PATCH 582/607] Fix misuse of FALSE for null pointer return values. x11_char_struct returns a pointer or NULL, so while returning FALSE would have ended up doing the right thing after macro expansion and integer->pointer conversion, it wasn't actually how I _meant_ to spell a failure return. --- unix/gtkfont.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/unix/gtkfont.c b/unix/gtkfont.c index c2a610f1..3dbf16f0 100644 --- a/unix/gtkfont.c +++ b/unix/gtkfont.c @@ -388,13 +388,13 @@ static const XCharStruct *x11_char_struct( */ if (byte2 < xfs->min_char_or_byte2 || byte2 > xfs->max_char_or_byte2) - return FALSE; + return NULL; if (xfs->min_byte1 == 0 && xfs->max_byte1 == 0) { index = byte2 - xfs->min_char_or_byte2; } else { if (byte1 < xfs->min_byte1 || byte1 > xfs->max_byte1) - return FALSE; + return NULL; index = ((byte2 - xfs->min_char_or_byte2) + ((byte1 - xfs->min_byte1) * (xfs->max_char_or_byte2 - xfs->min_char_or_byte2 + 1))); From 3a2afbc9c03010fa62ee7ed622c1d5eb1696c0ab Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Thu, 1 Nov 2018 18:17:41 +0000 Subject: [PATCH 583/607] Remove duplicate typedef for mainchan. In some compiler modes - notably the one that gtk-config selects when GTK PuTTY is built for GTK 1 - it's an error to typedef the same thing twice. 'mainchan' is defined in defs.h, so it doesn't need defining again where the structure contents are specified. --- mainchan.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mainchan.c b/mainchan.c index c196da52..a75b44e4 100644 --- a/mainchan.c +++ b/mainchan.c @@ -54,7 +54,7 @@ typedef enum MainChanType { MAINCHAN_SESSION, MAINCHAN_DIRECT_TCPIP } MainChanType; -typedef struct mainchan { +struct mainchan { SshChannel *sc; Conf *conf; PacketProtocolLayer *ppl; @@ -70,7 +70,7 @@ typedef struct mainchan { int term_width, term_height; Channel chan; -} mainchan; +}; mainchan *mainchan_new( PacketProtocolLayer *ppl, ConnectionLayer *cl, Conf *conf, From 5cb56389bdf78f98e44128afca39fba2dac74dfa Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Tue, 30 Oct 2018 18:09:12 +0000 Subject: [PATCH 584/607] Remove three uses of bitwise ops on boolean values. If values are boolean, it's confusing to use & and | in place of && and ||. In two of these three cases it was simply a typo and I've used the other one; in the third, it was a deliberate avoidance of short- circuit evaluation (and commented as such), but having seen how easy it is to make the same typo by accident, I've decided it's clearer to just move the LHS and RHS evaluations outside the expression. --- mainchan.c | 2 +- ssh2transport.c | 10 +++++----- unix/gtkask.c | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/mainchan.c b/mainchan.c index a75b44e4..c0738151 100644 --- a/mainchan.c +++ b/mainchan.c @@ -376,7 +376,7 @@ static void mainchan_send_eof(Channel *chan) mainchan *mc = container_of(chan, mainchan, chan); PacketProtocolLayer *ppl = mc->ppl; /* for ppl_logevent */ - if (!mc->eof_sent & (seat_eof(mc->ppl->seat) || mc->got_pty)) { + if (!mc->eof_sent && (seat_eof(mc->ppl->seat) || mc->got_pty)) { /* * Either seat_eof told us that the front end wants us to * close the outgoing side of the connection as soon as we see diff --git a/ssh2transport.c b/ssh2transport.c index 7b04e5f7..152d530d 100644 --- a/ssh2transport.c +++ b/ssh2transport.c @@ -1903,11 +1903,11 @@ static void ssh2_transport_reconfigure(PacketProtocolLayer *ppl, Conf *conf) if (s->max_data_size < old_max_data_size) { unsigned long diff = old_max_data_size - s->max_data_size; - /* Intentionally use bitwise OR instead of logical, so - * that we decrement both counters even if the first one - * runs out */ - if ((DTS_CONSUME(s->stats, out, diff) != 0) | - (DTS_CONSUME(s->stats, in, diff) != 0)) + /* We must decrement both counters, so avoid short-circuit + * evaluation skipping one */ + int out_expired = DTS_CONSUME(s->stats, out, diff) != 0; + int in_expired = DTS_CONSUME(s->stats, in, diff) != 0; + if (out_expired || in_expired) rekey_reason = "data limit lowered"; } else { unsigned long diff = s->max_data_size - old_max_data_size; diff --git a/unix/gtkask.c b/unix/gtkask.c index 97b78941..5b45d342 100644 --- a/unix/gtkask.c +++ b/unix/gtkask.c @@ -407,7 +407,7 @@ static const char *gtk_askpass_setup(struct askpass_ctx *ctx, ctx->cols[2].red = ctx->cols[2].green = ctx->cols[2].blue = 0x8000; gdk_colormap_alloc_colors(ctx->colmap, ctx->cols, 2, FALSE, TRUE, success); - if (!success[0] | !success[1]) + if (!success[0] || !success[1]) return "unable to allocate colours"; } #endif From a647f2ba1165393506c6c006c0bce4b82f5fa1ab Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Fri, 26 Oct 2018 23:08:58 +0100 Subject: [PATCH 585/607] Adopt C99 integer types. The annoying int64.h is completely retired, since C99 guarantees a 64-bit integer type that you can actually treat like an ordinary integer. Also, I've replaced the local typedefs uint32 and word32 (scattered through different parts of the crypto code) with the standard uint32_t. --- Recipe | 4 +- defs.h | 12 ++- int64.c | 175 -------------------------------------------- int64.h | 29 -------- marshal.c | 21 ++---- marshal.h | 5 +- misc.h | 56 ++++++++++++-- pgssapi.h | 2 +- pscp.c | 115 ++++++++++++----------------- psftp.c | 21 ++---- psftp.h | 10 +-- scpserver.c | 57 ++++++--------- sftp.c | 45 +++++------- sftp.h | 15 ++-- sftpserver.c | 2 +- ssh.h | 23 +++--- sshaes.c | 50 ++++++------- sshblowf.c | 86 +++++++++++----------- sshccp.c | 6 +- sshcrcda.c | 36 +++++---- sshdes.c | 39 +++++----- sshmd5.c | 37 ++++------ sshrand.c | 30 ++++---- sshsh256.c | 39 +++++----- sshsh512.c | 106 +++++++++------------------ sshsha.c | 46 ++++++------ unix/uxsftp.c | 29 ++------ unix/uxsftpserver.c | 31 +++----- windows/winsftp.c | 28 ++++--- 29 files changed, 433 insertions(+), 722 deletions(-) delete mode 100644 int64.c delete mode 100644 int64.h diff --git a/Recipe b/Recipe index ecdfcf33..0c4fd582 100644 --- a/Recipe +++ b/Recipe @@ -267,7 +267,7 @@ WINSSH = SSH winnoise wincapi winpgntc wingss winshare winnps winnpc UXSSH = SSH uxnoise uxagentc uxgss uxshare # SFTP implementation (pscp, psftp). -SFTP = sftp sftpcommon int64 logging cmdline +SFTP = sftp sftpcommon logging cmdline # Miscellaneous objects appearing in all the utilities, or all the # network ones, or the Unix or Windows subsets of those in turn. @@ -283,7 +283,7 @@ UXMISC = MISCNET UXMISCCOMMON uxproxy # SSH server. SSHSERVER = SSHCOMMON sshserver settings be_none logging ssh2kex-server + ssh2userauth-server sshrsag sshprime ssh2connection-server - + sesschan sftpcommon int64 sftpserver proxy cproxy ssh1login-server + + sesschan sftpcommon sftpserver proxy cproxy ssh1login-server + ssh1connection-server scpserver # import.c and dependencies, for PuTTYgen-like utilities that have to diff --git a/defs.h b/defs.h index 74aca8b1..809f7ed4 100644 --- a/defs.h +++ b/defs.h @@ -12,6 +12,15 @@ #define PUTTY_DEFS_H #include +#include + +#if defined _MSC_VER && _MSC_VER < 1800 +/* Work around lack of inttypes.h in older MSVC */ +#define PRIu64 "I64u" +#define SCNu64 "I64u" +#else +#include +#endif #ifndef FALSE #define FALSE 0 @@ -32,9 +41,6 @@ typedef struct strbuf strbuf; struct RSAKey; -#include -typedef uint32_t uint32; - typedef struct BinarySink BinarySink; typedef struct BinarySource BinarySource; diff --git a/int64.c b/int64.c deleted file mode 100644 index a6a98f31..00000000 --- a/int64.c +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Handling of the int64 and uint64 types. Done in 32-bit integers, - * for (pre-C99) portability. Hopefully once C99 becomes widespread - * we can kiss this lot goodbye... - */ - -#include -#include - -#include "int64.h" - -uint64 uint64_div10(uint64 x, int *remainder) -{ - uint64 y; - unsigned int rem, r2; - y.hi = x.hi / 10; - y.lo = x.lo / 10; - rem = x.lo % 10; - /* - * Now we have to add in the remainder left over from x.hi. - */ - r2 = x.hi % 10; - y.lo += r2 * 429496729; - rem += r2 * 6; - y.lo += rem / 10; - rem %= 10; - - if (remainder) - *remainder = rem; - return y; -} - -void uint64_decimal(uint64 x, char *buffer) -{ - char buf[20]; - int start = 20; - int d; - - do { - x = uint64_div10(x, &d); - assert(start > 0); - buf[--start] = d + '0'; - } while (x.hi || x.lo); - - memcpy(buffer, buf + start, sizeof(buf) - start); - buffer[sizeof(buf) - start] = '\0'; -} - -uint64 uint64_make(unsigned long hi, unsigned long lo) -{ - uint64 y; - y.hi = hi & 0xFFFFFFFFU; - y.lo = lo & 0xFFFFFFFFU; - return y; -} - -uint64 uint64_add(uint64 x, uint64 y) -{ - x.lo = (x.lo + y.lo) & 0xFFFFFFFFU; - x.hi += y.hi + (x.lo < y.lo ? 1 : 0); - return x; -} - -uint64 uint64_add32(uint64 x, unsigned long y) -{ - uint64 yy; - yy.hi = 0; - yy.lo = y; - return uint64_add(x, yy); -} - -int uint64_compare(uint64 x, uint64 y) -{ - if (x.hi != y.hi) - return x.hi < y.hi ? -1 : +1; - if (x.lo != y.lo) - return x.lo < y.lo ? -1 : +1; - return 0; -} - -uint64 uint64_subtract(uint64 x, uint64 y) -{ - x.lo = (x.lo - y.lo) & 0xFFFFFFFFU; - x.hi = (x.hi - y.hi - (x.lo > (y.lo ^ 0xFFFFFFFFU) ? 1 : 0)) & 0xFFFFFFFFU; - return x; -} - -double uint64_to_double(uint64 x) -{ - return (4294967296.0 * x.hi) + (double)x.lo; -} - -uint64 uint64_shift_right(uint64 x, int shift) -{ - if (shift < 32) { - x.lo >>= shift; - x.lo |= (x.hi << (32-shift)) & 0xFFFFFFFFU; - x.hi >>= shift; - } else { - x.lo = x.hi >> (shift-32); - x.hi = 0; - } - return x; -} - -uint64 uint64_shift_left(uint64 x, int shift) -{ - if (shift < 32) { - x.hi = (x.hi << shift) & 0xFFFFFFFFU; - x.hi |= (x.lo >> (32-shift)); - x.lo = (x.lo << shift) & 0xFFFFFFFFU; - } else { - x.hi = (x.lo << (shift-32)) & 0xFFFFFFFFU; - x.lo = 0; - } - return x; -} - -uint64 uint64_from_decimal(const char *str) -{ - uint64 ret; - ret.hi = ret.lo = 0; - while (*str >= '0' && *str <= '9') { - ret = uint64_add(uint64_shift_left(ret, 3), - uint64_shift_left(ret, 1)); - ret = uint64_add32(ret, *str - '0'); - str++; - } - return ret; -} - -#ifdef TESTMODE - -#include - -int main(void) -{ - uint64 x, y, z; - char buf[80]; - - x = uint64_make(0x3456789AUL, 0xDEF01234UL); - printf("%08lx.%08lx\n", x.hi, x.lo); - uint64_decimal(x, buf); - printf("%s\n", buf); - - y = uint64_add32(x, 0xFFFFFFFFU); - printf("%08lx.%08lx\n", y.hi, y.lo); - uint64_decimal(y, buf); - printf("%s\n", buf); - - z = uint64_subtract(y, x); - printf("%08lx.%08lx\n", z.hi, z.lo); - uint64_decimal(z, buf); - printf("%s\n", buf); - - z = uint64_subtract(x, y); - printf("%08lx.%08lx\n", z.hi, z.lo); - uint64_decimal(z, buf); - printf("%s\n", buf); - - y = uint64_shift_right(x, 4); - printf("%08lx.%08lx\n", y.hi, y.lo); - - y = uint64_shift_right(x, 36); - printf("%08lx.%08lx\n", y.hi, y.lo); - - y = uint64_shift_left(x, 4); - printf("%08lx.%08lx\n", x.hi, x.lo); - - y = uint64_shift_left(x, 36); - printf("%08lx.%08lx\n", x.hi, x.lo); - - return 0; -} -#endif diff --git a/int64.h b/int64.h deleted file mode 100644 index fb50fbaf..00000000 --- a/int64.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Header for int64.c. - */ - -#ifndef PUTTY_INT64_H -#define PUTTY_INT64_H - -#include "defs.h" - -typedef struct { - unsigned long hi, lo; -} uint64; - -uint64 uint64_div10(uint64 x, int *remainder); -void uint64_decimal(uint64 x, char *buffer); -uint64 uint64_make(unsigned long hi, unsigned long lo); -uint64 uint64_add(uint64 x, uint64 y); -uint64 uint64_add32(uint64 x, unsigned long y); -int uint64_compare(uint64 x, uint64 y); -uint64 uint64_subtract(uint64 x, uint64 y); -double uint64_to_double(uint64 x); -uint64 uint64_shift_right(uint64 x, int shift); -uint64 uint64_shift_left(uint64 x, int shift); -uint64 uint64_from_decimal(const char *str); - -void BinarySink_put_uint64(BinarySink *, uint64); -uint64 BinarySource_get_uint64(BinarySource *); - -#endif diff --git a/marshal.c b/marshal.c index f0612a85..c4fd268b 100644 --- a/marshal.c +++ b/marshal.c @@ -4,7 +4,6 @@ #include "marshal.h" #include "misc.h" -#include "int64.h" void BinarySink_put_data(BinarySink *bs, const void *data, size_t len) { @@ -47,10 +46,11 @@ void BinarySink_put_uint32(BinarySink *bs, unsigned long val) bs->write(bs, data, sizeof(data)); } -void BinarySink_put_uint64(BinarySink *bs, uint64 val) +void BinarySink_put_uint64(BinarySink *bs, uint64_t val) { - BinarySink_put_uint32(bs, val.hi); - BinarySink_put_uint32(bs, val.lo); + unsigned char data[8]; + PUT_64BIT_MSB_FIRST(data, val); + bs->write(bs, data, sizeof(data)); } void BinarySink_put_string(BinarySink *bs, const void *data, size_t len) @@ -167,20 +167,15 @@ unsigned long BinarySource_get_uint32(BinarySource *src) return GET_32BIT_MSB_FIRST(ucp); } -uint64 BinarySource_get_uint64(BinarySource *src) +uint64_t BinarySource_get_uint64(BinarySource *src) { const unsigned char *ucp; - uint64 toret; - if (!avail(8)) { - toret.hi = toret.lo = 0; - return toret; - } + if (!avail(8)) + return 0; ucp = consume(8); - toret.hi = GET_32BIT_MSB_FIRST(ucp); - toret.lo = GET_32BIT_MSB_FIRST(ucp + 4); - return toret; + return GET_64BIT_MSB_FIRST(ucp); } ptrlen BinarySource_get_string(BinarySource *src) diff --git a/marshal.h b/marshal.h index 631e2465..af35ff7e 100644 --- a/marshal.h +++ b/marshal.h @@ -76,8 +76,7 @@ struct BinarySink { * first parameter of any of these put_* macros. */ -/* Basic big-endian integer types. uint64 is the structure type - * defined in int64.h, not the C99 built-in type. */ +/* Basic big-endian integer types. */ #define put_byte(bs, val) \ BinarySink_put_byte(BinarySink_UPCAST(bs), val) #define put_uint16(bs, val) \ @@ -146,6 +145,7 @@ void BinarySink_put_byte(BinarySink *, unsigned char); void BinarySink_put_bool(BinarySink *, int); void BinarySink_put_uint16(BinarySink *, unsigned long); void BinarySink_put_uint32(BinarySink *, unsigned long); +void BinarySink_put_uint64(BinarySink *, uint64_t); void BinarySink_put_string(BinarySink *, const void *data, size_t len); void BinarySink_put_stringpl(BinarySink *, ptrlen); void BinarySink_put_stringz(BinarySink *, const char *str); @@ -277,6 +277,7 @@ unsigned char BinarySource_get_byte(BinarySource *); int BinarySource_get_bool(BinarySource *); unsigned BinarySource_get_uint16(BinarySource *); unsigned long BinarySource_get_uint32(BinarySource *); +uint64_t BinarySource_get_uint64(BinarySource *); ptrlen BinarySource_get_string(BinarySource *); const char *BinarySource_get_asciz(BinarySource *); ptrlen BinarySource_get_pstring(BinarySource *); diff --git a/misc.h b/misc.h index 90322092..587e97e3 100644 --- a/misc.h +++ b/misc.h @@ -166,11 +166,31 @@ void debug_memdump(const void *buf, int len, int L); #define max(x,y) ( (x) > (y) ? (x) : (y) ) #endif +#define GET_64BIT_LSB_FIRST(cp) \ + (((uint64_t)(unsigned char)(cp)[0]) | \ + ((uint64_t)(unsigned char)(cp)[1] << 8) | \ + ((uint64_t)(unsigned char)(cp)[2] << 16) | \ + ((uint64_t)(unsigned char)(cp)[3] << 24) | \ + ((uint64_t)(unsigned char)(cp)[4] << 32) | \ + ((uint64_t)(unsigned char)(cp)[5] << 40) | \ + ((uint64_t)(unsigned char)(cp)[6] << 48) | \ + ((uint64_t)(unsigned char)(cp)[7] << 56)) + +#define PUT_64BIT_LSB_FIRST(cp, value) ( \ + (cp)[0] = (unsigned char)(value), \ + (cp)[1] = (unsigned char)((value) >> 8), \ + (cp)[2] = (unsigned char)((value) >> 16), \ + (cp)[3] = (unsigned char)((value) >> 24), \ + (cp)[4] = (unsigned char)((value) >> 32), \ + (cp)[5] = (unsigned char)((value) >> 40), \ + (cp)[6] = (unsigned char)((value) >> 48), \ + (cp)[7] = (unsigned char)((value) >> 56) ) + #define GET_32BIT_LSB_FIRST(cp) \ - (((unsigned long)(unsigned char)(cp)[0]) | \ - ((unsigned long)(unsigned char)(cp)[1] << 8) | \ - ((unsigned long)(unsigned char)(cp)[2] << 16) | \ - ((unsigned long)(unsigned char)(cp)[3] << 24)) + (((uint32_t)(unsigned char)(cp)[0]) | \ + ((uint32_t)(unsigned char)(cp)[1] << 8) | \ + ((uint32_t)(unsigned char)(cp)[2] << 16) | \ + ((uint32_t)(unsigned char)(cp)[3] << 24)) #define PUT_32BIT_LSB_FIRST(cp, value) ( \ (cp)[0] = (unsigned char)(value), \ @@ -187,10 +207,10 @@ void debug_memdump(const void *buf, int len, int L); (cp)[1] = (unsigned char)((value) >> 8) ) #define GET_32BIT_MSB_FIRST(cp) \ - (((unsigned long)(unsigned char)(cp)[0] << 24) | \ - ((unsigned long)(unsigned char)(cp)[1] << 16) | \ - ((unsigned long)(unsigned char)(cp)[2] << 8) | \ - ((unsigned long)(unsigned char)(cp)[3])) + (((uint32_t)(unsigned char)(cp)[0] << 24) | \ + ((uint32_t)(unsigned char)(cp)[1] << 16) | \ + ((uint32_t)(unsigned char)(cp)[2] << 8) | \ + ((uint32_t)(unsigned char)(cp)[3])) #define GET_32BIT(cp) GET_32BIT_MSB_FIRST(cp) @@ -202,6 +222,26 @@ void debug_memdump(const void *buf, int len, int L); #define PUT_32BIT(cp, value) PUT_32BIT_MSB_FIRST(cp, value) +#define GET_64BIT_MSB_FIRST(cp) \ + (((uint64_t)(unsigned char)(cp)[0] << 56) | \ + ((uint64_t)(unsigned char)(cp)[1] << 48) | \ + ((uint64_t)(unsigned char)(cp)[2] << 40) | \ + ((uint64_t)(unsigned char)(cp)[3] << 32) | \ + ((uint64_t)(unsigned char)(cp)[4] << 24) | \ + ((uint64_t)(unsigned char)(cp)[5] << 16) | \ + ((uint64_t)(unsigned char)(cp)[6] << 8) | \ + ((uint64_t)(unsigned char)(cp)[7])) + +#define PUT_64BIT_MSB_FIRST(cp, value) ( \ + (cp)[0] = (unsigned char)((value) >> 56), \ + (cp)[1] = (unsigned char)((value) >> 48), \ + (cp)[2] = (unsigned char)((value) >> 40), \ + (cp)[3] = (unsigned char)((value) >> 32), \ + (cp)[4] = (unsigned char)((value) >> 24), \ + (cp)[5] = (unsigned char)((value) >> 16), \ + (cp)[6] = (unsigned char)((value) >> 8), \ + (cp)[7] = (unsigned char)(value) ) + #define GET_16BIT_MSB_FIRST(cp) \ (((unsigned long)(unsigned char)(cp)[0] << 8) | \ ((unsigned long)(unsigned char)(cp)[1])) diff --git a/pgssapi.h b/pgssapi.h index fd7a796d..74d9c774 100644 --- a/pgssapi.h +++ b/pgssapi.h @@ -24,7 +24,7 @@ typedef gss_OID const_gss_OID; /* for our prototypes below */ ******************************************************************************/ /* GSSAPI Type Definitions */ -typedef uint32 OM_uint32; +typedef uint32_t OM_uint32; typedef struct gss_OID_desc_struct { OM_uint32 length; diff --git a/pscp.c b/pscp.c index 230d8c5e..86525270 100644 --- a/pscp.c +++ b/pscp.c @@ -25,7 +25,6 @@ #include "ssh.h" #include "sftp.h" #include "storage.h" -#include "int64.h" static int list = 0; static int verbose = 0; @@ -506,7 +505,7 @@ static void do_cmd(char *host, char *user, char *cmd) /* * Update statistic information about current file. */ -static void print_stats(const char *name, uint64 size, uint64 done, +static void print_stats(const char *name, uint64_t size, uint64_t done, time_t start, time_t now) { float ratebs; @@ -515,42 +514,34 @@ static void print_stats(const char *name, uint64 size, uint64 done, int pct; int len; int elap; - double donedbl; - double sizedbl; elap = (unsigned long) difftime(now, start); if (now > start) - ratebs = (float) (uint64_to_double(done) / elap); + ratebs = (float)done / elap; else - ratebs = (float) uint64_to_double(done); + ratebs = (float)done; if (ratebs < 1.0) - eta = (unsigned long) (uint64_to_double(uint64_subtract(size, done))); - else { - eta = (unsigned long) - ((uint64_to_double(uint64_subtract(size, done)) / ratebs)); - } + eta = size - done; + else + eta = (unsigned long)((size - done) / ratebs); etastr = dupprintf("%02ld:%02ld:%02ld", eta / 3600, (eta % 3600) / 60, eta % 60); - donedbl = uint64_to_double(done); - sizedbl = uint64_to_double(size); - pct = (int) (100 * (donedbl * 1.0 / sizedbl)); + pct = (int) (100.0 * done / size); { - char donekb[40]; /* divide by 1024 to provide kB */ - uint64_decimal(uint64_shift_right(done, 10), donekb); - len = printf("\r%-25.25s | %s kB | %5.1f kB/s | ETA: %8s | %3d%%", - name, - donekb, ratebs / 1024.0, etastr, pct); + len = printf("\r%-25.25s | %"PRIu64" kB | %5.1f kB/s | " + "ETA: %8s | %3d%%", name, done >> 10, + ratebs / 1024.0, etastr, pct); if (len < prev_stats_len) printf("%*s", prev_stats_len - len, ""); prev_stats_len = len; - if (uint64_compare(done, size) == 0) + if (done == size) abandon_stats(); fflush(stdout); @@ -743,7 +734,7 @@ static unsigned long scp_sftp_mtime, scp_sftp_atime; static int scp_has_times; static struct fxp_handle *scp_sftp_filehandle; static struct fxp_xfer *scp_sftp_xfer; -static uint64 scp_sftp_fileoffset; +static uint64_t scp_sftp_fileoffset; int scp_source_setup(const char *target, int shouldbedir) { @@ -811,7 +802,7 @@ int scp_send_filetimes(unsigned long mtime, unsigned long atime) } } -int scp_send_filename(const char *name, uint64 size, int permissions) +int scp_send_filename(const char *name, uint64_t size, int permissions) { if (using_sftp) { char *fullname; @@ -841,18 +832,16 @@ int scp_send_filename(const char *name, uint64 size, int permissions) errs++; return 1; } - scp_sftp_fileoffset = uint64_make(0, 0); + scp_sftp_fileoffset = 0; scp_sftp_xfer = xfer_upload_init(scp_sftp_filehandle, scp_sftp_fileoffset); sfree(fullname); return 0; } else { char *buf; - char sizestr[40]; - uint64_decimal(size, sizestr); if (permissions < 0) permissions = 0644; - buf = dupprintf("C%04o %s ", (int)(permissions & 07777), sizestr); + buf = dupprintf("C%04o %"PRIu64" ", (int)(permissions & 07777), size); backend_send(backend, buf, strlen(buf)); sfree(buf); backend_send(backend, name, strlen(name)); @@ -885,7 +874,7 @@ int scp_send_filedata(char *data, int len) xfer_upload_data(scp_sftp_xfer, data, len); - scp_sftp_fileoffset = uint64_add32(scp_sftp_fileoffset, len); + scp_sftp_fileoffset += len; return 0; } else { int bufsize = backend_send(backend, data, len); @@ -1143,7 +1132,7 @@ struct scp_sink_action { char *buf; /* will need freeing after use */ char *name; /* filename or dirname (not ENDDIR) */ long permissions; /* access permissions (not ENDDIR) */ - uint64 size; /* file size (not ENDDIR) */ + uint64_t size; /* file size (not ENDDIR) */ int settime; /* 1 if atime and mtime are filled */ unsigned long atime, mtime; /* access times for the file */ }; @@ -1369,7 +1358,7 @@ int scp_get_sink_action(struct scp_sink_action *act) act->action = SCP_SINK_DIR; act->buf = dupstr(stripslashes(fname, 0)); act->name = act->buf; - act->size = uint64_make(0,0); /* duhh, it's a directory */ + act->size = 0; /* duhh, it's a directory */ act->permissions = 07777 & attrs.permissions; if (scp_sftp_preserve && (attrs.flags & SSH_FILEXFER_ATTR_ACMODTIME)) { @@ -1391,7 +1380,7 @@ int scp_get_sink_action(struct scp_sink_action *act) if (attrs.flags & SSH_FILEXFER_ATTR_SIZE) { act->size = attrs.size; } else - act->size = uint64_make(ULONG_MAX,ULONG_MAX); /* no idea */ + act->size = UINT64_MAX; /* no idea */ act->permissions = 07777 & attrs.permissions; if (scp_sftp_preserve && (attrs.flags & SSH_FILEXFER_ATTR_ACMODTIME)) { @@ -1476,12 +1465,9 @@ int scp_get_sink_action(struct scp_sink_action *act) * SCP_SINK_DIR. */ { - char sizestr[40]; - - if (sscanf(act->buf, "%lo %39s %n", &act->permissions, - sizestr, &i) != 2) + if (sscanf(act->buf, "%lo %"SCNu64" %n", &act->permissions, + &act->size, &i) != 2) bump("Protocol error: Illegal file descriptor format"); - act->size = uint64_from_decimal(sizestr); act->name = act->buf + i; return 0; } @@ -1504,7 +1490,7 @@ int scp_accept_filexfer(void) errs++; return 1; } - scp_sftp_fileoffset = uint64_make(0, 0); + scp_sftp_fileoffset = 0; scp_sftp_xfer = xfer_download_init(scp_sftp_filehandle, scp_sftp_fileoffset); sfree(scp_sftp_currentname); @@ -1552,7 +1538,7 @@ int scp_recv_filedata(char *data, int len) } else actuallen = 0; - scp_sftp_fileoffset = uint64_add32(scp_sftp_fileoffset, actuallen); + scp_sftp_fileoffset += actuallen; return actuallen; } else { @@ -1625,14 +1611,14 @@ static void run_err(const char *fmt, ...) */ static void source(const char *src) { - uint64 size; + uint64_t size; unsigned long mtime, atime; long permissions; const char *last; RFile *f; int attr; - uint64 i; - uint64 stat_bytes; + uint64_t i; + uint64_t stat_bytes; time_t stat_starttime, stat_lasttime; attr = file_type(src); @@ -1688,28 +1674,24 @@ static void source(const char *src) } if (verbose) { - char sizestr[40]; - uint64_decimal(size, sizestr); - tell_user(stderr, "Sending file %s, size=%s", last, sizestr); + tell_user(stderr, "Sending file %s, size=%"PRIu64, last, size); } if (scp_send_filename(last, size, permissions)) { close_rfile(f); return; } - stat_bytes = uint64_make(0,0); + stat_bytes = 0; stat_starttime = time(NULL); stat_lasttime = 0; #define PSCP_SEND_BLOCK 4096 - for (i = uint64_make(0,0); - uint64_compare(i,size) < 0; - i = uint64_add32(i,PSCP_SEND_BLOCK)) { + for (i = 0; i < size; i += PSCP_SEND_BLOCK) { char transbuf[PSCP_SEND_BLOCK]; int j, k = PSCP_SEND_BLOCK; - if (uint64_compare(uint64_add32(i, k),size) > 0) /* i + k > size */ - k = (uint64_subtract(size, i)).lo; /* k = size - i; */ + if (i + k > size) + k = size - i; if ((j = read_from_file(f, transbuf, k)) != k) { bump("%s: Read error", src); } @@ -1717,9 +1699,8 @@ static void source(const char *src) bump("%s: Network error occurred", src); if (statistics) { - stat_bytes = uint64_add32(stat_bytes, k); - if (time(NULL) != stat_lasttime || - (uint64_compare(uint64_add32(i, k), size) == 0)) { + stat_bytes += k; + if (time(NULL) != stat_lasttime || i + k == size) { stat_lasttime = time(NULL); print_stats(last, size, stat_bytes, stat_starttime, stat_lasttime); @@ -1786,9 +1767,9 @@ static void sink(const char *targ, const char *src) int exists; int attr; WFile *f; - uint64 received; + uint64_t received; int wrerror = 0; - uint64 stat_bytes; + uint64_t stat_bytes; time_t stat_starttime, stat_lasttime; char *stat_name; @@ -1926,24 +1907,24 @@ static void sink(const char *targ, const char *src) return; } - stat_bytes = uint64_make(0, 0); + stat_bytes = 0; stat_starttime = time(NULL); stat_lasttime = 0; stat_name = stripslashes(destfname, 1); - received = uint64_make(0, 0); - while (uint64_compare(received,act.size) < 0) { + received = 0; + while (received < act.size) { char transbuf[32768]; - uint64 blksize; + uint64_t blksize; int read; - blksize = uint64_make(0, 32768); - if (uint64_compare(blksize,uint64_subtract(act.size,received)) > 0) - blksize = uint64_subtract(act.size,received); - read = scp_recv_filedata(transbuf, (int)blksize.lo); + blksize = 32768; + if (blksize > act.size - received) + blksize = act.size - received; + read = scp_recv_filedata(transbuf, (int)blksize); if (read <= 0) bump("Lost connection"); if (wrerror) { - received = uint64_add32(received, read); + received += read; continue; } if (write_to_file(f, transbuf, read) != (int)read) { @@ -1953,19 +1934,19 @@ static void sink(const char *targ, const char *src) printf("\r%-25.25s | %50s\n", stat_name, "Write error.. waiting for end of file"); - received = uint64_add32(received, read); + received += read; continue; } if (statistics) { - stat_bytes = uint64_add32(stat_bytes,read); + stat_bytes += read; if (time(NULL) > stat_lasttime || - uint64_compare(uint64_add32(received, read), act.size) == 0) { + received + read == act.size) { stat_lasttime = time(NULL); print_stats(stat_name, act.size, stat_bytes, stat_starttime, stat_lasttime); } } - received = uint64_add32(received, read); + received += read; } if (act.settime) { set_file_times(f, act.mtime, act.atime); diff --git a/psftp.c b/psftp.c index 8ccbb503..6e65d83a 100644 --- a/psftp.c +++ b/psftp.c @@ -14,7 +14,6 @@ #include "storage.h" #include "ssh.h" #include "sftp.h" -#include "int64.h" const char *const appname = "PSFTP"; @@ -234,7 +233,7 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart) struct sftp_packet *pktin; struct sftp_request *req; struct fxp_xfer *xfer; - uint64 offset; + uint64_t offset; WFile *file; int ret, shown_err = FALSE; struct fxp_attrs attrs; @@ -434,8 +433,7 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart) } if (restart) { - char decbuf[30]; - if (seek_file(file, uint64_make(0,0) , FROM_END) == -1) { + if (seek_file(file, 0, FROM_END) == -1) { close_wfile(file); printf("reget: cannot restart %s - file too large\n", outfname); @@ -447,10 +445,9 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart) } offset = get_file_posn(file); - uint64_decimal(offset, decbuf); - printf("reget: restarting at file position %s\n", decbuf); + printf("reget: restarting at file position %"PRIu64"\n", offset); } else { - offset = uint64_make(0, 0); + offset = 0; } printf("remote:%s => local:%s\n", fname, outfname); @@ -519,7 +516,7 @@ int sftp_put_file(char *fname, char *outfname, int recurse, int restart) struct fxp_xfer *xfer; struct sftp_packet *pktin; struct sftp_request *req; - uint64 offset; + uint64_t offset; RFile *file; int err = 0, eof; struct fxp_attrs attrs; @@ -672,7 +669,6 @@ int sftp_put_file(char *fname, char *outfname, int recurse, int restart) } if (restart) { - char decbuf[30]; struct fxp_attrs attrs; int ret; @@ -691,13 +687,12 @@ int sftp_put_file(char *fname, char *outfname, int recurse, int restart) goto cleanup; } offset = attrs.size; - uint64_decimal(offset, decbuf); - printf("reput: restarting at file position %s\n", decbuf); + printf("reput: restarting at file position %"PRIu64"\n", offset); if (seek_file((WFile *)file, offset, FROM_START) != 0) - seek_file((WFile *)file, uint64_make(0,0), FROM_END); /* *shrug* */ + seek_file((WFile *)file, 0, FROM_END); /* *shrug* */ } else { - offset = uint64_make(0, 0); + offset = 0; } printf("local:%s => remote:%s\n", fname, outfname); diff --git a/psftp.h b/psftp.h index 36965489..33c03453 100644 --- a/psftp.h +++ b/psftp.h @@ -3,8 +3,6 @@ * platform-specific SFTP module. */ -#include "int64.h" - #ifndef PUTTY_PSFTP_H #define PUTTY_PSFTP_H @@ -93,10 +91,10 @@ typedef struct RFile RFile; typedef struct WFile WFile; /* Output params size, perms, mtime and atime can all be NULL if * desired. perms will be -1 if the OS does not support POSIX permissions. */ -RFile *open_existing_file(const char *name, uint64 *size, +RFile *open_existing_file(const char *name, uint64_t *size, unsigned long *mtime, unsigned long *atime, long *perms); -WFile *open_existing_wfile(const char *name, uint64 *size); +WFile *open_existing_wfile(const char *name, uint64_t *size); /* Returns <0 on error, 0 on eof, or number of bytes read, as usual */ int read_from_file(RFile *f, void *buffer, int length); /* Closes and frees the RFile */ @@ -109,9 +107,9 @@ void set_file_times(WFile *f, unsigned long mtime, unsigned long atime); void close_wfile(WFile *f); /* Seek offset bytes through file */ enum { FROM_START, FROM_CURRENT, FROM_END }; -int seek_file(WFile *f, uint64 offset, int whence); +int seek_file(WFile *f, uint64_t offset, int whence); /* Get file position */ -uint64 get_file_posn(WFile *f); +uint64_t get_file_posn(WFile *f); /* * Determine the type of a file: nonexistent, file, directory or * weird. `weird' covers anything else - named pipes, Unix sockets, diff --git a/scpserver.c b/scpserver.c index 74efc579..8ba902f6 100644 --- a/scpserver.c +++ b/scpserver.c @@ -381,7 +381,7 @@ struct ScpSource { strbuf *pending_commands[3]; int n_pending_commands; - uint64 file_offset, file_size; + uint64_t file_offset, file_size; ScpReplyReceiver reply; @@ -535,7 +535,7 @@ static void scp_source_send_E(ScpSource *scp) static void scp_source_send_CD( ScpSource *scp, char cmdchar, - struct fxp_attrs attrs, uint64 size, ptrlen name) + struct fxp_attrs attrs, uint64_t size, ptrlen name) { strbuf *cmd; @@ -547,18 +547,15 @@ static void scp_source_send_CD( strbuf_catf(cmd, "T%lu 0 %lu 0\012", attrs.mtime, attrs.atime); } - char sizebuf[32]; - uint64_decimal(size, sizebuf); - const char *slash; while ((slash = memchr(name.ptr, '/', name.len)) != NULL) name = make_ptrlen( slash+1, name.len - (slash+1 - (const char *)name.ptr)); scp->pending_commands[scp->n_pending_commands++] = cmd = strbuf_new(); - strbuf_catf(cmd, "%c%04o %s %.*s\012", cmdchar, + strbuf_catf(cmd, "%c%04o %"PRIu64" %.*s\012", cmdchar, (unsigned)(attrs.permissions & 07777), - sizebuf, PTRLEN_PRINTF(name)); + size, PTRLEN_PRINTF(name)); if (cmdchar == 'C') { /* We'll also wait for an ack before sending the file data, @@ -626,8 +623,7 @@ static void scp_source_process_stack(ScpSource *scp) /* * Mostly, we start by waiting for an ack byte from the receiver. */ - if (scp->head && scp->head->type == SCP_READFILE && - uint64_compare(scp->file_offset, uint64_make(0, 0)) != 0) { + if (scp->head && scp->head->type == SCP_READFILE && scp->file_offset) { /* * Exception: if we're already in the middle of transferring a * file, we'll be called back here because the channel backlog @@ -717,14 +713,12 @@ static void scp_source_process_stack(ScpSource *scp) * Transfer file data if our backlog hasn't filled up. */ int backlog; - uint64 remaining = - uint64_subtract(scp->file_size, scp->file_offset); - uint64 limit = uint64_make(0, 4096); - if (uint64_compare(remaining, limit) < 0) - limit = remaining; - if (limit.lo > 0) { + uint64_t limit = scp->file_size - scp->file_offset; + if (limit > 4096) + limit = 4096; + if (limit > 0) { sftpsrv_read(scp->sf, &scp->reply.srb, scp->head->handle, - scp->file_offset, limit.lo); + scp->file_offset, limit); if (scp->reply.err) { scp_source_abort( scp, "%.*s: unable to read: %s", @@ -734,8 +728,7 @@ static void scp_source_process_stack(ScpSource *scp) backlog = sshfwd_write( scp->sc, scp->reply.data.ptr, scp->reply.data.len); - scp->file_offset = uint64_add( - scp->file_offset, uint64_make(0, scp->reply.data.len)); + scp->file_offset += scp->reply.data.len; if (backlog < SCP_MAX_BACKLOG) scp_requeue(scp); @@ -819,8 +812,7 @@ static void scp_source_process_stack(ScpSource *scp) assert(scp->recursive || node->wildcard); if (!node->wildcard) - scp_source_send_CD(scp, 'D', node->attrs, - uint64_make(0, 0), node->pathname); + scp_source_send_CD(scp, 'D', node->attrs, 0, node->pathname); sftpsrv_opendir(scp->sf, &scp->reply.srb, node->pathname); if (scp->reply.err) { scp_source_err( @@ -855,7 +847,7 @@ static void scp_source_process_stack(ScpSource *scp) scp_requeue(scp); return; } - scp->file_offset = uint64_make(0, 0); + scp->file_offset = 0; scp->file_size = scp->reply.attrs.size; scp_source_send_CD(scp, 'C', node->attrs, scp->file_size, node->pathname); @@ -943,7 +935,7 @@ struct ScpSink { SshChannel *sc; ScpSinkStackEntry *head; - uint64 file_offset, file_size; + uint64_t file_offset, file_size; unsigned long atime, mtime; int got_file_times; @@ -1135,7 +1127,7 @@ static void scp_sink_coroutine(ScpSink *scp) if (*p != ' ') goto parse_error; p++; - scp->file_size = uint64_from_decimal(q); + scp->file_size = strtoull(q, NULL, 10); ptrlen leafname = make_ptrlen( p, scp->command->len - (p - scp->command->s)); @@ -1185,11 +1177,11 @@ static void scp_sink_coroutine(ScpSink *scp) * Now send an ack, and read the file data. */ sshfwd_write(scp->sc, "\0", 1); - scp->file_offset = uint64_make(0, 0); - while (uint64_compare(scp->file_offset, scp->file_size) < 0) { + scp->file_offset = 0; + while (scp->file_offset < scp->file_size) { void *vdata; int len; - uint64 this_len, remaining; + uint64_t this_len, remaining; crMaybeWaitUntilV( scp->input_eof || bufchain_size(&scp->data) > 0); @@ -1200,22 +1192,21 @@ static void scp_sink_coroutine(ScpSink *scp) } bufchain_prefix(&scp->data, &vdata, &len); - this_len = uint64_make(0, len); - remaining = uint64_subtract( - scp->file_size, scp->file_offset); - if (uint64_compare(this_len, remaining) > 0) + this_len = len; + remaining = scp->file_size - scp->file_offset; + if (this_len > remaining) this_len = remaining; sftpsrv_write(scp->sf, &scp->reply.srb, scp->reply.handle, scp->file_offset, - make_ptrlen(vdata, this_len.lo)); + make_ptrlen(vdata, this_len)); if (scp->reply.err) { scp->errmsg = dupprintf( "'%.*s': unable to write to file: %s", PTRLEN_PRINTF(scp->filename), scp->reply.errmsg); goto done; } - bufchain_consume(&scp->data, this_len.lo); - scp->file_offset = uint64_add(scp->file_offset, this_len); + bufchain_consume(&scp->data, this_len); + scp->file_offset += this_len; } /* diff --git a/sftp.c b/sftp.c index 98b8a6e8..47ea30c0 100644 --- a/sftp.c +++ b/sftp.c @@ -9,7 +9,6 @@ #include #include "misc.h" -#include "int64.h" #include "tree234.h" #include "sftp.h" @@ -683,7 +682,7 @@ int fxp_fsetstat_recv(struct sftp_packet *pktin, struct sftp_request *req) * error indicator. It might even depend on the SFTP server.) */ struct sftp_request *fxp_read_send(struct fxp_handle *handle, - uint64 offset, int len) + uint64_t offset, int len) { struct sftp_request *req = sftp_alloc_request(); struct sftp_packet *pktout; @@ -812,7 +811,7 @@ struct fxp_names *fxp_readdir_recv(struct sftp_packet *pktin, * Write to a file. Returns 0 on error, 1 on OK. */ struct sftp_request *fxp_write_send(struct fxp_handle *handle, - void *buffer, uint64 offset, int len) + void *buffer, uint64_t offset, int len) { struct sftp_request *req = sftp_alloc_request(); struct sftp_packet *pktout; @@ -894,18 +893,18 @@ void fxp_set_userdata(struct sftp_request *req, void *data) struct req { char *buffer; int len, retlen, complete; - uint64 offset; + uint64_t offset; struct req *next, *prev; }; struct fxp_xfer { - uint64 offset, furthestdata, filesize; + uint64_t offset, furthestdata, filesize; int req_totalsize, req_maxsize, eof, err; struct fxp_handle *fh; struct req *head, *tail; }; -static struct fxp_xfer *xfer_init(struct fxp_handle *fh, uint64 offset) +static struct fxp_xfer *xfer_init(struct fxp_handle *fh, uint64_t offset) { struct fxp_xfer *xfer = snew(struct fxp_xfer); @@ -915,8 +914,8 @@ static struct fxp_xfer *xfer_init(struct fxp_handle *fh, uint64 offset) xfer->req_totalsize = 0; xfer->req_maxsize = 1048576; xfer->err = 0; - xfer->filesize = uint64_make(ULONG_MAX, ULONG_MAX); - xfer->furthestdata = uint64_make(0, 0); + xfer->filesize = UINT64_MAX; + xfer->furthestdata = 0; return xfer; } @@ -958,16 +957,16 @@ void xfer_download_queue(struct fxp_xfer *xfer) sftp_register(req = fxp_read_send(xfer->fh, rr->offset, rr->len)); fxp_set_userdata(req, rr); - xfer->offset = uint64_add32(xfer->offset, rr->len); + xfer->offset += rr->len; xfer->req_totalsize += rr->len; #ifdef DEBUG_DOWNLOAD - { char buf[40]; uint64_decimal(rr->offset, buf); printf("queueing read request %p at %s\n", rr, buf); } + printf("queueing read request %p at %"PRIu64"\n", rr, rr->offset); #endif } } -struct fxp_xfer *xfer_download_init(struct fxp_handle *fh, uint64 offset) +struct fxp_xfer *xfer_download_init(struct fxp_handle *fh, uint64_t offset) { struct fxp_xfer *xfer = xfer_init(fh, offset); @@ -1027,24 +1026,19 @@ int xfer_download_gotpkt(struct fxp_xfer *xfer, struct sftp_packet *pktin) * I simply shouldn't have been queueing multiple requests in * the first place... */ - if (rr->retlen > 0 && uint64_compare(xfer->furthestdata, rr->offset) < 0) { + if (rr->retlen > 0 && xfer->furthestdata < rr->offset) { xfer->furthestdata = rr->offset; #ifdef DEBUG_DOWNLOAD - { char buf[40]; - uint64_decimal(xfer->furthestdata, buf); - printf("setting furthestdata = %s\n", buf); } + printf("setting furthestdata = %"PRIu64"\n", xfer->furthestdata); #endif } if (rr->retlen < rr->len) { - uint64 filesize = uint64_add32(rr->offset, - (rr->retlen < 0 ? 0 : rr->retlen)); + uint64_t filesize = rr->offset + (rr->retlen < 0 ? 0 : rr->retlen); #ifdef DEBUG_DOWNLOAD - { char buf[40]; - uint64_decimal(filesize, buf); - printf("short block! trying filesize = %s\n", buf); } + printf("short block! trying filesize = %"PRIu64"\n", filesize); #endif - if (uint64_compare(xfer->filesize, filesize) > 0) { + if (xfer->filesize > filesize) { xfer->filesize = filesize; #ifdef DEBUG_DOWNLOAD printf("actually changing filesize\n"); @@ -1052,7 +1046,7 @@ int xfer_download_gotpkt(struct fxp_xfer *xfer, struct sftp_packet *pktin) } } - if (uint64_compare(xfer->furthestdata, xfer->filesize) > 0) { + if (xfer->furthestdata > xfer->filesize) { fxp_error_message = "received a short buffer from FXP_READ, but not" " at EOF"; fxp_errtype = -1; @@ -1109,7 +1103,7 @@ int xfer_download_data(struct fxp_xfer *xfer, void **buf, int *len) return 0; } -struct fxp_xfer *xfer_upload_init(struct fxp_handle *fh, uint64 offset) +struct fxp_xfer *xfer_upload_init(struct fxp_handle *fh, uint64_t offset) { struct fxp_xfer *xfer = xfer_init(fh, offset); @@ -1157,11 +1151,12 @@ void xfer_upload_data(struct fxp_xfer *xfer, char *buffer, int len) sftp_register(req = fxp_write_send(xfer->fh, buffer, rr->offset, len)); fxp_set_userdata(req, rr); - xfer->offset = uint64_add32(xfer->offset, rr->len); + xfer->offset += rr->len; xfer->req_totalsize += rr->len; #ifdef DEBUG_UPLOAD - { char buf[40]; uint64_decimal(rr->offset, buf); printf("queueing write request %p at %s [len %d]\n", rr, buf, len); } + printf("queueing write request %p at %"PRIu64" [len %d]\n", + rr, rr->offset, len); #endif } diff --git a/sftp.h b/sftp.h index 8bbb7f7b..1fbb6fa9 100644 --- a/sftp.h +++ b/sftp.h @@ -3,7 +3,6 @@ */ #include "defs.h" -#include "int64.h" #define SSH_FXP_INIT 1 /* 0x1 */ #define SSH_FXP_VERSION 2 /* 0x2 */ @@ -81,7 +80,7 @@ void sftp_cleanup_request(void); struct fxp_attrs { unsigned long flags; - uint64 size; + uint64_t size; unsigned long uid; unsigned long gid; unsigned long permissions; @@ -248,7 +247,7 @@ int fxp_fsetstat_recv(struct sftp_packet *pktin, struct sftp_request *req); * Read from a file. */ struct sftp_request *fxp_read_send(struct fxp_handle *handle, - uint64 offset, int len); + uint64_t offset, int len); int fxp_read_recv(struct sftp_packet *pktin, struct sftp_request *req, char *buffer, int len); @@ -256,7 +255,7 @@ int fxp_read_recv(struct sftp_packet *pktin, struct sftp_request *req, * Write to a file. Returns 0 on error, 1 on OK. */ struct sftp_request *fxp_write_send(struct fxp_handle *handle, - void *buffer, uint64 offset, int len); + void *buffer, uint64_t offset, int len); int fxp_write_recv(struct sftp_packet *pktin, struct sftp_request *req); /* @@ -299,12 +298,12 @@ struct sftp_packet *sftp_recv(void); struct fxp_xfer; -struct fxp_xfer *xfer_download_init(struct fxp_handle *fh, uint64 offset); +struct fxp_xfer *xfer_download_init(struct fxp_handle *fh, uint64_t offset); void xfer_download_queue(struct fxp_xfer *xfer); int xfer_download_gotpkt(struct fxp_xfer *xfer, struct sftp_packet *pktin); int xfer_download_data(struct fxp_xfer *xfer, void **buf, int *len); -struct fxp_xfer *xfer_upload_init(struct fxp_handle *fh, uint64 offset); +struct fxp_xfer *xfer_upload_init(struct fxp_handle *fh, uint64_t offset); int xfer_upload_ready(struct fxp_xfer *xfer); void xfer_upload_data(struct fxp_xfer *xfer, char *buffer, int len); int xfer_upload_gotpkt(struct fxp_xfer *xfer, struct sftp_packet *pktin); @@ -378,11 +377,11 @@ struct SftpServerVtable { /* Should call fxp_reply_error or fxp_reply_data */ void (*read)(SftpServer *srv, SftpReplyBuilder *reply, - ptrlen handle, uint64 offset, unsigned length); + ptrlen handle, uint64_t offset, unsigned length); /* Should call fxp_reply_error or fxp_reply_ok */ void (*write)(SftpServer *srv, SftpReplyBuilder *reply, - ptrlen handle, uint64 offset, ptrlen data); + ptrlen handle, uint64_t offset, ptrlen data); /* Should call fxp_reply_error, or fxp_reply_name_count once and * then fxp_reply_full_name that many times */ diff --git a/sftpserver.c b/sftpserver.c index 4324137e..b84365f2 100644 --- a/sftpserver.c +++ b/sftpserver.c @@ -16,7 +16,7 @@ struct sftp_packet *sftp_handle_request( struct sftp_packet *reply; unsigned id; ptrlen path, dstpath, handle, data; - uint64 offset; + uint64_t offset; unsigned length; struct fxp_attrs attrs; DefaultSftpReplyBuilder dsrb; diff --git a/ssh.h b/ssh.h index 439eebb1..5a932fe4 100644 --- a/ssh.h +++ b/ssh.h @@ -4,7 +4,6 @@ #include "puttymem.h" #include "tree234.h" #include "network.h" -#include "int64.h" #include "misc.h" struct ssh_channel; @@ -507,8 +506,6 @@ void rsa_ssh1_public_blob(BinarySink *bs, struct RSAKey *key, int rsa_ssh1_public_blob_len(void *data, int maxlen); void freersakey(struct RSAKey *key); -typedef uint32 word32; - unsigned long crc32_compute(const void *s, size_t len); unsigned long crc32_update(unsigned long crc_input, const void *s, size_t len); @@ -516,7 +513,7 @@ unsigned long crc32_update(unsigned long crc_input, const void *s, size_t len); struct crcda_ctx; struct crcda_ctx *crcda_make_context(void); void crcda_free_context(struct crcda_ctx *ctx); -int detect_attack(struct crcda_ctx *ctx, unsigned char *buf, uint32 len, +int detect_attack(struct crcda_ctx *ctx, unsigned char *buf, uint32_t len, unsigned char *IV); /* @@ -556,14 +553,14 @@ struct ssh2_cipheralg; typedef const struct ssh2_cipheralg *ssh2_cipher; typedef struct { - uint32 h[4]; + uint32_t h[4]; } MD5_Core_State; struct MD5Context { MD5_Core_State core; unsigned char block[64]; int blkused; - uint32 lenhi, lenlo; + uint64_t len; BinarySink_IMPLEMENTATION; }; @@ -581,10 +578,10 @@ void hmacmd5_do_hmac(struct hmacmd5_context *ctx, int supports_sha_ni(void); typedef struct SHA_State { - uint32 h[5]; + uint32_t h[5]; unsigned char block[64]; int blkused; - uint32 lenhi, lenlo; + uint64_t len; void (*sha1)(struct SHA_State * s, const unsigned char *p, int len); BinarySink_IMPLEMENTATION; } SHA_State; @@ -596,10 +593,10 @@ void hmac_sha1_simple(const void *key, int keylen, const void *data, int datalen, unsigned char *output); typedef struct SHA256_State { - uint32 h[8]; + uint32_t h[8]; unsigned char block[64]; int blkused; - uint32 lenhi, lenlo; + uint64_t len; void (*sha256)(struct SHA256_State * s, const unsigned char *p, int len); BinarySink_IMPLEMENTATION; } SHA256_State; @@ -608,10 +605,10 @@ void SHA256_Final(SHA256_State * s, unsigned char *output); void SHA256_Simple(const void *p, int len, unsigned char *output); typedef struct { - uint64 h[8]; + uint64_t h[8]; unsigned char block[128]; int blkused; - uint32 len[4]; + uint64_t lenhi, lenlo; BinarySink_IMPLEMENTATION; } SHA512_State; #define SHA384_State SHA512_State @@ -898,7 +895,7 @@ extern const char sshver[]; */ extern int ssh_fallback_cmd(Backend *backend); -void SHATransform(word32 * digest, word32 * data); +void SHATransform(uint32_t *digest, uint32_t *data); /* * Check of compiler version diff --git a/sshaes.c b/sshaes.c index 0790fc61..45a9eba3 100644 --- a/sshaes.c +++ b/sshaes.c @@ -49,10 +49,10 @@ #endif struct AESContext { - word32 keysched_buf[(MAX_NR + 1) * NB + 3]; - word32 invkeysched_buf[(MAX_NR + 1) * NB + 3]; - word32 *keysched, *invkeysched; - word32 iv[NB]; + uint32_t keysched_buf[(MAX_NR + 1) * NB + 3]; + uint32_t invkeysched_buf[(MAX_NR + 1) * NB + 3]; + uint32_t *keysched, *invkeysched; + uint32_t iv[NB]; int Nr; /* number of rounds */ void (*encrypt_cbc)(unsigned char*, int, AESContext*); void (*decrypt_cbc)(unsigned char*, int, AESContext*); @@ -156,7 +156,7 @@ static const unsigned char Sboxinv[256] = { 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d }; -static const word32 E0[256] = { +static const uint32_t E0[256] = { 0xc66363a5, 0xf87c7c84, 0xee777799, 0xf67b7b8d, 0xfff2f20d, 0xd66b6bbd, 0xde6f6fb1, 0x91c5c554, 0x60303050, 0x02010103, 0xce6767a9, 0x562b2b7d, @@ -222,7 +222,7 @@ static const word32 E0[256] = { 0x824141c3, 0x299999b0, 0x5a2d2d77, 0x1e0f0f11, 0x7bb0b0cb, 0xa85454fc, 0x6dbbbbd6, 0x2c16163a, }; -static const word32 E1[256] = { +static const uint32_t E1[256] = { 0xa5c66363, 0x84f87c7c, 0x99ee7777, 0x8df67b7b, 0x0dfff2f2, 0xbdd66b6b, 0xb1de6f6f, 0x5491c5c5, 0x50603030, 0x03020101, 0xa9ce6767, 0x7d562b2b, @@ -288,7 +288,7 @@ static const word32 E1[256] = { 0xc3824141, 0xb0299999, 0x775a2d2d, 0x111e0f0f, 0xcb7bb0b0, 0xfca85454, 0xd66dbbbb, 0x3a2c1616, }; -static const word32 E2[256] = { +static const uint32_t E2[256] = { 0x63a5c663, 0x7c84f87c, 0x7799ee77, 0x7b8df67b, 0xf20dfff2, 0x6bbdd66b, 0x6fb1de6f, 0xc55491c5, 0x30506030, 0x01030201, 0x67a9ce67, 0x2b7d562b, @@ -354,7 +354,7 @@ static const word32 E2[256] = { 0x41c38241, 0x99b02999, 0x2d775a2d, 0x0f111e0f, 0xb0cb7bb0, 0x54fca854, 0xbbd66dbb, 0x163a2c16, }; -static const word32 E3[256] = { +static const uint32_t E3[256] = { 0x6363a5c6, 0x7c7c84f8, 0x777799ee, 0x7b7b8df6, 0xf2f20dff, 0x6b6bbdd6, 0x6f6fb1de, 0xc5c55491, 0x30305060, 0x01010302, 0x6767a9ce, 0x2b2b7d56, @@ -420,7 +420,7 @@ static const word32 E3[256] = { 0x4141c382, 0x9999b029, 0x2d2d775a, 0x0f0f111e, 0xb0b0cb7b, 0x5454fca8, 0xbbbbd66d, 0x16163a2c, }; -static const word32 D0[256] = { +static const uint32_t D0[256] = { 0x51f4a750, 0x7e416553, 0x1a17a4c3, 0x3a275e96, 0x3bab6bcb, 0x1f9d45f1, 0xacfa58ab, 0x4be30393, 0x2030fa55, 0xad766df6, 0x88cc7691, 0xf5024c25, @@ -486,7 +486,7 @@ static const word32 D0[256] = { 0x39a80171, 0x080cb3de, 0xd8b4e49c, 0x6456c190, 0x7bcb8461, 0xd532b670, 0x486c5c74, 0xd0b85742, }; -static const word32 D1[256] = { +static const uint32_t D1[256] = { 0x5051f4a7, 0x537e4165, 0xc31a17a4, 0x963a275e, 0xcb3bab6b, 0xf11f9d45, 0xabacfa58, 0x934be303, 0x552030fa, 0xf6ad766d, 0x9188cc76, 0x25f5024c, @@ -552,7 +552,7 @@ static const word32 D1[256] = { 0x7139a801, 0xde080cb3, 0x9cd8b4e4, 0x906456c1, 0x617bcb84, 0x70d532b6, 0x74486c5c, 0x42d0b857, }; -static const word32 D2[256] = { +static const uint32_t D2[256] = { 0xa75051f4, 0x65537e41, 0xa4c31a17, 0x5e963a27, 0x6bcb3bab, 0x45f11f9d, 0x58abacfa, 0x03934be3, 0xfa552030, 0x6df6ad76, 0x769188cc, 0x4c25f502, @@ -618,7 +618,7 @@ static const word32 D2[256] = { 0x017139a8, 0xb3de080c, 0xe49cd8b4, 0xc1906456, 0x84617bcb, 0xb670d532, 0x5c74486c, 0x5742d0b8, }; -static const word32 D3[256] = { +static const uint32_t D3[256] = { 0xf4a75051, 0x4165537e, 0x17a4c31a, 0x275e963a, 0xab6bcb3b, 0x9d45f11f, 0xfa58abac, 0xe303934b, 0x30fa5520, 0x766df6ad, 0xcc769188, 0x024c25f5, @@ -700,11 +700,11 @@ static void aes_setup(AESContext * ctx, const unsigned char *key, int keylen) /* Ensure the key schedule arrays are 16-byte aligned */ bufaddr = (size_t)ctx->keysched_buf; ctx->keysched = ctx->keysched_buf + - (0xF & -bufaddr) / sizeof(word32); + (0xF & -bufaddr) / sizeof(uint32_t); assert((size_t)ctx->keysched % 16 == 0); bufaddr = (size_t)ctx->invkeysched_buf; ctx->invkeysched = ctx->invkeysched_buf + - (0xF & -bufaddr) / sizeof(word32); + (0xF & -bufaddr) / sizeof(uint32_t); assert((size_t)ctx->invkeysched % 16 == 0); ctx->isNI = supports_aes_ni(); @@ -726,7 +726,7 @@ static void aes_setup(AESContext * ctx, const unsigned char *key, int keylen) if (i < Nk) ctx->keysched[i] = GET_32BIT_MSB_FIRST(key + 4 * i); else { - word32 temp = ctx->keysched[i - 1]; + uint32_t temp = ctx->keysched[i - 1]; if (i % Nk == 0) { int a, b, c, d; a = (temp >> 16) & 0xFF; @@ -758,7 +758,7 @@ static void aes_setup(AESContext * ctx, const unsigned char *key, int keylen) */ for (i = 0; i <= ctx->Nr; i++) { for (j = 0; j < NB; j++) { - word32 temp; + uint32_t temp; temp = ctx->keysched[(ctx->Nr - i) * NB + j]; if (i != 0 && i != ctx->Nr) { /* @@ -826,7 +826,7 @@ static void aes_setup(AESContext * ctx, const unsigned char *key, int keylen) */ static void aes_encrypt_cbc_sw(unsigned char *blk, int len, AESContext * ctx) { - word32 block[4]; + uint32_t block[4]; unsigned char* finish = blk + len; int i; @@ -835,8 +835,8 @@ static void aes_encrypt_cbc_sw(unsigned char *blk, int len, AESContext * ctx) memcpy(block, ctx->iv, sizeof(block)); while (blk < finish) { - word32 *keysched = ctx->keysched; - word32 newstate[4]; + uint32_t *keysched = ctx->keysched; + uint32_t newstate[4]; for (i = 0; i < 4; i++) block[i] ^= GET_32BIT_MSB_FIRST(blk + 4 * i); ADD_ROUND_KEY; @@ -872,7 +872,7 @@ static void aes_encrypt_cbc_sw(unsigned char *blk, int len, AESContext * ctx) static void aes_sdctr_sw(unsigned char *blk, int len, AESContext *ctx) { - word32 iv[4]; + uint32_t iv[4]; unsigned char* finish = blk + len; int i; @@ -881,8 +881,8 @@ static void aes_sdctr_sw(unsigned char *blk, int len, AESContext *ctx) memcpy(iv, ctx->iv, sizeof(iv)); while (blk < finish) { - word32 *keysched = ctx->keysched; - word32 newstate[4], block[4], tmp; + uint32_t *keysched = ctx->keysched; + uint32_t newstate[4], block[4], tmp; memcpy(block, iv, sizeof(block)); ADD_ROUND_KEY; switch (ctx->Nr) { @@ -922,7 +922,7 @@ static void aes_sdctr_sw(unsigned char *blk, int len, AESContext *ctx) static void aes_decrypt_cbc_sw(unsigned char *blk, int len, AESContext * ctx) { - word32 iv[4]; + uint32_t iv[4]; unsigned char* finish = blk + len; int i; @@ -931,8 +931,8 @@ static void aes_decrypt_cbc_sw(unsigned char *blk, int len, AESContext * ctx) memcpy(iv, ctx->iv, sizeof(iv)); while (blk < finish) { - word32 *keysched = ctx->invkeysched; - word32 newstate[4], ct[4], block[4]; + uint32_t *keysched = ctx->invkeysched; + uint32_t newstate[4], ct[4], block[4]; for (i = 0; i < 4; i++) block[i] = ct[i] = GET_32BIT_MSB_FIRST(blk + 4 * i); ADD_ROUND_KEY; diff --git a/sshblowf.c b/sshblowf.c index d1d53c11..c440556f 100644 --- a/sshblowf.c +++ b/sshblowf.c @@ -10,8 +10,8 @@ #include "sshblowf.h" struct BlowfishContext { - word32 S0[256], S1[256], S2[256], S3[256], P[18]; - word32 iv0, iv1; /* for CBC mode */ + uint32_t S0[256], S1[256], S2[256], S3[256], P[18]; + uint32_t iv0, iv1; /* for CBC mode */ }; /* @@ -27,7 +27,7 @@ struct BlowfishContext { open my $spig, "spigot -n -B16 -d8336 pi |"; read $spig, $ignore, 2; # throw away the leading "3." for my $name ("parray", "sbox0".."sbox3") { - print "static const word32 ${name}[] = {\n"; + print "static const uint32_t ${name}[] = {\n"; my $len = $name eq "parray" ? 18 : 256; for my $i (1..$len) { read $spig, $word, 8; @@ -39,13 +39,13 @@ for my $name ("parray", "sbox0".."sbox3") { close $spig; */ -static const word32 parray[] = { +static const uint32_t parray[] = { 0x243F6A88, 0x85A308D3, 0x13198A2E, 0x03707344, 0xA4093822, 0x299F31D0, 0x082EFA98, 0xEC4E6C89, 0x452821E6, 0x38D01377, 0xBE5466CF, 0x34E90C6C, 0xC0AC29B7, 0xC97C50DD, 0x3F84D5B5, 0xB5470917, 0x9216D5D9, 0x8979FB1B, }; -static const word32 sbox0[] = { +static const uint32_t sbox0[] = { 0xD1310BA6, 0x98DFB5AC, 0x2FFD72DB, 0xD01ADFB7, 0xB8E1AFED, 0x6A267E96, 0xBA7C9045, 0xF12C7F99, 0x24A19947, 0xB3916CF7, 0x0801F2E2, 0x858EFC16, 0x636920D8, 0x71574E69, 0xA458FEA3, 0xF4933D7E, 0x0D95748F, 0x728EB658, @@ -91,7 +91,7 @@ static const word32 sbox0[] = { 0x53B02D5D, 0xA99F8FA1, 0x08BA4799, 0x6E85076A, }; -static const word32 sbox1[] = { +static const uint32_t sbox1[] = { 0x4B7A70E9, 0xB5B32944, 0xDB75092E, 0xC4192623, 0xAD6EA6B0, 0x49A7DF7D, 0x9CEE60B8, 0x8FEDB266, 0xECAA8C71, 0x699A17FF, 0x5664526C, 0xC2B19EE1, 0x193602A5, 0x75094C29, 0xA0591340, 0xE4183A3E, 0x3F54989A, 0x5B429D65, @@ -137,7 +137,7 @@ static const word32 sbox1[] = { 0x153E21E7, 0x8FB03D4A, 0xE6E39F2B, 0xDB83ADF7, }; -static const word32 sbox2[] = { +static const uint32_t sbox2[] = { 0xE93D5A68, 0x948140F7, 0xF64C261C, 0x94692934, 0x411520F7, 0x7602D4F7, 0xBCF46B2E, 0xD4A20068, 0xD4082471, 0x3320F46A, 0x43B7D4B7, 0x500061AF, 0x1E39F62E, 0x97244546, 0x14214F74, 0xBF8B8840, 0x4D95FC1D, 0x96B591AF, @@ -183,7 +183,7 @@ static const word32 sbox2[] = { 0xD79A3234, 0x92638212, 0x670EFA8E, 0x406000E0, }; -static const word32 sbox3[] = { +static const uint32_t sbox3[] = { 0x3A39CE37, 0xD3FAF5CF, 0xABC27737, 0x5AC52D1B, 0x5CB0679E, 0x4FA33742, 0xD3822740, 0x99BC9BBE, 0xD5118E9D, 0xBF0F7315, 0xD62D1C7E, 0xC700C47B, 0xB78C1B6B, 0x21A19045, 0xB26EB1BE, 0x6A366EB4, 0x5748AB2F, 0xBC946E79, @@ -233,15 +233,15 @@ static const word32 sbox3[] = { #define F(x) Fprime( ((x>>24)&0xFF), ((x>>16)&0xFF), ((x>>8)&0xFF), (x&0xFF) ) #define ROUND(n) ( xL ^= P[n], t = xL, xL = F(xL) ^ xR, xR = t ) -static void blowfish_encrypt(word32 xL, word32 xR, word32 * output, +static void blowfish_encrypt(uint32_t xL, uint32_t xR, uint32_t *output, BlowfishContext * ctx) { - word32 *S0 = ctx->S0; - word32 *S1 = ctx->S1; - word32 *S2 = ctx->S2; - word32 *S3 = ctx->S3; - word32 *P = ctx->P; - word32 t; + uint32_t *S0 = ctx->S0; + uint32_t *S1 = ctx->S1; + uint32_t *S2 = ctx->S2; + uint32_t *S3 = ctx->S3; + uint32_t *P = ctx->P; + uint32_t t; ROUND(0); ROUND(1); @@ -266,15 +266,15 @@ static void blowfish_encrypt(word32 xL, word32 xR, word32 * output, output[1] = xL; } -static void blowfish_decrypt(word32 xL, word32 xR, word32 * output, +static void blowfish_decrypt(uint32_t xL, uint32_t xR, uint32_t *output, BlowfishContext * ctx) { - word32 *S0 = ctx->S0; - word32 *S1 = ctx->S1; - word32 *S2 = ctx->S2; - word32 *S3 = ctx->S3; - word32 *P = ctx->P; - word32 t; + uint32_t *S0 = ctx->S0; + uint32_t *S1 = ctx->S1; + uint32_t *S2 = ctx->S2; + uint32_t *S3 = ctx->S3; + uint32_t *P = ctx->P; + uint32_t t; ROUND(17); ROUND(16); @@ -302,7 +302,7 @@ static void blowfish_decrypt(word32 xL, word32 xR, word32 * output, static void blowfish_lsb_encrypt_cbc(unsigned char *blk, int len, BlowfishContext * ctx) { - word32 xL, xR, out[2], iv0, iv1; + uint32_t xL, xR, out[2], iv0, iv1; assert((len & 7) == 0); @@ -330,7 +330,7 @@ static void blowfish_lsb_encrypt_cbc(unsigned char *blk, int len, void blowfish_lsb_encrypt_ecb(void *vblk, int len, BlowfishContext * ctx) { unsigned char *blk = (unsigned char *)vblk; - word32 xL, xR, out[2]; + uint32_t xL, xR, out[2]; assert((len & 7) == 0); @@ -348,7 +348,7 @@ void blowfish_lsb_encrypt_ecb(void *vblk, int len, BlowfishContext * ctx) static void blowfish_lsb_decrypt_cbc(unsigned char *blk, int len, BlowfishContext * ctx) { - word32 xL, xR, out[2], iv0, iv1; + uint32_t xL, xR, out[2], iv0, iv1; assert((len & 7) == 0); @@ -376,7 +376,7 @@ static void blowfish_lsb_decrypt_cbc(unsigned char *blk, int len, static void blowfish_msb_encrypt_cbc(unsigned char *blk, int len, BlowfishContext * ctx) { - word32 xL, xR, out[2], iv0, iv1; + uint32_t xL, xR, out[2], iv0, iv1; assert((len & 7) == 0); @@ -404,7 +404,7 @@ static void blowfish_msb_encrypt_cbc(unsigned char *blk, int len, static void blowfish_msb_decrypt_cbc(unsigned char *blk, int len, BlowfishContext * ctx) { - word32 xL, xR, out[2], iv0, iv1; + uint32_t xL, xR, out[2], iv0, iv1; assert((len & 7) == 0); @@ -432,7 +432,7 @@ static void blowfish_msb_decrypt_cbc(unsigned char *blk, int len, static void blowfish_msb_sdctr(unsigned char *blk, int len, BlowfishContext * ctx) { - word32 b[2], iv0, iv1, tmp; + uint32_t b[2], iv0, iv1, tmp; assert((len & 7) == 0); @@ -477,12 +477,12 @@ void blowfish_expandkey(BlowfishContext * ctx, { const unsigned char *key = (const unsigned char *)vkey; const unsigned char *salt = (const unsigned char *)vsalt; - word32 *S0 = ctx->S0; - word32 *S1 = ctx->S1; - word32 *S2 = ctx->S2; - word32 *S3 = ctx->S3; - word32 *P = ctx->P; - word32 str[2]; + uint32_t *S0 = ctx->S0; + uint32_t *S1 = ctx->S1; + uint32_t *S2 = ctx->S2; + uint32_t *S3 = ctx->S3; + uint32_t *P = ctx->P; + uint32_t str[2]; int i, j; int saltpos; unsigned char dummysalt[1]; @@ -496,19 +496,19 @@ void blowfish_expandkey(BlowfishContext * ctx, for (i = 0; i < 18; i++) { P[i] ^= - ((word32) (unsigned char) (key[(i * 4 + 0) % keybytes])) << 24; + ((uint32_t) (unsigned char) (key[(i * 4 + 0) % keybytes])) << 24; P[i] ^= - ((word32) (unsigned char) (key[(i * 4 + 1) % keybytes])) << 16; + ((uint32_t) (unsigned char) (key[(i * 4 + 1) % keybytes])) << 16; P[i] ^= - ((word32) (unsigned char) (key[(i * 4 + 2) % keybytes])) << 8; - P[i] ^= ((word32) (unsigned char) (key[(i * 4 + 3) % keybytes])); + ((uint32_t) (unsigned char) (key[(i * 4 + 2) % keybytes])) << 8; + P[i] ^= ((uint32_t) (unsigned char) (key[(i * 4 + 3) % keybytes])); } str[0] = str[1] = 0; for (i = 0; i < 18; i += 2) { for (j = 0; j < 8; j++) - str[j/4] ^= ((word32)salt[saltpos++ % saltbytes]) << (24-8*(j%4)); + str[j/4] ^= ((uint32_t)salt[saltpos++ % saltbytes]) << (24-8*(j%4)); blowfish_encrypt(str[0], str[1], str, ctx); P[i] = str[0]; @@ -517,28 +517,28 @@ void blowfish_expandkey(BlowfishContext * ctx, for (i = 0; i < 256; i += 2) { for (j = 0; j < 8; j++) - str[j/4] ^= ((word32)salt[saltpos++ % saltbytes]) << (24-8*(j%4)); + str[j/4] ^= ((uint32_t)salt[saltpos++ % saltbytes]) << (24-8*(j%4)); blowfish_encrypt(str[0], str[1], str, ctx); S0[i] = str[0]; S0[i + 1] = str[1]; } for (i = 0; i < 256; i += 2) { for (j = 0; j < 8; j++) - str[j/4] ^= ((word32)salt[saltpos++ % saltbytes]) << (24-8*(j%4)); + str[j/4] ^= ((uint32_t)salt[saltpos++ % saltbytes]) << (24-8*(j%4)); blowfish_encrypt(str[0], str[1], str, ctx); S1[i] = str[0]; S1[i + 1] = str[1]; } for (i = 0; i < 256; i += 2) { for (j = 0; j < 8; j++) - str[j/4] ^= ((word32)salt[saltpos++ % saltbytes]) << (24-8*(j%4)); + str[j/4] ^= ((uint32_t)salt[saltpos++ % saltbytes]) << (24-8*(j%4)); blowfish_encrypt(str[0], str[1], str, ctx); S2[i] = str[0]; S2[i + 1] = str[1]; } for (i = 0; i < 256; i += 2) { for (j = 0; j < 8; j++) - str[j/4] ^= ((word32)salt[saltpos++ % saltbytes]) << (24-8*(j%4)); + str[j/4] ^= ((uint32_t)salt[saltpos++ % saltbytes]) << (24-8*(j%4)); blowfish_encrypt(str[0], str[1], str, ctx); S3[i] = str[0]; S3[i + 1] = str[1]; diff --git a/sshccp.c b/sshccp.c index 4b26a438..1ce40699 100644 --- a/sshccp.c +++ b/sshccp.c @@ -45,7 +45,7 @@ struct chacha20 { * 4-11 are the key * 12-13 are the counter * 14-15 are the IV */ - uint32 state[16]; + uint32_t state[16]; /* The output of the state above ready to xor */ unsigned char current[64]; /* The index of the above currently used to allow a true streaming cipher */ @@ -55,7 +55,7 @@ struct chacha20 { static INLINE void chacha20_round(struct chacha20 *ctx) { int i; - uint32 copy[16]; + uint32_t copy[16]; /* Take a copy */ memcpy(copy, ctx->state, sizeof(copy)); @@ -114,7 +114,7 @@ static INLINE void chacha20_round(struct chacha20 *ctx) /* Increment round counter */ ++ctx->state[12]; /* Check for overflow, not done in one line so the 32 bits are chopped by the type */ - if (!(uint32)(ctx->state[12])) { + if (!(uint32_t)(ctx->state[12])) { ++ctx->state[13]; } } diff --git a/sshcrcda.c b/sshcrcda.c index fe6598d3..2813ceed 100644 --- a/sshcrcda.c +++ b/sshcrcda.c @@ -25,16 +25,13 @@ #include "misc.h" #include "ssh.h" -typedef unsigned char uchar; -typedef unsigned short uint16; - /* SSH Constants */ #define SSH_MAXBLOCKS (32 * 1024) #define SSH_BLOCKSIZE (8) /* Hashing constants */ #define HASH_MINSIZE (8 * 1024) -#define HASH_ENTRYSIZE (sizeof(uint16)) +#define HASH_ENTRYSIZE (sizeof(uint16_t)) #define HASH_FACTOR(x) ((x)*3/2) #define HASH_UNUSEDCHAR (0xff) #define HASH_UNUSED (0xffff) @@ -47,12 +44,12 @@ typedef unsigned short uint16; #define CMP(a, b) (memcmp(a, b, SSH_BLOCKSIZE)) -uchar ONE[4] = { 1, 0, 0, 0 }; -uchar ZERO[4] = { 0, 0, 0, 0 }; +uint8_t ONE[4] = { 1, 0, 0, 0 }; +uint8_t ZERO[4] = { 0, 0, 0, 0 }; struct crcda_ctx { - uint16 *h; - uint32 n; + uint16_t *h; + uint32_t n; }; struct crcda_ctx *crcda_make_context(void) @@ -72,16 +69,16 @@ void crcda_free_context(struct crcda_ctx *ctx) } } -static void crc_update(uint32 *a, void *b) +static void crc_update(uint32_t *a, void *b) { *a = crc32_update(*a, b, 4); } /* detect if a block is used in a particular pattern */ -static int check_crc(uchar *S, uchar *buf, uint32 len, uchar *IV) +static int check_crc(uint8_t *S, uint8_t *buf, uint32_t len, uint8_t *IV) { - uint32 crc; - uchar *c; + uint32_t crc; + uint8_t *c; crc = 0; if (IV && !CMP(S, IV)) { @@ -101,12 +98,13 @@ static int check_crc(uchar *S, uchar *buf, uint32 len, uchar *IV) } /* Detect a crc32 compensation attack on a packet */ -int detect_attack(struct crcda_ctx *ctx, uchar *buf, uint32 len, uchar *IV) +int detect_attack( + struct crcda_ctx *ctx, uint8_t *buf, uint32_t len, uint8_t *IV) { - register uint32 i, j; - uint32 l; - register uchar *c; - uchar *d; + register uint32_t i, j; + uint32_t l; + register uint8_t *c; + uint8_t *d; assert(!(len > (SSH_MAXBLOCKS * SSH_BLOCKSIZE) || len % SSH_BLOCKSIZE != 0)); @@ -115,11 +113,11 @@ int detect_attack(struct crcda_ctx *ctx, uchar *buf, uint32 len, uchar *IV) if (ctx->h == NULL) { ctx->n = l; - ctx->h = snewn(ctx->n, uint16); + ctx->h = snewn(ctx->n, uint16_t); } else { if (l > ctx->n) { ctx->n = l; - ctx->h = sresize(ctx->h, ctx->n, uint16); + ctx->h = sresize(ctx->h, ctx->n, uint16_t); } } diff --git a/sshdes.c b/sshdes.c index b69e9bc0..3c5953f1 100644 --- a/sshdes.c +++ b/sshdes.c @@ -277,16 +277,16 @@ */ typedef struct { - word32 k0246[16], k1357[16]; - word32 iv0, iv1; + uint32_t k0246[16], k1357[16]; + uint32_t iv0, iv1; } DESContext; #define rotl(x, c) ( (x << c) | (x >> (32-c)) ) #define rotl28(x, c) ( ( (x << c) | (x >> (28-c)) ) & 0x0FFFFFFF) -static word32 bitsel(word32 * input, const int *bitnums, int size) +static uint32_t bitsel(uint32_t *input, const int *bitnums, int size) { - word32 ret = 0; + uint32_t ret = 0; while (size--) { int bitpos = *bitnums++; ret <<= 1; @@ -296,7 +296,8 @@ static word32 bitsel(word32 * input, const int *bitnums, int size) return ret; } -static void des_key_setup(word32 key_msw, word32 key_lsw, DESContext * sched) +static void des_key_setup( + uint32_t key_msw, uint32_t key_lsw, DESContext *sched) { static const int PC1_Cbits[] = { @@ -326,8 +327,8 @@ static void des_key_setup(word32 key_msw, word32 key_lsw, DESContext * sched) static const int leftshifts[] = { 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 }; - word32 C, D; - word32 buf[2]; + uint32_t C, D; + uint32_t buf[2]; int i; buf[0] = key_lsw; @@ -348,7 +349,7 @@ static void des_key_setup(word32 key_msw, word32 key_lsw, DESContext * sched) sched->iv0 = sched->iv1 = 0; } -static const word32 SPboxes[8][64] = { +static const uint32_t SPboxes[8][64] = { {0x01010400, 0x00000000, 0x00010000, 0x01010404, 0x01010004, 0x00010404, 0x00000004, 0x00010000, 0x00000400, 0x01010400, 0x01010404, 0x00000400, @@ -520,10 +521,10 @@ static const word32 SPboxes[8][64] = { bitswap(R, L, 16, 0x0000FFFF), \ bitswap(R, L, 4, 0x0F0F0F0F)) -static void des_encipher(word32 * output, word32 L, word32 R, - DESContext * sched) +static void des_encipher( + uint32_t *output, uint32_t L, uint32_t R, DESContext *sched) { - word32 swap, s0246, s1357; + uint32_t swap, s0246, s1357; IP(L, R); @@ -560,10 +561,10 @@ static void des_encipher(word32 * output, word32 L, word32 R, output[1] = R; } -static void des_decipher(word32 * output, word32 L, word32 R, - DESContext * sched) +static void des_decipher( + uint32_t *output, uint32_t L, uint32_t R, DESContext *sched) { - word32 swap, s0246, s1357; + uint32_t swap, s0246, s1357; IP(L, R); @@ -603,7 +604,7 @@ static void des_decipher(word32 * output, word32 L, word32 R, static void des_cbc_encrypt(unsigned char *blk, unsigned int len, DESContext * sched) { - word32 out[2], iv0, iv1; + uint32_t out[2], iv0, iv1; unsigned int i; assert((len & 7) == 0); @@ -627,7 +628,7 @@ static void des_cbc_encrypt(unsigned char *blk, static void des_cbc_decrypt(unsigned char *blk, unsigned int len, DESContext * sched) { - word32 out[2], iv0, iv1, xL, xR; + uint32_t out[2], iv0, iv1, xL, xR; unsigned int i; assert((len & 7) == 0); @@ -661,7 +662,7 @@ static void des_3cbc_encrypt(unsigned char *blk, static void des_cbc3_encrypt(unsigned char *blk, unsigned int len, DESContext * scheds) { - word32 out[2], iv0, iv1; + uint32_t out[2], iv0, iv1; unsigned int i; assert((len & 7) == 0); @@ -695,7 +696,7 @@ static void des_3cbc_decrypt(unsigned char *blk, static void des_cbc3_decrypt(unsigned char *blk, unsigned int len, DESContext * scheds) { - word32 out[2], iv0, iv1, xL, xR; + uint32_t out[2], iv0, iv1, xL, xR; unsigned int i; assert((len & 7) == 0); @@ -723,7 +724,7 @@ static void des_cbc3_decrypt(unsigned char *blk, static void des_sdctr3(unsigned char *blk, unsigned int len, DESContext * scheds) { - word32 b[2], iv0, iv1, tmp; + uint32_t b[2], iv0, iv1, tmp; unsigned int i; assert((len & 7) == 0); diff --git a/sshmd5.c b/sshmd5.c index 743df03f..a9058be8 100644 --- a/sshmd5.c +++ b/sshmd5.c @@ -15,7 +15,7 @@ #define H(x,y,z) ( (x) ^ (y) ^ (z) ) #define I(x,y,z) ( (y) ^ ( (x) | ~(z) ) ) -#define rol(x,y) ( ((x) << (y)) | (((uint32)x) >> (32-y)) ) +#define rol(x,y) ( ((x) << (y)) | (((uint32_t)x) >> (32-y)) ) #define subround(f,w,x,y,z,k,s,ti) \ w = x + rol(w + f(x,y,z) + block[k] + ti, s) @@ -28,9 +28,9 @@ static void MD5_Core_Init(MD5_Core_State * s) s->h[3] = 0x10325476; } -static void MD5_Block(MD5_Core_State * s, uint32 * block) +static void MD5_Block(MD5_Core_State *s, uint32_t *block) { - uint32 a, b, c, d; + uint32_t a, b, c, d; a = s->h[0]; b = s->h[1]; @@ -122,7 +122,7 @@ void MD5Init(struct MD5Context *s) { MD5_Core_Init(&s->core); s->blkused = 0; - s->lenhi = s->lenlo = 0; + s->len = 0; BinarySink_INIT(s, MD5_BinarySink_write); } @@ -130,8 +130,8 @@ static void MD5_BinarySink_write(BinarySink *bs, const void *data, size_t len) { struct MD5Context *s = BinarySink_DOWNCAST(bs, struct MD5Context); const unsigned char *q = (const unsigned char *)data; - uint32 wordblock[16]; - uint32 lenw = len; + uint32_t wordblock[16]; + uint32_t lenw = len; int i; assert(lenw == len); @@ -139,8 +139,7 @@ static void MD5_BinarySink_write(BinarySink *bs, const void *data, size_t len) /* * Update the length field. */ - s->lenlo += lenw; - s->lenhi += (s->lenlo < lenw); + s->len += lenw; if (s->blkused + len < BLKSIZE) { /* @@ -159,10 +158,10 @@ static void MD5_BinarySink_write(BinarySink *bs, const void *data, size_t len) /* Now process the block. Gather bytes little-endian into words */ for (i = 0; i < 16; i++) { wordblock[i] = - (((uint32) s->block[i * 4 + 3]) << 24) | - (((uint32) s->block[i * 4 + 2]) << 16) | - (((uint32) s->block[i * 4 + 1]) << 8) | - (((uint32) s->block[i * 4 + 0]) << 0); + (((uint32_t) s->block[i * 4 + 3]) << 24) | + (((uint32_t) s->block[i * 4 + 2]) << 16) | + (((uint32_t) s->block[i * 4 + 1]) << 8) | + (((uint32_t) s->block[i * 4 + 0]) << 0); } MD5_Block(&s->core, wordblock); s->blkused = 0; @@ -177,28 +176,20 @@ void MD5Final(unsigned char output[16], struct MD5Context *s) int i; unsigned pad; unsigned char c[64]; - uint32 lenhi, lenlo; + uint64_t len; if (s->blkused >= 56) pad = 56 + 64 - s->blkused; else pad = 56 - s->blkused; - lenhi = (s->lenhi << 3) | (s->lenlo >> (32 - 3)); - lenlo = (s->lenlo << 3); + len = (s->len << 3); memset(c, 0, pad); c[0] = 0x80; put_data(s, c, pad); - c[7] = (lenhi >> 24) & 0xFF; - c[6] = (lenhi >> 16) & 0xFF; - c[5] = (lenhi >> 8) & 0xFF; - c[4] = (lenhi >> 0) & 0xFF; - c[3] = (lenlo >> 24) & 0xFF; - c[2] = (lenlo >> 16) & 0xFF; - c[1] = (lenlo >> 8) & 0xFF; - c[0] = (lenlo >> 0) & 0xFF; + PUT_64BIT_LSB_FIRST(c, len); put_data(s, c, 8); diff --git a/sshrand.c b/sshrand.c index 31b1739e..1fcac420 100644 --- a/sshrand.c +++ b/sshrand.c @@ -70,8 +70,8 @@ int random_diagnostics = 0; static void random_stir(void) { - word32 block[HASHINPUT / sizeof(word32)]; - word32 digest[HASHSIZE / sizeof(word32)]; + uint32_t block[HASHINPUT / sizeof(uint32_t)]; + uint32_t digest[HASHSIZE / sizeof(uint32_t)]; int i, j, k; /* @@ -91,24 +91,24 @@ static void random_stir(void) for (p = 0; p < POOLSIZE; p += HASHSIZE) { printf(" "); for (q = 0; q < HASHSIZE; q += 4) { - printf(" %08x", *(word32 *)(pool.pool + p + q)); + printf(" %08x", *(uint32_t *)(pool.pool + p + q)); } printf("\n"); } printf("incoming:\n "); for (q = 0; q < HASHSIZE; q += 4) { - printf(" %08x", *(word32 *)(pool.incoming + q)); + printf(" %08x", *(uint32_t *)(pool.incoming + q)); } printf("\nincomingb:\n "); for (q = 0; q < HASHINPUT; q += 4) { - printf(" %08x", *(word32 *)(pool.incomingb + q)); + printf(" %08x", *(uint32_t *)(pool.incomingb + q)); } printf("\n"); random_diagnostics++; } #endif - SHATransform((word32 *) pool.incoming, (word32 *) pool.incomingb); + SHATransform((uint32_t *) pool.incoming, (uint32_t *) pool.incomingb); pool.incomingpos = 0; /* @@ -144,7 +144,7 @@ static void random_stir(void) */ for (k = 0; k < sizeof(digest) / sizeof(*digest); k++) - digest[k] ^= ((word32 *) (pool.pool + j))[k]; + digest[k] ^= ((uint32_t *) (pool.pool + j))[k]; /* * Munge our unrevealed first block of the pool into @@ -157,7 +157,7 @@ static void random_stir(void) */ for (k = 0; k < sizeof(digest) / sizeof(*digest); k++) - ((word32 *) (pool.pool + j))[k] = digest[k]; + ((uint32_t *) (pool.pool + j))[k] = digest[k]; } #ifdef RANDOM_DIAGNOSTICS @@ -167,17 +167,17 @@ static void random_stir(void) for (p = 0; p < POOLSIZE; p += HASHSIZE) { printf(" "); for (q = 0; q < HASHSIZE; q += 4) { - printf(" %08x", *(word32 *)(pool.pool + p + q)); + printf(" %08x", *(uint32_t *)(pool.pool + p + q)); } printf("\n"); } printf("incoming:\n "); for (q = 0; q < HASHSIZE; q += 4) { - printf(" %08x", *(word32 *)(pool.incoming + q)); + printf(" %08x", *(uint32_t *)(pool.incoming + q)); } printf("\nincomingb:\n "); for (q = 0; q < HASHINPUT; q += 4) { - printf(" %08x", *(word32 *)(pool.incomingb + q)); + printf(" %08x", *(uint32_t *)(pool.incomingb + q)); } printf("\n"); } @@ -202,17 +202,17 @@ static void random_stir(void) for (p = 0; p < POOLSIZE; p += HASHSIZE) { printf(" "); for (q = 0; q < HASHSIZE; q += 4) { - printf(" %08x", *(word32 *)(pool.pool + p + q)); + printf(" %08x", *(uint32_t *)(pool.pool + p + q)); } printf("\n"); } printf("incoming:\n "); for (q = 0; q < HASHSIZE; q += 4) { - printf(" %08x", *(word32 *)(pool.incoming + q)); + printf(" %08x", *(uint32_t *)(pool.incoming + q)); } printf("\nincomingb:\n "); for (q = 0; q < HASHINPUT; q += 4) { - printf(" %08x", *(word32 *)(pool.incomingb + q)); + printf(" %08x", *(uint32_t *)(pool.incomingb + q)); } printf("\n"); random_diagnostics--; @@ -238,7 +238,7 @@ void random_add_noise(void *noise, int length) HASHINPUT - pool.incomingpos); p += HASHINPUT - pool.incomingpos; length -= HASHINPUT - pool.incomingpos; - SHATransform((word32 *) pool.incoming, (word32 *) pool.incomingb); + SHATransform((uint32_t *) pool.incoming, (uint32_t *) pool.incomingb); for (i = 0; i < HASHSIZE; i++) { pool.pool[pool.poolpos++] ^= pool.incoming[i]; if (pool.poolpos >= POOLSIZE) diff --git a/sshsh256.c b/sshsh256.c index dbdfbcf0..da6782f1 100644 --- a/sshsh256.c +++ b/sshsh256.c @@ -11,8 +11,8 @@ * Core SHA256 algorithm: processes 16-word blocks into a message digest. */ -#define ror(x,y) ( ((x) << (32-y)) | (((uint32)(x)) >> (y)) ) -#define shr(x,y) ( (((uint32)(x)) >> (y)) ) +#define ror(x,y) ( ((x) << (32-y)) | (((uint32_t)(x)) >> (y)) ) +#define shr(x,y) ( (((uint32_t)(x)) >> (y)) ) #define Ch(x,y,z) ( ((x) & (y)) ^ (~(x) & (z)) ) #define Maj(x,y,z) ( ((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)) ) #define bigsigma0(x) ( ror((x),2) ^ ror((x),13) ^ ror((x),22) ) @@ -34,9 +34,9 @@ void SHA256_Core_Init(SHA256_State *s) { s->h[7] = 0x5be0cd19; } -void SHA256_Block(SHA256_State *s, uint32 *block) { - uint32 w[80]; - uint32 a,b,c,d,e,f,g,h; +void SHA256_Block(SHA256_State *s, uint32_t *block) { + uint32_t w[80]; + uint32_t a,b,c,d,e,f,g,h; static const int k[] = { 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, @@ -68,7 +68,7 @@ void SHA256_Block(SHA256_State *s, uint32 *block) { e = s->h[4]; f = s->h[5]; g = s->h[6]; h = s->h[7]; for (t = 0; t < 64; t+=8) { - uint32 t1, t2; + uint32_t t1, t2; #define ROUND(j,a,b,c,d,e,f,g,h) \ t1 = h + bigsigma1(e) + Ch(e,f,g) + k[j] + w[j]; \ @@ -103,7 +103,7 @@ static void SHA256_BinarySink_write(BinarySink *bs, void SHA256_Init(SHA256_State *s) { SHA256_Core_Init(s); s->blkused = 0; - s->lenhi = s->lenlo = 0; + s->len = 0; if (supports_sha_ni()) s->sha256 = &SHA256_ni; else @@ -117,19 +117,16 @@ static void SHA256_BinarySink_write(BinarySink *bs, struct SHA256_State *s = BinarySink_DOWNCAST(bs, struct SHA256_State); unsigned char *q = (unsigned char *)p; - uint32 lenw = len; - assert(len == lenw); - /* * Update the length field. */ - s->lenlo += lenw; - s->lenhi += (s->lenlo < lenw); + s->len += len; + (*(s->sha256))(s, q, len); } static void SHA256_sw(SHA256_State *s, const unsigned char *q, int len) { - uint32 wordblock[16]; + uint32_t wordblock[16]; int i; if (s->blkused && s->blkused+len < BLKSIZE) { @@ -149,10 +146,10 @@ static void SHA256_sw(SHA256_State *s, const unsigned char *q, int len) { /* Now process the block. Gather bytes big-endian into words */ for (i = 0; i < 16; i++) { wordblock[i] = - ( ((uint32)s->block[i*4+0]) << 24 ) | - ( ((uint32)s->block[i*4+1]) << 16 ) | - ( ((uint32)s->block[i*4+2]) << 8 ) | - ( ((uint32)s->block[i*4+3]) << 0 ); + ( ((uint32_t)s->block[i*4+0]) << 24 ) | + ( ((uint32_t)s->block[i*4+1]) << 16 ) | + ( ((uint32_t)s->block[i*4+2]) << 8 ) | + ( ((uint32_t)s->block[i*4+3]) << 0 ); } SHA256_Block(s, wordblock); s->blkused = 0; @@ -166,22 +163,20 @@ void SHA256_Final(SHA256_State *s, unsigned char *digest) { int i; int pad; unsigned char c[64]; - uint32 lenhi, lenlo; + uint64_t len; if (s->blkused >= 56) pad = 56 + 64 - s->blkused; else pad = 56 - s->blkused; - lenhi = (s->lenhi << 3) | (s->lenlo >> (32-3)); - lenlo = (s->lenlo << 3); + len = (s->len << 3); memset(c, 0, pad); c[0] = 0x80; put_data(s, &c, pad); - put_uint32(s, lenhi); - put_uint32(s, lenlo); + put_uint64(s, len); for (i = 0; i < 8; i++) { digest[i*4+0] = (s->h[i] >> 24) & 0xFF; diff --git a/sshsh512.c b/sshsh512.c index b518f6a5..09abf587 100644 --- a/sshsh512.c +++ b/sshsh512.c @@ -15,21 +15,17 @@ * Arithmetic implementations. Note that AND, XOR and NOT can * overlap destination with one source, but the others can't. */ -#define add(r,x,y) ( r.lo = y.lo + x.lo, \ - r.hi = y.hi + x.hi + ((uint32)r.lo < (uint32)y.lo) ) -#define rorB(r,x,y) ( r.lo = ((uint32)x.hi >> ((y)-32)) | ((uint32)x.lo << (64-(y))), \ - r.hi = ((uint32)x.lo >> ((y)-32)) | ((uint32)x.hi << (64-(y))) ) -#define rorL(r,x,y) ( r.lo = ((uint32)x.lo >> (y)) | ((uint32)x.hi << (32-(y))), \ - r.hi = ((uint32)x.hi >> (y)) | ((uint32)x.lo << (32-(y))) ) -#define shrB(r,x,y) ( r.lo = (uint32)x.hi >> ((y)-32), r.hi = 0 ) -#define shrL(r,x,y) ( r.lo = ((uint32)x.lo >> (y)) | ((uint32)x.hi << (32-(y))), \ - r.hi = (uint32)x.hi >> (y) ) -#define and(r,x,y) ( r.lo = x.lo & y.lo, r.hi = x.hi & y.hi ) -#define xor(r,x,y) ( r.lo = x.lo ^ y.lo, r.hi = x.hi ^ y.hi ) -#define not(r,x) ( r.lo = ~x.lo, r.hi = ~x.hi ) -#define INIT(h,l) { h, l } -#define BUILD(r,h,l) ( r.hi = h, r.lo = l ) -#define EXTRACT(h,l,r) ( h = r.hi, l = r.lo ) +#define add(r,x,y) ( r = (x) + (y) ) +#define rorB(r,x,y) ( r = ((x) >> (y)) | ((x) << (64-(y))) ) +#define rorL(r,x,y) ( r = ((x) >> (y)) | ((x) << (64-(y))) ) +#define shrB(r,x,y) ( r = (x) >> (y) ) +#define shrL(r,x,y) ( r = (x) >> (y) ) +#define and(r,x,y) ( r = (x) & (y) ) +#define xor(r,x,y) ( r = (x) ^ (y) ) +#define not(r,x) ( r = ~(x) ) +#define INIT(h,l) ((((uint64_t)(h)) << 32) | (l)) +#define BUILD(r,h,l) ( r = ((((uint64_t)(h)) << 32) | (l)) ) +#define EXTRACT(h,l,r) ( h = (r) >> 32, l = (r) & 0xFFFFFFFFU ) /* ---------------------------------------------------------------------- * Core SHA512 algorithm: processes 16-doubleword blocks into a @@ -49,7 +45,7 @@ shrL(t,x,6), xor(r,r,t) ) static void SHA512_Core_Init(SHA512_State *s) { - static const uint64 iv[] = { + static const uint64_t iv[] = { INIT(0x6a09e667, 0xf3bcc908), INIT(0xbb67ae85, 0x84caa73b), INIT(0x3c6ef372, 0xfe94f82b), @@ -65,7 +61,7 @@ static void SHA512_Core_Init(SHA512_State *s) { } static void SHA384_Core_Init(SHA512_State *s) { - static const uint64 iv[] = { + static const uint64_t iv[] = { INIT(0xcbbb9d5d, 0xc1059ed8), INIT(0x629a292a, 0x367cd507), INIT(0x9159015a, 0x3070dd17), @@ -80,10 +76,10 @@ static void SHA384_Core_Init(SHA512_State *s) { s->h[i] = iv[i]; } -static void SHA512_Block(SHA512_State *s, uint64 *block) { - uint64 w[80]; - uint64 a,b,c,d,e,f,g,h; - static const uint64 k[] = { +static void SHA512_Block(SHA512_State *s, uint64_t *block) { + uint64_t w[80]; + uint64_t a,b,c,d,e,f,g,h; + static const uint64_t k[] = { INIT(0x428a2f98, 0xd728ae22), INIT(0x71374491, 0x23ef65cd), INIT(0xb5c0fbcf, 0xec4d3b2f), INIT(0xe9b5dba5, 0x8189dbbc), INIT(0x3956c25b, 0xf348b538), INIT(0x59f111f1, 0xb605d019), @@ -132,7 +128,7 @@ static void SHA512_Block(SHA512_State *s, uint64 *block) { w[t] = block[t]; for (t = 16; t < 80; t++) { - uint64 p, q, r, tmp; + uint64_t p, q, r, tmp; smallsigma1(p, tmp, w[t-2]); smallsigma0(q, tmp, w[t-15]); add(r, p, q); @@ -144,7 +140,7 @@ static void SHA512_Block(SHA512_State *s, uint64 *block) { e = s->h[4]; f = s->h[5]; g = s->h[6]; h = s->h[7]; for (t = 0; t < 80; t+=8) { - uint64 tmp, p, q, r; + uint64_t tmp, p, q, r; #define ROUND(j,a,b,c,d,e,f,g,h) \ bigsigma1(p, tmp, e); \ @@ -171,7 +167,7 @@ static void SHA512_Block(SHA512_State *s, uint64 *block) { } { - uint64 tmp; + uint64_t tmp; #define UPDATE(state, local) ( tmp = state, add(state, tmp, local) ) UPDATE(s->h[0], a); UPDATE(s->h[1], b); UPDATE(s->h[2], c); UPDATE(s->h[3], d); @@ -190,20 +186,16 @@ static void SHA512_BinarySink_write(BinarySink *bs, const void *p, size_t len); void SHA512_Init(SHA512_State *s) { - int i; SHA512_Core_Init(s); s->blkused = 0; - for (i = 0; i < 4; i++) - s->len[i] = 0; + s->lenhi = s->lenlo = 0; BinarySink_INIT(s, SHA512_BinarySink_write); } void SHA384_Init(SHA512_State *s) { - int i; SHA384_Core_Init(s); s->blkused = 0; - for (i = 0; i < 4; i++) - s->len[i] = 0; + s->lenhi = s->lenlo = 0; BinarySink_INIT(s, SHA512_BinarySink_write); } @@ -212,19 +204,14 @@ static void SHA512_BinarySink_write(BinarySink *bs, { SHA512_State *s = BinarySink_DOWNCAST(bs, SHA512_State); unsigned char *q = (unsigned char *)p; - uint64 wordblock[16]; - uint32 lenw = len; + uint64_t wordblock[16]; int i; - assert(lenw == len); - /* * Update the length field. */ - for (i = 0; i < 4; i++) { - s->len[i] += lenw; - lenw = (s->len[i] < lenw); - } + s->lenlo += len; + s->lenhi += (s->lenlo < len); if (s->blkused && s->blkused+len < BLKSIZE) { /* @@ -241,18 +228,8 @@ static void SHA512_BinarySink_write(BinarySink *bs, q += BLKSIZE - s->blkused; len -= BLKSIZE - s->blkused; /* Now process the block. Gather bytes big-endian into words */ - for (i = 0; i < 16; i++) { - uint32 h, l; - h = ( ((uint32)s->block[i*8+0]) << 24 ) | - ( ((uint32)s->block[i*8+1]) << 16 ) | - ( ((uint32)s->block[i*8+2]) << 8 ) | - ( ((uint32)s->block[i*8+3]) << 0 ); - l = ( ((uint32)s->block[i*8+4]) << 24 ) | - ( ((uint32)s->block[i*8+5]) << 16 ) | - ( ((uint32)s->block[i*8+6]) << 8 ) | - ( ((uint32)s->block[i*8+7]) << 0 ); - BUILD(wordblock[i], h, l); - } + for (i = 0; i < 16; i++) + wordblock[i] = GET_64BIT_MSB_FIRST(s->block + i*8); SHA512_Block(s, wordblock); s->blkused = 0; } @@ -265,38 +242,25 @@ void SHA512_Final(SHA512_State *s, unsigned char *digest) { int i; int pad; unsigned char c[BLKSIZE]; - uint32 len[4]; + uint64_t lenhi, lenlo; if (s->blkused >= BLKSIZE-16) pad = (BLKSIZE-16) + BLKSIZE - s->blkused; else pad = (BLKSIZE-16) - s->blkused; - for (i = 4; i-- ;) { - uint32 lenhi = s->len[i]; - uint32 lenlo = i > 0 ? s->len[i-1] : 0; - len[i] = (lenhi << 3) | (lenlo >> (32-3)); - } + lenhi = (s->lenhi << 3) | (s->lenlo >> (32-3)); + lenlo = (s->lenlo << 3); memset(c, 0, pad); c[0] = 0x80; put_data(s, &c, pad); - for (i = 0; i < 4; i++) - put_uint32(s, len[3-i]); - - for (i = 0; i < 8; i++) { - uint32 h, l; - EXTRACT(h, l, s->h[i]); - digest[i*8+0] = (h >> 24) & 0xFF; - digest[i*8+1] = (h >> 16) & 0xFF; - digest[i*8+2] = (h >> 8) & 0xFF; - digest[i*8+3] = (h >> 0) & 0xFF; - digest[i*8+4] = (l >> 24) & 0xFF; - digest[i*8+5] = (l >> 16) & 0xFF; - digest[i*8+6] = (l >> 8) & 0xFF; - digest[i*8+7] = (l >> 0) & 0xFF; - } + put_uint64(s, lenhi); + put_uint64(s, lenlo); + + for (i = 0; i < 8; i++) + PUT_64BIT_MSB_FIRST(digest + i*8, s->h[i]); } void SHA384_Final(SHA512_State *s, unsigned char *digest) { diff --git a/sshsha.c b/sshsha.c index a7f02791..4e832e50 100644 --- a/sshsha.c +++ b/sshsha.c @@ -13,12 +13,12 @@ * Core SHA algorithm: processes 16-word blocks into a message digest. */ -#define rol(x,y) ( ((x) << (y)) | (((uint32)x) >> (32-y)) ) +#define rol(x,y) ( ((x) << (y)) | (((uint32_t)x) >> (32-y)) ) static void sha1_sw(SHA_State * s, const unsigned char *q, int len); static void sha1_ni(SHA_State * s, const unsigned char *q, int len); -static void SHA_Core_Init(uint32 h[5]) +static void SHA_Core_Init(uint32_t h[5]) { h[0] = 0x67452301; h[1] = 0xefcdab89; @@ -27,10 +27,10 @@ static void SHA_Core_Init(uint32 h[5]) h[4] = 0xc3d2e1f0; } -void SHATransform(word32 * digest, word32 * block) +void SHATransform(uint32_t * digest, uint32_t * block) { - word32 w[80]; - word32 a, b, c, d, e; + uint32_t w[80]; + uint32_t a, b, c, d, e; int t; #ifdef RANDOM_DIAGNOSTICS @@ -52,7 +52,7 @@ void SHATransform(word32 * digest, word32 * block) w[t] = block[t]; for (t = 16; t < 80; t++) { - word32 tmp = w[t - 3] ^ w[t - 8] ^ w[t - 14] ^ w[t - 16]; + uint32_t tmp = w[t - 3] ^ w[t - 8] ^ w[t - 14] ^ w[t - 16]; w[t] = rol(tmp, 1); } @@ -63,7 +63,7 @@ void SHATransform(word32 * digest, word32 * block) e = digest[4]; for (t = 0; t < 20; t++) { - word32 tmp = + uint32_t tmp = rol(a, 5) + ((b & c) | (d & ~b)) + e + w[t] + 0x5a827999; e = d; d = c; @@ -72,7 +72,7 @@ void SHATransform(word32 * digest, word32 * block) a = tmp; } for (t = 20; t < 40; t++) { - word32 tmp = rol(a, 5) + (b ^ c ^ d) + e + w[t] + 0x6ed9eba1; + uint32_t tmp = rol(a, 5) + (b ^ c ^ d) + e + w[t] + 0x6ed9eba1; e = d; d = c; c = rol(b, 30); @@ -80,7 +80,7 @@ void SHATransform(word32 * digest, word32 * block) a = tmp; } for (t = 40; t < 60; t++) { - word32 tmp = rol(a, + uint32_t tmp = rol(a, 5) + ((b & c) | (b & d) | (c & d)) + e + w[t] + 0x8f1bbcdc; e = d; @@ -90,7 +90,7 @@ void SHATransform(word32 * digest, word32 * block) a = tmp; } for (t = 60; t < 80; t++) { - word32 tmp = rol(a, 5) + (b ^ c ^ d) + e + w[t] + 0xca62c1d6; + uint32_t tmp = rol(a, 5) + (b ^ c ^ d) + e + w[t] + 0xca62c1d6; e = d; d = c; c = rol(b, 30); @@ -130,7 +130,7 @@ void SHA_Init(SHA_State * s) { SHA_Core_Init(s->h); s->blkused = 0; - s->lenhi = s->lenlo = 0; + s->len = 0; if (supports_sha_ni()) s->sha1 = &sha1_ni; else @@ -142,20 +142,18 @@ static void SHA_BinarySink_write(BinarySink *bs, const void *p, size_t len) { struct SHA_State *s = BinarySink_DOWNCAST(bs, struct SHA_State); const unsigned char *q = (const unsigned char *) p; - uint32 lenw = len; - assert(lenw == len); /* * Update the length field. */ - s->lenlo += lenw; - s->lenhi += (s->lenlo < lenw); + s->len += len; + (*(s->sha1))(s, q, len); } static void sha1_sw(SHA_State * s, const unsigned char *q, int len) { - uint32 wordblock[16]; + uint32_t wordblock[16]; int i; if (s->blkused && s->blkused + len < 64) { @@ -175,10 +173,10 @@ static void sha1_sw(SHA_State * s, const unsigned char *q, int len) /* Now process the block. Gather bytes big-endian into words */ for (i = 0; i < 16; i++) { wordblock[i] = - (((uint32) s->block[i * 4 + 0]) << 24) | - (((uint32) s->block[i * 4 + 1]) << 16) | - (((uint32) s->block[i * 4 + 2]) << 8) | - (((uint32) s->block[i * 4 + 3]) << 0); + (((uint32_t) s->block[i * 4 + 0]) << 24) | + (((uint32_t) s->block[i * 4 + 1]) << 16) | + (((uint32_t) s->block[i * 4 + 2]) << 8) | + (((uint32_t) s->block[i * 4 + 3]) << 0); } SHATransform(s->h, wordblock); s->blkused = 0; @@ -193,22 +191,20 @@ void SHA_Final(SHA_State * s, unsigned char *output) int i; int pad; unsigned char c[64]; - uint32 lenhi, lenlo; + uint64_t len; if (s->blkused >= 56) pad = 56 + 64 - s->blkused; else pad = 56 - s->blkused; - lenhi = (s->lenhi << 3) | (s->lenlo >> (32 - 3)); - lenlo = (s->lenlo << 3); + len = (s->len << 3); memset(c, 0, pad); c[0] = 0x80; put_data(s, &c, pad); - put_uint32(s, lenhi); - put_uint32(s, lenlo); + put_uint64(s, len); for (i = 0; i < 5; i++) { output[i * 4] = (s->h[i] >> 24) & 0xFF; diff --git a/unix/uxsftp.c b/unix/uxsftp.c index f6ac2bbb..275c38b1 100644 --- a/unix/uxsftp.c +++ b/unix/uxsftp.c @@ -20,7 +20,6 @@ #include "putty.h" #include "ssh.h" #include "psftp.h" -#include "int64.h" /* * In PSFTP our selects are synchronous, so these functions are @@ -118,7 +117,7 @@ struct RFile { int fd; }; -RFile *open_existing_file(const char *name, uint64 *size, +RFile *open_existing_file(const char *name, uint64_t *size, unsigned long *mtime, unsigned long *atime, long *perms) { @@ -140,8 +139,7 @@ RFile *open_existing_file(const char *name, uint64 *size, } if (size) - *size = uint64_make((statbuf.st_size >> 16) >> 16, - statbuf.st_size); + *size = statbuf.st_size; if (mtime) *mtime = statbuf.st_mtime; @@ -190,7 +188,7 @@ WFile *open_new_file(const char *name, long perms) } -WFile *open_existing_wfile(const char *name, uint64 *size) +WFile *open_existing_wfile(const char *name, uint64_t *size) { int fd; WFile *ret; @@ -210,8 +208,7 @@ WFile *open_existing_wfile(const char *name, uint64 *size) memset(&statbuf, 0, sizeof(statbuf)); } - *size = uint64_make((statbuf.st_size >> 16) >> 16, - statbuf.st_size); + *size = statbuf.st_size; } return ret; @@ -260,13 +257,10 @@ void close_wfile(WFile *f) /* Seek offset bytes through file, from whence, where whence is FROM_START, FROM_CURRENT, or FROM_END */ -int seek_file(WFile *f, uint64 offset, int whence) +int seek_file(WFile *f, uint64_t offset, int whence) { - off_t fileofft; int lseek_whence; - fileofft = (((off_t) offset.hi << 16) << 16) + offset.lo; - switch (whence) { case FROM_START: lseek_whence = SEEK_SET; @@ -281,19 +275,12 @@ int seek_file(WFile *f, uint64 offset, int whence) return -1; } - return lseek(f->fd, fileofft, lseek_whence) >= 0 ? 0 : -1; + return lseek(f->fd, offset, lseek_whence) >= 0 ? 0 : -1; } -uint64 get_file_posn(WFile *f) +uint64_t get_file_posn(WFile *f) { - off_t fileofft; - uint64 ret; - - fileofft = lseek(f->fd, (off_t) 0, SEEK_CUR); - - ret = uint64_make((fileofft >> 16) >> 16, fileofft); - - return ret; + return lseek(f->fd, (off_t) 0, SEEK_CUR); } int file_type(const char *name) diff --git a/unix/uxsftpserver.c b/unix/uxsftpserver.c index 9427a2e2..8b59b3ab 100644 --- a/unix/uxsftpserver.c +++ b/unix/uxsftpserver.c @@ -356,11 +356,6 @@ static void uss_rename(SftpServer *srv, SftpReplyBuilder *reply, } } -static uint64 uint64_from_off_t(off_t off) -{ - return uint64_make((off >> 16) >> 16, (off & 0xFFFFFFFFU)); -} - static struct fxp_attrs uss_translate_struct_stat(const struct stat *st) { struct fxp_attrs attrs; @@ -370,7 +365,7 @@ static struct fxp_attrs uss_translate_struct_stat(const struct stat *st) SSH_FILEXFER_ATTR_UIDGID | SSH_FILEXFER_ATTR_ACMODTIME); - attrs.size = uint64_from_off_t(st->st_size); + attrs.size = st->st_size; attrs.permissions = st->st_mode; attrs.uid = st->st_uid; attrs.gid = st->st_gid; @@ -421,11 +416,6 @@ static void uss_fstat(SftpServer *srv, SftpReplyBuilder *reply, } } -static off_t uint64_to_off_t(uint64 u) -{ - return ((((off_t)u.hi) << 16) << 16) | (off_t)u.lo; -} - /* * The guts of setstat and fsetstat, macroised so that they can call * fchown(fd,...) or chown(path,...) depending on parameters. @@ -433,8 +423,7 @@ static off_t uint64_to_off_t(uint64 u) #define SETSTAT_GUTS(api_prefix, api_arg, attrs, success) do \ { \ if (attrs.flags & SSH_FILEXFER_ATTR_SIZE) \ - if (api_prefix(truncate)( \ - api_arg, uint64_to_off_t(attrs.size)) < 0) \ + if (api_prefix(truncate)(api_arg, attrs.size) < 0) \ success = FALSE; \ if (attrs.flags & SSH_FILEXFER_ATTR_UIDGID) \ if (api_prefix(chown)(api_arg, attrs.uid, attrs.gid) < 0) \ @@ -492,7 +481,7 @@ static void uss_fsetstat(SftpServer *srv, SftpReplyBuilder *reply, } static void uss_read(SftpServer *srv, SftpReplyBuilder *reply, - ptrlen handle, uint64 offset, unsigned length) + ptrlen handle, uint64_t offset, unsigned length) { UnixSftpServer *uss = container_of(srv, UnixSftpServer, srv); int fd; @@ -513,7 +502,7 @@ static void uss_read(SftpServer *srv, SftpReplyBuilder *reply, char *p = buf; - int status = lseek(fd, uint64_to_off_t(offset), SEEK_SET); + int status = lseek(fd, offset, SEEK_SET); if (status >= 0 || errno == ESPIPE) { int seekable = (status >= 0); while (length > 0) { @@ -549,7 +538,7 @@ static void uss_read(SftpServer *srv, SftpReplyBuilder *reply, } static void uss_write(SftpServer *srv, SftpReplyBuilder *reply, - ptrlen handle, uint64 offset, ptrlen data) + ptrlen handle, uint64_t offset, ptrlen data) { UnixSftpServer *uss = container_of(srv, UnixSftpServer, srv); int fd; @@ -560,7 +549,7 @@ static void uss_write(SftpServer *srv, SftpReplyBuilder *reply, const char *p = data.ptr; unsigned length = data.len; - int status = lseek(fd, uint64_to_off_t(offset), SEEK_SET); + int status = lseek(fd, offset, SEEK_SET); if (status >= 0 || errno == ESPIPE) { while (length > 0) { @@ -609,7 +598,7 @@ static void uss_readdir(SftpServer *srv, SftpReplyBuilder *reply, #if defined HAVE_FSTATAT && defined HAVE_DIRFD struct stat st; if (!fstatat(dirfd(udh->dp), de->d_name, &st, AT_SYMLINK_NOFOLLOW)) { - char perms[11], sizebuf[32], *uidbuf = NULL, *gidbuf = NULL; + char perms[11], *uidbuf = NULL, *gidbuf = NULL; struct passwd *pwd; struct group *grp; const char *user, *group; @@ -660,13 +649,11 @@ static void uss_readdir(SftpServer *srv, SftpReplyBuilder *reply, else group = gidbuf = dupprintf("%u", (unsigned)st.st_gid); - uint64_decimal(uint64_from_off_t(st.st_size), sizebuf); - tm = *localtime(&st.st_mtime); longnamebuf = dupprintf( - "%s %3u %-8s %-8s %8s %.3s %2d %02d:%02d %s", - perms, (unsigned)st.st_nlink, user, group, sizebuf, + "%s %3u %-8s %-8s %8"PRIu64" %.3s %2d %02d:%02d %s", + perms, (unsigned)st.st_nlink, user, group, st.st_size, (&"JanFebMarAprMayJunJulAugSepOctNovDec"[3*tm.tm_mon]), tm.tm_mday, tm.tm_hour, tm.tm_min, de->d_name); longname = ptrlen_from_asciz(longnamebuf); diff --git a/windows/winsftp.c b/windows/winsftp.c index 6a8aba77..06531529 100644 --- a/windows/winsftp.c +++ b/windows/winsftp.c @@ -10,7 +10,6 @@ #include "putty.h" #include "psftp.h" #include "ssh.h" -#include "int64.h" #include "winsecur.h" int filexfer_get_userpass_input(Seat *seat, prompts_t *p, bufchain *input) @@ -71,6 +70,11 @@ char *psftp_getcwd(void) return ret; } +static inline uint64_t uint64_from_words(uint32_t hi, uint32_t lo) +{ + return (((uint64_t)hi) << 32) | lo; +} + #define TIME_POSIX_TO_WIN(t, ft) do { \ ULARGE_INTEGER uli; \ uli.QuadPart = ((ULONGLONG)(t) + 11644473600ull) * 10000000ull; \ @@ -89,7 +93,7 @@ struct RFile { HANDLE h; }; -RFile *open_existing_file(const char *name, uint64 *size, +RFile *open_existing_file(const char *name, uint64_t *size, unsigned long *mtime, unsigned long *atime, long *perms) { @@ -107,8 +111,7 @@ RFile *open_existing_file(const char *name, uint64 *size, if (size) { DWORD lo, hi; lo = GetFileSize(h, &hi); - size->lo = lo; - size->hi = hi; + *size = uint64_from_words(hi, lo); } if (mtime || atime) { @@ -163,7 +166,7 @@ WFile *open_new_file(const char *name, long perms) return ret; } -WFile *open_existing_wfile(const char *name, uint64 *size) +WFile *open_existing_wfile(const char *name, uint64_t *size) { HANDLE h; WFile *ret; @@ -179,8 +182,7 @@ WFile *open_existing_wfile(const char *name, uint64 *size) if (size) { DWORD lo, hi; lo = GetFileSize(h, &hi); - size->lo = lo; - size->hi = hi; + *size = uint64_from_words(hi, lo); } return ret; @@ -213,7 +215,7 @@ void close_wfile(WFile *f) /* Seek offset bytes through file, from whence, where whence is FROM_START, FROM_CURRENT, or FROM_END */ -int seek_file(WFile *f, uint64 offset, int whence) +int seek_file(WFile *f, uint64_t offset, int whence) { DWORD movemethod; @@ -232,7 +234,7 @@ int seek_file(WFile *f, uint64 offset, int whence) } { - LONG lo = offset.lo, hi = offset.hi; + LONG lo = offset & 0xFFFFFFFFU, hi = offset >> 32; SetFilePointer(f->h, lo, &hi, movemethod); } @@ -242,16 +244,12 @@ int seek_file(WFile *f, uint64 offset, int whence) return 0; } -uint64 get_file_posn(WFile *f) +uint64_t get_file_posn(WFile *f) { - uint64 ret; LONG lo, hi = 0; lo = SetFilePointer(f->h, 0L, &hi, FILE_CURRENT); - ret.lo = lo; - ret.hi = hi; - - return ret; + return uint64_from_words(hi, lo); } int file_type(const char *name) From a6f1709c2f4d07a9312c5a6dd591fa0cf529808f Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Mon, 29 Oct 2018 19:50:29 +0000 Subject: [PATCH 586/607] Adopt C99 's true/false. This commit includes from defs.h and deletes my traditional definitions of TRUE and FALSE, but other than that, it's a 100% mechanical search-and-replace transforming all uses of TRUE and FALSE into the C99-standardised lowercase spellings. No actual types are changed in this commit; that will come next. This is just getting the noise out of the way, so that subsequent commits can have a higher proportion of signal. --- agentf.c | 6 +- callback.c | 8 +- cmdgen.c | 80 +++---- cmdline.c | 36 ++-- conf.c | 8 +- config.c | 54 ++--- contrib/cygtermd/telnet.c | 8 +- defs.h | 8 +- dialog.c | 6 +- dialog.h | 2 +- fuzzterm.c | 10 +- import.c | 20 +- ldisc.c | 4 +- logging.c | 14 +- mainchan.c | 76 +++---- marshal.c | 10 +- misc.c | 38 ++-- nocmdline.c | 2 +- pageant.c | 14 +- pinger.c | 8 +- portfwd.c | 26 +-- proxy.c | 4 +- pscp.c | 26 +-- psftp.c | 106 ++++----- psftp.h | 6 +- putty.h | 26 +-- raw.c | 16 +- rlogin.c | 8 +- scpserver.c | 70 +++--- sesschan.c | 64 +++--- settings.c | 16 +- sftp.c | 4 +- sftpserver.c | 6 +- ssh.c | 36 ++-- ssh.h | 18 +- ssh1bpp.c | 10 +- ssh1connection-client.c | 54 ++--- ssh1connection-server.c | 52 ++--- ssh1connection.c | 46 ++-- ssh1login-server.c | 6 +- ssh1login.c | 58 ++--- ssh2bpp-bare.c | 6 +- ssh2bpp.c | 22 +- ssh2connection-client.c | 22 +- ssh2connection-server.c | 32 +-- ssh2connection.c | 58 ++--- ssh2kex-client.c | 10 +- ssh2kex-server.c | 4 +- ssh2transhk.c | 4 +- ssh2transport.c | 132 ++++++------ ssh2userauth-server.c | 6 +- ssh2userauth.c | 100 ++++----- sshbpp.h | 4 +- sshchan.h | 4 +- sshcommon.c | 70 +++--- sshecc.c | 8 +- sshpubk.c | 54 ++--- sshrand.c | 4 +- sshrsa.c | 4 +- sshserver.c | 22 +- sshserver.h | 2 +- sshshare.c | 28 +-- sshverstring.c | 2 +- sshzlib.c | 21 +- telnet.c | 24 +-- terminal.c | 438 +++++++++++++++++++------------------- terminal.h | 4 +- testbn.c | 8 +- timing.c | 4 +- unix/gtkapp.c | 6 +- unix/gtkask.c | 50 ++--- unix/gtkcols.c | 37 ++-- unix/gtkcomm.c | 14 +- unix/gtkcompat.h | 2 +- unix/gtkdlg.c | 166 +++++++-------- unix/gtkfont.c | 152 ++++++------- unix/gtkmain.c | 8 +- unix/gtkmisc.c | 12 +- unix/gtkwin.c | 288 ++++++++++++------------- unix/unix.h | 4 +- unix/ux_x11.c | 8 +- unix/uxagentc.c | 4 +- unix/uxcons.c | 4 +- unix/uxmisc.c | 6 +- unix/uxnet.c | 50 ++--- unix/uxpeer.c | 4 +- unix/uxpgnt.c | 110 +++++----- unix/uxplink.c | 38 ++-- unix/uxpterm.c | 2 +- unix/uxpty.c | 30 +-- unix/uxputty.c | 8 +- unix/uxser.c | 8 +- unix/uxserver.c | 28 +-- unix/uxsftp.c | 16 +- unix/uxsftpserver.c | 22 +- unix/uxucs.c | 2 +- windows/sizetip.c | 4 +- windows/wincapi.c | 4 +- windows/wincfg.c | 4 +- windows/wincons.c | 2 +- windows/winctrls.c | 56 ++--- windows/windlg.c | 32 +-- windows/window.c | 222 +++++++++---------- windows/winhandl.c | 64 +++--- windows/winhelp.c | 8 +- windows/winhsock.c | 8 +- windows/winjump.c | 16 +- windows/winmisc.c | 16 +- windows/winnet.c | 44 ++-- windows/winnoise.c | 2 +- windows/winnpc.c | 2 +- windows/winnps.c | 16 +- windows/winpgen.c | 58 ++--- windows/winpgnt.c | 32 +-- windows/winpgntc.c | 8 +- windows/winplink.c | 28 +-- windows/winprint.c | 8 +- windows/winproxy.c | 6 +- windows/winsecur.c | 24 +-- windows/winsecur.h | 4 +- windows/winser.c | 32 +-- windows/winsftp.c | 14 +- windows/winshare.c | 4 +- windows/winstore.c | 6 +- windows/winstuff.h | 4 +- windows/winx11.c | 2 +- x11fwd.c | 30 +-- 127 files changed, 1994 insertions(+), 2012 deletions(-) diff --git a/agentf.c b/agentf.c index e2a26065..db4f702a 100644 --- a/agentf.c +++ b/agentf.c @@ -178,10 +178,10 @@ Channel *agentf_new(SshChannel *c) af->c = c; af->chan.vt = &agentf_channelvt; af->chan.initial_fixed_window_size = 0; - af->rcvd_eof = FALSE; + af->rcvd_eof = false; bufchain_init(&af->inbuffer); af->pending = NULL; - af->input_wanted = TRUE; + af->input_wanted = true; return &af->chan; } @@ -220,7 +220,7 @@ static void agentf_send_eof(Channel *chan) assert(chan->vt == &agentf_channelvt); agentf *af = container_of(chan, agentf, chan); - af->rcvd_eof = TRUE; + af->rcvd_eof = true; /* Call try_forward, which will respond to the EOF now if * appropriate, or wait until the queue of outstanding requests is diff --git a/callback.c b/callback.c index 6a888e89..b0ecbca2 100644 --- a/callback.c +++ b/callback.c @@ -29,7 +29,7 @@ void request_callback_notifications(toplevel_callback_notify_fn_t fn, static void run_idempotent_callback(void *ctx) { struct IdempotentCallback *ic = (struct IdempotentCallback *)ctx; - ic->queued = FALSE; + ic->queued = false; ic->fn(ic->ctx); } @@ -37,7 +37,7 @@ void queue_idempotent_callback(struct IdempotentCallback *ic) { if (ic->queued) return; - ic->queued = TRUE; + ic->queued = true; queue_toplevel_callback(run_idempotent_callback, ic); } @@ -101,7 +101,7 @@ void queue_toplevel_callback(toplevel_callback_fn_t fn, void *ctx) int run_toplevel_callbacks(void) { - int done_something = FALSE; + int done_something = false; if (cbhead) { /* @@ -122,7 +122,7 @@ int run_toplevel_callbacks(void) sfree(cbcurr); cbcurr = NULL; - done_something = TRUE; + done_something = true; } return done_something; } diff --git a/cmdgen.c b/cmdgen.c index 78ac274e..16c63a5d 100644 --- a/cmdgen.c +++ b/cmdgen.c @@ -134,7 +134,7 @@ void help(void) */ printf("PuTTYgen: key generator and converter for the PuTTY tools\n" "%s\n", ver); - usage(FALSE); + usage(false); printf(" -t specify key type when generating (ed25519, ecdsa, rsa, " "dsa, rsa1)\n" " -b specify number of bits when generating key\n" @@ -177,9 +177,9 @@ static int move(char *from, char *to) } if (ret) { perror("puttygen: cannot move new file on to old one"); - return FALSE; + return false; } - return TRUE; + return true; } static char *readpassphrase(const char *filename) @@ -208,7 +208,7 @@ static char *readpassphrase(const char *filename) #define DEFAULT_RSADSA_BITS 2048 /* For Unix in particular, but harmless if this main() is reused elsewhere */ -const int buildinfo_gtk_relevant = FALSE; +const int buildinfo_gtk_relevant = false; int main(int argc, char **argv) { @@ -220,8 +220,8 @@ int main(int argc, char **argv) OPENSSH_NEW, SSHCOM } outtype = PRIVATE; int bits = -1; char *comment = NULL, *origcomment = NULL; - int change_passphrase = FALSE; - int errs = FALSE, nogo = FALSE; + int change_passphrase = false; + int errs = false, nogo = false; int intype = SSH_KEYTYPE_UNOPENABLE; int sshver = 0; struct ssh2_userkey *ssh2key = NULL; @@ -242,7 +242,7 @@ int main(int argc, char **argv) * return success. */ if (argc <= 1) { - usage(TRUE); + usage(true); return 0; } @@ -275,68 +275,68 @@ int main(int argc, char **argv) if (!strcmp(opt, "-help")) { if (val) { - errs = TRUE; + errs = true; fprintf(stderr, "puttygen: option `-%s'" " expects no argument\n", opt); } else { help(); - nogo = TRUE; + nogo = true; } } else if (!strcmp(opt, "-version")) { if (val) { - errs = TRUE; + errs = true; fprintf(stderr, "puttygen: option `-%s'" " expects no argument\n", opt); } else { showversion(); - nogo = TRUE; + nogo = true; } } else if (!strcmp(opt, "-pgpfp")) { if (val) { - errs = TRUE; + errs = true; fprintf(stderr, "puttygen: option `-%s'" " expects no argument\n", opt); } else { /* support --pgpfp for consistency */ pgp_fingerprints(); - nogo = TRUE; + nogo = true; } } else if (!strcmp(opt, "-old-passphrase")) { if (!val && argc > 1) --argc, val = *++argv; if (!val) { - errs = TRUE; + errs = true; fprintf(stderr, "puttygen: option `-%s'" " expects an argument\n", opt); } else { old_passphrase = readpassphrase(val); if (!old_passphrase) - errs = TRUE; + errs = true; } } else if (!strcmp(opt, "-new-passphrase")) { if (!val && argc > 1) --argc, val = *++argv; if (!val) { - errs = TRUE; + errs = true; fprintf(stderr, "puttygen: option `-%s'" " expects an argument\n", opt); } else { new_passphrase = readpassphrase(val); if (!new_passphrase) - errs = TRUE; + errs = true; } } else if (!strcmp(opt, "-random-device")) { if (!val && argc > 1) --argc, val = *++argv; if (!val) { - errs = TRUE; + errs = true; fprintf(stderr, "puttygen: option `-%s'" " expects an argument\n", opt); } else { random_device = val; } } else { - errs = TRUE; + errs = true; fprintf(stderr, "puttygen: no such option `-%s'\n", opt); } @@ -356,14 +356,14 @@ int main(int argc, char **argv) switch (c) { case 'h': help(); - nogo = TRUE; + nogo = true; break; case 'V': showversion(); - nogo = TRUE; + nogo = true; break; case 'P': - change_passphrase = TRUE; + change_passphrase = true; break; case 'l': outtype = FP; @@ -393,7 +393,7 @@ int main(int argc, char **argv) else if (!*p) { fprintf(stderr, "puttygen: option `-%c' expects a" " parameter\n", c); - errs = TRUE; + errs = true; } /* * Now c is the option and p is the parameter. @@ -413,7 +413,7 @@ int main(int argc, char **argv) else { fprintf(stderr, "puttygen: unknown key type `%s'\n", p); - errs = TRUE; + errs = true; } break; case 'b': @@ -440,7 +440,7 @@ int main(int argc, char **argv) else { fprintf(stderr, "puttygen: unknown output type `%s'\n", p); - errs = TRUE; + errs = true; } break; case 'o': @@ -453,7 +453,7 @@ int main(int argc, char **argv) /* * Unrecognised option. */ - errs = TRUE; + errs = true; fprintf(stderr, "puttygen: no such option `-%c'\n", c); break; } @@ -465,7 +465,7 @@ int main(int argc, char **argv) if (!infile) infile = p; else { - errs = TRUE; + errs = true; fprintf(stderr, "puttygen: cannot handle more than one" " input file\n"); } @@ -492,19 +492,19 @@ int main(int argc, char **argv) if (keytype == ECDSA && (bits != 256 && bits != 384 && bits != 521)) { fprintf(stderr, "puttygen: invalid bits for ECDSA, choose 256, 384 or 521\n"); - errs = TRUE; + errs = true; } if (keytype == ED25519 && (bits != 256)) { fprintf(stderr, "puttygen: invalid bits for ED25519, choose 256\n"); - errs = TRUE; + errs = true; } if (keytype == RSA2 || keytype == RSA1 || keytype == DSA) { if (bits < 256) { fprintf(stderr, "puttygen: cannot generate %s keys shorter than" " 256 bits\n", (keytype == DSA ? "DSA" : "RSA")); - errs = TRUE; + errs = true; } else if (bits < DEFAULT_RSADSA_BITS) { fprintf(stderr, "puttygen: warning: %s keys shorter than" " %d bits are probably not secure\n", @@ -524,7 +524,7 @@ int main(int argc, char **argv) * ones, print the usage message and return failure. */ if (!infile && keytype == NOKEYGEN) { - usage(TRUE); + usage(true); return 1; } @@ -648,9 +648,9 @@ int main(int argc, char **argv) intype == SSH_KEYTYPE_OPENSSH_PEM || intype == SSH_KEYTYPE_OPENSSH_NEW || intype == SSH_KEYTYPE_SSHCOM) - load_encrypted = TRUE; + load_encrypted = true; else - load_encrypted = FALSE; + load_encrypted = false; if (load_encrypted && (intype == SSH_KEYTYPE_SSH1_PUBLIC || intype == SSH_KEYTYPE_SSH2_PUBLIC_RFC4716 || @@ -756,9 +756,9 @@ int main(int argc, char **argv) if (!old_passphrase) { prompts_t *p = new_prompts(); int ret; - p->to_server = FALSE; + p->to_server = false; p->name = dupstr("SSH key passphrase"); - add_prompt(p, dupstr("Enter passphrase to load key: "), FALSE); + add_prompt(p, dupstr("Enter passphrase to load key: "), false); ret = console_get_userpass_input(p); assert(ret >= 0); if (!ret) { @@ -891,10 +891,10 @@ int main(int argc, char **argv) prompts_t *p = new_prompts(NULL); int ret; - p->to_server = FALSE; + p->to_server = false; p->name = dupstr("New SSH key passphrase"); - add_prompt(p, dupstr("Enter passphrase to save key: "), FALSE); - add_prompt(p, dupstr("Re-enter passphrase to verify: "), FALSE); + add_prompt(p, dupstr("Enter passphrase to save key: "), false); + add_prompt(p, dupstr("Re-enter passphrase to verify: "), false); ret = console_get_userpass_input(p); assert(ret >= 0); if (!ret) { @@ -960,7 +960,7 @@ int main(int argc, char **argv) FILE *fp; if (outfile) { - fp = f_open(outfilename, "w", FALSE); + fp = f_open(outfilename, "w", false); if (!fp) { fprintf(stderr, "unable to open output file\n"); exit(1); @@ -1009,7 +1009,7 @@ int main(int argc, char **argv) } if (outfile) { - fp = f_open(outfilename, "w", FALSE); + fp = f_open(outfilename, "w", false); if (!fp) { fprintf(stderr, "unable to open output file\n"); exit(1); diff --git a/cmdline.c b/cmdline.c index cf25e584..5e94e866 100644 --- a/cmdline.c +++ b/cmdline.c @@ -159,8 +159,8 @@ static int cmdline_check_unavailable(int flag, const char *p) if (need_save < 0) return x; \ } while (0) -static int seen_hostname_argument = FALSE; -static int seen_port_argument = FALSE; +static int seen_hostname_argument = false; +static int seen_port_argument = false; int cmdline_process_param(const char *p, char *value, int need_save, Conf *conf) @@ -227,7 +227,7 @@ int cmdline_process_param(const char *p, char *value, buf = dupprintf("%.*s", (int)(p - host), host); conf_set_str(conf, CONF_host, buf); sfree(buf); - seen_hostname_argument = TRUE; + seen_hostname_argument = true; } /* @@ -243,7 +243,7 @@ int cmdline_process_param(const char *p, char *value, * the next argument as a separate port; this one * counts as explicitly provided. */ - seen_port_argument = TRUE; + seen_port_argument = true; } else { conf_set_int(conf, CONF_port, -1); } @@ -322,7 +322,7 @@ int cmdline_process_param(const char *p, char *value, while (len > 0 && (hostname[len-1] == ' ' || hostname[len-1] == '\t')) hostname[--len] = '\0'; - seen_hostname_argument = TRUE; + seen_hostname_argument = true; conf_set_str(conf, CONF_host, hostname); if ((cmdline_tooltype & TOOLTYPE_HOST_ARG_CAN_BE_SESSION) && @@ -353,7 +353,7 @@ int cmdline_process_param(const char *p, char *value, do_defaults(hostname_after_user, conf2); if (conf_launchable(conf2)) { conf_copy_into(conf, conf2); - loaded_session = TRUE; + loaded_session = true; /* And override the username if one was given. */ if (user) conf_set_str(conf, CONF_username, user); @@ -385,7 +385,7 @@ int cmdline_process_param(const char *p, char *value, int retd = cmdline_process_param("-P", dup, 1, conf); sfree(dup); assert(retd == 2); - seen_port_argument = TRUE; + seen_port_argument = true; return 1; } else { /* @@ -401,7 +401,7 @@ int cmdline_process_param(const char *p, char *value, /* This parameter must be processed immediately rather than being * saved. */ do_defaults(value, conf); - loaded_session = TRUE; + loaded_session = true; cmdline_session_name = dupstr(value); return 2; } @@ -594,7 +594,7 @@ int cmdline_process_param(const char *p, char *value, fclose(fp); conf_set_str(conf, CONF_remote_cmd, command); conf_set_str(conf, CONF_remote_cmd2, ""); - conf_set_int(conf, CONF_nopty, TRUE); /* command => no terminal */ + conf_set_int(conf, CONF_nopty, true); /* command => no terminal */ sfree(command); } if (!strcmp(p, "-P")) { @@ -626,26 +626,26 @@ int cmdline_process_param(const char *p, char *value, RETURN(1); UNAVAILABLE_IN(TOOLTYPE_NONNETWORK); SAVEABLE(0); - conf_set_int(conf, CONF_tryagent, TRUE); + conf_set_int(conf, CONF_tryagent, true); } if (!strcmp(p, "-noagent") || !strcmp(p, "-nopagent") || !strcmp(p, "-nopageant")) { RETURN(1); UNAVAILABLE_IN(TOOLTYPE_NONNETWORK); SAVEABLE(0); - conf_set_int(conf, CONF_tryagent, FALSE); + conf_set_int(conf, CONF_tryagent, false); } if (!strcmp(p, "-share")) { RETURN(1); UNAVAILABLE_IN(TOOLTYPE_NONNETWORK); SAVEABLE(0); - conf_set_int(conf, CONF_ssh_connection_sharing, TRUE); + conf_set_int(conf, CONF_ssh_connection_sharing, true); } if (!strcmp(p, "-noshare")) { RETURN(1); UNAVAILABLE_IN(TOOLTYPE_NONNETWORK); SAVEABLE(0); - conf_set_int(conf, CONF_ssh_connection_sharing, FALSE); + conf_set_int(conf, CONF_ssh_connection_sharing, false); } if (!strcmp(p, "-A")) { RETURN(1); @@ -860,7 +860,7 @@ int cmdline_process_param(const char *p, char *value, !strcmp(p, "-restrictacl")) { RETURN(1); restrict_process_acl(); - restricted_acl = TRUE; + restricted_acl = true; } #endif @@ -884,7 +884,7 @@ void cmdline_run_saved(Conf *conf) int cmdline_host_ok(Conf *conf) { /* - * Return TRUE if the command-line arguments we've processed in + * Return true if the command-line arguments we've processed in * TOOLTYPE_HOST_ARG mode are sufficient to justify launching a * session. */ @@ -895,7 +895,7 @@ int cmdline_host_ok(Conf *conf) * clearly no. */ if (!conf_launchable(conf)) - return FALSE; + return false; /* * But also, if we haven't seen either a -load option or a @@ -908,7 +908,7 @@ int cmdline_host_ok(Conf *conf) * option to connect to something else or change the setting. */ if (!seen_hostname_argument && !loaded_session) - return FALSE; + return false; - return TRUE; + return true; } diff --git a/conf.c b/conf.c index 118e5944..a8578b10 100644 --- a/conf.c +++ b/conf.c @@ -513,11 +513,11 @@ int conf_deserialise(Conf *conf, BinarySource *src) primary = get_uint32(src); if (get_err(src)) - return FALSE; + return false; if (primary == 0xFFFFFFFFU) - return TRUE; + return true; if (primary >= N_CONFIG_OPTIONS) - return FALSE; + return false; entry = snew(struct conf_entry); entry->key.primary = primary; @@ -548,7 +548,7 @@ int conf_deserialise(Conf *conf, BinarySource *src) if (get_err(src)) { free_entry(entry); - return FALSE; + return false; } conf_insert(conf, entry); diff --git a/config.c b/config.c index 18c41f8f..3205b862 100644 --- a/config.c +++ b/config.c @@ -340,11 +340,11 @@ static void numeric_keypad_handler(union control *ctrl, dlgparam *dlg, button = dlg_radiobutton_get(ctrl, dlg); assert(button >= 0 && button < ctrl->radio.nbuttons); if (button == 2) { - conf_set_int(conf, CONF_app_keypad, FALSE); - conf_set_int(conf, CONF_nethack_keypad, TRUE); + conf_set_int(conf, CONF_app_keypad, false); + conf_set_int(conf, CONF_nethack_keypad, true); } else { conf_set_int(conf, CONF_app_keypad, (button != 0)); - conf_set_int(conf, CONF_nethack_keypad, FALSE); + conf_set_int(conf, CONF_nethack_keypad, false); } } } @@ -613,7 +613,7 @@ struct sessionsaver_data { static void sessionsaver_data_free(void *ssdv) { struct sessionsaver_data *ssd = (struct sessionsaver_data *)ssdv; - get_sesslist(&ssd->sesslist, FALSE); + get_sesslist(&ssd->sesslist, false); sfree(ssd->savedsession); sfree(ssd); } @@ -685,7 +685,7 @@ static void sessionsaver_handler(union control *ctrl, dlgparam *dlg, dlg_listbox_select(ssd->listbox, dlg, top); } } else if (event == EVENT_ACTION) { - int mbl = FALSE; + int mbl = false; if (!ssd->midsession && (ctrl == ssd->listbox || (ssd->loadbutton && ctrl == ssd->loadbutton))) { @@ -720,8 +720,8 @@ static void sessionsaver_handler(union control *ctrl, dlgparam *dlg, sfree(errmsg); } } - get_sesslist(&ssd->sesslist, FALSE); - get_sesslist(&ssd->sesslist, TRUE); + get_sesslist(&ssd->sesslist, false); + get_sesslist(&ssd->sesslist, true); dlg_refresh(ssd->editbox, dlg); dlg_refresh(ssd->listbox, dlg); } else if (!ssd->midsession && @@ -731,8 +731,8 @@ static void sessionsaver_handler(union control *ctrl, dlgparam *dlg, dlg_beep(dlg); } else { del_settings(ssd->sesslist.sessions[i]); - get_sesslist(&ssd->sesslist, FALSE); - get_sesslist(&ssd->sesslist, TRUE); + get_sesslist(&ssd->sesslist, false); + get_sesslist(&ssd->sesslist, true); dlg_refresh(ssd->listbox, dlg); } } else if (ctrl == ssd->okbutton) { @@ -751,7 +751,7 @@ static void sessionsaver_handler(union control *ctrl, dlgparam *dlg, if (dlg_last_focused(ctrl, dlg) == ssd->listbox && !conf_launchable(conf)) { Conf *conf2 = conf_new(); - int mbl = FALSE; + int mbl = false; if (!load_selected_session(ssd, dlg, conf2, &mbl)) { dlg_beep(dlg); conf_free(conf2); @@ -847,7 +847,7 @@ static void colour_handler(union control *ctrl, dlgparam *dlg, Conf *conf = (Conf *)data; struct colour_data *cd = (struct colour_data *)ctrl->generic.context.p; - int update = FALSE, clear = FALSE, r, g, b; + int update = false, clear = false, r, g, b; if (event == EVENT_REFRESH) { if (ctrl == cd->listbox) { @@ -857,22 +857,22 @@ static void colour_handler(union control *ctrl, dlgparam *dlg, for (i = 0; i < lenof(colours); i++) dlg_listbox_add(ctrl, dlg, colours[i]); dlg_update_done(ctrl, dlg); - clear = TRUE; - update = TRUE; + clear = true; + update = true; } } else if (event == EVENT_SELCHANGE) { if (ctrl == cd->listbox) { /* The user has selected a colour. Update the RGB text. */ int i = dlg_listbox_index(ctrl, dlg); if (i < 0) { - clear = TRUE; + clear = true; } else { - clear = FALSE; + clear = false; r = conf_get_int_int(conf, CONF_colours, i*3+0); g = conf_get_int_int(conf, CONF_colours, i*3+1); b = conf_get_int_int(conf, CONF_colours, i*3+2); } - update = TRUE; + update = true; } } else if (event == EVENT_VALCHANGE) { if (ctrl == cd->redit || ctrl == cd->gedit || ctrl == cd->bedit) { @@ -925,8 +925,8 @@ static void colour_handler(union control *ctrl, dlgparam *dlg, conf_set_int_int(conf, CONF_colours, i*3+0, r); conf_set_int_int(conf, CONF_colours, i*3+1, g); conf_set_int_int(conf, CONF_colours, i*3+2, b); - clear = FALSE; - update = TRUE; + clear = false; + update = true; } } } @@ -1468,11 +1468,11 @@ void setup_config_box(struct controlbox *b, int midsession, (char)(midsession ? 'a' : 'o'), HELPCTX(no_help), sessionsaver_handler, P(ssd)); - ssd->okbutton->button.isdefault = TRUE; + ssd->okbutton->button.isdefault = true; ssd->okbutton->generic.column = 3; ssd->cancelbutton = ctrl_pushbutton(s, "Cancel", 'c', HELPCTX(no_help), sessionsaver_handler, P(ssd)); - ssd->cancelbutton->button.iscancel = TRUE; + ssd->cancelbutton->button.iscancel = true; ssd->cancelbutton->generic.column = 4; /* We carefully don't close the 5-column part, so that platform- * specific add-ons can put extra buttons alongside Open and Cancel. */ @@ -1530,7 +1530,7 @@ void setup_config_box(struct controlbox *b, int midsession, midsession ? "Save the current session settings" : "Load, save or delete a stored session"); ctrl_columns(s, 2, 75, 25); - get_sesslist(&ssd->sesslist, TRUE); + get_sesslist(&ssd->sesslist, true); ssd->editbox = ctrl_editbox(s, "Saved Sessions", 'e', 100, HELPCTX(session_saved), sessionsaver_handler, P(ssd), P(NULL)); @@ -1613,7 +1613,7 @@ void setup_config_box(struct controlbox *b, int midsession, NULL); } ctrl_filesel(s, "Log file name:", 'f', - NULL, TRUE, "Select session log file name", + NULL, true, "Select session log file name", HELPCTX(logging_filename), conf_filesel_handler, I(CONF_logfilename)); ctrl_text(s, "(Log file name can contain &Y, &M, &D for date," @@ -2144,8 +2144,8 @@ void setup_config_box(struct controlbox *b, int midsession, HELPCTX(connection_username_from_env), conf_radiobutton_handler, I(CONF_username_from_env), - "Prompt", I(FALSE), - userlabel, I(TRUE), + "Prompt", I(false), + userlabel, I(true), NULL); sfree(userlabel); } @@ -2482,7 +2482,7 @@ void setup_config_box(struct controlbox *b, int midsession, * it become really unhelpful if a horizontal scrollbar * appears, so we suppress that. */ mh->listbox->listbox.height = 2; - mh->listbox->listbox.hscroll = FALSE; + mh->listbox->listbox.hscroll = false; ctrl_tabdelay(s, mh->rembutton); mh->keybox = ctrl_editbox(s, "Key", 'k', 80, HELPCTX(ssh_kex_manual_hostkeys), @@ -2558,7 +2558,7 @@ void setup_config_box(struct controlbox *b, int midsession, conf_checkbox_handler, I(CONF_change_username)); ctrl_filesel(s, "Private key file for authentication:", 'k', - FILTER_KEY_FILES, FALSE, "Select private key file", + FILTER_KEY_FILES, false, "Select private key file", HELPCTX(ssh_auth_privkey), conf_filesel_handler, I(CONF_keyfile)); @@ -2615,7 +2615,7 @@ void setup_config_box(struct controlbox *b, int midsession, */ ctrl_filesel(s, "User-supplied GSSAPI library path:", 's', - FILTER_DYNLIB_FILES, FALSE, "Select library file", + FILTER_DYNLIB_FILES, false, "Select library file", HELPCTX(ssh_gssapi_libraries), conf_filesel_handler, I(CONF_ssh_gss_custom)); diff --git a/contrib/cygtermd/telnet.c b/contrib/cygtermd/telnet.c index a41e6cea..6c96eed5 100644 --- a/contrib/cygtermd/telnet.c +++ b/contrib/cygtermd/telnet.c @@ -5,6 +5,7 @@ #include #include +#include #include #include "sel.h" @@ -12,13 +13,6 @@ #include "malloc.h" #include "pty.h" -#ifndef FALSE -#define FALSE 0 -#endif -#ifndef TRUE -#define TRUE 1 -#endif - #define IAC 255 /* interpret as command: */ #define DONT 254 /* you are not to use option */ #define DO 253 /* please, you use option */ diff --git a/defs.h b/defs.h index 809f7ed4..6a789389 100644 --- a/defs.h +++ b/defs.h @@ -13,6 +13,7 @@ #include #include +#include #if defined _MSC_VER && _MSC_VER < 1800 /* Work around lack of inttypes.h in older MSVC */ @@ -22,13 +23,6 @@ #include #endif -#ifndef FALSE -#define FALSE 0 -#endif -#ifndef TRUE -#define TRUE 1 -#endif - typedef struct conf_tag Conf; typedef struct terminal_tag Terminal; diff --git a/dialog.c b/dialog.c index 31a9627b..e712c452 100644 --- a/dialog.c +++ b/dialog.c @@ -364,7 +364,7 @@ union control *ctrl_listbox(struct controlset *s, const char *label, c->listbox.percentwidth = 100; c->listbox.ncols = 0; c->listbox.percentages = NULL; - c->listbox.hscroll = TRUE; + c->listbox.hscroll = true; return c; } @@ -381,7 +381,7 @@ union control *ctrl_droplist(struct controlset *s, const char *label, c->listbox.percentwidth = percentage; c->listbox.ncols = 0; c->listbox.percentages = NULL; - c->listbox.hscroll = FALSE; + c->listbox.hscroll = false; return c; } @@ -398,7 +398,7 @@ union control *ctrl_draglist(struct controlset *s, const char *label, c->listbox.percentwidth = 100; c->listbox.ncols = 0; c->listbox.percentages = NULL; - c->listbox.hscroll = FALSE; + c->listbox.hscroll = false; return c; } diff --git a/dialog.h b/dialog.h index 4b708489..fe32da72 100644 --- a/dialog.h +++ b/dialog.h @@ -340,7 +340,7 @@ union control { int ncols; /* number of columns */ int *percentages; /* % width of each column */ /* - * Flag which can be set to FALSE to suppress the horizontal + * Flag which can be set to false to suppress the horizontal * scroll bar if a list box entry goes off the right-hand * side. */ diff --git a/fuzzterm.c b/fuzzterm.c index d6a8337f..2e35677f 100644 --- a/fuzzterm.c +++ b/fuzzterm.c @@ -7,7 +7,7 @@ #include "terminal.h" /* For Unix in particular, but harmless if this main() is reused elsewhere */ -const int buildinfo_gtk_relevant = FALSE; +const int buildinfo_gtk_relevant = false; static const TermWinVtable fuzz_termwin_vt; @@ -44,7 +44,7 @@ int main(int argc, char **argv) } /* functions required by terminal.c */ -static int fuzz_setup_draw_ctx(TermWin *tw) { return TRUE; } +static int fuzz_setup_draw_ctx(TermWin *tw) { return true; } static void fuzz_draw_text( TermWin *tw, int x, int y, wchar_t *text, int len, unsigned long attr, int lattr, truecolour tc) @@ -84,18 +84,18 @@ static void fuzz_request_resize(TermWin *tw, int w, int h) {} static void fuzz_set_title(TermWin *tw, const char *title) {} static void fuzz_set_icon_title(TermWin *tw, const char *icontitle) {} static void fuzz_set_minimised(TermWin *tw, int minimised) {} -static int fuzz_is_minimised(TermWin *tw) { return FALSE; } +static int fuzz_is_minimised(TermWin *tw) { return false; } static void fuzz_set_maximised(TermWin *tw, int maximised) {} static void fuzz_move(TermWin *tw, int x, int y) {} static void fuzz_set_zorder(TermWin *tw, int top) {} static int fuzz_palette_get(TermWin *tw, int n, int *r, int *g, int *b) -{ return FALSE; } +{ return false; } static void fuzz_palette_set(TermWin *tw, int n, int r, int g, int b) {} static void fuzz_palette_reset(TermWin *tw) {} static void fuzz_get_pos(TermWin *tw, int *x, int *y) { *x = *y = 0; } static void fuzz_get_pixels(TermWin *tw, int *x, int *y) { *x = *y = 0; } static const char *fuzz_get_title(TermWin *tw, int icon) { return "moo"; } -static int fuzz_is_utf8(TermWin *tw) { return TRUE; } +static int fuzz_is_utf8(TermWin *tw) { return true; } static const TermWinVtable fuzz_termwin_vt = { fuzz_setup_draw_ctx, diff --git a/import.c b/import.c index 66be77cb..d3b1d331 100644 --- a/import.c +++ b/import.c @@ -316,7 +316,7 @@ static struct openssh_pem_key *load_openssh_pem_key(const Filename *filename, ret = snew(struct openssh_pem_key); ret->keyblob = strbuf_new(); - fp = f_open(filename, "r", FALSE); + fp = f_open(filename, "r", false); if (!fp) { errmsg = "unable to open key file"; goto error; @@ -355,7 +355,7 @@ static struct openssh_pem_key *load_openssh_pem_key(const Filename *filename, sfree(line); line = NULL; - ret->encrypted = FALSE; + ret->encrypted = false; memset(ret->iv, 0, sizeof(ret->iv)); headers_done = 0; @@ -385,7 +385,7 @@ static struct openssh_pem_key *load_openssh_pem_key(const Filename *filename, } p += 2; if (!strcmp(p, "ENCRYPTED")) - ret->encrypted = TRUE; + ret->encrypted = true; } else if (!strcmp(line, "DEK-Info")) { int i, ivlen; @@ -1048,7 +1048,7 @@ int openssh_pem_write(const Filename *filename, struct ssh2_userkey *key, * And save it. We'll use Unix line endings just in case it's * subsequently transferred in binary mode. */ - fp = f_open(filename, "wb", TRUE); /* ensure Unix line endings */ + fp = f_open(filename, "wb", true); /* ensure Unix line endings */ if (!fp) goto error; fputs(header, fp); @@ -1125,7 +1125,7 @@ static struct openssh_new_key *load_openssh_new_key(const Filename *filename, ret->keyblob = NULL; ret->keyblob_len = ret->keyblob_size = 0; - fp = f_open(filename, "r", FALSE); + fp = f_open(filename, "r", false); if (!fp) { errmsg = "unable to open key file"; goto error; @@ -1621,7 +1621,7 @@ int openssh_new_write(const Filename *filename, struct ssh2_userkey *key, * And save it. We'll use Unix line endings just in case it's * subsequently transferred in binary mode. */ - fp = f_open(filename, "wb", TRUE); /* ensure Unix line endings */ + fp = f_open(filename, "wb", true); /* ensure Unix line endings */ if (!fp) goto error; fputs("-----BEGIN OPENSSH PRIVATE KEY-----\n", fp); @@ -1762,7 +1762,7 @@ static struct sshcom_key *load_sshcom_key(const Filename *filename, ret->keyblob = NULL; ret->keyblob_len = ret->keyblob_size = 0; - fp = f_open(filename, "r", FALSE); + fp = f_open(filename, "r", false); if (!fp) { errmsg = "unable to open key file"; goto error; @@ -1910,7 +1910,7 @@ int sshcom_encrypted(const Filename *filename, char **comment) struct sshcom_key *key = load_sshcom_key(filename, NULL); BinarySource src[1]; ptrlen str; - int answer = FALSE; + int answer = false; *comment = NULL; if (!key) @@ -1926,7 +1926,7 @@ int sshcom_encrypted(const Filename *filename, char **comment) if (get_err(src)) goto done; /* key is invalid */ if (!ptrlen_eq_string(str, "none")) - answer = TRUE; + answer = true; done: if (key) { @@ -2338,7 +2338,7 @@ int sshcom_write(const Filename *filename, struct ssh2_userkey *key, * And save it. We'll use Unix line endings just in case it's * subsequently transferred in binary mode. */ - fp = f_open(filename, "wb", TRUE); /* ensure Unix line endings */ + fp = f_open(filename, "wb", true); /* ensure Unix line endings */ if (!fp) goto error; fputs("---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----\n", fp); diff --git a/ldisc.c b/ldisc.c index a72adbcb..449e6659 100644 --- a/ldisc.c +++ b/ldisc.c @@ -233,7 +233,7 @@ void ldisc_send(Ldisc *ldisc, const void *vbuf, int len, int interactive) } break; case CTRL('V'): /* quote next char */ - ldisc->quotenext = TRUE; + ldisc->quotenext = true; break; case CTRL('D'): /* logout or send */ if (ldisc->buflen == 0) { @@ -298,7 +298,7 @@ void ldisc_send(Ldisc *ldisc, const void *vbuf, int len, int interactive) ldisc->buf[ldisc->buflen++] = c; if (ECHOING) pwrite(ldisc, (unsigned char) c); - ldisc->quotenext = FALSE; + ldisc->quotenext = false; break; } } diff --git a/logging.c b/logging.c index a04ca633..bf747b27 100644 --- a/logging.c +++ b/logging.c @@ -87,18 +87,18 @@ static void logfopen_callback(void *vctx, int mode) char buf[256], *event; struct tm tm; const char *fmode; - int shout = FALSE; + int shout = false; if (mode == 0) { ctx->state = L_ERROR; /* disable logging */ } else { fmode = (mode == 1 ? "ab" : "wb"); - ctx->lgfp = f_open(ctx->currlogfilename, fmode, FALSE); + ctx->lgfp = f_open(ctx->currlogfilename, fmode, false); if (ctx->lgfp) { ctx->state = L_OPEN; } else { ctx->state = L_ERROR; - shout = TRUE; + shout = true; } } @@ -425,9 +425,9 @@ void log_reconfig(LogContext *ctx, Conf *conf) conf_get_filename(conf, CONF_logfilename)) || conf_get_int(ctx->conf, CONF_logtype) != conf_get_int(conf, CONF_logtype)) - reset_logging = TRUE; + reset_logging = true; else - reset_logging = FALSE; + reset_logging = false; if (reset_logging) logfclose(ctx); @@ -463,7 +463,7 @@ static Filename *xlatlognam(Filename *src, char *hostname, int port, s = filename_to_str(src); while (*s) { - int sanitise = FALSE; + int sanitise = false; /* Let (bufp, len) be the string to append. */ bufp = buf; /* don't usually override this */ if (*s == '&') { @@ -501,7 +501,7 @@ static Filename *xlatlognam(Filename *src, char *hostname, int port, * auto-format directives. E.g. 'hostname' can contain * colons, if it's an IPv6 address, and colons aren't * legal in filenames on Windows. */ - sanitise = TRUE; + sanitise = true; } else { buf[0] = *s++; size = 1; diff --git a/mainchan.c b/mainchan.c index c0738151..bf2deabb 100644 --- a/mainchan.c +++ b/mainchan.c @@ -139,7 +139,7 @@ static void mainchan_open_confirmation(Channel *chan) char *key, *val, *cmd; struct X11Display *x11disp; struct X11FakeAuth *x11auth; - int retry_cmd_now = FALSE; + int retry_cmd_now = false; if (conf_get_int(mc->conf, CONF_x11_forward)) {; char *x11_setup_err; @@ -154,27 +154,27 @@ static void mainchan_open_confirmation(Channel *chan) mc->cl, conf_get_int(mc->conf, CONF_x11_auth), x11disp); sshfwd_request_x11_forwarding( - mc->sc, TRUE, x11auth->protoname, x11auth->datastring, - x11disp->screennum, FALSE); - mc->req_x11 = TRUE; + mc->sc, true, x11auth->protoname, x11auth->datastring, + x11disp->screennum, false); + mc->req_x11 = true; } } if (ssh_agent_forwarding_permitted(mc->cl)) { - sshfwd_request_agent_forwarding(mc->sc, TRUE); - mc->req_agent = TRUE; + sshfwd_request_agent_forwarding(mc->sc, true); + mc->req_agent = true; } if (!conf_get_int(mc->conf, CONF_nopty)) { sshfwd_request_pty( - mc->sc, TRUE, mc->conf, mc->term_width, mc->term_height); - mc->req_pty = TRUE; + mc->sc, true, mc->conf, mc->term_width, mc->term_height); + mc->req_pty = true; } for (val = conf_get_str_strs(mc->conf, CONF_environmt, NULL, &key); val != NULL; val = conf_get_str_strs(mc->conf, CONF_environmt, key, &key)) { - sshfwd_send_env_var(mc->sc, TRUE, key, val); + sshfwd_send_env_var(mc->sc, true, key, val); mc->n_req_env++; } if (mc->n_req_env) @@ -182,21 +182,21 @@ static void mainchan_open_confirmation(Channel *chan) cmd = conf_get_str(mc->conf, CONF_remote_cmd); if (conf_get_int(mc->conf, CONF_ssh_subsys)) { - retry_cmd_now = !sshfwd_start_subsystem(mc->sc, TRUE, cmd); + retry_cmd_now = !sshfwd_start_subsystem(mc->sc, true, cmd); } else if (*cmd) { - sshfwd_start_command(mc->sc, TRUE, cmd); + sshfwd_start_command(mc->sc, true, cmd); } else { - sshfwd_start_shell(mc->sc, TRUE); + sshfwd_start_shell(mc->sc, true); } if (retry_cmd_now) mainchan_try_fallback_command(mc); else - mc->req_cmd_primary = TRUE; + mc->req_cmd_primary = true; } else { - ssh_set_ldisc_option(mc->cl, LD_ECHO, TRUE); - ssh_set_ldisc_option(mc->cl, LD_EDIT, TRUE); + ssh_set_ldisc_option(mc->cl, LD_ECHO, true); + ssh_set_ldisc_option(mc->cl, LD_EDIT, true); mainchan_ready(mc); } } @@ -205,11 +205,11 @@ static void mainchan_try_fallback_command(mainchan *mc) { const char *cmd = conf_get_str(mc->conf, CONF_remote_cmd2); if (conf_get_int(mc->conf, CONF_ssh_subsys2)) { - sshfwd_start_subsystem(mc->sc, TRUE, cmd); + sshfwd_start_subsystem(mc->sc, true, cmd); } else { - sshfwd_start_command(mc->sc, TRUE, cmd); + sshfwd_start_command(mc->sc, true, cmd); } - mc->req_cmd_fallback = TRUE; + mc->req_cmd_fallback = true; } static void mainchan_request_response(Channel *chan, int success) @@ -219,7 +219,7 @@ static void mainchan_request_response(Channel *chan, int success) PacketProtocolLayer *ppl = mc->ppl; /* for ppl_logevent */ if (mc->req_x11) { - mc->req_x11 = FALSE; + mc->req_x11 = false; if (success) { ppl_logevent(("X11 forwarding enabled")); @@ -231,7 +231,7 @@ static void mainchan_request_response(Channel *chan, int success) } if (mc->req_agent) { - mc->req_agent = FALSE; + mc->req_agent = false; if (success) { ppl_logevent(("Agent forwarding enabled")); @@ -243,16 +243,16 @@ static void mainchan_request_response(Channel *chan, int success) } if (mc->req_pty) { - mc->req_pty = FALSE; + mc->req_pty = false; if (success) { ppl_logevent(("Allocated pty")); - mc->got_pty = TRUE; + mc->got_pty = true; } else { ppl_logevent(("Server refused to allocate pty")); ppl_printf(("Server refused to allocate pty\r\n")); - ssh_set_ldisc_option(mc->cl, LD_ECHO, TRUE); - ssh_set_ldisc_option(mc->cl, LD_EDIT, TRUE); + ssh_set_ldisc_option(mc->cl, LD_ECHO, true); + ssh_set_ldisc_option(mc->cl, LD_EDIT, true); } return; } @@ -282,7 +282,7 @@ static void mainchan_request_response(Channel *chan, int success) } if (mc->req_cmd_primary) { - mc->req_cmd_primary = FALSE; + mc->req_cmd_primary = false; if (success) { ppl_logevent(("Started a shell/command")); @@ -302,7 +302,7 @@ static void mainchan_request_response(Channel *chan, int success) } if (mc->req_cmd_fallback) { - mc->req_cmd_fallback = FALSE; + mc->req_cmd_fallback = false; if (success) { ppl_logevent(("Started a shell/command")); @@ -318,14 +318,14 @@ static void mainchan_request_response(Channel *chan, int success) static void mainchan_ready(mainchan *mc) { - mc->ready = TRUE; + mc->ready = true; - ssh_set_wants_user_input(mc->cl, TRUE); + ssh_set_wants_user_input(mc->cl, true); ssh_ppl_got_user_input(mc->ppl); /* in case any is already queued */ /* If an EOF arrived before we were ready, handle it now. */ if (mc->eof_pending) { - mc->eof_pending = FALSE; + mc->eof_pending = false; mainchan_special_cmd(mc, SS_EOF, 0); } @@ -387,8 +387,8 @@ static void mainchan_send_eof(Channel *chan) sshfwd_write_eof(mc->sc); ppl_logevent(("Sent EOF message")); } - mc->eof_sent = TRUE; - ssh_set_wants_user_input(mc->cl, FALSE); /* now stop reading from stdin */ + mc->eof_sent = true; + ssh_set_wants_user_input(mc->cl, false); /* now stop reading from stdin */ } static void mainchan_set_input_wanted(Channel *chan, int wanted) @@ -418,7 +418,7 @@ static int mainchan_rcvd_exit_status(Channel *chan, int status) ssh_got_exitcode(mc->ppl->ssh, status); ppl_logevent(("Session sent command exit status %d", status)); - return TRUE; + return true; } static void mainchan_log_exit_signal_common( @@ -466,7 +466,7 @@ static int mainchan_rcvd_exit_signal( signame_str = dupprintf("signal SIG%.*s", PTRLEN_PRINTF(signame)); mainchan_log_exit_signal_common(mc, signame_str, core_dumped, msg); sfree(signame_str); - return TRUE; + return true; } static int mainchan_rcvd_exit_signal_numeric( @@ -480,7 +480,7 @@ static int mainchan_rcvd_exit_signal_numeric( signum_str = dupprintf("signal %d", signum); mainchan_log_exit_signal_common(mc, signum_str, core_dumped, msg); sfree(signum_str); - return TRUE; + return true; } void mainchan_get_specials( @@ -533,17 +533,17 @@ void mainchan_special_cmd(mainchan *mc, SessionSpecialCode code, int arg) * Buffer the EOF to send as soon as the main channel is * fully set up. */ - mc->eof_pending = TRUE; + mc->eof_pending = true; } else if (!mc->eof_sent) { sshfwd_write_eof(mc->sc); - mc->eof_sent = TRUE; + mc->eof_sent = true; } } else if (code == SS_BRK) { sshfwd_send_serial_break( - mc->sc, FALSE, 0 /* default break length */); + mc->sc, false, 0 /* default break length */); } else if ((signame = ssh_signal_lookup(code)) != NULL) { /* It's a signal. */ - sshfwd_send_signal(mc->sc, FALSE, signame); + sshfwd_send_signal(mc->sc, false, signame); ppl_logevent(("Sent signal SIG%s", signame)); } } diff --git a/marshal.c b/marshal.c index c4fd268b..349367aa 100644 --- a/marshal.c +++ b/marshal.c @@ -88,10 +88,10 @@ int BinarySink_put_pstring(BinarySink *bs, const char *str) { size_t len = strlen(str); if (len > 255) - return FALSE; /* can't write a Pascal-style string this long */ + return false; /* can't write a Pascal-style string this long */ BinarySink_put_byte(bs, len); bs->write(bs, str, len); - return TRUE; + return true; } /* ---------------------------------------------------------------------- */ @@ -99,13 +99,13 @@ int BinarySink_put_pstring(BinarySink *bs, const char *str) static int BinarySource_data_avail(BinarySource *src, size_t wanted) { if (src->err) - return FALSE; + return false; if (wanted <= src->len - src->pos) - return TRUE; + return true; src->err = BSE_OUT_OF_DATA; - return FALSE; + return false; } #define avail(wanted) BinarySource_data_avail(src, wanted) diff --git a/misc.c b/misc.c index 39e77f76..b1f0a0ec 100644 --- a/misc.c +++ b/misc.c @@ -123,7 +123,7 @@ static const char *host_strchr_internal(const char *s, const char *set, } size_t host_strcspn(const char *s, const char *set) { - const char *answer = host_strchr_internal(s, set, TRUE); + const char *answer = host_strchr_internal(s, set, true); if (answer) return answer - s; else @@ -134,14 +134,14 @@ char *host_strchr(const char *s, int c) char set[2]; set[0] = c; set[1] = '\0'; - return (char *) host_strchr_internal(s, set, TRUE); + return (char *) host_strchr_internal(s, set, true); } char *host_strrchr(const char *s, int c) { char set[2]; set[0] = c; set[1] = '\0'; - return (char *) host_strchr_internal(s, set, FALSE); + return (char *) host_strchr_internal(s, set, false); } #ifdef TEST_HOST_STRFOO @@ -235,9 +235,9 @@ prompts_t *new_prompts(void) p->prompts = NULL; p->n_prompts = 0; p->data = NULL; - p->to_server = TRUE; /* to be on the safe side */ + p->to_server = true; /* to be on the safe side */ p->name = p->instruction = NULL; - p->name_reqd = p->instr_reqd = FALSE; + p->name_reqd = p->instr_reqd = false; return p; } void add_prompt(prompts_t *p, char *promptstr, int echo) @@ -830,9 +830,9 @@ int bufchain_try_fetch_consume(bufchain *ch, void *data, int len) { if (ch->buffersize >= len) { bufchain_fetch_consume(ch, data, len); - return TRUE; + return true; } else { - return FALSE; + return false; } } @@ -1113,11 +1113,11 @@ void smemclr(void *b, size_t n) { /* * Validate a manual host key specification (either entered in the - * GUI, or via -hostkey). If valid, we return TRUE, and update 'key' + * GUI, or via -hostkey). If valid, we return true, and update 'key' * to contain a canonicalised version of the key string in 'key' * (which is guaranteed to take up at most as much space as the * original version), suitable for putting into the Conf. If not - * valid, we return FALSE. + * valid, we return false. */ int validate_manual_hostkey(char *key) { @@ -1154,7 +1154,7 @@ int validate_manual_hostkey(char *key) for (i = 0; i < 16*3 - 1; i++) key[i] = tolower(q[i]); key[16*3 - 1] = '\0'; - return TRUE; + return true; } not_fingerprint:; @@ -1200,12 +1200,12 @@ int validate_manual_hostkey(char *key) goto not_ssh2_blob; /* sorry */ strcpy(key, q); - return TRUE; + return true; } not_ssh2_blob:; } - return FALSE; + return false; } int smemeq(const void *av, const void *bv, size_t len) @@ -1272,9 +1272,9 @@ int ptrlen_startswith(ptrlen whole, ptrlen prefix, ptrlen *tail) tail->ptr = (const char *)whole.ptr + prefix.len; tail->len = whole.len - prefix.len; } - return TRUE; + return true; } - return FALSE; + return false; } char *mkstr(ptrlen pl) @@ -1391,7 +1391,7 @@ char *buildinfo(const char *newline) int nullseat_output( Seat *seat, int is_stderr, const void *data, int len) { return 0; } -int nullseat_eof(Seat *seat) { return TRUE; } +int nullseat_eof(Seat *seat) { return true; } int nullseat_get_userpass_input( Seat *seat, prompts_t *p, bufchain *input) { return 0; } void nullseat_notify_remote_exit(Seat *seat) {} @@ -1409,13 +1409,13 @@ int nullseat_confirm_weak_crypto_primitive( int nullseat_confirm_weak_cached_hostkey( Seat *seat, const char *algname, const char *betteralgs, void (*callback)(void *ctx, int result), void *ctx) { return 0; } -int nullseat_is_never_utf8(Seat *seat) { return FALSE; } -int nullseat_is_always_utf8(Seat *seat) { return TRUE; } +int nullseat_is_never_utf8(Seat *seat) { return false; } +int nullseat_is_always_utf8(Seat *seat) { return true; } void nullseat_echoedit_update(Seat *seat, int echoing, int editing) {} const char *nullseat_get_x_display(Seat *seat) { return NULL; } -int nullseat_get_windowid(Seat *seat, long *id_out) { return FALSE; } +int nullseat_get_windowid(Seat *seat, long *id_out) { return false; } int nullseat_get_window_pixel_size( - Seat *seat, int *width, int *height) { return FALSE; } + Seat *seat, int *width, int *height) { return false; } void sk_free_peer_info(SocketPeerInfo *pi) { diff --git a/nocmdline.c b/nocmdline.c index a6f62bf5..090bfba7 100644 --- a/nocmdline.c +++ b/nocmdline.c @@ -33,7 +33,7 @@ int cmdline_get_passwd_input(prompts_t *p) int cmdline_process_param(const char *p, char *value, int need_save, Conf *conf) { - assert(FALSE && "cmdline_process_param should never be called"); + assert(false && "cmdline_process_param should never be called"); } /* diff --git a/pageant.c b/pageant.c index bde0f66e..a50a4397 100644 --- a/pageant.c +++ b/pageant.c @@ -27,7 +27,7 @@ int random_byte(void) return 0; /* unreachable, but placate optimiser */ } -static int pageant_local = FALSE; +static int pageant_local = false; /* * rsakeys stores SSH-1 RSA keys. ssh2keys stores all SSH-2 keys. @@ -627,7 +627,7 @@ void pageant_failure_msg(BinarySink *bs, void pageant_init(void) { - pageant_local = TRUE; + pageant_local = true; rsakeys = newtree234(cmpkeys_rsa); ssh2keys = newtree234(cmpkeys_ssh2); } @@ -666,18 +666,18 @@ int pageant_delete_ssh1_key(struct RSAKey *rkey) { struct RSAKey *deleted = del234(rsakeys, rkey); if (!deleted) - return FALSE; + return false; assert(deleted == rkey); - return TRUE; + return true; } int pageant_delete_ssh2_key(struct ssh2_userkey *skey) { struct ssh2_userkey *deleted = del234(ssh2keys, skey); if (!deleted) - return FALSE; + return false; assert(deleted == skey); - return TRUE; + return true; } /* ---------------------------------------------------------------------- @@ -842,7 +842,7 @@ static int pageant_listen_accepting(Plug *plug, if ((err = sk_socket_error(pc->connsock)) != NULL) { sk_close(pc->connsock); sfree(pc); - return TRUE; + return true; } sk_set_frozen(pc->connsock, 0); diff --git a/pinger.c b/pinger.c index e14c32d1..d03210e2 100644 --- a/pinger.c +++ b/pinger.c @@ -20,7 +20,7 @@ static void pinger_timer(void *ctx, unsigned long now) if (pinger->pending && now == pinger->next) { backend_special(pinger->backend, SS_PING, 0); - pinger->pending = FALSE; + pinger->pending = false; pinger_schedule(pinger); } } @@ -30,7 +30,7 @@ static void pinger_schedule(Pinger *pinger) unsigned long next; if (!pinger->interval) { - pinger->pending = FALSE; /* cancel any pending ping */ + pinger->pending = false; /* cancel any pending ping */ return; } @@ -40,7 +40,7 @@ static void pinger_schedule(Pinger *pinger) (next - pinger->when_set) < (pinger->next - pinger->when_set)) { pinger->next = next; pinger->when_set = timing_last_clock(); - pinger->pending = TRUE; + pinger->pending = true; } } @@ -49,7 +49,7 @@ Pinger *pinger_new(Conf *conf, Backend *backend) Pinger *pinger = snew(Pinger); pinger->interval = conf_get_int(conf, CONF_ping_interval); - pinger->pending = FALSE; + pinger->pending = false; pinger->backend = backend; pinger_schedule(pinger); diff --git a/portfwd.c b/portfwd.c index af4b541d..c4a3210b 100644 --- a/portfwd.c +++ b/portfwd.c @@ -254,7 +254,7 @@ static void pfd_receive(Plug *plug, int urgent, char *data, int len) return; if (socks_version == 4 && message_type == 1) { /* CONNECT message */ - int name_based = FALSE; + int name_based = false; port = get_uint16(src); ipv4 = get_uint32(src); @@ -264,7 +264,7 @@ static void pfd_receive(Plug *plug, int urgent, char *data, int len) * extension to specify a hostname, which comes * after the username. */ - name_based = TRUE; + name_based = true; } get_asciz(src); /* skip username */ socks4_hostname = name_based ? get_asciz(src) : NULL; @@ -475,12 +475,12 @@ Channel *portfwd_raw_new(ConnectionLayer *cl, Plug **plug) pf->plug.vt = &PortForwarding_plugvt; pf->chan.initial_fixed_window_size = 0; pf->chan.vt = &PortForwarding_channelvt; - pf->input_wanted = TRUE; + pf->input_wanted = true; pf->c = NULL; pf->cl = cl; - pf->input_wanted = TRUE; + pf->input_wanted = true; pf->ready = 0; pf->socks_state = SOCKS_NONE; @@ -526,7 +526,7 @@ static int pfl_accepting(Plug *p, accept_fn_t constructor, accept_ctx_t ctx) s = constructor(ctx, plug); if ((err = sk_socket_error(s)) != NULL) { portfwd_raw_free(chan); - return TRUE; + return true; } pf = container_of(chan, struct PortForwarding, chan); @@ -581,9 +581,9 @@ static char *pfl_listen(const char *desthost, int destport, if (desthost) { pl->hostname = dupstr(desthost); pl->port = destport; - pl->is_dynamic = FALSE; + pl->is_dynamic = false; } else - pl->is_dynamic = TRUE; + pl->is_dynamic = true; pl->cl = cl; pl->s = new_listener(srcaddr, port, &pl->plug, @@ -1072,7 +1072,7 @@ int portfwdmgr_listen(PortFwdManager *mgr, const char *host, int port, * We had this record already. Return failure. */ pfr_free(pfr); - return FALSE; + return false; } char *err = pfl_listen(keyhost, keyport, host, port, @@ -1085,10 +1085,10 @@ int portfwdmgr_listen(PortFwdManager *mgr, const char *host, int port, sfree(err); del234(mgr->forwardings, pfr); pfr_free(pfr); - return FALSE; + return false; } - return TRUE; + return true; } int portfwdmgr_unlisten(PortFwdManager *mgr, const char *host, int port) @@ -1108,12 +1108,12 @@ int portfwdmgr_unlisten(PortFwdManager *mgr, const char *host, int port) PortFwdRecord *pfr = del234(mgr->forwardings, &pfr_key); if (!pfr) - return FALSE; + return false; logeventf(mgr->cl->logctx, "Closing listening port %s:%d", host, port); pfr_free(pfr); - return TRUE; + return true; } /* @@ -1152,7 +1152,7 @@ char *portfwdmgr_connect(PortFwdManager *mgr, Channel **chan_ret, pf->plug.vt = &PortForwarding_plugvt; pf->chan.initial_fixed_window_size = 0; pf->chan.vt = &PortForwarding_channelvt; - pf->input_wanted = TRUE; + pf->input_wanted = true; pf->ready = 1; pf->c = c; pf->cl = mgr->cl; diff --git a/proxy.c b/proxy.c index 14f72e2b..0e1eeeed 100644 --- a/proxy.c +++ b/proxy.c @@ -778,7 +778,7 @@ int proxy_socks4_negotiate (ProxySocket *p, int change) strbuf *command = strbuf_new(); char hostname[512]; - int write_hostname = FALSE; + int write_hostname = false; put_byte(command, 4); /* SOCKS version 4 */ put_byte(command, 1); /* CONNECT command */ @@ -795,7 +795,7 @@ int proxy_socks4_negotiate (ProxySocket *p, int change) case ADDRTYPE_NAME: sk_getaddr(p->remote_addr, hostname, lenof(hostname)); put_uint32(command, 1); - write_hostname = TRUE; + write_hostname = true; break; case ADDRTYPE_IPV6: p->error = "Proxy error: SOCKS version 4 does not support IPv6"; diff --git a/pscp.c b/pscp.c index 86525270..11f3f5c9 100644 --- a/pscp.c +++ b/pscp.c @@ -44,7 +44,7 @@ static int uploading = 0; static Backend *backend; static Conf *conf; -int sent_eof = FALSE; +int sent_eof = false; static void source(const char *src); static void rsource(const char *src); @@ -199,7 +199,7 @@ static int pscp_eof(Seat *seat) seat_connection_fatal( pscp_seat, "Received unexpected end-of-file from server"); } - return FALSE; + return false; } static int ssh_scp_recv(void *buf, int len) { @@ -286,7 +286,7 @@ static void bump(const char *fmt, ...) if (backend && backend_connected(backend)) { char ch; backend_special(backend, SS_EOF, 0); - sent_eof = TRUE; + sent_eof = true; ssh_scp_recv(&ch, 1); } @@ -439,7 +439,7 @@ static void do_cmd(char *host, char *user, char *cmd) */ conf_set_int(conf, CONF_x11_forward, 0); conf_set_int(conf, CONF_agentfwd, 0); - conf_set_int(conf, CONF_ssh_simple, TRUE); + conf_set_int(conf, CONF_ssh_simple, true); { char *key; while ((key = conf_get_str_nthstrkey(conf, CONF_portfwd, 0)) != NULL) @@ -457,12 +457,12 @@ static void do_cmd(char *host, char *user, char *cmd) /* First choice is SFTP subsystem. */ main_cmd_is_sftp = 1; conf_set_str(conf, CONF_remote_cmd, "sftp"); - conf_set_int(conf, CONF_ssh_subsys, TRUE); + conf_set_int(conf, CONF_ssh_subsys, true); if (try_scp) { /* Fallback is to use the provided scp command. */ fallback_cmd_is_sftp = 0; conf_set_str(conf, CONF_remote_cmd2, cmd); - conf_set_int(conf, CONF_ssh_subsys2, FALSE); + conf_set_int(conf, CONF_ssh_subsys2, false); } else { /* Since we're not going to try SCP, we may as well try * harder to find an SFTP server, since in the current @@ -475,15 +475,15 @@ static void do_cmd(char *host, char *user, char *cmd) "test -x /usr/local/lib/sftp-server &&" " exec /usr/local/lib/sftp-server\n" "exec sftp-server"); - conf_set_int(conf, CONF_ssh_subsys2, FALSE); + conf_set_int(conf, CONF_ssh_subsys2, false); } } else { /* Don't try SFTP at all; just try the scp command. */ main_cmd_is_sftp = 0; conf_set_str(conf, CONF_remote_cmd, cmd); - conf_set_int(conf, CONF_ssh_subsys, FALSE); + conf_set_int(conf, CONF_ssh_subsys, false); } - conf_set_int(conf, CONF_nopty, TRUE); + conf_set_int(conf, CONF_nopty, true); logctx = log_init(default_logpolicy, conf); @@ -2239,8 +2239,8 @@ void cmdline_error(const char *p, ...) exit(1); } -const int share_can_be_downstream = TRUE; -const int share_can_be_upstream = FALSE; +const int share_can_be_downstream = true; +const int share_can_be_upstream = false; /* * Main program. (Called `psftp_main' because it gets called from @@ -2263,7 +2263,7 @@ int psftp_main(int argc, char *argv[]) /* Load Default Settings before doing anything else. */ conf = conf_new(); do_defaults(NULL, conf); - loaded_session = FALSE; + loaded_session = false; for (i = 1; i < argc; i++) { int ret; @@ -2336,7 +2336,7 @@ int psftp_main(int argc, char *argv[]) if (backend && backend_connected(backend)) { char ch; backend_special(backend, SS_EOF, 0); - sent_eof = TRUE; + sent_eof = true; ssh_scp_recv(&ch, 1); } random_save_seed(); diff --git a/psftp.c b/psftp.c index 6e65d83a..6ab158b9 100644 --- a/psftp.c +++ b/psftp.c @@ -35,7 +35,7 @@ void do_sftp_cleanup(); char *pwd, *homedir; static Backend *backend; static Conf *conf; -int sent_eof = FALSE; +int sent_eof = false; /* ------------------------------------------------------------ * Seat vtable. @@ -235,7 +235,7 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart) struct fxp_xfer *xfer; uint64_t offset; WFile *file; - int ret, shown_err = FALSE; + int ret, shown_err = false; struct fxp_attrs attrs; /* @@ -378,7 +378,7 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart) nextfname = dupcat(fname, "/", ournames[i]->filename, NULL); nextoutfname = dir_file_cat(outfname, ournames[i]->filename); ret = sftp_get_file(nextfname, nextoutfname, recurse, restart); - restart = FALSE; /* after first partial file, do full */ + restart = false; /* after first partial file, do full */ sfree(nextoutfname); sfree(nextfname); if (!ret) { @@ -469,7 +469,7 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart) if (ret <= 0) { if (!shown_err) { printf("error while reading: %s\n", fxp_error()); - shown_err = TRUE; + shown_err = true; } if (ret == INT_MIN) /* pktin not even freed */ sfree(pktin); @@ -622,7 +622,7 @@ int sftp_put_file(char *fname, char *outfname, int recurse, int restart) nextfname = dir_file_cat(fname, ournames[i]); nextoutfname = dupcat(outfname, "/", ournames[i], NULL); ret = sftp_put_file(nextfname, nextoutfname, recurse, restart); - restart = FALSE; /* after first partial file, do full */ + restart = false; /* after first partial file, do full */ sfree(nextoutfname); sfree(nextfname); if (!ret) { @@ -914,7 +914,7 @@ int wildcard_iterate(char *filename, int (*func)(void *, char *), void *ctx) if (is_wc) { SftpWildcardMatcher *swcm = sftp_begin_wildcard_matching(filename); - int matched = FALSE; + int matched = false; sfree(unwcfname); if (!swcm) @@ -929,7 +929,7 @@ int wildcard_iterate(char *filename, int (*func)(void *, char *), void *ctx) ret = 0; } sfree(newname); - matched = TRUE; + matched = true; ret &= func(ctx, cname); sfree(cname); } @@ -1000,7 +1000,7 @@ int sftp_cmd_close(struct sftp_command *cmd) if (backend_connected(backend)) { char ch; backend_special(backend, SS_EOF, 0); - sent_eof = TRUE; + sent_eof = true; sftp_recvdata(&ch, 1); } do_sftp_cleanup(); @@ -1211,7 +1211,7 @@ int sftp_general_get(struct sftp_command *cmd, int restart, int multiple) { char *fname, *unwcfname, *origfname, *origwfname, *outfname; int i, ret; - int recurse = FALSE; + int recurse = false; if (!backend) { not_connected(); @@ -1225,7 +1225,7 @@ int sftp_general_get(struct sftp_command *cmd, int restart, int multiple) i++; break; } else if (!strcmp(cmd->words[i], "-r")) { - recurse = TRUE; + recurse = true; } else { printf("%s: unrecognised option '%s'\n", cmd->words[0], cmd->words[i]); return 0; @@ -1327,7 +1327,7 @@ int sftp_general_put(struct sftp_command *cmd, int restart, int multiple) { char *fname, *wfname, *origoutfname, *outfname; int i, ret; - int recurse = FALSE; + int recurse = false; if (!backend) { not_connected(); @@ -1341,7 +1341,7 @@ int sftp_general_put(struct sftp_command *cmd, int restart, int multiple) i++; break; } else if (!strcmp(cmd->words[i], "-r")) { - recurse = TRUE; + recurse = true; } else { printf("%s: unrecognised option '%s'\n", cmd->words[0], cmd->words[i]); return 0; @@ -1359,7 +1359,7 @@ int sftp_general_put(struct sftp_command *cmd, int restart, int multiple) WildcardMatcher *wcm; fname = cmd->words[i++]; - if (multiple && test_wildcard(fname, FALSE) == WCTYPE_WILDCARD) { + if (multiple && test_wildcard(fname, false) == WCTYPE_WILDCARD) { wcm = begin_wildcard_matching(fname); wfname = wildcard_get_filename(wcm); if (!wfname) { @@ -1560,9 +1560,9 @@ static int check_is_dir(char *dstfname) if (result && (attrs.flags & SSH_FILEXFER_ATTR_PERMISSIONS) && (attrs.permissions & 0040000)) - return TRUE; + return true; else - return FALSE; + return false; } struct sftp_context_mv { @@ -1935,20 +1935,20 @@ static struct sftp_cmd_lookup { * in ASCII order. */ { - "!", TRUE, "run a local command", + "!", true, "run a local command", "\n" /* FIXME: this example is crap for non-Windows. */ " Runs a local command. For example, \"!del myfile\".\n", sftp_cmd_pling }, { - "bye", TRUE, "finish your SFTP session", + "bye", true, "finish your SFTP session", "\n" " Terminates your SFTP session and quits the PSFTP program.\n", sftp_cmd_quit }, { - "cd", TRUE, "change your remote working directory", + "cd", true, "change your remote working directory", " [ ]\n" " Change the remote working directory for your SFTP session.\n" " If a new working directory is not supplied, you will be\n" @@ -1956,7 +1956,7 @@ static struct sftp_cmd_lookup { sftp_cmd_cd }, { - "chmod", TRUE, "change file permissions and modes", + "chmod", true, "change file permissions and modes", " [ ... ]\n" " Change the file permissions on one or more remote files or\n" " directories.\n" @@ -1984,7 +1984,7 @@ static struct sftp_cmd_lookup { sftp_cmd_chmod }, { - "close", TRUE, "finish your SFTP session but do not quit PSFTP", + "close", true, "finish your SFTP session but do not quit PSFTP", "\n" " Terminates your SFTP session, but does not quit the PSFTP\n" " program. You can then use \"open\" to start another SFTP\n" @@ -1992,16 +1992,16 @@ static struct sftp_cmd_lookup { sftp_cmd_close }, { - "del", TRUE, "delete files on the remote server", + "del", true, "delete files on the remote server", " [ ... ]\n" " Delete a file or files from the server.\n", sftp_cmd_rm }, { - "delete", FALSE, "del", NULL, sftp_cmd_rm + "delete", false, "del", NULL, sftp_cmd_rm }, { - "dir", TRUE, "list remote files", + "dir", true, "list remote files", " [ ]/[ ]\n" " List the contents of a specified directory on the server.\n" " If is not given, the current working directory\n" @@ -2011,10 +2011,10 @@ static struct sftp_cmd_lookup { sftp_cmd_ls }, { - "exit", TRUE, "bye", NULL, sftp_cmd_quit + "exit", true, "bye", NULL, sftp_cmd_quit }, { - "get", TRUE, "download a file from the server to your local machine", + "get", true, "download a file from the server to your local machine", " [ -r ] [ -- ] [ ]\n" " Downloads a file on the server and stores it locally under\n" " the same name, or under a different one if you supply the\n" @@ -2023,7 +2023,7 @@ static struct sftp_cmd_lookup { sftp_cmd_get }, { - "help", TRUE, "give help", + "help", true, "give help", " [ [ ... ] ]\n" " Give general help if no commands are specified.\n" " If one or more commands are specified, give specific help on\n" @@ -2031,25 +2031,25 @@ static struct sftp_cmd_lookup { sftp_cmd_help }, { - "lcd", TRUE, "change local working directory", + "lcd", true, "change local working directory", " \n" " Change the local working directory of the PSFTP program (the\n" " default location where the \"get\" command will save files).\n", sftp_cmd_lcd }, { - "lpwd", TRUE, "print local working directory", + "lpwd", true, "print local working directory", "\n" " Print the local working directory of the PSFTP program (the\n" " default location where the \"get\" command will save files).\n", sftp_cmd_lpwd }, { - "ls", TRUE, "dir", NULL, + "ls", true, "dir", NULL, sftp_cmd_ls }, { - "mget", TRUE, "download multiple files at once", + "mget", true, "download multiple files at once", " [ -r ] [ -- ] [ ... ]\n" " Downloads many files from the server, storing each one under\n" " the same name it has on the server side. You can use wildcards\n" @@ -2058,13 +2058,13 @@ static struct sftp_cmd_lookup { sftp_cmd_mget }, { - "mkdir", TRUE, "create directories on the remote server", + "mkdir", true, "create directories on the remote server", " [ ... ]\n" " Creates directories with the given names on the server.\n", sftp_cmd_mkdir }, { - "mput", TRUE, "upload multiple files at once", + "mput", true, "upload multiple files at once", " [ -r ] [ -- ] [ ... ]\n" " Uploads many files to the server, storing each one under the\n" " same name it has on the client side. You can use wildcards\n" @@ -2073,7 +2073,7 @@ static struct sftp_cmd_lookup { sftp_cmd_mput }, { - "mv", TRUE, "move or rename file(s) on the remote server", + "mv", true, "move or rename file(s) on the remote server", " [ ... ] \n" " Moves or renames (s) on the server to ,\n" " also on the server.\n" @@ -2085,14 +2085,14 @@ static struct sftp_cmd_lookup { sftp_cmd_mv }, { - "open", TRUE, "connect to a host", + "open", true, "connect to a host", " [@] []\n" " Establishes an SFTP connection to a given host. Only usable\n" " when you are not already connected to a server.\n", sftp_cmd_open }, { - "put", TRUE, "upload a file from your local machine to the server", + "put", true, "upload a file from your local machine to the server", " [ -r ] [ -- ] [ ]\n" " Uploads a file to the server and stores it there under\n" " the same name, or under a different one if you supply the\n" @@ -2101,17 +2101,17 @@ static struct sftp_cmd_lookup { sftp_cmd_put }, { - "pwd", TRUE, "print your remote working directory", + "pwd", true, "print your remote working directory", "\n" " Print the current remote working directory for your SFTP session.\n", sftp_cmd_pwd }, { - "quit", TRUE, "bye", NULL, + "quit", true, "bye", NULL, sftp_cmd_quit }, { - "reget", TRUE, "continue downloading files", + "reget", true, "continue downloading files", " [ -r ] [ -- ] [ ]\n" " Works exactly like the \"get\" command, but the local file\n" " must already exist. The download will begin at the end of the\n" @@ -2120,15 +2120,15 @@ static struct sftp_cmd_lookup { sftp_cmd_reget }, { - "ren", TRUE, "mv", NULL, + "ren", true, "mv", NULL, sftp_cmd_mv }, { - "rename", FALSE, "mv", NULL, + "rename", false, "mv", NULL, sftp_cmd_mv }, { - "reput", TRUE, "continue uploading files", + "reput", true, "continue uploading files", " [ -r ] [ -- ] [ ]\n" " Works exactly like the \"put\" command, but the remote file\n" " must already exist. The upload will begin at the end of the\n" @@ -2137,11 +2137,11 @@ static struct sftp_cmd_lookup { sftp_cmd_reput }, { - "rm", TRUE, "del", NULL, + "rm", true, "del", NULL, sftp_cmd_rm }, { - "rmdir", TRUE, "remove directories on the remote server", + "rmdir", true, "remove directories on the remote server", " [ ... ]\n" " Removes the directory with the given name on the server.\n" " The directory will not be removed unless it is empty.\n" @@ -2382,7 +2382,7 @@ void do_sftp_cleanup() char ch; if (backend) { backend_special(backend, SS_EOF, 0); - sent_eof = TRUE; + sent_eof = true; sftp_recvdata(&ch, 1); backend_free(backend); sftp_cleanup_request(); @@ -2545,7 +2545,7 @@ static int psftp_eof(Seat *seat) seat_connection_fatal( psftp_seat, "Received unexpected end-of-file from SFTP server"); } - return FALSE; + return false; } int sftp_recvdata(char *buf, int len) @@ -2763,7 +2763,7 @@ static int psftp_connect(char *userhost, char *user, int portnumber) */ conf_set_int(conf, CONF_x11_forward, 0); conf_set_int(conf, CONF_agentfwd, 0); - conf_set_int(conf, CONF_ssh_simple, TRUE); + conf_set_int(conf, CONF_ssh_simple, true); { char *key; while ((key = conf_get_str_nthstrkey(conf, CONF_portfwd, 0)) != NULL) @@ -2772,8 +2772,8 @@ static int psftp_connect(char *userhost, char *user, int portnumber) /* Set up subsystem name. */ conf_set_str(conf, CONF_remote_cmd, "sftp"); - conf_set_int(conf, CONF_ssh_subsys, TRUE); - conf_set_int(conf, CONF_nopty, TRUE); + conf_set_int(conf, CONF_ssh_subsys, true); + conf_set_int(conf, CONF_nopty, true); /* * Set up fallback option, for SSH-1 servers or servers with the @@ -2798,7 +2798,7 @@ static int psftp_connect(char *userhost, char *user, int portnumber) "test -x /usr/local/lib/sftp-server &&" " exec /usr/local/lib/sftp-server\n" "exec sftp-server"); - conf_set_int(conf, CONF_ssh_subsys2, FALSE); + conf_set_int(conf, CONF_ssh_subsys2, false); logctx = log_init(default_logpolicy, conf); @@ -2839,8 +2839,8 @@ void cmdline_error(const char *p, ...) exit(1); } -const int share_can_be_downstream = TRUE; -const int share_can_be_upstream = FALSE; +const int share_can_be_downstream = true; +const int share_can_be_upstream = false; /* * Main program. Parse arguments etc. @@ -2867,7 +2867,7 @@ int psftp_main(int argc, char *argv[]) /* Load Default Settings before doing anything else. */ conf = conf_new(); do_defaults(NULL, conf); - loaded_session = FALSE; + loaded_session = false; for (i = 1; i < argc; i++) { int ret; @@ -2948,7 +2948,7 @@ int psftp_main(int argc, char *argv[]) if (backend && backend_connected(backend)) { char ch; backend_special(backend, SS_EOF, 0); - sent_eof = TRUE; + sent_eof = true; sftp_recvdata(&ch, 1); } do_sftp_cleanup(); diff --git a/psftp.h b/psftp.h index 33c03453..c41675a9 100644 --- a/psftp.h +++ b/psftp.h @@ -36,11 +36,11 @@ int ssh_sftp_loop_iteration(void); * Read a command line for PSFTP from standard input. Caller must * free. * - * If `backend_required' is TRUE, should also listen for activity + * If `backend_required' is true, should also listen for activity * at the backend (rekeys, clientalives, unexpected closures etc) * and respond as necessary, and if the backend closes it should * treat this as a failure condition. If `backend_required' is - * FALSE, a back end is not (intentionally) active at all (e.g. + * false, a back end is not (intentionally) active at all (e.g. * psftp before an `open' command). */ char *ssh_sftp_get_cmdline(const char *prompt, int backend_required); @@ -166,7 +166,7 @@ void finish_wildcard_matching(WildcardMatcher *dir); * to filenames returned from FXP_READDIR, which means we can panic * if we see _anything_ resembling a directory separator. * - * Returns TRUE if the filename is kosher, FALSE if dangerous. + * Returns true if the filename is kosher, false if dangerous. */ int vet_filename(const char *name); diff --git a/putty.h b/putty.h index 010935a7..0212d083 100644 --- a/putty.h +++ b/putty.h @@ -511,7 +511,7 @@ struct BackendVtable { const SessionSpecial *(*get_specials) (Backend *be); int (*connected) (Backend *be); int (*exitcode) (Backend *be); - /* If back->sendok() returns FALSE, the backend doesn't currently + /* If back->sendok() returns false, the backend doesn't currently * want input data, so the frontend should avoid acquiring any if * possible (passing back-pressure on to its sender). */ int (*sendok) (Backend *be); @@ -593,7 +593,7 @@ GLOBAL int default_protocol; GLOBAL int default_port; /* - * This is set TRUE by cmdline.c iff a session is loaded with "-load". + * This is set true by cmdline.c iff a session is loaded with "-load". */ GLOBAL int loaded_session; /* @@ -746,9 +746,9 @@ struct SeatVtable { /* * Called when the back end wants to indicate that EOF has arrived - * on the server-to-client stream. Returns FALSE to indicate that + * on the server-to-client stream. Returns false to indicate that * we intend to keep the session open in the other direction, or - * TRUE to indicate that if they're closing so are we. + * true to indicate that if they're closing so are we. */ int (*eof)(Seat *seat); @@ -901,16 +901,16 @@ struct SeatVtable { /* * Return the X11 id of the X terminal window relevant to a seat, - * by returning TRUE and filling in the output pointer. Return - * FALSE if there isn't one or if the concept is meaningless. + * by returning true and filling in the output pointer. Return + * false if there isn't one or if the concept is meaningless. */ int (*get_windowid)(Seat *seat, long *id_out); /* * Return the size of the terminal window in pixels. If the * concept is meaningless or the information is unavailable, - * return FALSE; otherwise fill in the output pointers and return - * TRUE. + * return false; otherwise fill in the output pointers and return + * true. */ int (*get_window_pixel_size)(Seat *seat, int *width, int *height); }; @@ -953,9 +953,9 @@ void seat_connection_fatal(Seat *seat, const char *fmt, ...); /* Handy aliases for seat_output which set is_stderr to a fixed value. */ #define seat_stdout(seat, data, len) \ - seat_output(seat, FALSE, data, len) + seat_output(seat, false, data, len) #define seat_stderr(seat, data, len) \ - seat_output(seat, TRUE, data, len) + seat_output(seat, true, data, len) /* * Stub methods for seat implementations that want to use the obvious @@ -1922,9 +1922,9 @@ int open_for_write_would_lose_data(const Filename *fn); * run_timers() is called from the front end when it has reason to * think some timers have reached their moment, or when it simply * needs to know how long to wait next. We pass it the time we - * think it is. It returns TRUE and places the time when the next + * think it is. It returns true and places the time when the next * timer needs to go off in `next', or alternatively it returns - * FALSE if there are no timers at all pending. + * false if there are no timers at all pending. * * timer_change_notify() must be supplied by the front end; it * notifies the front end that a new timer has been added to the @@ -2020,7 +2020,7 @@ unsigned long timing_last_clock(void); * call) then it can call toplevel_callback_pending(), which will * return true if at least one callback is in the queue. * - * run_toplevel_callbacks() returns TRUE if it ran any actual code. + * run_toplevel_callbacks() returns true if it ran any actual code. * This can be used as a means of speculatively terminating a select * loop, as in PSFTP, for example - if a callback has run then perhaps * it might have done whatever the loop's caller was waiting for. diff --git a/raw.c b/raw.c index b6fcbe96..827193ea 100644 --- a/raw.c +++ b/raw.c @@ -66,7 +66,7 @@ static void raw_closing(Plug *plug, const char *error_msg, int error_code, if (raw->s) { sk_close(raw->s); raw->s = NULL; - raw->closed_on_socket_error = TRUE; + raw->closed_on_socket_error = true; seat_notify_remote_exit(raw->seat); } logevent(raw->logctx, error_msg); @@ -81,10 +81,10 @@ static void raw_closing(Plug *plug, const char *error_msg, int error_code, if (!raw->sent_socket_eof) { if (raw->s) sk_write_eof(raw->s); - raw->sent_socket_eof= TRUE; + raw->sent_socket_eof= true; } } - raw->sent_console_eof = TRUE; + raw->sent_console_eof = true; raw_check_close(raw); } } @@ -95,7 +95,7 @@ static void raw_receive(Plug *plug, int urgent, char *data, int len) c_write(raw, data, len); /* We count 'session start', for proxy logging purposes, as being * when data is received from the network and printed. */ - raw->session_started = TRUE; + raw->session_started = true; } static void raw_sent(Plug *plug, int bufsize) @@ -134,11 +134,11 @@ static const char *raw_init(Seat *seat, Backend **backend_handle, raw->plug.vt = &Raw_plugvt; raw->backend.vt = &raw_backend; raw->s = NULL; - raw->closed_on_socket_error = FALSE; + raw->closed_on_socket_error = false; *backend_handle = &raw->backend; - raw->sent_console_eof = raw->sent_socket_eof = FALSE; + raw->sent_console_eof = raw->sent_socket_eof = false; raw->bufsize = 0; - raw->session_started = FALSE; + raw->session_started = false; raw->conf = conf_copy(conf); raw->seat = seat; @@ -239,7 +239,7 @@ static void raw_special(Backend *be, SessionSpecialCode code, int arg) Raw *raw = container_of(be, Raw, backend); if (code == SS_EOF && raw->s) { sk_write_eof(raw->s); - raw->sent_socket_eof= TRUE; + raw->sent_socket_eof= true; raw_check_close(raw); } diff --git a/rlogin.c b/rlogin.c index d91b93cc..1b70443e 100644 --- a/rlogin.c +++ b/rlogin.c @@ -61,7 +61,7 @@ static void rlogin_closing(Plug *plug, const char *error_msg, int error_code, sk_close(rlogin->s); rlogin->s = NULL; if (error_msg) - rlogin->closed_on_socket_error = TRUE; + rlogin->closed_on_socket_error = true; seat_notify_remote_exit(rlogin->seat); } if (error_msg) { @@ -166,7 +166,7 @@ static const char *rlogin_init(Seat *seat, Backend **backend_handle, rlogin->plug.vt = &Rlogin_plugvt; rlogin->backend.vt = &rlogin_backend; rlogin->s = NULL; - rlogin->closed_on_socket_error = FALSE; + rlogin->closed_on_socket_error = false; rlogin->seat = seat; rlogin->logctx = logctx; rlogin->term_width = conf_get_int(conf, CONF_width); @@ -224,9 +224,9 @@ static const char *rlogin_init(Seat *seat, Backend **backend_handle, int ret; rlogin->prompt = new_prompts(); - rlogin->prompt->to_server = TRUE; + rlogin->prompt->to_server = true; rlogin->prompt->name = dupstr("Rlogin login name"); - add_prompt(rlogin->prompt, dupstr("rlogin username: "), TRUE); + add_prompt(rlogin->prompt, dupstr("rlogin username: "), true); ret = seat_get_userpass_input(rlogin->seat, rlogin->prompt, NULL); if (ret >= 0) { rlogin_startup(rlogin, rlogin->prompt->prompts[0]->result); diff --git a/scpserver.c b/scpserver.c index 8ba902f6..1c9912a3 100644 --- a/scpserver.c +++ b/scpserver.c @@ -268,14 +268,14 @@ struct ScpReplyReceiver { static void scp_reply_ok(SftpReplyBuilder *srb) { ScpReplyReceiver *reply = container_of(srb, ScpReplyReceiver, srb); - reply->err = FALSE; + reply->err = false; } static void scp_reply_error( SftpReplyBuilder *srb, unsigned code, const char *msg) { ScpReplyReceiver *reply = container_of(srb, ScpReplyReceiver, srb); - reply->err = TRUE; + reply->err = true; reply->code = code; sfree(reply->errmsg); reply->errmsg = dupstr(msg); @@ -284,7 +284,7 @@ static void scp_reply_error( static void scp_reply_name_count(SftpReplyBuilder *srb, unsigned count) { ScpReplyReceiver *reply = container_of(srb, ScpReplyReceiver, srb); - reply->err = FALSE; + reply->err = false; } static void scp_reply_full_name( @@ -293,7 +293,7 @@ static void scp_reply_full_name( { ScpReplyReceiver *reply = container_of(srb, ScpReplyReceiver, srb); char *p; - reply->err = FALSE; + reply->err = false; sfree((void *)reply->name.ptr); reply->name.ptr = p = mkstr(name); reply->name.len = name.len; @@ -303,14 +303,14 @@ static void scp_reply_full_name( static void scp_reply_simple_name(SftpReplyBuilder *srb, ptrlen name) { ScpReplyReceiver *reply = container_of(srb, ScpReplyReceiver, srb); - reply->err = FALSE; + reply->err = false; } static void scp_reply_handle(SftpReplyBuilder *srb, ptrlen handle) { ScpReplyReceiver *reply = container_of(srb, ScpReplyReceiver, srb); char *p; - reply->err = FALSE; + reply->err = false; sfree((void *)reply->handle.ptr); reply->handle.ptr = p = mkstr(handle); reply->handle.len = handle.len; @@ -320,7 +320,7 @@ static void scp_reply_data(SftpReplyBuilder *srb, ptrlen data) { ScpReplyReceiver *reply = container_of(srb, ScpReplyReceiver, srb); char *p; - reply->err = FALSE; + reply->err = false; sfree((void *)reply->data.ptr); reply->data.ptr = p = mkstr(data); reply->data.len = data.len; @@ -330,7 +330,7 @@ static void scp_reply_attrs( SftpReplyBuilder *srb, struct fxp_attrs attrs) { ScpReplyReceiver *reply = container_of(srb, ScpReplyReceiver, srb); - reply->err = FALSE; + reply->err = false; reply->attrs = attrs; } @@ -426,8 +426,8 @@ static void scp_source_push(ScpSource *scp, ScpSourceNodeType type, static char *scp_source_err_base(ScpSource *scp, const char *fmt, va_list ap) { char *msg = dupvprintf(fmt, ap); - sshfwd_write_ext(scp->sc, TRUE, msg, strlen(msg)); - sshfwd_write_ext(scp->sc, TRUE, "\012", 1); + sshfwd_write_ext(scp->sc, true, msg, strlen(msg)); + sshfwd_write_ext(scp->sc, true, "\012", 1); return msg; } static void scp_source_err(ScpSource *scp, const char *fmt, ...) @@ -451,7 +451,7 @@ static void scp_source_abort(ScpSource *scp, const char *fmt, ...) sshfwd_write_eof(scp->sc); sshfwd_initiate_close(scp->sc, msg); - scp->finished = TRUE; + scp->finished = true; } static void scp_source_push_name( @@ -687,7 +687,7 @@ static void scp_source_process_stack(ScpSource *scp) * wildcard (if any) we're using to match the filenames we get * back. */ - sftpsrv_stat(scp->sf, &scp->reply.srb, pathname, TRUE); + sftpsrv_stat(scp->sf, &scp->reply.srb, pathname, true); if (scp->reply.err) { scp_source_abort( scp, "%.*s: unable to access: %s", @@ -755,7 +755,7 @@ static void scp_source_process_stack(ScpSource *scp) sshfwd_send_exit_status(scp->sc, 0); sshfwd_write_eof(scp->sc); sshfwd_initiate_close(scp->sc, NULL); - scp->finished = TRUE; + scp->finished = true; return; } @@ -766,7 +766,7 @@ static void scp_source_process_stack(ScpSource *scp) scp->head = node->next; if (node->type == SCP_READDIR) { - sftpsrv_readdir(scp->sf, &scp->reply.srb, node->handle, 1, TRUE); + sftpsrv_readdir(scp->sf, &scp->reply.srb, node->handle, 1, true); if (scp->reply.err) { if (scp->reply.code != SSH_FX_EOF) scp_source_err(scp, "%.*s: unable to list directory: %s", @@ -871,7 +871,7 @@ static int scp_source_send(ScpServer *s, const void *vdata, size_t length) if (scp->expect_newline) { if (data[i] == '\012') { /* End of an error message following a 1 byte */ - scp->expect_newline = FALSE; + scp->expect_newline = false; scp->acks++; } } else { @@ -880,7 +880,7 @@ static int scp_source_send(ScpServer *s, const void *vdata, size_t length) scp->acks++; break; case 1: /* non-fatal error; consume it */ - scp->expect_newline = TRUE; + scp->expect_newline = true; break; case 2: scp_source_abort( @@ -918,7 +918,7 @@ static void scp_source_eof(ScpServer *s) if (scp->finished) return; - scp->eof = TRUE; + scp->eof = true; scp_source_process_stack(scp); } @@ -962,8 +962,8 @@ struct ScpSinkStackEntry { ptrlen destpath; /* - * If isdir is TRUE, then destpath identifies a directory that the - * files we receive should be created inside. If it's FALSE, then + * If isdir is true, then destpath identifies a directory that the + * files we receive should be created inside. If it's false, then * it identifies the exact pathname the next file we receive * should be created _as_ - regardless of the filename in the 'C' * command. @@ -1031,11 +1031,11 @@ static ScpSink *scp_sink_new( * directory because of the -d option in the command line, * test it ourself to see whether it is or not. */ - sftpsrv_stat(scp->sf, &scp->reply.srb, pathname, TRUE); + sftpsrv_stat(scp->sf, &scp->reply.srb, pathname, true); if (!scp->reply.err && (scp->reply.attrs.flags & SSH_FILEXFER_ATTR_PERMISSIONS) && (scp->reply.attrs.permissions & PERMS_DIRECTORY)) - pathname_is_definitely_dir = TRUE; + pathname_is_definitely_dir = true; } scp_sink_push(scp, pathname, pathname_is_definitely_dir); @@ -1102,7 +1102,7 @@ static void scp_sink_coroutine(ScpSink *scp) if (sscanf(scp->command->s, "T%lu %lu %lu %lu", &scp->mtime, &dummy1, &scp->atime, &dummy2) != 4) goto parse_error; - scp->got_file_times = TRUE; + scp->got_file_times = true; } else if (scp->command_chr == 'C' || scp->command_chr == 'D') { /* * Common handling of the start of this case, because the @@ -1148,7 +1148,7 @@ static void scp_sink_coroutine(ScpSink *scp) scp->attrs.atime = scp->atime; scp->attrs.flags |= SSH_FILEXFER_ATTR_ACMODTIME; } - scp->got_file_times = FALSE; + scp->got_file_times = false; if (scp->command_chr == 'D') { sftpsrv_mkdir(scp->sf, &scp->reply.srb, @@ -1161,7 +1161,7 @@ static void scp_sink_coroutine(ScpSink *scp) goto done; } - scp_sink_push(scp, scp->filename, TRUE); + scp_sink_push(scp, scp->filename, true); } else { sftpsrv_open(scp->sf, &scp->reply.srb, scp->filename, SSH_FXF_WRITE | SSH_FXF_CREAT | SSH_FXF_TRUNC, @@ -1227,7 +1227,7 @@ static void scp_sink_coroutine(ScpSink *scp) goto done; } scp_sink_pop(scp); - scp->got_file_times = FALSE; + scp->got_file_times = false; } else { ptrlen cmd_pl; @@ -1245,8 +1245,8 @@ static void scp_sink_coroutine(ScpSink *scp) done: if (scp->errmsg) { - sshfwd_write_ext(scp->sc, TRUE, scp->errmsg, strlen(scp->errmsg)); - sshfwd_write_ext(scp->sc, TRUE, "\012", 1); + sshfwd_write_ext(scp->sc, true, scp->errmsg, strlen(scp->errmsg)); + sshfwd_write_ext(scp->sc, true, "\012", 1); sshfwd_send_exit_status(scp->sc, 1); } else { sshfwd_send_exit_status(scp->sc, 0); @@ -1273,7 +1273,7 @@ static void scp_sink_eof(ScpServer *s) { ScpSink *scp = container_of(s, ScpSink, scpserver); - scp->input_eof = TRUE; + scp->input_eof = true; scp_sink_coroutine(scp); } @@ -1307,8 +1307,8 @@ static struct ScpServerVtable ScpError_ScpServer_vt = { static void scp_error_send_message_cb(void *vscp) { ScpError *scp = (ScpError *)vscp; - sshfwd_write_ext(scp->sc, TRUE, scp->message, strlen(scp->message)); - sshfwd_write_ext(scp->sc, TRUE, "\n", 1); + sshfwd_write_ext(scp->sc, true, scp->message, strlen(scp->message)); + sshfwd_write_ext(scp->sc, true, "\n", 1); sshfwd_send_exit_status(scp->sc, 1); sshfwd_write_eof(scp->sc); sshfwd_initiate_close(scp->sc, scp->message); @@ -1353,8 +1353,8 @@ static void scp_error_free(ScpServer *s) ScpServer *scp_recognise_exec( SshChannel *sc, const SftpServerVtable *sftpserver_vt, ptrlen command) { - int recursive = FALSE, preserve = FALSE; - int targetshouldbedirectory = FALSE; + int recursive = false, preserve = false; + int targetshouldbedirectory = false; ptrlen command_orig = command; if (!ptrlen_startswith(command, PTRLEN_LITERAL("scp "), &command)) @@ -1366,15 +1366,15 @@ ScpServer *scp_recognise_exec( continue; } if (ptrlen_startswith(command, PTRLEN_LITERAL("-r "), &command)) { - recursive = TRUE; + recursive = true; continue; } if (ptrlen_startswith(command, PTRLEN_LITERAL("-p "), &command)) { - preserve = TRUE; + preserve = true; continue; } if (ptrlen_startswith(command, PTRLEN_LITERAL("-d "), &command)) { - targetshouldbedirectory = TRUE; + targetshouldbedirectory = true; continue; } break; diff --git a/sesschan.c b/sesschan.c index 9a1c6c44..4a390167 100644 --- a/sesschan.c +++ b/sesschan.c @@ -206,7 +206,7 @@ Channel *sesschan_new(SshChannel *c, LogContext *logctx, sess->conf = conf_new(); load_open_settings(NULL, sess->conf); - /* Set close-on-exit = TRUE to suppress uxpty.c's "[pterm: process + /* Set close-on-exit = true to suppress uxpty.c's "[pterm: process * terminated with status x]" message */ conf_set_int(sess->conf, CONF_close_on_exit, FORCE_ON); @@ -282,10 +282,10 @@ int sesschan_run_shell(Channel *chan) sesschan *sess = container_of(chan, sesschan, chan); if (sess->backend) - return FALSE; + return false; sesschan_start_backend(sess, NULL); - return TRUE; + return true; } int sesschan_run_command(Channel *chan, ptrlen command) @@ -293,21 +293,21 @@ int sesschan_run_command(Channel *chan, ptrlen command) sesschan *sess = container_of(chan, sesschan, chan); if (sess->backend) - return FALSE; + return false; /* FIXME: make this possible to configure off */ if ((sess->scpsrv = scp_recognise_exec(sess->c, sess->sftpserver_vt, command)) != NULL) { sess->chan.vt = &scp_channelvt; logevent(sess->parent_logctx, "Starting built-in SCP server"); - return TRUE; + return true; } char *command_str = mkstr(command); sesschan_start_backend(sess, command_str); sfree(command_str); - return TRUE; + return true; } int sesschan_run_subsystem(Channel *chan, ptrlen subsys) @@ -318,10 +318,10 @@ int sesschan_run_subsystem(Channel *chan, ptrlen subsys) sess->sftpsrv = sftpsrv_new(sess->sftpserver_vt); sess->chan.vt = &sftp_channelvt; logevent(sess->parent_logctx, "Starting built-in SFTP subsystem"); - return TRUE; + return true; } - return FALSE; + return false; } static void fwd_log(Plug *plug, int type, SockAddr *addr, int port, @@ -344,13 +344,13 @@ static int xfwd_accepting(Plug *p, accept_fn_t constructor, accept_ctx_t ctx) s = constructor(ctx, plug); if ((err = sk_socket_error(s)) != NULL) { portfwd_raw_free(chan); - return TRUE; + return true; } pi = sk_peer_info(s); portfwd_raw_setup(chan, s, ssh_serverside_x11_open(sess->c->cl, chan, pi)); sk_free_peer_info(pi); - return FALSE; + return false; } static const PlugVtable xfwd_plugvt = { @@ -371,7 +371,7 @@ int sesschan_enable_x11_forwarding( char screensuffix[32]; if (oneshot) - return FALSE; /* not supported */ + return false; /* not supported */ snprintf(screensuffix, sizeof(screensuffix), ".%u", screen_number); @@ -379,7 +379,7 @@ int sesschan_enable_x11_forwarding( * Decode the authorisation data from ASCII hex into binary. */ if (authdata_hex.len % 2) - return FALSE; /* expected an even number of digits */ + return false; /* expected an even number of digits */ authdata_bin = strbuf_new(); for (i = 0; i < authdata_hex.len; i += 2) { const unsigned char *hex = authdata_hex.ptr; @@ -387,7 +387,7 @@ int sesschan_enable_x11_forwarding( if (!isxdigit(hex[i]) || !isxdigit(hex[i+1])) { strbuf_free(authdata_bin); - return FALSE; /* not hex */ + return false; /* not hex */ } hexbuf[0] = hex[i]; @@ -420,11 +420,11 @@ static int agentfwd_accepting( s = constructor(ctx, plug); if ((err = sk_socket_error(s)) != NULL) { portfwd_raw_free(chan); - return TRUE; + return true; } portfwd_raw_setup(chan, s, ssh_serverside_agent_open(sess->c->cl, chan)); - return FALSE; + return false; } static const PlugVtable agentfwd_plugvt = { @@ -467,20 +467,20 @@ int sesschan_allocate_pty( char *s; if (sess->want_pty) - return FALSE; + return false; s = mkstr(termtype); conf_set_str(sess->conf, CONF_termtype, s); sfree(s); - sess->want_pty = TRUE; + sess->want_pty = true; sess->ttymodes = modes; sess->wc = width; sess->hc = height; sess->wp = pixwidth; sess->hp = pixheight; - return TRUE; + return true; } int sesschan_set_env(Channel *chan, ptrlen var, ptrlen value) @@ -492,7 +492,7 @@ int sesschan_set_env(Channel *chan, ptrlen var, ptrlen value) sfree(svar); sfree(svalue); - return TRUE; + return true; } int sesschan_send_break(Channel *chan, unsigned length) @@ -506,9 +506,9 @@ int sesschan_send_break(Channel *chan, unsigned length) * implementation-defined semantics to _its_ duration * parameter, this all just sounds too difficult. */ backend_special(sess->backend, SS_BRK, 0); - return TRUE; + return true; } - return FALSE; + return false; } int sesschan_send_signal(Channel *chan, ptrlen signame) @@ -527,10 +527,10 @@ int sesschan_send_signal(Channel *chan, ptrlen signame) #undef SIGNAL_SUB if (code == SS_EXITMENU) - return FALSE; + return false; backend_special(sess->backend, code, 0); - return TRUE; + return true; } int sesschan_change_window_size( @@ -540,7 +540,7 @@ int sesschan_change_window_size( sesschan *sess = container_of(chan, sesschan, chan); if (!sess->want_pty) - return FALSE; + return false; sess->wc = width; sess->hc = height; @@ -550,7 +550,7 @@ int sesschan_change_window_size( if (sess->backend) backend_size(sess->backend, sess->wc, sess->hc); - return TRUE; + return true; } static int sesschan_seat_output( @@ -590,10 +590,10 @@ static int sesschan_seat_eof(Seat *seat) sesschan *sess = container_of(seat, sesschan, seat); sshfwd_write_eof(sess->c); - sess->seen_eof = TRUE; + sess->seen_eof = true; queue_toplevel_callback(sesschan_check_close_callback, sess); - return TRUE; + return true; } static void sesschan_notify_remote_exit(Seat *seat) @@ -611,14 +611,14 @@ static void sesschan_notify_remote_exit(Seat *seat) sigmsg = dupstr(""); sshfwd_send_exit_signal( - sess->c, signame, FALSE, ptrlen_from_asciz(sigmsg)); + sess->c, signame, false, ptrlen_from_asciz(sigmsg)); sfree(sigmsg); } else { sshfwd_send_exit_status(sess->c, backend_exitcode(sess->backend)); } - sess->seen_exit = TRUE; + sess->seen_exit = true; queue_toplevel_callback(sesschan_check_close_callback, sess); } @@ -628,9 +628,9 @@ static void sesschan_connection_fatal(Seat *seat, const char *message) /* Closest translation I can think of */ sshfwd_send_exit_signal( - sess->c, PTRLEN_LITERAL("HUP"), FALSE, ptrlen_from_asciz(message)); + sess->c, PTRLEN_LITERAL("HUP"), false, ptrlen_from_asciz(message)); - sess->ignoring_input = TRUE; + sess->ignoring_input = true; } static int sesschan_get_window_pixel_size(Seat *seat, int *width, int *height) @@ -640,7 +640,7 @@ static int sesschan_get_window_pixel_size(Seat *seat, int *width, int *height) *width = sess->wp; *height = sess->hp; - return TRUE; + return true; } /* ---------------------------------------------------------------------- diff --git a/settings.c b/settings.c index e5d40714..73e8e319 100644 --- a/settings.c +++ b/settings.c @@ -183,7 +183,7 @@ static int gppmap(settings_r *sesskey, const char *name, */ buf = gpps_raw(sesskey, name, NULL); if (!buf) - return FALSE; + return false; p = buf; while (*p) { @@ -227,12 +227,12 @@ static int gppmap(settings_r *sesskey, const char *name, } sfree(buf); - return TRUE; + return true; } /* * Write a set of name/value pairs in the above format, or just the - * names if include_values is FALSE. + * names if include_values is false. */ static void wmap(settings_w *sesskey, char const *outkey, Conf *conf, int primary, int include_values) @@ -549,7 +549,7 @@ void save_open_settings(settings_w *sesskey, Conf *conf) write_setting_i(sesskey, "TCPKeepalives", conf_get_int(conf, CONF_tcp_keepalives)); write_setting_s(sesskey, "TerminalType", conf_get_str(conf, CONF_termtype)); write_setting_s(sesskey, "TerminalSpeed", conf_get_str(conf, CONF_termspeed)); - wmap(sesskey, "TerminalModes", conf, CONF_ttymodes, TRUE); + wmap(sesskey, "TerminalModes", conf, CONF_ttymodes, true); /* Address family selection */ write_setting_i(sesskey, "AddressFamily", conf_get_int(conf, CONF_addressfamily)); @@ -565,7 +565,7 @@ void save_open_settings(settings_w *sesskey, Conf *conf) write_setting_s(sesskey, "ProxyPassword", conf_get_str(conf, CONF_proxy_password)); write_setting_s(sesskey, "ProxyTelnetCommand", conf_get_str(conf, CONF_proxy_telnet_command)); write_setting_i(sesskey, "ProxyLogToTerm", conf_get_int(conf, CONF_proxy_log_to_term)); - wmap(sesskey, "Environment", conf, CONF_environmt, TRUE); + wmap(sesskey, "Environment", conf, CONF_environmt, true); write_setting_s(sesskey, "UserName", conf_get_str(conf, CONF_username)); write_setting_i(sesskey, "UserNameFromEnvironment", conf_get_int(conf, CONF_username_from_env)); write_setting_s(sesskey, "LocalUserName", conf_get_str(conf, CONF_localusername)); @@ -727,7 +727,7 @@ void save_open_settings(settings_w *sesskey, Conf *conf) write_setting_filename(sesskey, "X11AuthFile", conf_get_filename(conf, CONF_xauthfile)); write_setting_i(sesskey, "LocalPortAcceptAll", conf_get_int(conf, CONF_lport_acceptall)); write_setting_i(sesskey, "RemotePortAcceptAll", conf_get_int(conf, CONF_rport_acceptall)); - wmap(sesskey, "PortForwardings", conf, CONF_portfwd, TRUE); + wmap(sesskey, "PortForwardings", conf, CONF_portfwd, true); write_setting_i(sesskey, "BugIgnore1", 2-conf_get_int(conf, CONF_sshbug_ignore1)); write_setting_i(sesskey, "BugPlainPW1", 2-conf_get_int(conf, CONF_sshbug_plainpw1)); write_setting_i(sesskey, "BugRSA1", 2-conf_get_int(conf, CONF_sshbug_rsa1)); @@ -759,7 +759,7 @@ void save_open_settings(settings_w *sesskey, Conf *conf) write_setting_i(sesskey, "ConnectionSharing", conf_get_int(conf, CONF_ssh_connection_sharing)); write_setting_i(sesskey, "ConnectionSharingUpstream", conf_get_int(conf, CONF_ssh_connection_sharing_upstream)); write_setting_i(sesskey, "ConnectionSharingDownstream", conf_get_int(conf, CONF_ssh_connection_sharing_downstream)); - wmap(sesskey, "SSHManualHostKeys", conf, CONF_ssh_manual_hostkeys, FALSE); + wmap(sesskey, "SSHManualHostKeys", conf, CONF_ssh_manual_hostkeys, false); } void load_settings(const char *section, Conf *conf) @@ -1195,7 +1195,7 @@ void load_open_settings(settings_r *sesskey, Conf *conf) i = gppi_raw(sesskey, "BugOldGex2", 0); conf_set_int(conf, CONF_sshbug_oldgex2, 2-i); i = gppi_raw(sesskey, "BugWinadj", 0); conf_set_int(conf, CONF_sshbug_winadj, 2-i); i = gppi_raw(sesskey, "BugChanReq", 0); conf_set_int(conf, CONF_sshbug_chanreq, 2-i); - conf_set_int(conf, CONF_ssh_simple, FALSE); + conf_set_int(conf, CONF_ssh_simple, false); gppi(sesskey, "StampUtmp", 1, conf, CONF_stamp_utmp); gppi(sesskey, "LoginShell", 1, conf, CONF_login_shell); gppi(sesskey, "ScrollbarOnLeft", 0, conf, CONF_scrollbar_on_left); diff --git a/sftp.c b/sftp.c index 47ea30c0..c6ef9fde 100644 --- a/sftp.c +++ b/sftp.c @@ -970,7 +970,7 @@ struct fxp_xfer *xfer_download_init(struct fxp_handle *fh, uint64_t offset) { struct fxp_xfer *xfer = xfer_init(fh, offset); - xfer->eof = FALSE; + xfer->eof = false; xfer_download_queue(xfer); return xfer; @@ -999,7 +999,7 @@ int xfer_download_gotpkt(struct fxp_xfer *xfer, struct sftp_packet *pktin) #endif if ((rr->retlen < 0 && fxp_error_type()==SSH_FX_EOF) || rr->retlen == 0) { - xfer->eof = TRUE; + xfer->eof = true; rr->retlen = 0; rr->complete = -1; #ifdef DEBUG_DOWNLOAD diff --git a/sftpserver.c b/sftpserver.c index b84365f2..1ff3d378 100644 --- a/sftpserver.c +++ b/sftpserver.c @@ -125,14 +125,14 @@ struct sftp_packet *sftp_handle_request( path = get_string(req); if (get_err(req)) goto decode_error; - sftpsrv_stat(srv, rb, path, TRUE); + sftpsrv_stat(srv, rb, path, true); break; case SSH_FXP_LSTAT: path = get_string(req); if (get_err(req)) goto decode_error; - sftpsrv_stat(srv, rb, path, FALSE); + sftpsrv_stat(srv, rb, path, false); break; case SSH_FXP_FSTAT: @@ -171,7 +171,7 @@ struct sftp_packet *sftp_handle_request( handle = get_string(req); if (get_err(req)) goto decode_error; - sftpsrv_readdir(srv, rb, handle, INT_MAX, FALSE); + sftpsrv_readdir(srv, rb, handle, INT_MAX, false); break; case SSH_FXP_WRITE: diff --git a/ssh.c b/ssh.c index 251634f1..808833ea 100644 --- a/ssh.c +++ b/ssh.c @@ -98,7 +98,7 @@ struct Ssh { ConnectionLayer cl_dummy; /* - * session_started is FALSE until we initialise the main protocol + * session_started is false until we initialise the main protocol * layers. So it distinguishes between base_layer==NULL meaning * that the SSH protocol hasn't been set up _yet_, and * base_layer==NULL meaning the SSH protocol has run and finished. @@ -153,7 +153,7 @@ static void ssh_got_ssh_version(struct ssh_version_receiver *rcv, BinaryPacketProtocol *old_bpp; PacketProtocolLayer *connection_layer; - ssh->session_started = TRUE; + ssh->session_started = true; /* * We don't support choosing a major protocol version dynamically, @@ -180,7 +180,7 @@ static void ssh_got_ssh_version(struct ssh_version_receiver *rcv, int is_simple = (conf_get_int(ssh->conf, CONF_ssh_simple) && !ssh->connshare); - ssh->bpp = ssh2_bpp_new(ssh->logctx, &ssh->stats, FALSE); + ssh->bpp = ssh2_bpp_new(ssh->logctx, &ssh->stats, false); ssh_connect_bpp(ssh); #ifndef NO_GSSAPI @@ -246,7 +246,7 @@ static void ssh_got_ssh_version(struct ssh_version_receiver *rcv, ssh_verstring_get_local(old_bpp), ssh_verstring_get_remote(old_bpp), &ssh->gss_state, - &ssh->stats, transport_child_layer, FALSE); + &ssh->stats, transport_child_layer, false); ssh_connect_ppl(ssh, ssh->base_layer); if (userauth_layer) @@ -272,7 +272,7 @@ static void ssh_got_ssh_version(struct ssh_version_receiver *rcv, ssh_connect_bpp(ssh); connection_layer = ssh2_connection_new( - ssh, NULL, FALSE, ssh->conf, ssh_verstring_get_remote(old_bpp), + ssh, NULL, false, ssh->conf, ssh_verstring_get_remote(old_bpp), &ssh->cl); ssh_connect_ppl(ssh, connection_layer); ssh->base_layer = connection_layer; @@ -380,13 +380,13 @@ static void ssh_initiate_connection_close(Ssh *ssh) /* Force any remaining queued SSH packets through the BPP, and * schedule closing the network socket after they go out. */ ssh_bpp_handle_output(ssh->bpp); - ssh->pending_close = TRUE; + ssh->pending_close = true; queue_idempotent_callback(&ssh->ic_out_raw); /* Now we expect the other end to close the connection too in * response, so arrange that we'll receive notification of that * via ssh_remote_eof. */ - ssh->bpp->expect_close = TRUE; + ssh->bpp->expect_close = true; } #define GET_FORMATTED_MSG \ @@ -521,7 +521,7 @@ static void ssh_closing(Plug *plug, const char *error_msg, int error_code, if (error_msg) { ssh_remote_error(ssh, "Network error: %s", error_msg); } else if (ssh->bpp) { - ssh->bpp->input_eof = TRUE; + ssh->bpp->input_eof = true; queue_idempotent_callback(&ssh->bpp->ic_in_raw); } } @@ -644,18 +644,18 @@ static const char *connect_to_host(Ssh *ssh, const char *host, int port, * downstream and need to do our connection setup differently. */ ssh->connshare = NULL; - ssh->attempting_connshare = TRUE; /* affects socket logging behaviour */ + ssh->attempting_connshare = true; /* affects socket logging behaviour */ ssh->s = ssh_connection_sharing_init( ssh->savedhost, ssh->savedport, ssh->conf, ssh->logctx, &ssh->plug, &ssh->connshare); if (ssh->connshare) ssh_connshare_provide_connlayer(ssh->connshare, &ssh->cl_dummy); - ssh->attempting_connshare = FALSE; + ssh->attempting_connshare = false; if (ssh->s != NULL) { /* * We are a downstream. */ - ssh->bare_connection = TRUE; + ssh->bare_connection = true; ssh->fullhostname = NULL; *realhost = dupstr(host); /* best we can do */ @@ -718,7 +718,7 @@ static const char *connect_to_host(Ssh *ssh, const char *host, int port, ssh->bpp = ssh_verstring_new( ssh->conf, ssh->logctx, ssh->bare_connection, ssh->version == 1 ? "1.5" : "2.0", &ssh->version_receiver, - FALSE, "PuTTY"); + false, "PuTTY"); ssh_connect_bpp(ssh); queue_idempotent_callback(&ssh->bpp->ic_in_raw); @@ -745,9 +745,9 @@ void ssh_throttle_conn(Ssh *ssh, int adjust) assert(ssh->conn_throttle_count >= 0); if (ssh->conn_throttle_count && !old_count) { - frozen = TRUE; + frozen = true; } else if (!ssh->conn_throttle_count && old_count) { - frozen = FALSE; + frozen = false; } else { return; /* don't change current frozen state */ } @@ -819,7 +819,7 @@ static const char *ssh_init(Seat *seat, Backend **backend_handle, ssh->cl_dummy.logctx = ssh->logctx = logctx; random_ref(); /* do this now - may be needed by sharing setup code */ - ssh->need_random_unref = TRUE; + ssh->need_random_unref = true; p = connect_to_host(ssh, host, port, realhost, nodelay, keepalive); if (p != NULL) { @@ -827,7 +827,7 @@ static const char *ssh_init(Seat *seat, Backend **backend_handle, * frees this useless Ssh object, in case the caller is * impatient and just exits without bothering, in which case * the random seed won't be re-saved. */ - ssh->need_random_unref = FALSE; + ssh->need_random_unref = false; random_unref(); return p; } @@ -1038,7 +1038,7 @@ void ssh_ldisc_update(Ssh *ssh) static int ssh_ldisc(Backend *be, int option) { Ssh *ssh = container_of(be, Ssh, backend); - return ssh->cl ? ssh_ldisc_option(ssh->cl, option) : FALSE; + return ssh->cl ? ssh_ldisc_option(ssh->cl, option) : false; } static void ssh_provide_ldisc(Backend *be, Ldisc *ldisc) @@ -1090,7 +1090,7 @@ extern int ssh_fallback_cmd(Backend *be) void ssh_got_fallback_cmd(Ssh *ssh) { - ssh->fallback_cmd = TRUE; + ssh->fallback_cmd = true; } const struct BackendVtable ssh_backend = { diff --git a/ssh.h b/ssh.h index 5a932fe4..91f15a2f 100644 --- a/ssh.h +++ b/ssh.h @@ -108,22 +108,22 @@ void pq_in_clear(PktInQueue *pq); void pq_out_clear(PktOutQueue *pq); #define pq_push(pq, pkt) \ - TYPECHECK((pq)->after(&(pq)->pqb, NULL, FALSE) == pkt, \ + TYPECHECK((pq)->after(&(pq)->pqb, NULL, false) == pkt, \ pq_base_push(&(pq)->pqb, &(pkt)->qnode)) #define pq_push_front(pq, pkt) \ - TYPECHECK((pq)->after(&(pq)->pqb, NULL, FALSE) == pkt, \ + TYPECHECK((pq)->after(&(pq)->pqb, NULL, false) == pkt, \ pq_base_push_front(&(pq)->pqb, &(pkt)->qnode)) -#define pq_peek(pq) ((pq)->after(&(pq)->pqb, &(pq)->pqb.end, FALSE)) -#define pq_pop(pq) ((pq)->after(&(pq)->pqb, &(pq)->pqb.end, TRUE)) +#define pq_peek(pq) ((pq)->after(&(pq)->pqb, &(pq)->pqb.end, false)) +#define pq_pop(pq) ((pq)->after(&(pq)->pqb, &(pq)->pqb.end, true)) #define pq_concatenate(dst, q1, q2) \ - TYPECHECK((q1)->after(&(q1)->pqb, NULL, FALSE) == \ - (dst)->after(&(dst)->pqb, NULL, FALSE) && \ - (q2)->after(&(q2)->pqb, NULL, FALSE) == \ - (dst)->after(&(dst)->pqb, NULL, FALSE), \ + TYPECHECK((q1)->after(&(q1)->pqb, NULL, false) == \ + (dst)->after(&(dst)->pqb, NULL, false) && \ + (q2)->after(&(q2)->pqb, NULL, false) == \ + (dst)->after(&(dst)->pqb, NULL, false), \ pq_base_concatenate(&(dst)->pqb, &(q1)->pqb, &(q2)->pqb)) #define pq_first(pq) pq_peek(pq) -#define pq_next(pq, pkt) ((pq)->after(&(pq)->pqb, &(pkt)->qnode, FALSE)) +#define pq_next(pq, pkt) ((pq)->after(&(pq)->pqb, &(pkt)->qnode, false)) /* * Packet type contexts, so that ssh2_pkt_type can correctly decode diff --git a/ssh1bpp.c b/ssh1bpp.c index 59fe5104..f4abd98f 100644 --- a/ssh1bpp.c +++ b/ssh1bpp.c @@ -145,7 +145,7 @@ static void ssh1_bpp_handle_input(BinaryPacketProtocol *bpp) */ s->pktin = snew_plus(PktIn, s->biglen); s->pktin->qnode.prev = s->pktin->qnode.next = NULL; - s->pktin->qnode.on_free_queue = FALSE; + s->pktin->qnode.on_free_queue = false; s->pktin->type = 0; s->maxlen = s->biglen; @@ -209,7 +209,7 @@ static void ssh1_bpp_handle_input(BinaryPacketProtocol *bpp) if (s->bpp.logctx) { logblank_t blanks[MAX_BLANKS]; int nblanks = ssh1_censor_packet( - s->bpp.pls, s->pktin->type, FALSE, + s->bpp.pls, s->pktin->type, false, make_ptrlen(s->data, s->length), blanks); log_packet(s->bpp.logctx, PKT_INCOMING, s->pktin->type, ssh1_pkt_type(s->pktin->type), @@ -244,7 +244,7 @@ static void ssh1_bpp_handle_input(BinaryPacketProtocol *bpp) * schedule a run of our output side in case we * had any packets queued up in the meantime. */ - s->pending_compression_request = FALSE; + s->pending_compression_request = false; queue_idempotent_callback(&s->bpp.ic_out_pq); } break; @@ -287,7 +287,7 @@ static void ssh1_bpp_format_packet(struct ssh1_bpp_state *s, PktOut *pkt) pkt->length - pkt->prefix); logblank_t blanks[MAX_BLANKS]; int nblanks = ssh1_censor_packet( - s->bpp.pls, pkt->type, TRUE, pktdata, blanks); + s->bpp.pls, pkt->type, true, pktdata, blanks); log_packet(s->bpp.logctx, PKT_OUTGOING, pkt->type, ssh1_pkt_type(pkt->type), pktdata.ptr, pktdata.len, nblanks, blanks, @@ -353,7 +353,7 @@ static void ssh1_bpp_handle_output(BinaryPacketProtocol *bpp) * the pending flag, and stop processing packets this * time. */ - s->pending_compression_request = TRUE; + s->pending_compression_request = true; break; } } diff --git a/ssh1connection-client.c b/ssh1connection-client.c index db2d5b23..6c7c224f 100644 --- a/ssh1connection-client.c +++ b/ssh1connection-client.c @@ -24,7 +24,7 @@ void ssh1_connection_direction_specific_setup( */ s->mainchan = mainchan_new( &s->ppl, &s->cl, s->conf, s->term_width, s->term_height, - FALSE /* is_simple */, NULL); + false /* is_simple */, NULL); } } @@ -85,7 +85,7 @@ static void ssh1_connection_process_trivial_succfails(void *vs) { struct ssh1_connection_state *s = (struct ssh1_connection_state *)vs; while (s->succfail_head && s->succfail_head->trivial) - ssh1_connection_process_succfail(s, TRUE); + ssh1_connection_process_succfail(s, true); } int ssh1_handle_direction_specific_packet( @@ -107,7 +107,7 @@ int ssh1_handle_direction_specific_packet( ssh_remote_error(s->ppl.ssh, "Received %s with no outstanding request", ssh1_pkt_type(pktin->type)); - return TRUE; + return true; } ssh1_connection_process_succfail( @@ -115,7 +115,7 @@ int ssh1_handle_direction_specific_packet( queue_toplevel_callback( ssh1_connection_process_trivial_succfails, s); - return TRUE; + return true; case SSH1_SMSG_X11_OPEN: remid = get_uint32(pktin); @@ -133,9 +133,9 @@ int ssh1_handle_direction_specific_packet( ssh1_channel_init(c); c->remoteid = remid; c->chan = x11_new_channel(s->x11authtree, &c->sc, - NULL, -1, FALSE); + NULL, -1, false); c->remoteid = remid; - c->halfopen = FALSE; + c->halfopen = false; pktout = ssh_bpp_new_pktout( s->ppl.bpp, SSH1_MSG_CHANNEL_OPEN_CONFIRMATION); @@ -145,7 +145,7 @@ int ssh1_handle_direction_specific_packet( ppl_logevent(("Opened X11 forward channel")); } - return TRUE; + return true; case SSH1_SMSG_AGENT_OPEN: remid = get_uint32(pktin); @@ -162,7 +162,7 @@ int ssh1_handle_direction_specific_packet( ssh1_channel_init(c); c->remoteid = remid; c->chan = agentf_new(&c->sc); - c->halfopen = FALSE; + c->halfopen = false; pktout = ssh_bpp_new_pktout( s->ppl.bpp, SSH1_MSG_CHANNEL_OPEN_CONFIRMATION); @@ -171,7 +171,7 @@ int ssh1_handle_direction_specific_packet( pq_push(s->ppl.out_pq, pktout); } - return TRUE; + return true; case SSH1_MSG_PORT_OPEN: remid = get_uint32(pktin); @@ -211,7 +211,7 @@ int ssh1_handle_direction_specific_packet( } else { ssh1_channel_init(c); c->remoteid = remid; - c->halfopen = FALSE; + c->halfopen = false; pktout = ssh_bpp_new_pktout( s->ppl.bpp, SSH1_MSG_CHANNEL_OPEN_CONFIRMATION); put_uint32(pktout, c->remoteid); @@ -223,7 +223,7 @@ int ssh1_handle_direction_specific_packet( sfree(pf.dhost); - return TRUE; + return true; case SSH1_SMSG_STDOUT_DATA: case SSH1_SMSG_STDERR_DATA: @@ -238,7 +238,7 @@ int ssh1_handle_direction_specific_packet( } } - return TRUE; + return true; case SSH1_SMSG_EXIT_STATUS: { @@ -246,12 +246,12 @@ int ssh1_handle_direction_specific_packet( ppl_logevent(("Server sent command exit status %d", exitcode)); ssh_got_exitcode(s->ppl.ssh, exitcode); - s->session_terminated = TRUE; + s->session_terminated = true; } - return TRUE; + return true; default: - return FALSE; + return false; } } @@ -289,7 +289,7 @@ static void ssh1mainchan_request_x11_forwarding( put_uint32(pktout, screen_number); pq_push(s->ppl.out_pq, pktout); - ssh1mainchan_queue_response(s, want_reply, FALSE); + ssh1mainchan_queue_response(s, want_reply, false); } static void ssh1mainchan_request_agent_forwarding( @@ -303,7 +303,7 @@ static void ssh1mainchan_request_agent_forwarding( s->ppl.bpp, SSH1_CMSG_AGENT_REQUEST_FORWARDING); pq_push(s->ppl.out_pq, pktout); - ssh1mainchan_queue_response(s, want_reply, FALSE); + ssh1mainchan_queue_response(s, want_reply, false); } static void ssh1mainchan_request_pty( @@ -324,13 +324,13 @@ static void ssh1mainchan_request_pty( get_ttymodes_from_conf(s->ppl.seat, conf)); pq_push(s->ppl.out_pq, pktout); - ssh1mainchan_queue_response(s, want_reply, FALSE); + ssh1mainchan_queue_response(s, want_reply, false); } static int ssh1mainchan_send_env_var( SshChannel *sc, int want_reply, const char *var, const char *value) { - return FALSE; /* SSH-1 doesn't support this at all */ + return false; /* SSH-1 doesn't support this at all */ } static void ssh1mainchan_start_shell( @@ -343,7 +343,7 @@ static void ssh1mainchan_start_shell( pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_EXEC_SHELL); pq_push(s->ppl.out_pq, pktout); - ssh1mainchan_queue_response(s, want_reply, TRUE); + ssh1mainchan_queue_response(s, want_reply, true); } static void ssh1mainchan_start_command( @@ -357,25 +357,25 @@ static void ssh1mainchan_start_command( put_stringz(pktout, command); pq_push(s->ppl.out_pq, pktout); - ssh1mainchan_queue_response(s, want_reply, TRUE); + ssh1mainchan_queue_response(s, want_reply, true); } static int ssh1mainchan_start_subsystem( SshChannel *sc, int want_reply, const char *subsystem) { - return FALSE; /* SSH-1 doesn't support this at all */ + return false; /* SSH-1 doesn't support this at all */ } static int ssh1mainchan_send_serial_break( SshChannel *sc, int want_reply, int length) { - return FALSE; /* SSH-1 doesn't support this at all */ + return false; /* SSH-1 doesn't support this at all */ } static int ssh1mainchan_send_signal( SshChannel *sc, int want_reply, const char *signame) { - return FALSE; /* SSH-1 doesn't support this at all */ + return false; /* SSH-1 doesn't support this at all */ } static void ssh1mainchan_send_terminal_size_change( @@ -512,7 +512,7 @@ struct ssh_rportfwd *ssh1_rportfwd_alloc( put_uint32(pktout, rpf->dport); pq_push(s->ppl.out_pq, pktout); - ssh1_queue_succfail_handler(s, ssh1_rportfwd_response, rpf, FALSE); + ssh1_queue_succfail_handler(s, ssh1_rportfwd_response, rpf, false); return rpf; } @@ -520,12 +520,12 @@ struct ssh_rportfwd *ssh1_rportfwd_alloc( SshChannel *ssh1_serverside_x11_open( ConnectionLayer *cl, Channel *chan, const SocketPeerInfo *pi) { - assert(FALSE && "Should never be called in the client"); + assert(false && "Should never be called in the client"); return NULL; } SshChannel *ssh1_serverside_agent_open(ConnectionLayer *cl, Channel *chan) { - assert(FALSE && "Should never be called in the client"); + assert(false && "Should never be called in the client"); return NULL; } diff --git a/ssh1connection-server.c b/ssh1connection-server.c index 330b9058..1e8ddeea 100644 --- a/ssh1connection-server.c +++ b/ssh1connection-server.c @@ -72,8 +72,8 @@ int ssh1_handle_direction_specific_packet( ppl_logevent(("Client requested a shell")); chan_run_shell(s->mainchan_chan); - s->finished_setup = TRUE; - return TRUE; + s->finished_setup = true; + return true; case SSH1_CMSG_EXEC_CMD: if (s->finished_setup) @@ -82,8 +82,8 @@ int ssh1_handle_direction_specific_packet( cmd = get_string(pktin); ppl_logevent(("Client sent command '%.*s'", PTRLEN_PRINTF(cmd))); chan_run_command(s->mainchan_chan, cmd); - s->finished_setup = TRUE; - return TRUE; + s->finished_setup = true; + return true; case SSH1_CMSG_REQUEST_COMPRESSION: if (s->compressing) { @@ -99,10 +99,10 @@ int ssh1_handle_direction_specific_packet( /* And now ensure that the _next_ packet will be the first * compressed one. */ ssh1_bpp_start_compression(s->ppl.bpp); - s->compressing = TRUE; + s->compressing = true; } - return TRUE; + return true; case SSH1_CMSG_REQUEST_PTY: if (s->finished_setup) @@ -118,21 +118,21 @@ int ssh1_handle_direction_specific_packet( if (get_err(pktin)) { ppl_logevent(("Unable to decode pty request packet")); - success = FALSE; + success = false; } else if (!chan_allocate_pty( s->mainchan_chan, termtype, width, height, pixwidth, pixheight, modes)) { ppl_logevent(("Unable to allocate a pty")); - success = FALSE; + success = false; } else { - success = TRUE; + success = true; } } pktout = ssh_bpp_new_pktout( s->ppl.bpp, (success ? SSH1_SMSG_SUCCESS : SSH1_SMSG_FAILURE)); pq_push(s->ppl.out_pq, pktout); - return TRUE; + return true; case SSH1_CMSG_PORT_FORWARD_REQUEST: if (s->finished_setup) @@ -153,7 +153,7 @@ int ssh1_handle_direction_specific_packet( pktout = ssh_bpp_new_pktout( s->ppl.bpp, (success ? SSH1_SMSG_SUCCESS : SSH1_SMSG_FAILURE)); pq_push(s->ppl.out_pq, pktout); - return TRUE; + return true; case SSH1_CMSG_X11_REQUEST_FORWARDING: if (s->finished_setup) @@ -167,13 +167,13 @@ int ssh1_handle_direction_specific_packet( screen_number = get_uint32(pktin); success = chan_enable_x11_forwarding( - s->mainchan_chan, FALSE, authproto, authdata, screen_number); + s->mainchan_chan, false, authproto, authdata, screen_number); } pktout = ssh_bpp_new_pktout( s->ppl.bpp, (success ? SSH1_SMSG_SUCCESS : SSH1_SMSG_FAILURE)); pq_push(s->ppl.out_pq, pktout); - return TRUE; + return true; case SSH1_CMSG_AGENT_REQUEST_FORWARDING: if (s->finished_setup) @@ -184,19 +184,19 @@ int ssh1_handle_direction_specific_packet( pktout = ssh_bpp_new_pktout( s->ppl.bpp, (success ? SSH1_SMSG_SUCCESS : SSH1_SMSG_FAILURE)); pq_push(s->ppl.out_pq, pktout); - return TRUE; + return true; case SSH1_CMSG_STDIN_DATA: data = get_string(pktin); - chan_send(s->mainchan_chan, FALSE, data.ptr, data.len); - return TRUE; + chan_send(s->mainchan_chan, false, data.ptr, data.len); + return true; case SSH1_CMSG_EOF: chan_send_eof(s->mainchan_chan); - return TRUE; + return true; case SSH1_CMSG_WINDOW_SIZE: - return TRUE; + return true; case SSH1_MSG_PORT_OPEN: remid = get_uint32(pktin); @@ -226,7 +226,7 @@ int ssh1_handle_direction_specific_packet( } else { ssh1_channel_init(c); c->remoteid = remid; - c->halfopen = FALSE; + c->halfopen = false; pktout = ssh_bpp_new_pktout( s->ppl.bpp, SSH1_MSG_CHANNEL_OPEN_CONFIRMATION); put_uint32(pktout, c->remoteid); @@ -235,10 +235,10 @@ int ssh1_handle_direction_specific_packet( ppl_logevent(("Forwarded port opened successfully")); } - return TRUE; + return true; default: - return FALSE; + return false; } unexpected_setup_packet: @@ -246,12 +246,12 @@ int ssh1_handle_direction_specific_packet( "setup phase, type %d (%s)", pktin->type, ssh1_pkt_type(pktin->type)); /* FIXME: ensure caller copes with us just having freed the whole layer */ - return TRUE; + return true; } SshChannel *ssh1_session_open(ConnectionLayer *cl, Channel *chan) { - assert(FALSE && "Should never be called in the server"); + assert(false && "Should never be called in the server"); } struct ssh_rportfwd *ssh1_rportfwd_alloc( @@ -260,7 +260,7 @@ struct ssh_rportfwd *ssh1_rportfwd_alloc( int addressfamily, const char *log_description, PortFwdRecord *pfr, ssh_sharing_connstate *share_ctx) { - assert(FALSE && "Should never be called in the server"); + assert(false && "Should never be called in the server"); return NULL; } @@ -320,7 +320,7 @@ SshChannel *ssh1_serverside_x11_open( c->connlayer = s; ssh1_channel_init(c); - c->halfopen = TRUE; + c->halfopen = true; c->chan = chan; ppl_logevent(("Forwarding X11 connection to client")); @@ -342,7 +342,7 @@ SshChannel *ssh1_serverside_agent_open(ConnectionLayer *cl, Channel *chan) c->connlayer = s; ssh1_channel_init(c); - c->halfopen = TRUE; + c->halfopen = true; c->chan = chan; ppl_logevent(("Forwarding agent connection to client")); diff --git a/ssh1connection.c b/ssh1connection.c index a64ccb3d..bdbc29b0 100644 --- a/ssh1connection.c +++ b/ssh1connection.c @@ -234,9 +234,9 @@ static int ssh1_connection_filter_queue(struct ssh1_connection_state *s) while (1) { if (ssh1_common_filter_queue(&s->ppl)) - return TRUE; + return true; if ((pktin = pq_peek(s->ppl.in_pq)) == NULL) - return FALSE; + return false; switch (pktin->type) { case SSH1_MSG_CHANNEL_DATA: @@ -263,15 +263,15 @@ static int ssh1_connection_filter_queue(struct ssh1_connection_state *s) ssh1_pkt_type(pktin->type), !c ? "nonexistent" : c->halfopen ? "half-open" : "open", localid); - return TRUE; + return true; } switch (pktin->type) { case SSH1_MSG_CHANNEL_OPEN_CONFIRMATION: assert(c->halfopen); c->remoteid = get_uint32(pktin); - c->halfopen = FALSE; - c->throttling_conn = FALSE; + c->halfopen = false; + c->throttling_conn = false; chan_open_confirmation(c->chan); @@ -288,7 +288,7 @@ static int ssh1_connection_filter_queue(struct ssh1_connection_state *s) * message. We'll have handled that in this code by * having already turned c->chan into a zombie, so its * want_close method (which ssh1_channel_check_close - * will consult) will already be returning TRUE. + * will consult) will already be returning true. */ ssh1_channel_check_close(c); @@ -310,10 +310,10 @@ static int ssh1_connection_filter_queue(struct ssh1_connection_state *s) data = get_string(pktin); if (!get_err(pktin)) { int bufsize = chan_send( - c->chan, FALSE, data.ptr, data.len); + c->chan, false, data.ptr, data.len); if (!c->throttling_conn && bufsize > SSH1_BUFFER_LIMIT) { - c->throttling_conn = TRUE; + c->throttling_conn = true; ssh_throttle_conn(s->ppl.ssh, +1); } } @@ -335,7 +335,7 @@ static int ssh1_connection_filter_queue(struct ssh1_connection_state *s) "Received CHANNEL_CLOSE_CONFIRMATION for channel" " %u for which we never sent CHANNEL_CLOSE\n", c->localid); - return TRUE; + return true; } c->closes |= CLOSES_RCVD_CLOSECONF; @@ -351,9 +351,9 @@ static int ssh1_connection_filter_queue(struct ssh1_connection_state *s) if (ssh1_handle_direction_specific_packet(s, pktin)) { pq_pop(s->ppl.in_pq); if (ssh1_check_termination(s)) - return TRUE; + return true; } else { - return FALSE; + return false; } } } @@ -377,7 +377,7 @@ static void ssh1_connection_process_queue(PacketProtocolLayer *ppl) crBegin(s->crState); portfwdmgr_config(s->portfwdmgr, s->conf); - s->portfwdmgr_configured = TRUE; + s->portfwdmgr_configured = true; while (!s->finished_setup) { ssh1_connection_direction_specific_setup(s); @@ -460,7 +460,7 @@ static void ssh1_channel_try_eof(struct ssh1_channel *c) if (c->halfopen) return; /* can't close: not even opened yet */ - c->pending_eof = FALSE; /* we're about to send it */ + c->pending_eof = false; /* we're about to send it */ pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_MSG_CHANNEL_CLOSE); put_uint32(pktout, c->remoteid); @@ -525,10 +525,10 @@ int ssh1_check_termination(struct ssh1_connection_state *s) pq_push(s->ppl.out_pq, pktout); ssh_user_close(s->ppl.ssh, "Session finished"); - return TRUE; + return true; } - return FALSE; + return false; } /* @@ -539,8 +539,8 @@ void ssh1_channel_init(struct ssh1_channel *c) { struct ssh1_connection_state *s = c->connlayer; c->closes = 0; - c->pending_eof = FALSE; - c->throttling_conn = FALSE; + c->pending_eof = false; + c->throttling_conn = false; c->sc.vt = &ssh1channel_vtable; c->sc.cl = &s->cl; c->localid = alloc_channel_id(s->channels, struct ssh1_channel); @@ -561,7 +561,7 @@ static void ssh1channel_write_eof(SshChannel *sc) if (c->closes & CLOSES_SENT_CLOSE) return; - c->pending_eof = TRUE; + c->pending_eof = true; ssh1_channel_try_eof(c); } @@ -573,7 +573,7 @@ static void ssh1channel_initiate_close(SshChannel *sc, const char *err) reason = err ? dupprintf("due to local error: %s", err) : NULL; ssh1_channel_close_local(c, reason); sfree(reason); - c->pending_eof = FALSE; /* this will confuse a zombie channel */ + c->pending_eof = false; /* this will confuse a zombie channel */ ssh1_channel_check_close(c); } @@ -634,7 +634,7 @@ static SshChannel *ssh1_lportfwd_open( c->connlayer = s; ssh1_channel_init(c); - c->halfopen = TRUE; + c->halfopen = true; c->chan = chan; ppl_logevent(("Opening connection to %s:%d for %s", @@ -743,7 +743,7 @@ static void ssh1_enable_x_fwd(ConnectionLayer *cl) struct ssh1_connection_state *s = container_of(cl, struct ssh1_connection_state, cl); - s->X11_fwd_enabled = TRUE; + s->X11_fwd_enabled = true; } static void ssh1_enable_agent_fwd(ConnectionLayer *cl) @@ -751,7 +751,7 @@ static void ssh1_enable_agent_fwd(ConnectionLayer *cl) struct ssh1_connection_state *s = container_of(cl, struct ssh1_connection_state, cl); - s->agent_fwd_enabled = TRUE; + s->agent_fwd_enabled = true; } static void ssh1_set_wants_user_input(ConnectionLayer *cl, int wanted) @@ -760,7 +760,7 @@ static void ssh1_set_wants_user_input(ConnectionLayer *cl, int wanted) container_of(cl, struct ssh1_connection_state, cl); s->want_user_input = wanted; - s->finished_setup = TRUE; + s->finished_setup = true; } static int ssh1_connection_want_user_input(PacketProtocolLayer *ppl) diff --git a/ssh1login-server.c b/ssh1login-server.c index 4e3f5a92..4e0c7ca0 100644 --- a/ssh1login-server.c +++ b/ssh1login-server.c @@ -45,11 +45,11 @@ static void ssh1_login_server_process_queue(PacketProtocolLayer *); static int ssh1_login_server_get_specials( PacketProtocolLayer *ppl, add_special_fn_t add_special, - void *ctx) { return FALSE; } + void *ctx) { return false; } static void ssh1_login_server_special_cmd(PacketProtocolLayer *ppl, SessionSpecialCode code, int arg) {} static int ssh1_login_server_want_user_input( - PacketProtocolLayer *ppl) { return FALSE; } + PacketProtocolLayer *ppl) { return false; } static void ssh1_login_server_got_user_input(PacketProtocolLayer *ppl) {} static void ssh1_login_server_reconfigure( PacketProtocolLayer *ppl, Conf *conf) {} @@ -138,7 +138,7 @@ static void ssh1_login_server_process_queue(PacketProtocolLayer *ppl) s->servkey = snew(struct RSAKey); rsa_generate(s->servkey, server_key_bits, no_progress, NULL); s->servkey->comment = NULL; - s->servkey_generated_here = TRUE; + s->servkey_generated_here = true; } s->local_protoflags = SSH1_PROTOFLAGS_SUPPORTED; diff --git a/ssh1login.c b/ssh1login.c index ae02b314..e58f4cd1 100644 --- a/ssh1login.c +++ b/ssh1login.c @@ -394,9 +394,9 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl) if ((s->username = get_remote_username(s->conf)) == NULL) { s->cur_prompt = new_prompts(); - s->cur_prompt->to_server = TRUE; + s->cur_prompt->to_server = true; s->cur_prompt->name = dupstr("SSH login name"); - add_prompt(s->cur_prompt, dupstr("login as: "), TRUE); + add_prompt(s->cur_prompt, dupstr("login as: "), true); s->userpass_ret = seat_get_userpass_input( s->ppl.seat, s->cur_prompt, NULL); while (1) { @@ -408,9 +408,9 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl) if (s->userpass_ret >= 0) break; - s->want_user_input = TRUE; + s->want_user_input = true; crReturnV; - s->want_user_input = FALSE; + s->want_user_input = false; } if (!s->userpass_ret) { /* @@ -436,11 +436,11 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl) if (!(s->supported_auths_mask & (1 << SSH1_AUTH_RSA))) { /* We must not attempt PK auth. Pretend we've already tried it. */ - s->tried_publickey = s->tried_agent = TRUE; + s->tried_publickey = s->tried_agent = true; } else { - s->tried_publickey = s->tried_agent = FALSE; + s->tried_publickey = s->tried_agent = false; } - s->tis_auth_refused = s->ccard_auth_refused = FALSE; + s->tis_auth_refused = s->ccard_auth_refused = false; /* * Load the public half of any configured keyfile for later use. @@ -491,7 +491,7 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl) /* * Attempt RSA authentication using Pageant. */ - s->authed = FALSE; + s->authed = false; s->tried_agent = 1; ppl_logevent(("Pageant is running. Requesting keys.")); @@ -597,7 +597,7 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl) "agent\r\n", PTRLEN_PRINTF( s->comment))); } - s->authed = TRUE; + s->authed = true; } else ppl_logevent(("Pageant's response not " "accepted")); @@ -638,7 +638,7 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl) ppl_logevent(("Trying public key \"%s\"", filename_to_str(s->keyfile))); s->tried_publickey = 1; - got_passphrase = FALSE; + got_passphrase = false; while (!got_passphrase) { /* * Get a passphrase, if necessary. @@ -652,11 +652,11 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl) passphrase = NULL; } else { s->cur_prompt = new_prompts(s->ppl.seat); - s->cur_prompt->to_server = FALSE; + s->cur_prompt->to_server = false; s->cur_prompt->name = dupstr("SSH key passphrase"); add_prompt(s->cur_prompt, dupprintf("Passphrase for key \"%.100s\": ", - s->publickey_comment), FALSE); + s->publickey_comment), false); s->userpass_ret = seat_get_userpass_input( s->ppl.seat, s->cur_prompt, NULL); while (1) { @@ -668,9 +668,9 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl) if (s->userpass_ret >= 0) break; - s->want_user_input = TRUE; + s->want_user_input = true; crReturnV; - s->want_user_input = FALSE; + s->want_user_input = false; } if (!s->userpass_ret) { /* Failed to get a passphrase. Terminate. */ @@ -693,19 +693,19 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl) } if (retd == 1) { /* Correct passphrase. */ - got_passphrase = TRUE; + got_passphrase = true; } else if (retd == 0) { ppl_printf(("Couldn't load private key from %s (%s).\r\n", filename_to_str(s->keyfile), error)); - got_passphrase = FALSE; + got_passphrase = false; break; /* go and try something else */ } else if (retd == -1) { ppl_printf(("Wrong passphrase.\r\n")); - got_passphrase = FALSE; + got_passphrase = false; /* and try again */ } else { assert(0 && "unexpected return from rsa_ssh1_loadkey()"); - got_passphrase = FALSE; /* placate optimisers */ + got_passphrase = false; /* placate optimisers */ } } @@ -818,7 +818,7 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl) return; } ppl_logevent(("Received TIS challenge")); - s->cur_prompt->to_server = TRUE; + s->cur_prompt->to_server = true; s->cur_prompt->name = dupstr("SSH TIS authentication"); /* Prompt heuristic comes from OpenSSH */ if (!memchr(challenge.ptr, '\n', challenge.len)) { @@ -832,8 +832,8 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl) dupprintf("Using TIS authentication.%s%s", (*instr_suf) ? "\n" : "", instr_suf); - s->cur_prompt->instr_reqd = TRUE; - add_prompt(s->cur_prompt, prompt, FALSE); + s->cur_prompt->instr_reqd = true; + add_prompt(s->cur_prompt, prompt, false); sfree(instr_suf); } else { ssh_proto_error(s->ppl.ssh, "Received unexpected packet" @@ -866,9 +866,9 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl) return; } ppl_logevent(("Received CryptoCard challenge")); - s->cur_prompt->to_server = TRUE; + s->cur_prompt->to_server = true; s->cur_prompt->name = dupstr("SSH CryptoCard authentication"); - s->cur_prompt->name_reqd = FALSE; + s->cur_prompt->name_reqd = false; /* Prompt heuristic comes from OpenSSH */ if (!memchr(challenge.ptr, '\n', challenge.len)) { instr_suf = dupstr(""); @@ -881,8 +881,8 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl) dupprintf("Using CryptoCard authentication.%s%s", (*instr_suf) ? "\n" : "", instr_suf); - s->cur_prompt->instr_reqd = TRUE; - add_prompt(s->cur_prompt, prompt, FALSE); + s->cur_prompt->instr_reqd = true; + add_prompt(s->cur_prompt, prompt, false); sfree(instr_suf); } else { ssh_proto_error(s->ppl.ssh, "Received unexpected packet" @@ -898,11 +898,11 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl) "available"); return; } - s->cur_prompt->to_server = TRUE; + s->cur_prompt->to_server = true; s->cur_prompt->name = dupstr("SSH password"); add_prompt(s->cur_prompt, dupprintf("%s@%s's password: ", s->username, s->savedhost), - FALSE); + false); } /* @@ -921,9 +921,9 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl) if (s->userpass_ret >= 0) break; - s->want_user_input = TRUE; + s->want_user_input = true; crReturnV; - s->want_user_input = FALSE; + s->want_user_input = false; } if (!s->userpass_ret) { /* diff --git a/ssh2bpp-bare.c b/ssh2bpp-bare.c index e6dfb710..cabb2cd1 100644 --- a/ssh2bpp-bare.c +++ b/ssh2bpp-bare.c @@ -85,7 +85,7 @@ static void ssh2_bare_bpp_handle_input(BinaryPacketProtocol *bpp) */ s->pktin = snew_plus(PktIn, s->packetlen); s->pktin->qnode.prev = s->pktin->qnode.next = NULL; - s->pktin->qnode.on_free_queue = FALSE; + s->pktin->qnode.on_free_queue = false; s->maxlen = 0; s->data = snew_plus_get_aux(s->pktin); @@ -111,7 +111,7 @@ static void ssh2_bare_bpp_handle_input(BinaryPacketProtocol *bpp) if (s->bpp.logctx) { logblank_t blanks[MAX_BLANKS]; int nblanks = ssh2_censor_packet( - s->bpp.pls, s->pktin->type, FALSE, + s->bpp.pls, s->pktin->type, false, make_ptrlen(s->data, s->packetlen), blanks); log_packet(s->bpp.logctx, PKT_INCOMING, s->pktin->type, ssh2_pkt_type(s->bpp.pls->kctx, s->bpp.pls->actx, @@ -158,7 +158,7 @@ static void ssh2_bare_bpp_format_packet(struct ssh2_bare_bpp_state *s, ptrlen pktdata = make_ptrlen(pkt->data + 5, pkt->length - 5); logblank_t blanks[MAX_BLANKS]; int nblanks = ssh2_censor_packet( - s->bpp.pls, pkt->type, TRUE, pktdata, blanks); + s->bpp.pls, pkt->type, true, pktdata, blanks); log_packet(s->bpp.logctx, PKT_OUTGOING, pkt->type, ssh2_pkt_type(s->bpp.pls->kctx, s->bpp.pls->actx, pkt->type), diff --git a/ssh2bpp.c b/ssh2bpp.c index f67b4ece..fddfce00 100644 --- a/ssh2bpp.c +++ b/ssh2bpp.c @@ -117,7 +117,7 @@ void ssh2_bpp_new_outgoing_crypto( ssh2_cipher_alg(s->out.cipher)->text_name)); } else { s->out.cipher = NULL; - s->cbc_ignore_workaround = FALSE; + s->cbc_ignore_workaround = false; } s->out.etm_mode = etm_mode; if (mac) { @@ -217,7 +217,7 @@ void ssh2_bpp_new_incoming_crypto( /* Clear the pending_newkeys flag, so that handle_input below will * start consuming the input data again. */ - s->pending_newkeys = FALSE; + s->pending_newkeys = false; /* And schedule a run of handle_input, in case there's already * input data in the queue. */ @@ -349,7 +349,7 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp) s->pktin = snew_plus(PktIn, s->maxlen); s->pktin->qnode.prev = s->pktin->qnode.next = NULL; s->pktin->type = 0; - s->pktin->qnode.on_free_queue = FALSE; + s->pktin->qnode.on_free_queue = false; s->data = snew_plus_get_aux(s->pktin); memcpy(s->data, s->buf, s->maxlen); } else if (s->in.mac && s->in.etm_mode) { @@ -399,7 +399,7 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp) s->pktin = snew_plus(PktIn, OUR_V2_PACKETLIMIT + s->maclen); s->pktin->qnode.prev = s->pktin->qnode.next = NULL; s->pktin->type = 0; - s->pktin->qnode.on_free_queue = FALSE; + s->pktin->qnode.on_free_queue = false; s->data = snew_plus_get_aux(s->pktin); memcpy(s->data, s->buf, 4); @@ -465,7 +465,7 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp) s->pktin = snew_plus(PktIn, s->maxlen); s->pktin->qnode.prev = s->pktin->qnode.next = NULL; s->pktin->type = 0; - s->pktin->qnode.on_free_queue = FALSE; + s->pktin->qnode.on_free_queue = false; s->data = snew_plus_get_aux(s->pktin); memcpy(s->data, s->buf, s->cipherblk); @@ -562,7 +562,7 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp) if (s->bpp.logctx) { logblank_t blanks[MAX_BLANKS]; int nblanks = ssh2_censor_packet( - s->bpp.pls, s->pktin->type, FALSE, + s->bpp.pls, s->pktin->type, false, make_ptrlen(s->data, s->length), blanks); log_packet(s->bpp.logctx, PKT_INCOMING, s->pktin->type, ssh2_pkt_type(s->bpp.pls->kctx, s->bpp.pls->actx, @@ -590,7 +590,7 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp) * the transport layer has initialised the new keys by * calling ssh2_bpp_new_incoming_crypto above. */ - s->pending_newkeys = TRUE; + s->pending_newkeys = true; crWaitUntilV(!s->pending_newkeys); continue; } @@ -611,7 +611,7 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp) * that a delayed compression method enabled in any * future rekey will be treated as un-delayed. */ - s->seen_userauth_success = TRUE; + s->seen_userauth_success = true; } if (s->pending_compression && userauth_range(type)) { @@ -627,7 +627,7 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp) * to authenticate. The next userauth packet we send * will re-block the output direction. */ - s->pending_compression = FALSE; + s->pending_compression = false; queue_idempotent_callback(&s->bpp.ic_out_pq); } } @@ -665,7 +665,7 @@ static void ssh2_bpp_format_packet_inner(struct ssh2_bpp_state *s, PktOut *pkt) pkt->length - pkt->prefix); logblank_t blanks[MAX_BLANKS]; int nblanks = ssh2_censor_packet( - s->bpp.pls, pkt->type, TRUE, pktdata, blanks); + s->bpp.pls, pkt->type, true, pktdata, blanks); log_packet(s->bpp.logctx, PKT_OUTGOING, pkt->type, ssh2_pkt_type(s->bpp.pls->kctx, s->bpp.pls->actx, pkt->type), @@ -894,7 +894,7 @@ static void ssh2_bpp_handle_output(BinaryPacketProtocol *bpp) * USERAUTH_SUCCESS. Block (non-userauth) outgoing packets * until we see the reply. */ - s->pending_compression = TRUE; + s->pending_compression = true; return; } else if (type == SSH2_MSG_USERAUTH_SUCCESS && s->is_server) { ssh2_bpp_enable_pending_compression(s); diff --git a/ssh2connection-client.c b/ssh2connection-client.c index dbccf42a..8a481f50 100644 --- a/ssh2connection-client.c +++ b/ssh2connection-client.c @@ -131,7 +131,7 @@ int ssh2_connection_parse_global_request( * We don't know of any global requests that an SSH client needs * to honour. */ - return FALSE; + return false; } PktOut *ssh2_portfwd_chanopen( @@ -290,7 +290,7 @@ SshChannel *ssh2_session_open(ConnectionLayer *cl, Channel *chan) c->connlayer = s; ssh2_channel_init(c); - c->halfopen = TRUE; + c->halfopen = true; c->chan = chan; ppl_logevent(("Opening main session channel")); @@ -304,13 +304,13 @@ SshChannel *ssh2_session_open(ConnectionLayer *cl, Channel *chan) SshChannel *ssh2_serverside_x11_open( ConnectionLayer *cl, Channel *chan, const SocketPeerInfo *pi) { - assert(FALSE && "Should never be called in the client"); + assert(false && "Should never be called in the client"); return 0; /* placate optimiser */ } SshChannel *ssh2_serverside_agent_open(ConnectionLayer *cl, Channel *chan) { - assert(FALSE && "Should never be called in the client"); + assert(false && "Should never be called in the client"); return 0; /* placate optimiser */ } @@ -353,24 +353,24 @@ int ssh2channel_start_subsystem( put_stringz(pktout, subsystem); pq_push(s->ppl.out_pq, pktout); - return TRUE; + return true; } void ssh2channel_send_exit_status(SshChannel *sc, int status) { - assert(FALSE && "Should never be called in the client"); + assert(false && "Should never be called in the client"); } void ssh2channel_send_exit_signal( SshChannel *sc, ptrlen signame, int core_dumped, ptrlen msg) { - assert(FALSE && "Should never be called in the client"); + assert(false && "Should never be called in the client"); } void ssh2channel_send_exit_signal_numeric( SshChannel *sc, int signum, int core_dumped, ptrlen msg) { - assert(FALSE && "Should never be called in the client"); + assert(false && "Should never be called in the client"); } void ssh2channel_request_x11_forwarding( @@ -434,7 +434,7 @@ int ssh2channel_send_env_var( put_stringz(pktout, value); pq_push(s->ppl.out_pq, pktout); - return TRUE; + return true; } int ssh2channel_send_serial_break(SshChannel *sc, int want_reply, int length) @@ -447,7 +447,7 @@ int ssh2channel_send_serial_break(SshChannel *sc, int want_reply, int length) put_uint32(pktout, length); pq_push(s->ppl.out_pq, pktout); - return TRUE; + return true; } int ssh2channel_send_signal( @@ -461,7 +461,7 @@ int ssh2channel_send_signal( put_stringz(pktout, signame); pq_push(s->ppl.out_pq, pktout); - return TRUE; + return true; } void ssh2channel_send_terminal_size_change(SshChannel *sc, int w, int h) diff --git a/ssh2connection-server.c b/ssh2connection-server.c index 7691ffb1..e49f591e 100644 --- a/ssh2connection-server.c +++ b/ssh2connection-server.c @@ -100,7 +100,7 @@ int ssh2_connection_parse_global_request( return toret; } else { /* Unrecognised request. */ - return FALSE; + return false; } } @@ -142,17 +142,17 @@ struct ssh_rportfwd *ssh2_rportfwd_alloc( int addressfamily, const char *log_description, PortFwdRecord *pfr, ssh_sharing_connstate *share_ctx) { - assert(FALSE && "Should never be called in the server"); + assert(false && "Should never be called in the server"); } void ssh2_rportfwd_remove(ConnectionLayer *cl, struct ssh_rportfwd *rpf) { - assert(FALSE && "Should never be called in the server"); + assert(false && "Should never be called in the server"); } SshChannel *ssh2_session_open(ConnectionLayer *cl, Channel *chan) { - assert(FALSE && "Should never be called in the server"); + assert(false && "Should never be called in the server"); } SshChannel *ssh2_serverside_x11_open( @@ -166,7 +166,7 @@ SshChannel *ssh2_serverside_x11_open( c->connlayer = s; ssh2_channel_init(c); - c->halfopen = TRUE; + c->halfopen = true; c->chan = chan; ppl_logevent(("Forwarding X11 channel to client")); @@ -189,7 +189,7 @@ SshChannel *ssh2_serverside_agent_open(ConnectionLayer *cl, Channel *chan) c->connlayer = s; ssh2_channel_init(c); - c->halfopen = TRUE; + c->halfopen = true; c->chan = chan; ppl_logevent(("Forwarding SSH agent to client")); @@ -202,19 +202,19 @@ SshChannel *ssh2_serverside_agent_open(ConnectionLayer *cl, Channel *chan) void ssh2channel_start_shell(SshChannel *sc, int want_reply) { - assert(FALSE && "Should never be called in the server"); + assert(false && "Should never be called in the server"); } void ssh2channel_start_command( SshChannel *sc, int want_reply, const char *command) { - assert(FALSE && "Should never be called in the server"); + assert(false && "Should never be called in the server"); } int ssh2channel_start_subsystem( SshChannel *sc, int want_reply, const char *subsystem) { - assert(FALSE && "Should never be called in the server"); + assert(false && "Should never be called in the server"); } void ssh2channel_send_exit_status(SshChannel *sc, int status) @@ -262,38 +262,38 @@ void ssh2channel_request_x11_forwarding( SshChannel *sc, int want_reply, const char *authproto, const char *authdata, int screen_number, int oneshot) { - assert(FALSE && "Should never be called in the server"); + assert(false && "Should never be called in the server"); } void ssh2channel_request_agent_forwarding(SshChannel *sc, int want_reply) { - assert(FALSE && "Should never be called in the server"); + assert(false && "Should never be called in the server"); } void ssh2channel_request_pty( SshChannel *sc, int want_reply, Conf *conf, int w, int h) { - assert(FALSE && "Should never be called in the server"); + assert(false && "Should never be called in the server"); } int ssh2channel_send_env_var( SshChannel *sc, int want_reply, const char *var, const char *value) { - assert(FALSE && "Should never be called in the server"); + assert(false && "Should never be called in the server"); } int ssh2channel_send_serial_break(SshChannel *sc, int want_reply, int length) { - assert(FALSE && "Should never be called in the server"); + assert(false && "Should never be called in the server"); } int ssh2channel_send_signal( SshChannel *sc, int want_reply, const char *signame) { - assert(FALSE && "Should never be called in the server"); + assert(false && "Should never be called in the server"); } void ssh2channel_send_terminal_size_change(SshChannel *sc, int w, int h) { - assert(FALSE && "Should never be called in the server"); + assert(false && "Should never be called in the server"); } diff --git a/ssh2connection.c b/ssh2connection.c index b858a04c..04a44740 100644 --- a/ssh2connection.c +++ b/ssh2connection.c @@ -334,9 +334,9 @@ static int ssh2_connection_filter_queue(struct ssh2_connection_state *s) while (1) { if (ssh2_common_filter_queue(&s->ppl)) - return TRUE; + return true; if ((pktin = pq_peek(s->ppl.in_pq)) == NULL) - return FALSE; + return false; switch (pktin->type) { case SSH2_MSG_GLOBAL_REQUEST: @@ -363,7 +363,7 @@ static int ssh2_connection_filter_queue(struct ssh2_connection_state *s) "Received %s with no outstanding global request", ssh2_pkt_type(s->ppl.bpp->pls->kctx, s->ppl.bpp->pls->actx, pktin->type)); - return TRUE; + return true; } s->globreq_head->handler(s, pktin, s->globreq_head->ctx); @@ -405,7 +405,7 @@ static int ssh2_connection_filter_queue(struct ssh2_connection_state *s) } c->remoteid = remid; - c->halfopen = FALSE; + c->halfopen = false; if (chanopen_result.outcome == CHANOPEN_RESULT_FAILURE) { pktout = ssh_bpp_new_pktout( s->ppl.bpp, SSH2_MSG_CHANNEL_OPEN_FAILURE); @@ -479,14 +479,14 @@ static int ssh2_connection_filter_queue(struct ssh2_connection_state *s) (!c ? "nonexistent" : c->halfopen ? "half-open" : "open"), localid); - return TRUE; + return true; } switch (pktin->type) { case SSH2_MSG_CHANNEL_OPEN_CONFIRMATION: assert(c->halfopen); c->remoteid = get_uint32(pktin); - c->halfopen = FALSE; + c->halfopen = false; c->remwindow = get_uint32(pktin); c->remmaxpkt = get_uint32(pktin); @@ -505,7 +505,7 @@ static int ssh2_connection_filter_queue(struct ssh2_connection_state *s) * message. We'll have handled that in this code by * having already turned c->chan into a zombie, so its * want_close method (which ssh2_channel_check_close - * will consult) will already be returning TRUE. + * will consult) will already be returning true. */ ssh2_channel_check_close(c); @@ -569,7 +569,7 @@ static int ssh2_connection_filter_queue(struct ssh2_connection_state *s) if ((bufsize > c->locmaxwin || (s->ssh_is_simple && bufsize>0)) && !c->throttling_conn) { - c->throttling_conn = TRUE; + c->throttling_conn = true; ssh_throttle_conn(s->ppl.ssh, +1); } } @@ -586,7 +586,7 @@ static int ssh2_connection_filter_queue(struct ssh2_connection_state *s) type = get_string(pktin); want_reply = get_bool(pktin); - reply_success = FALSE; + reply_success = false; if (c->closes & CLOSES_SENT_CLOSE) { /* @@ -596,7 +596,7 @@ static int ssh2_connection_filter_queue(struct ssh2_connection_state *s) * side's CHANNEL_CLOSE and arrive after they have * wound the channel up completely. */ - want_reply = FALSE; + want_reply = false; } /* @@ -610,7 +610,7 @@ static int ssh2_connection_filter_queue(struct ssh2_connection_state *s) } else if (ptrlen_eq_string(type, "exit-signal")) { ptrlen signame; int signum; - int core = FALSE; + int core = false; ptrlen errmsg; int format; @@ -657,7 +657,7 @@ static int ssh2_connection_filter_queue(struct ssh2_connection_state *s) break; default: /* Couldn't parse this message in either format */ - reply_success = FALSE; + reply_success = false; break; } } else if (ptrlen_eq_string(type, "shell")) { @@ -694,7 +694,7 @@ static int ssh2_connection_filter_queue(struct ssh2_connection_state *s) if (get_err(bs_modes) || get_avail(bs_modes) > 0) { ppl_logevent(("Unable to decode terminal mode " "string")); - reply_success = FALSE; + reply_success = false; } else { reply_success = chan_allocate_pty( c->chan, termtype, width, height, @@ -740,7 +740,7 @@ static int ssh2_connection_filter_queue(struct ssh2_connection_state *s) "channel request", ssh2_pkt_type(s->ppl.bpp->pls->kctx, s->ppl.bpp->pls->actx, pktin->type)); - return TRUE; + return true; } ocr->handler(c, pktin, ocr->ctx); c->chanreq_head = ocr->next; @@ -839,7 +839,7 @@ static int ssh2_connection_filter_queue(struct ssh2_connection_state *s) break; default: - return FALSE; + return false; } } } @@ -966,7 +966,7 @@ static void ssh2_connection_process_queue(PacketProtocolLayer *ppl) * Enable port forwardings. */ portfwdmgr_config(s->portfwdmgr, s->conf); - s->portfwdmgr_configured = TRUE; + s->portfwdmgr_configured = true; /* * Create the main session channel, if any. @@ -1051,7 +1051,7 @@ static void ssh2_channel_try_eof(struct ssh2_channel *c) if (bufchain_size(&c->outbuffer) > 0 || bufchain_size(&c->errbuffer) > 0) return; /* can't send EOF: pending outgoing data */ - c->pending_eof = FALSE; /* we're about to send it */ + c->pending_eof = false; /* we're about to send it */ pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH2_MSG_CHANNEL_EOF); put_uint32(pktout, c->remoteid); @@ -1120,7 +1120,7 @@ static void ssh2_try_send_and_unthrottle(struct ssh2_channel *c) return; /* don't send on channels we've EOFed */ bufsize = ssh2_try_send(c); if (bufsize == 0) { - c->throttled_by_backlog = FALSE; + c->throttled_by_backlog = false; ssh2_channel_check_throttle(c); } } @@ -1227,9 +1227,9 @@ void ssh2_channel_init(struct ssh2_channel *c) { struct ssh2_connection_state *s = c->connlayer; c->closes = 0; - c->pending_eof = FALSE; - c->throttling_conn = FALSE; - c->throttled_by_backlog = FALSE; + c->pending_eof = false; + c->throttling_conn = false; + c->throttled_by_backlog = false; c->sharectx = NULL; c->locwindow = c->locmaxwin = c->remlocwin = s->ssh_is_simple ? OUR_V2_BIGWIN : OUR_V2_WINSIZE; @@ -1313,7 +1313,7 @@ static void ssh2channel_write_eof(SshChannel *sc) if (c->closes & CLOSES_SENT_EOF) return; - c->pending_eof = TRUE; + c->pending_eof = true; ssh2_channel_try_eof(c); } @@ -1325,7 +1325,7 @@ static void ssh2channel_initiate_close(SshChannel *sc, const char *err) reason = err ? dupprintf("due to local error: %s", err) : NULL; ssh2_channel_close_local(c, reason); sfree(reason); - c->pending_eof = FALSE; /* this will confuse a zombie channel */ + c->pending_eof = false; /* this will confuse a zombie channel */ ssh2_channel_check_close(c); } @@ -1414,7 +1414,7 @@ static SshChannel *ssh2_lportfwd_open( c->connlayer = s; ssh2_channel_init(c); - c->halfopen = TRUE; + c->halfopen = true; c->chan = chan; pktout = ssh2_portfwd_chanopen(s, c, hostname, port, description, pi); @@ -1534,11 +1534,11 @@ static int ssh2_connection_get_specials( { struct ssh2_connection_state *s = container_of(ppl, struct ssh2_connection_state, ppl); - int toret = FALSE; + int toret = false; if (s->mainchan) { mainchan_get_specials(s->mainchan, add_special, ctx); - toret = TRUE; + toret = true; } /* @@ -1551,7 +1551,7 @@ static int ssh2_connection_get_specials( add_special(ctx, NULL, SS_SEP, 0); add_special(ctx, "IGNORE message", SS_NOP, 0); - toret = TRUE; + toret = true; } return toret; @@ -1642,7 +1642,7 @@ static void ssh2_enable_x_fwd(ConnectionLayer *cl) struct ssh2_connection_state *s = container_of(cl, struct ssh2_connection_state, cl); - s->X11_fwd_enabled = TRUE; + s->X11_fwd_enabled = true; } static void ssh2_enable_agent_fwd(ConnectionLayer *cl) @@ -1650,7 +1650,7 @@ static void ssh2_enable_agent_fwd(ConnectionLayer *cl) struct ssh2_connection_state *s = container_of(cl, struct ssh2_connection_state, cl); - s->agent_fwd_enabled = TRUE; + s->agent_fwd_enabled = true; } static void ssh2_set_wants_user_input(ConnectionLayer *cl, int wanted) diff --git a/ssh2kex-client.c b/ssh2kex-client.c index ff09dcf7..a83f32ec 100644 --- a/ssh2kex-client.c +++ b/ssh2kex-client.c @@ -618,7 +618,7 @@ void ssh2kex_coroutine(struct ssh2_transport_state *s) return; } - s->gss_kex_used = TRUE; + s->gss_kex_used = true; /*- * If this the first KEX, save the GSS context for "gssapi-keyex" @@ -695,7 +695,7 @@ void ssh2kex_coroutine(struct ssh2_transport_state *s) * cache. */ if (s->hostkey_alg) { - s->need_gss_transient_hostkey = TRUE; + s->need_gss_transient_hostkey = true; } else { /* * If we negotiated the "null" host key algorithm @@ -718,7 +718,7 @@ void ssh2kex_coroutine(struct ssh2_transport_state *s) */ if (!s->warned_about_no_gss_transient_hostkey) { ppl_logevent(("No fallback host key available")); - s->warned_about_no_gss_transient_hostkey = TRUE; + s->warned_about_no_gss_transient_hostkey = true; } } } @@ -738,7 +738,7 @@ void ssh2kex_coroutine(struct ssh2_transport_state *s) ppl_logevent(("Post-GSS rekey provided fallback host key:")); ppl_logevent(("%s", s->fingerprint)); ssh_transient_hostkey_cache_add(s->thc, s->hkey); - s->need_gss_transient_hostkey = FALSE; + s->need_gss_transient_hostkey = false; } else if (!ssh_transient_hostkey_cache_verify(s->thc, s->hkey)) { ppl_logevent(("Non-GSS rekey after initial GSS kex " "used host key:")); @@ -836,7 +836,7 @@ void ssh2kex_coroutine(struct ssh2_transport_state *s) s->fingerprint = NULL; store_host_key(s->savedhost, s->savedport, ssh_key_cache_id(s->hkey), s->keystr); - s->cross_certifying = FALSE; + s->cross_certifying = false; /* * Don't forget to store the new key as the one we'll be * re-checking in future normal rekeys. diff --git a/ssh2kex-server.c b/ssh2kex-server.c index 4b62d56d..893add05 100644 --- a/ssh2kex-server.c +++ b/ssh2kex-server.c @@ -82,12 +82,12 @@ void ssh2kex_coroutine(struct ssh2_transport_state *s) } if (pktin->type != SSH2_MSG_KEX_DH_GEX_REQUEST_OLD) { - s->dh_got_size_bounds = TRUE; + s->dh_got_size_bounds = true; s->dh_min_size = get_uint32(pktin); s->pbits = get_uint32(pktin); s->dh_max_size = get_uint32(pktin); } else { - s->dh_got_size_bounds = FALSE; + s->dh_got_size_bounds = false; s->pbits = get_uint32(pktin); } diff --git a/ssh2transhk.c b/ssh2transhk.c index 6551f73f..46e2cf58 100644 --- a/ssh2transhk.c +++ b/ssh2transhk.c @@ -91,7 +91,7 @@ int ssh_transient_hostkey_cache_verify( ssh_transient_hostkey_cache *thc, ssh_key *key) { struct ssh_transient_hostkey_cache_entry *ent; - int toret = FALSE; + int toret = false; if ((ent = find234(thc->cache, (void *)ssh_key_alg(key), ssh_transient_hostkey_cache_find)) != NULL) { @@ -101,7 +101,7 @@ int ssh_transient_hostkey_cache_verify( if (this_blob->len == ent->pub_blob->len && !memcmp(this_blob->s, ent->pub_blob->s, this_blob->len)) - toret = TRUE; + toret = true; strbuf_free(this_blob); } diff --git a/ssh2transport.c b/ssh2transport.c index 152d530d..c1f645c0 100644 --- a/ssh2transport.c +++ b/ssh2transport.c @@ -141,7 +141,7 @@ PacketProtocolLayer *ssh2_transport_new( s->shgss->ctx = NULL; #endif s->thc = ssh_transient_hostkey_cache_new(); - s->gss_kex_used = FALSE; + s->gss_kex_used = false; s->outgoing_kexinit = strbuf_new(); s->incoming_kexinit = strbuf_new(); @@ -336,7 +336,7 @@ int ssh2_common_filter_queue(PacketProtocolLayer *ppl) ssh2_disconnect_reasons[reason] : "unknown"), PTRLEN_PRINTF(msg)); pq_pop(ppl->in_pq); - return TRUE; /* indicate that we've been freed */ + return true; /* indicate that we've been freed */ case SSH2_MSG_DEBUG: /* XXX maybe we should actually take notice of the return value */ @@ -352,11 +352,11 @@ int ssh2_common_filter_queue(PacketProtocolLayer *ppl) break; default: - return FALSE; + return false; } } - return FALSE; + return false; } static int ssh2_transport_filter_queue(struct ssh2_transport_state *s) @@ -365,9 +365,9 @@ static int ssh2_transport_filter_queue(struct ssh2_transport_state *s) while (1) { if (ssh2_common_filter_queue(&s->ppl)) - return TRUE; + return true; if ((pktin = pq_peek(s->ppl.in_pq)) == NULL) - return FALSE; + return false; /* Pass on packets to the next layer if they're outside * the range reserved for the transport protocol. */ @@ -381,7 +381,7 @@ static int ssh2_transport_filter_queue(struct ssh2_transport_state *s) ssh2_pkt_type(s->ppl.bpp->pls->kctx, s->ppl.bpp->pls->actx, pktin->type)); - return TRUE; + return true; } pq_pop(s->ppl.in_pq); @@ -389,7 +389,7 @@ static int ssh2_transport_filter_queue(struct ssh2_transport_state *s) } else { /* Anything else is a transport-layer packet that the main * process_queue coroutine should handle. */ - return FALSE; + return false; } } } @@ -522,10 +522,10 @@ static void ssh2_write_kexinit_lists( for (j = 0; j < MAXKEXLIST; j++) kexlists[i][j].name = NULL; /* List key exchange algorithms. */ - warn = FALSE; + warn = false; for (i = 0; i < n_preferred_kex; i++) { const struct ssh_kexes *k = preferred_kex[i]; - if (!k) warn = TRUE; + if (!k) warn = true; else for (j = 0; j < k->nkexes; j++) { alg = ssh2_kexinit_addalg(kexlists[KEXLIST_KEX], k->list[j]->name); @@ -543,7 +543,7 @@ static void ssh2_write_kexinit_lists( alg = ssh2_kexinit_addalg(kexlists[KEXLIST_HOSTKEY], ssh_key_alg(our_hostkeys[i])->ssh_id); alg->u.hk.hostkey = ssh_key_alg(our_hostkeys[i]); - alg->u.hk.warn = FALSE; + alg->u.hk.warn = false; } } else if (first_time) { /* @@ -558,10 +558,10 @@ static void ssh2_write_kexinit_lists( * they surely _do_ want to be alerted that a server * they're actually connecting to is using it. */ - warn = FALSE; + warn = false; for (i = 0; i < n_preferred_hk; i++) { if (preferred_hk[i] == HK_WARN) - warn = TRUE; + warn = true; for (j = 0; j < lenof(ssh2_hostkey_algs); j++) { if (ssh2_hostkey_algs[j].id != preferred_hk[i]) continue; @@ -574,10 +574,10 @@ static void ssh2_write_kexinit_lists( } } } - warn = FALSE; + warn = false; for (i = 0; i < n_preferred_hk; i++) { if (preferred_hk[i] == HK_WARN) - warn = TRUE; + warn = true; for (j = 0; j < lenof(ssh2_hostkey_algs); j++) { if (ssh2_hostkey_algs[j].id != preferred_hk[i]) continue; @@ -601,10 +601,10 @@ static void ssh2_write_kexinit_lists( * in which case the cache will currently be empty, which * isn't helpful! */ - warn = FALSE; + warn = false; for (i = 0; i < n_preferred_hk; i++) { if (preferred_hk[i] == HK_WARN) - warn = TRUE; + warn = true; for (j = 0; j < lenof(ssh2_hostkey_algs); j++) { if (ssh2_hostkey_algs[j].id != preferred_hk[i]) continue; @@ -629,7 +629,7 @@ static void ssh2_write_kexinit_lists( assert(hk_prev); alg = ssh2_kexinit_addalg(kexlists[KEXLIST_HOSTKEY], hk_prev->ssh_id); alg->u.hk.hostkey = hk_prev; - alg->u.hk.warn = FALSE; + alg->u.hk.warn = false; } if (can_gssapi_keyex) { alg = ssh2_kexinit_addalg(kexlists[KEXLIST_HOSTKEY], "null"); @@ -637,7 +637,7 @@ static void ssh2_write_kexinit_lists( } /* List encryption algorithms (client->server then server->client). */ for (k = KEXLIST_CSCIPHER; k <= KEXLIST_SCCIPHER; k++) { - warn = FALSE; + warn = false; #ifdef FUZZING alg = ssh2_kexinit_addalg(kexlists[k], "none"); alg->u.cipher.cipher = NULL; @@ -645,7 +645,7 @@ static void ssh2_write_kexinit_lists( #endif /* FUZZING */ for (i = 0; i < n_preferred_ciphers; i++) { const struct ssh2_ciphers *c = preferred_ciphers[i]; - if (!c) warn = TRUE; + if (!c) warn = true; else for (j = 0; j < c->nciphers; j++) { alg = ssh2_kexinit_addalg(kexlists[k], c->list[j]->name); @@ -671,12 +671,12 @@ static void ssh2_write_kexinit_lists( #ifdef FUZZING alg = ssh2_kexinit_addalg(kexlists[j], "none"); alg->u.mac.mac = NULL; - alg->u.mac.etm = FALSE; + alg->u.mac.etm = false; #endif /* FUZZING */ for (i = 0; i < nmacs; i++) { alg = ssh2_kexinit_addalg(kexlists[j], maclist[i]->name); alg->u.mac.mac = maclist[i]; - alg->u.mac.etm = FALSE; + alg->u.mac.etm = false; } for (i = 0; i < nmacs; i++) { /* For each MAC, there may also be an ETM version, @@ -684,7 +684,7 @@ static void ssh2_write_kexinit_lists( if (maclist[i]->etm_name) { alg = ssh2_kexinit_addalg(kexlists[j], maclist[i]->etm_name); alg->u.mac.mac = maclist[i]; - alg->u.mac.etm = TRUE; + alg->u.mac.etm = true; } } } @@ -697,22 +697,22 @@ static void ssh2_write_kexinit_lists( /* Prefer non-delayed versions */ alg = ssh2_kexinit_addalg(kexlists[j], preferred_comp->name); alg->u.comp.comp = preferred_comp; - alg->u.comp.delayed = FALSE; + alg->u.comp.delayed = false; if (preferred_comp->delayed_name) { alg = ssh2_kexinit_addalg(kexlists[j], preferred_comp->delayed_name); alg->u.comp.comp = preferred_comp; - alg->u.comp.delayed = TRUE; + alg->u.comp.delayed = true; } for (i = 0; i < lenof(compressions); i++) { const struct ssh_compression_alg *c = compressions[i]; alg = ssh2_kexinit_addalg(kexlists[j], c->name); alg->u.comp.comp = c; - alg->u.comp.delayed = FALSE; + alg->u.comp.delayed = false; if (c->delayed_name) { alg = ssh2_kexinit_addalg(kexlists[j], c->delayed_name); alg->u.comp.comp = c; - alg->u.comp.delayed = TRUE; + alg->u.comp.delayed = true; } } } @@ -757,7 +757,7 @@ static int ssh2_scan_kexinits( get_data(client, 1 + 16); get_data(server, 1 + 16); - guess_correct = TRUE; + guess_correct = true; /* Find the matching string in each list, and map it to its * kexinit_algorithm structure. */ @@ -772,13 +772,13 @@ static int ssh2_scan_kexinits( * agree" that we'd generate if we pressed on regardless * and treated the empty get_string() result as genuine */ ssh_proto_error(ssh, "KEXINIT packet was incomplete"); - return FALSE; + return false; } - for (cfirst = TRUE, clist = clists[i]; - get_commasep_word(&clist, &cword); cfirst = FALSE) - for (sfirst = TRUE, slist = slists[i]; - get_commasep_word(&slist, &sword); sfirst = FALSE) + for (cfirst = true, clist = clists[i]; + get_commasep_word(&clist, &cword); cfirst = false) + for (sfirst = true, slist = slists[i]; + get_commasep_word(&slist, &sword); sfirst = false) if (ptrlen_eq_ptrlen(cword, sword)) { found = cword; goto found_match; @@ -798,7 +798,7 @@ static int ssh2_scan_kexinits( * PROTOCOL.chacha20poly1305 or as far as I can see by their * code.) */ - guess_correct = FALSE; + guess_correct = false; continue; @@ -819,7 +819,7 @@ static int ssh2_scan_kexinits( * packet (if any) is officially wrong. */ if ((i == KEXLIST_KEX || i == KEXLIST_HOSTKEY) && !(cfirst || sfirst)) - guess_correct = FALSE; + guess_correct = false; } /* @@ -867,7 +867,7 @@ static int ssh2_scan_kexinits( */ ssh_sw_abort(ssh, "Couldn't agree a %s (available: %.*s)", kexlist_descr[i], PTRLEN_PRINTF(slists[i])); - return FALSE; + return false; } switch (i) { @@ -922,7 +922,7 @@ static int ssh2_scan_kexinits( break; default: - assert(FALSE && "Bad list index in scan_kexinits"); + assert(false && "Bad list index in scan_kexinits"); } } @@ -943,7 +943,7 @@ static int ssh2_scan_kexinits( server_hostkeys[(*n_server_hostkeys)++] = i; } - return TRUE; + return true; } void ssh2transport_finalise_exhash(struct ssh2_transport_state *s) @@ -979,9 +979,9 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) s->in.mac = s->out.mac = NULL; s->in.comp = s->out.comp = NULL; - s->got_session_id = FALSE; - s->need_gss_transient_hostkey = FALSE; - s->warned_about_no_gss_transient_hostkey = FALSE; + s->got_session_id = false; + s->need_gss_transient_hostkey = false; + s->warned_about_no_gss_transient_hostkey = false; begin_key_exchange: @@ -992,7 +992,7 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) * GSS key exchange even if we could. (See comments below, * where the flag was set on the previous key exchange.) */ - s->can_gssapi_keyex = FALSE; + s->can_gssapi_keyex = false; } else if (conf_get_int(s->conf, CONF_try_gssapi_kex)) { /* * We always check if we have GSS creds before we come up with @@ -1007,7 +1007,7 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) * state is "fresh". */ if (s->rekey_class != RK_GSS_UPDATE) - ssh2_transport_gss_update(s, TRUE); + ssh2_transport_gss_update(s, true); /* Do GSSAPI KEX when capable */ s->can_gssapi_keyex = s->gss_status & GSS_KEX_CAPABLE; @@ -1028,7 +1028,7 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) s->can_gssapi_keyex = 0; s->gss_delegate = conf_get_int(s->conf, CONF_gssapifwd); } else { - s->can_gssapi_keyex = FALSE; + s->can_gssapi_keyex = false; } #endif @@ -1053,7 +1053,7 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) !s->got_session_id, s->can_gssapi_keyex, s->gss_kex_used && !s->need_gss_transient_hostkey); /* First KEX packet does _not_ follow, because we're not that brave. */ - put_bool(s->outgoing_kexinit, FALSE); + put_bool(s->outgoing_kexinit, false); put_uint32(s->outgoing_kexinit, 0); /* reserved */ /* @@ -1067,7 +1067,7 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) /* * Flag that KEX is in progress. */ - s->kex_in_progress = TRUE; + s->kex_in_progress = true; /* * Wait for the other side's KEXINIT, and save it. @@ -1097,7 +1097,7 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) s->kexlists, &s->kex_alg, &s->hostkey_alg, &s->out, &s->in, &s->warn_kex, &s->warn_hk, &s->warn_cscipher, &s->warn_sccipher, s->ppl.ssh, NULL, &s->ignorepkt, &nhk, hks)) - return; /* FALSE means a fatal error function was called */ + return; /* false means a fatal error function was called */ /* * In addition to deciding which host key we're actually going @@ -1147,13 +1147,13 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) for (j = 0; j < s->n_uncert_hostkeys; j++) { const struct ssh_signkey_with_user_pref_id *hktype = &ssh2_hostkey_algs[s->uncert_hostkeys[j]]; - int better = FALSE; + int better = false; for (k = 0; k < HK_MAX; k++) { int id = conf_get_int_int(s->conf, CONF_ssh_hklist, k); if (id == HK_WARN) { break; } else if (id == hktype->id) { - better = TRUE; + better = true; break; } } @@ -1245,7 +1245,7 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) memcpy(s->session_id, s->exchange_hash, sizeof(s->exchange_hash)); s->session_id_len = s->kex_alg->hash->hlen; assert(s->session_id_len <= sizeof(s->session_id)); - s->got_session_id = TRUE; + s->got_session_id = true; } /* @@ -1254,7 +1254,7 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH2_MSG_NEWKEYS); pq_push(s->ppl.out_pq, pktout); /* Start counting down the outgoing-data limit for these cipher keys. */ - s->stats->out.running = TRUE; + s->stats->out.running = true; s->stats->out.remaining = s->max_data_size; /* @@ -1317,7 +1317,7 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) return; } /* Start counting down the incoming-data limit for these cipher keys. */ - s->stats->in.running = TRUE; + s->stats->in.running = true; s->stats->in.remaining = s->max_data_size; /* @@ -1377,7 +1377,7 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) /* * Otherwise, schedule a timer for our next rekey. */ - s->kex_in_progress = FALSE; + s->kex_in_progress = false; s->last_rekey = GETTICKCOUNT(); (void) ssh2_transport_timer_update(s, 0); @@ -1429,7 +1429,7 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) pq_push(s->ppl.out_pq, pktout); } - s->higher_layer_ok = TRUE; + s->higher_layer_ok = true; queue_idempotent_callback(&s->higher_layer->ic_process_queue); } @@ -1504,7 +1504,7 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) s->rekey_reason)); /* Reset the counters, so that at least this message doesn't * hit the event log _too_ often. */ - s->stats->in.running = s->stats->out.running = TRUE; + s->stats->in.running = s->stats->out.running = true; s->stats->in.remaining = s->stats->out.remaining = s->max_data_size; (void) ssh2_transport_timer_update(s, 0); @@ -1556,7 +1556,7 @@ static void ssh2_transport_timer(void *ctx, unsigned long now) * but not if this is unsafe. */ if (conf_get_int(s->conf, CONF_gssapirekey)) { - ssh2_transport_gss_update(s, FALSE); + ssh2_transport_gss_update(s, false); if ((s->gss_status & GSS_KEX_CAPABLE) != 0 && (s->gss_status & GSS_CTXT_MAYFAIL) == 0 && (s->gss_status & (GSS_CRED_UPDATED|GSS_CTXT_EXPIRES)) != 0) { @@ -1797,12 +1797,12 @@ static int ssh2_transport_get_specials( { struct ssh2_transport_state *s = container_of(ppl, struct ssh2_transport_state, ppl); - int need_separator = FALSE; + int need_separator = false; int toret; if (ssh_ppl_get_specials(s->higher_layer, add_special, ctx)) { - need_separator = TRUE; - toret = TRUE; + need_separator = true; + toret = true; } /* @@ -1813,11 +1813,11 @@ static int ssh2_transport_get_specials( if (!(s->ppl.remote_bugs & BUG_SSH2_REKEY)) { if (need_separator) { add_special(ctx, NULL, SS_SEP, 0); - need_separator = FALSE; + need_separator = false; } add_special(ctx, "Repeat key exchange", SS_REKEY, 0); - toret = TRUE; + toret = true; if (s->n_uncert_hostkeys) { int i; @@ -1852,7 +1852,7 @@ static void ssh2_transport_special_cmd(PacketProtocolLayer *ppl, } else if (code == SS_XCERT) { if (!s->kex_in_progress) { s->hostkey_alg = ssh2_hostkey_algs[arg].alg; - s->cross_certifying = TRUE; + s->cross_certifying = true; s->rekey_reason = "cross-certifying new host key"; s->rekey_class = RK_NORMAL; queue_idempotent_callback(&s->ppl.ic_process_queue); @@ -1884,7 +1884,7 @@ static void ssh2_transport_reconfigure(PacketProtocolLayer *ppl, Conf *conf) { struct ssh2_transport_state *s; const char *rekey_reason = NULL; - int rekey_mandatory = FALSE; + int rekey_mandatory = false; unsigned long old_max_data_size, rekey_time; int i; @@ -1921,19 +1921,19 @@ static void ssh2_transport_reconfigure(PacketProtocolLayer *ppl, Conf *conf) if (conf_get_int(s->conf, CONF_compression) != conf_get_int(conf, CONF_compression)) { rekey_reason = "compression setting changed"; - rekey_mandatory = TRUE; + rekey_mandatory = true; } for (i = 0; i < CIPHER_MAX; i++) if (conf_get_int_int(s->conf, CONF_ssh_cipherlist, i) != conf_get_int_int(conf, CONF_ssh_cipherlist, i)) { rekey_reason = "cipher settings changed"; - rekey_mandatory = TRUE; + rekey_mandatory = true; } if (conf_get_int(s->conf, CONF_ssh2_des_cbc) != conf_get_int(conf, CONF_ssh2_des_cbc)) { rekey_reason = "cipher settings changed"; - rekey_mandatory = TRUE; + rekey_mandatory = true; } conf_free(s->conf); diff --git a/ssh2userauth-server.c b/ssh2userauth-server.c index 224097ad..685cf5c0 100644 --- a/ssh2userauth-server.c +++ b/ssh2userauth-server.c @@ -146,13 +146,13 @@ static void ssh2_userauth_server_process_queue(PacketProtocolLayer *ppl) */ pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH2_MSG_USERAUTH_FAILURE); put_stringz(pktout, ""); - put_bool(pktout, FALSE); + put_bool(pktout, false); pq_push(s->ppl.out_pq, pktout); continue; } s->methods = auth_methods(s->authpolicy); - s->partial_success = FALSE; + s->partial_success = false; if (ptrlen_eq_string(s->method, "none")) { s->this_method = AUTHMETHOD_NONE; @@ -327,7 +327,7 @@ static void ssh2_userauth_server_process_queue(PacketProtocolLayer *ppl) */ s->methods = auth_methods(s->authpolicy); } - s->partial_success = TRUE; + s->partial_success = true; failure: pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH2_MSG_USERAUTH_FAILURE); diff --git a/ssh2userauth.c b/ssh2userauth.c index 7cbb425e..c667ab5e 100644 --- a/ssh2userauth.c +++ b/ssh2userauth.c @@ -206,8 +206,8 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) crBegin(s->crState); #ifndef NO_GSSAPI - s->tried_gssapi = FALSE; - s->tried_gssapi_keyex_auth = FALSE; + s->tried_gssapi = false; + s->tried_gssapi_keyex_auth = false; #endif /* @@ -351,7 +351,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) * the username they will want to be able to get back and * retype it! */ - s->got_username = FALSE; + s->got_username = false; while (1) { /* * Get a username. @@ -364,9 +364,9 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) */ } else if ((s->username = s->default_username) == NULL) { s->cur_prompt = new_prompts(); - s->cur_prompt->to_server = TRUE; + s->cur_prompt->to_server = true; s->cur_prompt->name = dupstr("SSH login name"); - add_prompt(s->cur_prompt, dupstr("login as: "), TRUE); + add_prompt(s->cur_prompt, dupstr("login as: "), true); s->userpass_ret = seat_get_userpass_input( s->ppl.seat, s->cur_prompt, NULL); while (1) { @@ -378,9 +378,9 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) if (s->userpass_ret >= 0) break; - s->want_user_input = TRUE; + s->want_user_input = true; crReturnV; - s->want_user_input = FALSE; + s->want_user_input = false; } if (!s->userpass_ret) { /* @@ -397,7 +397,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) if ((flags & FLAG_VERBOSE) || (flags & FLAG_INTERACTIVE)) ppl_printf(("Using username \"%s\".\r\n", s->username)); } - s->got_username = TRUE; + s->got_username = true; /* * Send an authentication request using method "none": (a) @@ -413,11 +413,11 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) pq_push(s->ppl.out_pq, s->pktout); s->type = AUTH_TYPE_NONE; - s->tried_pubkey_config = FALSE; - s->kbd_inter_refused = FALSE; + s->tried_pubkey_config = false; + s->kbd_inter_refused = false; /* Reset agent request state. */ - s->done_agent = FALSE; + s->done_agent = false; if (s->agent_response.ptr) { if (s->pkblob_pos_in_agent) { s->asrc->pos = s->pkblob_pos_in_agent; @@ -590,7 +590,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) /* gssapi-keyex authentication */ s->type = AUTH_TYPE_GSSAPI; - s->tried_gssapi_keyex_auth = TRUE; + s->tried_gssapi_keyex_auth = true; s->ppl.bpp->pls->actx = SSH2_PKTCTX_GSSAPI; if (s->shgss->lib->gsslogmsg) @@ -632,7 +632,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) put_stringz(s->pktout, s->successor_layer->vt->name); put_stringz(s->pktout, "publickey"); /* method */ - put_bool(s->pktout, FALSE); /* no signature included */ + put_bool(s->pktout, false); /* no signature included */ put_stringpl(s->pktout, s->alg); put_stringpl(s->pktout, s->pk); pq_push(s->ppl.out_pq, s->pktout); @@ -663,7 +663,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) put_stringz(s->pktout, s->successor_layer->vt->name); put_stringz(s->pktout, "publickey"); /* method */ - put_bool(s->pktout, TRUE); /* signature included */ + put_bool(s->pktout, true); /* signature included */ put_stringpl(s->pktout, s->alg); put_stringpl(s->pktout, s->pk); @@ -707,12 +707,12 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) /* Do we have any keys left to try? */ if (s->pkblob_pos_in_agent) { - s->done_agent = TRUE; - s->tried_pubkey_config = TRUE; + s->done_agent = true; + s->tried_pubkey_config = true; } else { s->keyi++; if (s->keyi >= s->nkeys) - s->done_agent = TRUE; + s->done_agent = true; } } else if (s->can_pubkey && s->publickey_blob && @@ -723,7 +723,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) s->ppl.bpp->pls->actx = SSH2_PKTCTX_PUBLICKEY; - s->tried_pubkey_config = TRUE; + s->tried_pubkey_config = true; /* * Try the public key supplied in the configuration. @@ -736,7 +736,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) put_stringz(s->pktout, s->username); put_stringz(s->pktout, s->successor_layer->vt->name); put_stringz(s->pktout, "publickey"); /* method */ - put_bool(s->pktout, FALSE); + put_bool(s->pktout, false); /* no signature included */ put_stringz(s->pktout, s->publickey_algorithm); put_string(s->pktout, s->publickey_blob->s, @@ -769,12 +769,12 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) * Get a passphrase from the user. */ s->cur_prompt = new_prompts(); - s->cur_prompt->to_server = FALSE; + s->cur_prompt->to_server = false; s->cur_prompt->name = dupstr("SSH key passphrase"); add_prompt(s->cur_prompt, dupprintf("Passphrase for key \"%.100s\": ", s->publickey_comment), - FALSE); + false); s->userpass_ret = seat_get_userpass_input( s->ppl.seat, s->cur_prompt, NULL); while (1) { @@ -787,9 +787,9 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) if (s->userpass_ret >= 0) break; - s->want_user_input = TRUE; + s->want_user_input = true; crReturnV; - s->want_user_input = FALSE; + s->want_user_input = false; } if (!s->userpass_ret) { /* Failed to get a passphrase. Terminate. */ @@ -845,7 +845,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) put_stringz(s->pktout, s->username); put_stringz(s->pktout, s->successor_layer->vt->name); put_stringz(s->pktout, "publickey"); /* method */ - put_bool(s->pktout, TRUE); /* signature follows */ + put_bool(s->pktout, true); /* signature follows */ put_stringz(s->pktout, ssh_key_ssh_id(key->key)); pkblob = strbuf_new(); ssh_key_public_blob(key->key, BinarySink_UPCAST(pkblob)); @@ -889,7 +889,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) ptrlen data; s->type = AUTH_TYPE_GSSAPI; - s->tried_gssapi = TRUE; + s->tried_gssapi = true; s->ppl.bpp->pls->actx = SSH2_PKTCTX_GSSAPI; if (s->shgss->lib->gsslogmsg) @@ -1073,7 +1073,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) * Give up on it entirely. */ pq_push_front(s->ppl.in_pq, pktin); s->type = AUTH_TYPE_KEYBOARD_INTERACTIVE_QUIET; - s->kbd_inter_refused = TRUE; /* don't try it again */ + s->kbd_inter_refused = true; /* don't try it again */ continue; } @@ -1093,7 +1093,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) inst = get_string(pktin); get_string(pktin); /* skip language tag */ s->cur_prompt = new_prompts(); - s->cur_prompt->to_server = TRUE; + s->cur_prompt->to_server = true; /* * Get any prompt(s) from the packet. @@ -1119,11 +1119,11 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) * local prompts? */ s->cur_prompt->name = dupprintf("SSH server: %.*s", PTRLEN_PRINTF(name)); - s->cur_prompt->name_reqd = TRUE; + s->cur_prompt->name_reqd = true; } else { s->cur_prompt->name = dupstr("SSH server authentication"); - s->cur_prompt->name_reqd = FALSE; + s->cur_prompt->name_reqd = false; } /* We add a prefix to try to make it clear that a prompt * has come from the server. @@ -1138,9 +1138,9 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) "authentication.%s%.*s", inst.len ? "\n" : "", PTRLEN_PRINTF(inst)); - s->cur_prompt->instr_reqd = TRUE; + s->cur_prompt->instr_reqd = true; } else { - s->cur_prompt->instr_reqd = FALSE; + s->cur_prompt->instr_reqd = false; } /* @@ -1158,9 +1158,9 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) if (s->userpass_ret >= 0) break; - s->want_user_input = TRUE; + s->want_user_input = true; crReturnV; - s->want_user_input = FALSE; + s->want_user_input = false; } if (!s->userpass_ret) { /* @@ -1218,11 +1218,11 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) s->ppl.bpp->pls->actx = SSH2_PKTCTX_PASSWORD; s->cur_prompt = new_prompts(); - s->cur_prompt->to_server = TRUE; + s->cur_prompt->to_server = true; s->cur_prompt->name = dupstr("SSH password"); add_prompt(s->cur_prompt, dupprintf("%s@%s's password: ", s->username, s->hostname), - FALSE); + false); s->userpass_ret = seat_get_userpass_input( s->ppl.seat, s->cur_prompt, NULL); @@ -1235,9 +1235,9 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) if (s->userpass_ret >= 0) break; - s->want_user_input = TRUE; + s->want_user_input = true; crReturnV; - s->want_user_input = FALSE; + s->want_user_input = false; } if (!s->userpass_ret) { /* @@ -1274,7 +1274,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) put_stringz(s->pktout, s->username); put_stringz(s->pktout, s->successor_layer->vt->name); put_stringz(s->pktout, "password"); - put_bool(s->pktout, FALSE); + put_bool(s->pktout, false); put_stringz(s->pktout, s->password); s->pktout->minlen = 256; pq_push(s->ppl.out_pq, s->pktout); @@ -1286,7 +1286,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) * request. */ crMaybeWaitUntilV((pktin = ssh2_userauth_pop(s)) != NULL); - changereq_first_time = TRUE; + changereq_first_time = true; while (pktin->type == SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ) { @@ -1296,7 +1296,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) * Loop until the server accepts it. */ - int got_new = FALSE; /* not live over crReturn */ + int got_new = false; /* not live over crReturn */ ptrlen prompt; /* not live over crReturn */ { @@ -1312,10 +1312,10 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) prompt = get_string(pktin); s->cur_prompt = new_prompts(); - s->cur_prompt->to_server = TRUE; + s->cur_prompt->to_server = true; s->cur_prompt->name = dupstr("New SSH password"); s->cur_prompt->instruction = mkstr(prompt); - s->cur_prompt->instr_reqd = TRUE; + s->cur_prompt->instr_reqd = true; /* * There's no explicit requirement in the protocol * for the "old" passwords in the original and @@ -1330,11 +1330,11 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) */ add_prompt(s->cur_prompt, dupstr("Current password (blank for previously entered password): "), - FALSE); + false); add_prompt(s->cur_prompt, dupstr("Enter new password: "), - FALSE); + false); add_prompt(s->cur_prompt, dupstr("Confirm new password: "), - FALSE); + false); /* * Loop until the user manages to enter the same @@ -1353,9 +1353,9 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) if (s->userpass_ret >= 0) break; - s->want_user_input = TRUE; + s->want_user_input = true; crReturnV; - s->want_user_input = FALSE; + s->want_user_input = false; } if (!s->userpass_ret) { /* @@ -1409,7 +1409,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) put_stringz(s->pktout, s->username); put_stringz(s->pktout, s->successor_layer->vt->name); put_stringz(s->pktout, "password"); - put_bool(s->pktout, TRUE); + put_bool(s->pktout, true); put_stringz(s->pktout, s->password); put_stringz(s->pktout, s->cur_prompt->prompts[1]->result); @@ -1424,7 +1424,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) * new password.) */ crMaybeWaitUntilV((pktin = ssh2_userauth_pop(s)) != NULL); - changereq_first_time = FALSE; + changereq_first_time = false; } @@ -1638,7 +1638,7 @@ static int ssh2_userauth_get_specials( PacketProtocolLayer *ppl, add_special_fn_t add_special, void *ctx) { /* No specials provided by this layer. */ - return FALSE; + return false; } static void ssh2_userauth_special_cmd(PacketProtocolLayer *ppl, diff --git a/sshbpp.h b/sshbpp.h index 04c1f5ed..2b09fdea 100644 --- a/sshbpp.h +++ b/sshbpp.h @@ -99,8 +99,8 @@ struct DataTransferStats { #define DTS_CONSUME(stats, direction, size) \ ((stats)->direction.running && \ (stats)->direction.remaining <= (size) ? \ - ((stats)->direction.running = FALSE, TRUE) : \ - ((stats)->direction.remaining -= (size), FALSE)) + ((stats)->direction.running = false, true) : \ + ((stats)->direction.remaining -= (size), false)) BinaryPacketProtocol *ssh2_bpp_new( LogContext *logctx, struct DataTransferStats *stats, int is_server); diff --git a/sshchan.h b/sshchan.h index e01d6bb5..dd82fd63 100644 --- a/sshchan.h +++ b/sshchan.h @@ -28,7 +28,7 @@ struct ChannelVtable { int (*want_close)(Channel *, int sent_local_eof, int rcvd_remote_eof); /* A method for every channel request we know of. All of these - * return TRUE for success or FALSE for failure. */ + * return true for success or false for failure. */ int (*rcvd_exit_status)(Channel *, int status); int (*rcvd_exit_signal)( Channel *chan, ptrlen signame, int core_dumped, ptrlen msg); @@ -217,7 +217,7 @@ struct SshChannel { ConnectionLayer *cl; }; -#define sshfwd_write(c, buf, len) ((c)->vt->write(c, FALSE, buf, len)) +#define sshfwd_write(c, buf, len) ((c)->vt->write(c, false, buf, len)) #define sshfwd_write_ext(c, stderr, buf, len) \ ((c)->vt->write(c, stderr, buf, len)) #define sshfwd_write_eof(c) ((c)->vt->write_eof(c)) diff --git a/sshcommon.c b/sshcommon.c index 56f4b420..4f3622a7 100644 --- a/sshcommon.c +++ b/sshcommon.c @@ -52,7 +52,7 @@ void pq_base_push_front(PacketQueueBase *pqb, PacketQueueNode *node) } static PacketQueueNode pktin_freeq_head = { - &pktin_freeq_head, &pktin_freeq_head, TRUE + &pktin_freeq_head, &pktin_freeq_head, true }; static void pktin_free_queue_callback(void *vctx) @@ -68,7 +68,7 @@ static void pktin_free_queue_callback(void *vctx) } static IdempotentCallback ic_pktin_free = { - pktin_free_queue_callback, NULL, FALSE + pktin_free_queue_callback, NULL, false }; static PktIn *pq_in_after(PacketQueueBase *pqb, @@ -86,7 +86,7 @@ static PktIn *pq_in_after(PacketQueueBase *pqb, node->next = &pktin_freeq_head; node->next->prev = node; node->prev->next = node; - node->on_free_queue = TRUE; + node->on_free_queue = true; queue_idempotent_callback(&ic_pktin_free); } @@ -224,7 +224,7 @@ PktOut *ssh_new_packet(void) pkt->downstream_id = 0; pkt->additional_log_text = NULL; pkt->qnode.next = pkt->qnode.prev = NULL; - pkt->qnode.on_free_queue = FALSE; + pkt->qnode.on_free_queue = false; return pkt; } @@ -331,7 +331,7 @@ static void zombiechan_set_input_wanted(Channel *chan, int enable) static int zombiechan_want_close(Channel *chan, int sent_eof, int rcvd_eof) { - return TRUE; + return true; } /* ---------------------------------------------------------------------- @@ -361,75 +361,75 @@ int chan_default_want_close( int chan_no_exit_status(Channel *chan, int status) { - return FALSE; + return false; } int chan_no_exit_signal( Channel *chan, ptrlen signame, int core_dumped, ptrlen msg) { - return FALSE; + return false; } int chan_no_exit_signal_numeric( Channel *chan, int signum, int core_dumped, ptrlen msg) { - return FALSE; + return false; } int chan_no_run_shell(Channel *chan) { - return FALSE; + return false; } int chan_no_run_command(Channel *chan, ptrlen command) { - return FALSE; + return false; } int chan_no_run_subsystem(Channel *chan, ptrlen subsys) { - return FALSE; + return false; } int chan_no_enable_x11_forwarding( Channel *chan, int oneshot, ptrlen authproto, ptrlen authdata, unsigned screen_number) { - return FALSE; + return false; } int chan_no_enable_agent_forwarding(Channel *chan) { - return FALSE; + return false; } int chan_no_allocate_pty( Channel *chan, ptrlen termtype, unsigned width, unsigned height, unsigned pixwidth, unsigned pixheight, struct ssh_ttymodes modes) { - return FALSE; + return false; } int chan_no_set_env(Channel *chan, ptrlen var, ptrlen value) { - return FALSE; + return false; } int chan_no_send_break(Channel *chan, unsigned length) { - return FALSE; + return false; } int chan_no_send_signal(Channel *chan, ptrlen signame) { - return FALSE; + return false; } int chan_no_change_window_size( Channel *chan, unsigned width, unsigned height, unsigned pixwidth, unsigned pixheight) { - return FALSE; + return false; } void chan_no_request_response(Channel *chan, int success) @@ -558,7 +558,7 @@ struct ssh_ttymodes get_ttymodes_from_conf(Seat *seat, Conf *conf) assert(0 && "Bad mode->type"); } - modes.have_mode[mode->opcode] = TRUE; + modes.have_mode[mode->opcode] = true; modes.mode_val[mode->opcode] = ival; } @@ -572,9 +572,9 @@ struct ssh_ttymodes get_ttymodes_from_conf(Seat *seat, Conf *conf) ospeed = ispeed = 38400; /* last-resort defaults */ sscanf(conf_get_str(conf, CONF_termspeed), "%u,%u", &ospeed, &ispeed); /* Currently we unconditionally set these */ - modes.have_mode[TTYMODE_ISPEED] = TRUE; + modes.have_mode[TTYMODE_ISPEED] = true; modes.mode_val[TTYMODE_ISPEED] = ispeed; - modes.have_mode[TTYMODE_OSPEED] = TRUE; + modes.have_mode[TTYMODE_OSPEED] = true; modes.mode_val[TTYMODE_OSPEED] = ospeed; } @@ -613,7 +613,7 @@ struct ssh_ttymodes read_ttymodes_from_packet( our_opcode = our_ttymode_opcode(real_opcode, ssh_version); assert(our_opcode < TTYMODE_LIMIT); - modes.have_mode[our_opcode] = TRUE; + modes.have_mode[our_opcode] = true; if (ssh_version == 1 && real_opcode >= 1 && real_opcode <= 127) modes.mode_val[our_opcode] = get_byte(bs); @@ -709,19 +709,19 @@ int in_commasep_string(char const *needle, char const *haystack, int haylen) char *p; if (!needle || !haystack) /* protect against null pointers */ - return FALSE; + return false; /* * Is it at the start of the string? */ if (first_in_commasep_string(needle, haystack, haylen)) - return TRUE; + return true; /* * If not, search for the next comma and resume after that. * If no comma found, terminate. */ p = memchr(haystack, ',', haylen); if (!p) - return FALSE; + return false; /* + 1 to skip over comma */ return in_commasep_string(needle, p + 1, haylen - (p + 1 - haystack)); } @@ -749,7 +749,7 @@ int get_commasep_word(ptrlen *list, ptrlen *word) } if (!list->len) - return FALSE; + return false; comma = memchr(list->ptr, ',', list->len); if (!comma) { @@ -762,7 +762,7 @@ int get_commasep_word(ptrlen *list, ptrlen *word) list->ptr = (const char *)list->ptr + wordlen + 1; list->len -= wordlen + 1; } - return TRUE; + return true; } /* ---------------------------------------------------------------------- @@ -873,7 +873,7 @@ void ssh_bpp_common_setup(BinaryPacketProtocol *bpp) { pq_in_init(&bpp->in_pq); pq_out_init(&bpp->out_pq); - bpp->input_eof = FALSE; + bpp->input_eof = false; bpp->ic_in_raw.fn = ssh_bpp_input_raw_data_callback; bpp->ic_in_raw.ctx = bpp; bpp->ic_out_pq.fn = ssh_bpp_output_packet_callback; @@ -923,10 +923,10 @@ int ssh2_bpp_check_unimplemented(BinaryPacketProtocol *bpp, PktIn *pktin) PktOut *pkt = ssh_bpp_new_pktout(bpp, SSH2_MSG_UNIMPLEMENTED); put_uint32(pkt, pktin->sequence); pq_push(&bpp->out_pq, pkt); - return TRUE; + return true; } - return FALSE; + return false; } #undef BITMAP_UNIVERSAL @@ -1002,10 +1002,10 @@ int ssh1_common_get_specials( */ if (!(ppl->remote_bugs & BUG_CHOKES_ON_SSH1_IGNORE)) { add_special(ctx, "IGNORE message", SS_NOP, 0); - return TRUE; + return true; } - return FALSE; + return false; } int ssh1_common_filter_queue(PacketProtocolLayer *ppl) @@ -1021,7 +1021,7 @@ int ssh1_common_filter_queue(PacketProtocolLayer *ppl) "Remote side sent disconnect message:\n\"%.*s\"", PTRLEN_PRINTF(msg)); pq_pop(ppl->in_pq); - return TRUE; /* indicate that we've been freed */ + return true; /* indicate that we've been freed */ case SSH1_MSG_DEBUG: msg = get_string(pktin); @@ -1035,11 +1035,11 @@ int ssh1_common_filter_queue(PacketProtocolLayer *ppl) break; default: - return FALSE; + return false; } } - return FALSE; + return false; } void ssh1_compute_session_id( diff --git a/sshecc.c b/sshecc.c index 2806ea51..13e432e2 100644 --- a/sshecc.c +++ b/sshecc.c @@ -2754,10 +2754,10 @@ int ec_nist_alg_and_curve_by_bits(int bits, case 256: *alg = &ssh_ecdsa_nistp256; break; case 384: *alg = &ssh_ecdsa_nistp384; break; case 521: *alg = &ssh_ecdsa_nistp521; break; - default: return FALSE; + default: return false; } *curve = ((struct ecsign_extra *)(*alg)->extra)->curve(); - return TRUE; + return true; } int ec_ed_alg_and_curve_by_bits(int bits, @@ -2766,8 +2766,8 @@ int ec_ed_alg_and_curve_by_bits(int bits, { switch (bits) { case 256: *alg = &ssh_ecdsa_ed25519; break; - default: return FALSE; + default: return false; } *curve = ((struct ecsign_extra *)(*alg)->extra)->curve(); - return TRUE; + return true; } diff --git a/sshpubk.c b/sshpubk.c index 309e634d..a0d73c78 100644 --- a/sshpubk.c +++ b/sshpubk.c @@ -148,7 +148,7 @@ int rsa_ssh1_loadkey(const Filename *filename, struct RSAKey *key, int ret = 0; const char *error = NULL; - fp = f_open(filename, "rb", FALSE); + fp = f_open(filename, "rb", false); if (!fp) { error = "can't open file"; goto end; @@ -162,7 +162,7 @@ int rsa_ssh1_loadkey(const Filename *filename, struct RSAKey *key, /* * This routine will take care of calling fclose() for us. */ - ret = rsa_ssh1_load_main(fp, key, FALSE, NULL, passphrase, &error); + ret = rsa_ssh1_load_main(fp, key, false, NULL, passphrase, &error); fp = NULL; goto end; } @@ -189,7 +189,7 @@ int rsa_ssh1_encrypted(const Filename *filename, char **comment) FILE *fp; char buf[64]; - fp = f_open(filename, "rb", FALSE); + fp = f_open(filename, "rb", false); if (!fp) return 0; /* doesn't even exist */ @@ -202,7 +202,7 @@ int rsa_ssh1_encrypted(const Filename *filename, char **comment) /* * This routine will take care of calling fclose() for us. */ - return rsa_ssh1_load_main(fp, NULL, FALSE, comment, NULL, &dummy); + return rsa_ssh1_load_main(fp, NULL, false, comment, NULL, &dummy); } fclose(fp); return 0; /* wasn't the right kind of file */ @@ -222,9 +222,9 @@ int rsa_ssh1_loadpub(const Filename *filename, BinarySink *bs, const char *error = NULL; /* Default return if we fail. */ - ret = FALSE; + ret = false; - fp = f_open(filename, "rb", FALSE); + fp = f_open(filename, "rb", false); if (!fp) { error = "can't open file"; goto end; @@ -236,10 +236,10 @@ int rsa_ssh1_loadpub(const Filename *filename, BinarySink *bs, */ if (fgets(buf, sizeof(buf), fp) && !strcmp(buf, rsa_signature)) { memset(&key, 0, sizeof(key)); - if (rsa_ssh1_load_main(fp, &key, TRUE, commentptr, NULL, &error)) { + if (rsa_ssh1_load_main(fp, &key, true, commentptr, NULL, &error)) { rsa_ssh1_public_blob(bs, &key, RSA_SSH1_EXPONENT_FIRST); freersakey(&key); - ret = TRUE; + ret = true; } fp = NULL; /* rsa_ssh1_load_main unconditionally closes fp */ } else { @@ -291,7 +291,7 @@ int rsa_ssh1_loadpub(const Filename *filename, BinarySink *bs, freersakey(&key); sfree(line); fclose(fp); - return TRUE; + return true; not_public_either: sfree(line); @@ -375,7 +375,7 @@ int rsa_ssh1_savekey(const Filename *filename, struct RSAKey *key, /* * Done. Write the result to the file. */ - fp = f_open(filename, "wb", TRUE); + fp = f_open(filename, "wb", true); if (fp) { int ret = (fwrite(buf->u, 1, buf->len, fp) == (size_t) (buf->len)); if (fclose(fp)) @@ -536,13 +536,13 @@ static int read_blob(FILE *fp, int nlines, BinarySink *bs) line = read_body(fp); if (!line) { sfree(blob); - return FALSE; + return false; } linelen = strlen(line); if (linelen % 4 != 0 || linelen > 64) { sfree(blob); sfree(line); - return FALSE; + return false; } for (j = 0; j < linelen; j += 4) { unsigned char decoded[3]; @@ -550,13 +550,13 @@ static int read_blob(FILE *fp, int nlines, BinarySink *bs) if (!k) { sfree(line); sfree(blob); - return FALSE; + return false; } put_data(bs, decoded, k); } sfree(line); } - return TRUE; + return true; } /* @@ -605,7 +605,7 @@ struct ssh2_userkey *ssh2_load_userkey(const Filename *filename, encryption = comment = mac = NULL; public_blob = private_blob = NULL; - fp = f_open(filename, "rb", FALSE); + fp = f_open(filename, "rb", false); if (!fp) { error = "can't open file"; goto error; @@ -737,7 +737,7 @@ struct ssh2_userkey *ssh2_load_userkey(const Filename *filename, if (old_fmt) { /* MAC (or hash) only covers the private blob. */ macdata = private_blob; - free_macdata = FALSE; + free_macdata = false; } else { macdata = strbuf_new(); put_stringz(macdata, alg->ssh_id); @@ -747,7 +747,7 @@ struct ssh2_userkey *ssh2_load_userkey(const Filename *filename, public_blob->len); put_string(macdata, private_blob->s, private_blob->len); - free_macdata = TRUE; + free_macdata = true; } if (is_mac) { @@ -957,7 +957,7 @@ int rfc4716_loadpub(FILE *fp, char **algorithm, sfree(comment); put_data(bs, pubblob, pubbloblen); sfree(pubblob); - return TRUE; + return true; error: sfree(line); @@ -965,7 +965,7 @@ int rfc4716_loadpub(FILE *fp, char **algorithm, sfree(pubblob); if (errorstr) *errorstr = error; - return FALSE; + return false; } int openssh_loadpub(FILE *fp, char **algorithm, @@ -1033,7 +1033,7 @@ int openssh_loadpub(FILE *fp, char **algorithm, sfree(line); put_data(bs, pubblob, pubbloblen); sfree(pubblob); - return TRUE; + return true; error: sfree(line); @@ -1041,7 +1041,7 @@ int openssh_loadpub(FILE *fp, char **algorithm, sfree(pubblob); if (errorstr) *errorstr = error; - return FALSE; + return false; } int ssh2_userkey_loadpub(const Filename *filename, char **algorithm, @@ -1055,7 +1055,7 @@ int ssh2_userkey_loadpub(const Filename *filename, char **algorithm, const char *error = NULL; char *comment = NULL; - fp = f_open(filename, "rb", FALSE); + fp = f_open(filename, "rb", false); if (!fp) { error = "can't open file"; goto error; @@ -1128,7 +1128,7 @@ int ssh2_userkey_loadpub(const Filename *filename, char **algorithm, fclose(fp); if (algorithm) *algorithm = dupstr(alg->ssh_id); - return TRUE; + return true; /* * Error processing. @@ -1142,7 +1142,7 @@ int ssh2_userkey_loadpub(const Filename *filename, char **algorithm, sfree(comment); *commentptr = NULL; } - return FALSE; + return false; } int ssh2_userkey_encrypted(const Filename *filename, char **commentptr) @@ -1154,7 +1154,7 @@ int ssh2_userkey_encrypted(const Filename *filename, char **commentptr) if (commentptr) *commentptr = NULL; - fp = f_open(filename, "rb", FALSE); + fp = f_open(filename, "rb", false); if (!fp) return 0; if (!read_header(fp, header) @@ -1323,7 +1323,7 @@ int ssh2_save_userkey(const Filename *filename, struct ssh2_userkey *key, smemclr(&s, sizeof(s)); } - fp = f_open(filename, "w", TRUE); + fp = f_open(filename, "w", true); if (!fp) { strbuf_free(pub_blob); strbuf_free(priv_blob); @@ -1586,7 +1586,7 @@ int key_type(const Filename *filename) FILE *fp; int ret; - fp = f_open(filename, "r", FALSE); + fp = f_open(filename, "r", false); if (!fp) return SSH_KEYTYPE_UNOPENABLE; ret = key_type_fp(fp); diff --git a/sshrand.c b/sshrand.c index 1fcac420..d0448703 100644 --- a/sshrand.c +++ b/sshrand.c @@ -80,7 +80,7 @@ static void random_stir(void) */ if (pool.stir_pending) return; - pool.stir_pending = TRUE; + pool.stir_pending = true; noise_get_light(random_add_noise); @@ -193,7 +193,7 @@ static void random_stir(void) pool.poolpos = sizeof(pool.incoming); - pool.stir_pending = FALSE; + pool.stir_pending = false; #ifdef RANDOM_DIAGNOSTICS { diff --git a/sshrsa.c b/sshrsa.c index 86a392eb..c033bb94 100644 --- a/sshrsa.c +++ b/sshrsa.c @@ -288,7 +288,7 @@ Bignum rsa_ssh1_decrypt(Bignum input, struct RSAKey *key) int rsa_ssh1_decrypt_pkcs1(Bignum input, struct RSAKey *key, strbuf *outbuf) { strbuf *data = strbuf_new(); - int success = FALSE; + int success = false; BinarySource src[1]; { @@ -313,7 +313,7 @@ int rsa_ssh1_decrypt_pkcs1(Bignum input, struct RSAKey *key, strbuf *outbuf) } /* Everything else is the payload */ - success = TRUE; + success = true; put_data(outbuf, get_ptr(src), get_avail(src)); out: diff --git a/sshserver.c b/sshserver.c index 9c3963e1..f12ec5cd 100644 --- a/sshserver.c +++ b/sshserver.c @@ -74,7 +74,7 @@ void share_setup_x11_channel(ssh_sharing_connstate *cs, share_channel *chan, int protomajor, int protominor, const void *initial_data, int initial_len) {} Channel *agentf_new(SshChannel *c) { return NULL; } -int agent_exists(void) { return FALSE; } +int agent_exists(void) { return false; } void ssh_got_exitcode(Ssh *ssh, int exitcode) {} mainchan *mainchan_new( @@ -128,7 +128,7 @@ static void server_closing(Plug *plug, const char *error_msg, int error_code, if (error_msg) { ssh_remote_error(&srv->ssh, "Network error: %s", error_msg); } else if (srv->bpp) { - srv->bpp->input_eof = TRUE; + srv->bpp->input_eof = true; queue_idempotent_callback(&srv->bpp->ic_in_raw); } } @@ -181,9 +181,9 @@ void ssh_throttle_conn(Ssh *ssh, int adjust) assert(srv->conn_throttle_count >= 0); if (srv->conn_throttle_count && !old_count) { - frozen = TRUE; + frozen = true; } else if (!srv->conn_throttle_count && old_count) { - frozen = FALSE; + frozen = false; } else { return; /* don't change current frozen state */ } @@ -221,7 +221,7 @@ Plug *ssh_server_plug( srv->plug.vt = &ssh_server_plugvt; srv->conf = conf_copy(conf); srv->logctx = log_init(logpolicy, conf); - conf_set_int(srv->conf, CONF_ssh_no_shell, TRUE); + conf_set_int(srv->conf, CONF_ssh_no_shell, true); srv->nhostkeys = nhostkeys; srv->hostkeys = hostkeys; srv->hostkey1 = hostkey1; @@ -261,9 +261,9 @@ void ssh_server_start(Plug *plug, Socket *socket) srv->ic_out_raw.ctx = srv; srv->version_receiver.got_ssh_version = server_got_ssh_version; srv->bpp = ssh_verstring_new( - srv->conf, srv->logctx, FALSE /* bare_connection */, + srv->conf, srv->logctx, false /* bare_connection */, our_protoversion, &srv->version_receiver, - TRUE, "Uppity"); + true, "Uppity"); server_connect_bpp(srv); queue_idempotent_callback(&srv->bpp->ic_in_raw); } @@ -304,7 +304,7 @@ static void server_connect_bpp(server *srv) srv->bpp->remote_bugs = srv->remote_bugs; /* Servers don't really have a notion of 'unexpected' connection * closure. The client is free to close if it likes. */ - srv->bpp->expect_close = TRUE; + srv->bpp->expect_close = true; } static void server_connect_ppl(server *srv, PacketProtocolLayer *ppl) @@ -409,11 +409,11 @@ static void server_got_ssh_version(struct ssh_version_receiver *rcv, if (major_version == 2) { PacketProtocolLayer *userauth_layer, *transport_child_layer; - srv->bpp = ssh2_bpp_new(srv->logctx, &srv->stats, TRUE); + srv->bpp = ssh2_bpp_new(srv->logctx, &srv->stats, true); server_connect_bpp(srv); connection_layer = ssh2_connection_new( - &srv->ssh, NULL, FALSE, srv->conf, + &srv->ssh, NULL, false, srv->conf, ssh_verstring_get_local(old_bpp), &srv->cl); ssh2connection_server_configure(connection_layer, srv->sftpserver_vt); server_connect_ppl(srv, connection_layer); @@ -432,7 +432,7 @@ static void server_got_ssh_version(struct ssh_version_receiver *rcv, srv->conf, NULL, 0, NULL, ssh_verstring_get_remote(old_bpp), ssh_verstring_get_local(old_bpp), - &srv->gss_state, &srv->stats, transport_child_layer, TRUE); + &srv->gss_state, &srv->stats, transport_child_layer, true); ssh2_transport_provide_hostkeys( srv->base_layer, srv->hostkeys, srv->nhostkeys); if (userauth_layer) diff --git a/sshserver.h b/sshserver.h index 846c40c5..348004ed 100644 --- a/sshserver.h +++ b/sshserver.h @@ -63,7 +63,7 @@ int auth_ssh1int_response(AuthPolicy *, ptrlen response); struct RSAKey *auth_publickey_ssh1( AuthPolicy *ap, ptrlen username, Bignum rsa_modulus); -/* auth_successful returns FALSE if further authentication is needed */ +/* auth_successful returns false if further authentication is needed */ int auth_successful(AuthPolicy *, ptrlen username, unsigned method); PacketProtocolLayer *ssh2_userauth_server_new( diff --git a/sshshare.c b/sshshare.c index c964de13..227f213a 100644 --- a/sshshare.c +++ b/sshshare.c @@ -631,7 +631,7 @@ static struct share_xchannel *share_add_xchannel struct share_xchannel *xc = snew(struct share_xchannel); xc->upstream_id = upstream_id; xc->server_id = server_id; - xc->live = TRUE; + xc->live = true; xc->msghead = xc->msgtail = NULL; if (add234(cs->xchannels_by_us, xc) != xc) { sfree(xc); @@ -676,7 +676,7 @@ static struct share_forwarding *share_add_forwarding struct share_forwarding *fwd = snew(struct share_forwarding); fwd->host = dupstr(host); fwd->port = port; - fwd->active = FALSE; + fwd->active = false; if (add234(cs->forwardings, fwd) != fwd) { /* Duplicate?! */ sfree(fwd); @@ -875,7 +875,7 @@ static void share_try_cleanup(struct ssh_sharing_connstate *cs) if (fwd->active) { strbuf *packet = strbuf_new(); put_stringz(packet, "cancel-tcpip-forward"); - put_bool(packet, FALSE); /* !want_reply */ + put_bool(packet, false); /* !want_reply */ put_stringz(packet, fwd->host); put_uint32(packet, fwd->port); ssh_send_packet_from_downstream( @@ -997,7 +997,7 @@ void share_dead_xchannel_respond(struct ssh_sharing_connstate *cs, * Handle queued incoming messages from the server destined for an * xchannel which is dead (i.e. downstream sent OPEN_FAILURE). */ - int delete = FALSE; + int delete = false; while (xc->msghead) { struct share_xchannel_message *msg = xc->msghead; xc->msghead = msg->next; @@ -1024,7 +1024,7 @@ void share_dead_xchannel_respond(struct ssh_sharing_connstate *cs, /* * On CHANNEL_CLOSE we can discard the channel completely. */ - delete = TRUE; + delete = true; } sfree(msg); @@ -1092,7 +1092,7 @@ void share_xchannel_failure(struct ssh_sharing_connstate *cs, * Now mark the xchannel as dead, and respond to anything sent on * it until we see CLOSE for it in turn. */ - xc->live = FALSE; + xc->live = false; share_dead_xchannel_respond(cs, xc); } @@ -1183,7 +1183,7 @@ void share_got_pkt_from_server(ssh_sharing_connstate *cs, int type, if (type == SSH2_MSG_REQUEST_FAILURE) { share_remove_forwarding(cs, globreq->fwd); } else { - globreq->fwd->active = TRUE; + globreq->fwd->active = true; } } else if (globreq->type == GLOBREQ_CANCEL_TCPIP_FORWARD) { if (type == SSH2_MSG_REQUEST_SUCCESS) { @@ -1795,7 +1795,7 @@ static void share_receive(Plug *plug, int urgent, char *data, int len) cs->recvlen--; /* trim off \r before \n */ log_downstream(cs, "Downstream version string: %.*s", cs->recvlen, cs->recvbuf); - cs->got_verstring = TRUE; + cs->got_verstring = true; /* * Loop round reading packets. @@ -1861,7 +1861,7 @@ static void share_send_verstring(ssh_sharing_connstate *cs) sk_write(cs->sock, fullstring, strlen(fullstring)); sfree(fullstring); - cs->sent_verstring = TRUE; + cs->sent_verstring = true; } int share_ndownstreams(ssh_sharing_state *sharestate) @@ -1942,11 +1942,11 @@ static int share_listen_accepting(Plug *plug, add234(cs->parent->connections, cs); - cs->sent_verstring = FALSE; + cs->sent_verstring = false; if (sharestate->server_verstring) share_send_verstring(cs); - cs->got_verstring = FALSE; + cs->got_verstring = false; cs->recvlen = 0; cs->crLine = 0; cs->halfchannels = newtree234(share_halfchannel_cmp); @@ -2026,7 +2026,7 @@ int ssh_share_test_for_upstream(const char *host, int port, Conf *conf) sock = NULL; logtext = ds_err = us_err = NULL; result = platform_ssh_share(sockname, conf, nullplug, (Plug *)NULL, &sock, - &logtext, &ds_err, &us_err, FALSE, TRUE); + &logtext, &ds_err, &us_err, false, true); sfree(logtext); sfree(ds_err); @@ -2035,11 +2035,11 @@ int ssh_share_test_for_upstream(const char *host, int port, Conf *conf) if (result == SHARE_NONE) { assert(sock == NULL); - return FALSE; + return false; } else { assert(result == SHARE_DOWNSTREAM); sk_close(sock); - return TRUE; + return true; } } diff --git a/sshverstring.c b/sshverstring.c index 758c9e15..578ee99f 100644 --- a/sshverstring.c +++ b/sshverstring.c @@ -265,7 +265,7 @@ void ssh_verstring_handle_input(BinaryPacketProtocol *bpp) } } - s->found_prefix = TRUE; + s->found_prefix = true; /* * Start a buffer to store the full greeting line. diff --git a/sshzlib.c b/sshzlib.c index d0cbef8f..ae3e28d2 100644 --- a/sshzlib.c +++ b/sshzlib.c @@ -59,13 +59,6 @@ #define sresize(x, n, type) ( (type *) realloc((x), (n) * sizeof(type)) ) #define sfree(x) ( free((x)) ) -#ifndef FALSE -#define FALSE 0 -#endif -#ifndef TRUE -#define TRUE 1 -#endif - typedef struct { const struct dummy *vt; } ssh_compressor; typedef struct { const struct dummy *vt; } ssh_decompressor; static const struct dummy { int i; } ssh_zlib; @@ -97,7 +90,7 @@ static int lz77_init(struct LZ77Context *ctx); /* * Supply data to be compressed. Will update the private fields of * the LZ77Context, and will call literal() and match() to output. - * If `compress' is FALSE, it will never emit a match, but will + * If `compress' is false, it will never emit a match, but will * instead call literal() for everything. */ static void lz77_compress(struct LZ77Context *ctx, @@ -657,9 +650,9 @@ void zlib_compress_block(ssh_compressor *sc, unsigned char *block, int len, outbits(out, 0x9C78, 16); out->firstblock = 0; - in_block = FALSE; + in_block = false; } else - in_block = TRUE; + in_block = true; if (!in_block) { /* @@ -674,7 +667,7 @@ void zlib_compress_block(ssh_compressor *sc, unsigned char *block, int len, /* * Do the compression. */ - lz77_compress(&comp->ectx, block, len, TRUE); + lz77_compress(&comp->ectx, block, len, true); /* * End the block (by transmitting code 256, which is @@ -1235,7 +1228,7 @@ int main(int argc, char **argv) unsigned char buf[16], *outbuf; int ret, outlen; ssh_decompressor *handle; - int noheader = FALSE, opts = TRUE; + int noheader = false, opts = true; char *filename = NULL; FILE *fp; @@ -1244,9 +1237,9 @@ int main(int argc, char **argv) if (p[0] == '-' && opts) { if (!strcmp(p, "-d")) - noheader = TRUE; + noheader = true; else if (!strcmp(p, "--")) - opts = FALSE; /* next thing is filename */ + opts = false; /* next thing is filename */ else { fprintf(stderr, "unknown command line option '%s'\n", p); return 1; diff --git a/telnet.c b/telnet.c index bdb24e2f..5c7baa93 100644 --- a/telnet.c +++ b/telnet.c @@ -271,7 +271,7 @@ static void option_side_effects(Telnet *telnet, const struct Opt *o, int enabled telnet->opt_states[o_they_sga.index] = REQUESTED; send_opt(telnet, o_they_sga.send, o_they_sga.option); } - telnet->activated = TRUE; + telnet->activated = true; } } @@ -647,7 +647,7 @@ static void telnet_closing(Plug *plug, const char *error_msg, int error_code, sk_close(telnet->s); telnet->s = NULL; if (error_msg) - telnet->closed_on_socket_error = TRUE; + telnet->closed_on_socket_error = true; seat_notify_remote_exit(telnet->seat); } if (error_msg) { @@ -661,8 +661,8 @@ static void telnet_receive(Plug *plug, int urgent, char *data, int len) { Telnet *telnet = container_of(plug, Telnet, plug); if (urgent) - telnet->in_synch = TRUE; - telnet->session_started = TRUE; + telnet->in_synch = true; + telnet->session_started = true; do_telnet_read(telnet, data, len); } @@ -703,10 +703,10 @@ static const char *telnet_init(Seat *seat, Backend **backend_handle, telnet->backend.vt = &telnet_backend; telnet->conf = conf_copy(conf); telnet->s = NULL; - telnet->closed_on_socket_error = FALSE; - telnet->echoing = TRUE; - telnet->editing = TRUE; - telnet->activated = FALSE; + telnet->closed_on_socket_error = false; + telnet->echoing = true; + telnet->editing = true; + telnet->activated = false; telnet->sb_buf = NULL; telnet->sb_size = 0; telnet->seat = seat; @@ -716,7 +716,7 @@ static const char *telnet_init(Seat *seat, Backend **backend_handle, telnet->state = TOP_LEVEL; telnet->ldisc = NULL; telnet->pinger = NULL; - telnet->session_started = TRUE; + telnet->session_started = true; *backend_handle = &telnet->backend; /* @@ -759,13 +759,13 @@ static const char *telnet_init(Seat *seat, Backend **backend_handle, if (telnet->opt_states[(*o)->index] == REQUESTED) send_opt(telnet, (*o)->send, (*o)->option); } - telnet->activated = TRUE; + telnet->activated = true; } /* * Set up SYNCH state. */ - telnet->in_synch = FALSE; + telnet->in_synch = false; /* * We can send special commands from the start. @@ -1025,7 +1025,7 @@ static int telnet_ldisc(Backend *be, int option) return telnet->echoing; if (option == LD_EDIT) return telnet->editing; - return FALSE; + return false; } static void telnet_provide_ldisc(Backend *be, Ldisc *ldisc) diff --git a/terminal.c b/terminal.c index 6708c61a..ff39968d 100644 --- a/terminal.c +++ b/terminal.c @@ -122,7 +122,7 @@ static termline *newline(Terminal *term, int cols, int bce) line->chars[j] = (bce ? term->erase_char : term->basic_erase_char); line->cols = line->size = cols; line->lattr = LATTR_NORM; - line->temporary = FALSE; + line->temporary = false; line->cc_free = 0; return line; @@ -168,7 +168,7 @@ static void cc_check(termline *line) j += line->chars[j].cc_next; assert(j >= line->cols && j < line->size); assert(!flags[j]); - flags[j] = TRUE; + flags[j] = true; } } @@ -177,7 +177,7 @@ static void cc_check(termline *line) while (1) { assert(j >= line->cols && j < line->size); assert(!flags[j]); - flags[j] = TRUE; + flags[j] = true; if (line->chars[j].cc_next) j += line->chars[j].cc_next; else @@ -283,20 +283,20 @@ static int termchars_equal_override(termchar *a, termchar *b, { /* FULL-TERMCHAR */ if (!truecolour_equal(a->truecolour, b->truecolour)) - return FALSE; + return false; if (a->chr != bchr) - return FALSE; + return false; if ((a->attr &~ DATTR_MASK) != (battr &~ DATTR_MASK)) - return FALSE; + return false; while (a->cc_next || b->cc_next) { if (!a->cc_next || !b->cc_next) - return FALSE; /* one cc-list ends, other does not */ + return false; /* one cc-list ends, other does not */ a += a->cc_next; b += b->cc_next; if (a->chr != b->chr) - return FALSE; + return false; } - return TRUE; + return true; } static int termchars_equal(termchar *a, termchar *b) @@ -385,7 +385,7 @@ static void makerle(struct buf *b, termline *ldata, hdrsize = 0; add(b, 0); prevlen = prevpos = 0; - prev2 = FALSE; + prev2 = false; while (n-- > 0) { thispos = b->len; @@ -461,7 +461,7 @@ static void makerle(struct buf *b, termline *ldata, add(b, 0); /* And ensure this run doesn't interfere with the next. */ prevlen = prevpos = 0; - prev2 = FALSE; + prev2 = false; continue; } else { @@ -470,12 +470,12 @@ static void makerle(struct buf *b, termline *ldata, * identical, in case we find a third identical one * we want to turn into a run. */ - prev2 = TRUE; + prev2 = true; prevlen = thislen; prevpos = thispos; } } else { - prev2 = FALSE; + prev2 = false; prevlen = thislen; prevpos = thispos; } @@ -491,7 +491,7 @@ static void makerle(struct buf *b, termline *ldata, hdrsize = 0; add(b, 0); prevlen = prevpos = 0; - prev2 = FALSE; + prev2 = false; } } @@ -852,7 +852,7 @@ static void readliteral_truecolour(struct buf *b, termchar *c, termline *ldata, int flags = get(b); if (flags & 1) { - c->truecolour.fg.enabled = TRUE; + c->truecolour.fg.enabled = true; c->truecolour.fg.r = get(b); c->truecolour.fg.g = get(b); c->truecolour.fg.b = get(b); @@ -861,7 +861,7 @@ static void readliteral_truecolour(struct buf *b, termchar *c, termline *ldata, } if (flags & 2) { - c->truecolour.bg.enabled = TRUE; + c->truecolour.bg.enabled = true; c->truecolour.bg.r = get(b); c->truecolour.bg.g = get(b); c->truecolour.bg.b = get(b); @@ -912,7 +912,7 @@ static termline *decompressline(unsigned char *data, int *bytes_used) ldata = snew(termline); ldata->chars = snewn(ncols, termchar); ldata->cols = ldata->size = ncols; - ldata->temporary = TRUE; + ldata->temporary = true; ldata->cc_free = 0; /* @@ -1132,8 +1132,8 @@ static termline *lineptr(Terminal *term, int y, int lineno, int screen) return line; } -#define lineptr(x) (lineptr)(term,x,__LINE__,FALSE) -#define scrlineptr(x) (lineptr)(term,x,__LINE__,TRUE) +#define lineptr(x) (lineptr)(term,x,__LINE__,false) +#define scrlineptr(x) (lineptr)(term,x,__LINE__,true) /* * Coerce a termline to the terminal's current width. Unlike the @@ -1157,25 +1157,25 @@ static void term_schedule_cblink(Terminal *term); static void term_timer(void *ctx, unsigned long now) { Terminal *term = (Terminal *)ctx; - int update = FALSE; + int update = false; if (term->tblink_pending && now == term->next_tblink) { term->tblinker = !term->tblinker; - term->tblink_pending = FALSE; + term->tblink_pending = false; term_schedule_tblink(term); - update = TRUE; + update = true; } if (term->cblink_pending && now == term->next_cblink) { term->cblinker = !term->cblinker; - term->cblink_pending = FALSE; + term->cblink_pending = false; term_schedule_cblink(term); - update = TRUE; + update = true; } if (term->in_vbell && now == term->vbell_end) { - term->in_vbell = FALSE; - update = TRUE; + term->in_vbell = false; + update = true; } if (update || @@ -1186,7 +1186,7 @@ static void term_timer(void *ctx, unsigned long now) static void term_schedule_update(Terminal *term) { if (!term->window_update_pending) { - term->window_update_pending = TRUE; + term->window_update_pending = true; term->next_update = schedule_timer(UPDATE_DELAY, term_timer, term); } } @@ -1197,7 +1197,7 @@ static void term_schedule_update(Terminal *term) */ static void seen_disp_event(Terminal *term) { - term->seen_disp_event = TRUE; /* for scrollback-reset-on-activity */ + term->seen_disp_event = true; /* for scrollback-reset-on-activity */ term_schedule_update(term); } @@ -1210,10 +1210,10 @@ static void term_schedule_tblink(Terminal *term) if (term->blink_is_real) { if (!term->tblink_pending) term->next_tblink = schedule_timer(TBLINK_DELAY, term_timer, term); - term->tblink_pending = TRUE; + term->tblink_pending = true; } else { term->tblinker = 1; /* reset when not in use */ - term->tblink_pending = FALSE; + term->tblink_pending = false; } } @@ -1225,10 +1225,10 @@ static void term_schedule_cblink(Terminal *term) if (term->blink_cur && term->has_focus) { if (!term->cblink_pending) term->next_cblink = schedule_timer(CBLINK_DELAY, term_timer, term); - term->cblink_pending = TRUE; + term->cblink_pending = true; } else { term->cblinker = 1; /* reset when not in use */ - term->cblink_pending = FALSE; + term->cblink_pending = false; } } @@ -1239,7 +1239,7 @@ static void term_reset_cblink(Terminal *term) { seen_disp_event(term); term->cblinker = 1; - term->cblink_pending = FALSE; + term->cblink_pending = false; term_schedule_cblink(term); } @@ -1257,11 +1257,11 @@ static void term_schedule_vbell(Terminal *term, int already_started, ticks_already_gone = 0; if (ticks_already_gone < VBELL_DELAY) { - term->in_vbell = TRUE; + term->in_vbell = true; term->vbell_end = schedule_timer(VBELL_DELAY - ticks_already_gone, term_timer, term); } else { - term->in_vbell = FALSE; + term->in_vbell = false; } } @@ -1284,12 +1284,12 @@ static void power_on(Terminal *term, int clear) if (term->cols != -1) { int i; for (i = 0; i < term->cols; i++) - term->tabs[i] = (i % 8 == 0 ? TRUE : FALSE); + term->tabs[i] = (i % 8 == 0 ? true : false); } term->alt_om = term->dec_om = conf_get_int(term->conf, CONF_dec_om); - term->alt_ins = term->insert = FALSE; + term->alt_ins = term->insert = false; term->alt_wnext = term->wrapnext = - term->save_wnext = term->alt_save_wnext = FALSE; + term->save_wnext = term->alt_save_wnext = false; term->alt_wrap = term->wrap = conf_get_int(term->conf, CONF_wrap_mode); term->alt_cset = term->cset = term->save_cset = term->alt_save_cset = 0; term->alt_utf = term->utf = term->save_utf = term->alt_save_utf = 0; @@ -1299,14 +1299,14 @@ static void power_on(Terminal *term, int clear) term->cset_attr[0] = term->cset_attr[1] = term->save_csattr = term->alt_save_csattr = CSET_ASCII; term->rvideo = 0; - term->in_vbell = FALSE; + term->in_vbell = false; term->cursor_on = 1; term->big_cursor = 0; term->default_attr = term->save_attr = term->alt_save_attr = term->curr_attr = ATTR_DEFAULT; term->curr_truecolour.fg = term->curr_truecolour.bg = optionalrgb_none; term->save_truecolour = term->alt_save_truecolour = term->curr_truecolour; - term->term_editing = term->term_echoing = FALSE; + term->term_editing = term->term_echoing = false; term->app_cursor_keys = conf_get_int(term->conf, CONF_app_cursor); term->app_keypad_keys = conf_get_int(term->conf, CONF_app_keypad); term->use_bce = conf_get_int(term->conf, CONF_bce); @@ -1317,23 +1317,23 @@ static void power_on(Terminal *term, int clear) term->xterm_mouse = 0; term->xterm_extended_mouse = 0; term->urxvt_extended_mouse = 0; - win_set_raw_mouse_mode(term->win, FALSE); - term->bracketed_paste = FALSE; + win_set_raw_mouse_mode(term->win, false); + term->bracketed_paste = false; { int i; for (i = 0; i < 256; i++) term->wordness[i] = conf_get_int_int(term->conf, CONF_wordness, i); } if (term->screen) { - swap_screen(term, 1, FALSE, FALSE); - erase_lots(term, FALSE, TRUE, TRUE); - swap_screen(term, 0, FALSE, FALSE); + swap_screen(term, 1, false, false); + erase_lots(term, false, true, true); + swap_screen(term, 0, false, false); if (clear) - erase_lots(term, FALSE, TRUE, TRUE); + erase_lots(term, false, true, true); term->curs.y = find_last_nonempty_line(term, term->screen) + 1; if (term->curs.y == term->rows) { term->curs.y--; - scroll(term, 0, term->rows - 1, 1, TRUE); + scroll(term, 0, term->rows - 1, 1, true); } } else { term->curs.y = 0; @@ -1348,14 +1348,14 @@ static void power_on(Terminal *term, int clear) */ void term_update(Terminal *term) { - term->window_update_pending = FALSE; + term->window_update_pending = false; if (win_setup_draw_ctx(term->win)) { int need_sbar_update = term->seen_disp_event; if (term->seen_disp_event && term->scroll_on_disp) { term->disptop = 0; /* return to main screen */ term->seen_disp_event = 0; - need_sbar_update = TRUE; + need_sbar_update = true; } if (need_sbar_update) @@ -1380,7 +1380,7 @@ void term_seen_key_event(Terminal *term) * to be intended (e.g. beeps from filename completion * blocking repeatedly). */ - term->beep_overloaded = FALSE; + term->beep_overloaded = false; while (term->beephead) { struct beeptime *tmp = term->beephead; term->beephead = tmp->next; @@ -1563,7 +1563,7 @@ void term_reconfig(Terminal *term, Conf *conf) term->wordness[i] = conf_get_int_int(term->conf, CONF_wordness, i); if (conf_get_int(term->conf, CONF_no_alt_screen)) - swap_screen(term, 0, FALSE, FALSE); + swap_screen(term, 0, false, false); if (conf_get_int(term->conf, CONF_no_mouse_rep)) { term->xterm_mouse = 0; win_set_raw_mouse_mode(term->win, 0); @@ -1648,21 +1648,21 @@ Terminal *term_init(Conf *myconf, struct unicode_data *ucsdata, TermWin *win) term->logctx = NULL; term->compatibility_level = TM_PUTTY; strcpy(term->id_string, "\033[?6c"); - term->cblink_pending = term->tblink_pending = FALSE; + term->cblink_pending = term->tblink_pending = false; term->paste_buffer = NULL; term->paste_len = 0; bufchain_init(&term->inbuf); bufchain_init(&term->printer_buf); - term->printing = term->only_printing = FALSE; + term->printing = term->only_printing = false; term->print_job = NULL; - term->vt52_mode = FALSE; - term->cr_lf_return = FALSE; - term->seen_disp_event = FALSE; - term->mouse_is_down = FALSE; - term->reset_132 = FALSE; + term->vt52_mode = false; + term->cr_lf_return = false; + term->seen_disp_event = false; + term->mouse_is_down = false; + term->reset_132 = false; term->cblinker = term->tblinker = 0; term->has_focus = 1; - term->repeat_off = FALSE; + term->repeat_off = false; term->termstate = TOPLEVEL; term->selstate = NO_SELECTION; term->curstype = 0; @@ -1678,21 +1678,21 @@ Terminal *term_init(Conf *myconf, struct unicode_data *ucsdata, TermWin *win) term->tabs = NULL; deselect(term); term->rows = term->cols = -1; - power_on(term, TRUE); + power_on(term, true); term->beephead = term->beeptail = NULL; term->nbeeps = 0; - term->lastbeep = FALSE; - term->beep_overloaded = FALSE; + term->lastbeep = false; + term->beep_overloaded = false; term->attr_mask = 0xffffffff; term->backend = NULL; - term->in_term_out = FALSE; + term->in_term_out = false; term->ltemp = NULL; term->ltemp_size = 0; term->wcFrom = NULL; term->wcTo = NULL; term->wcFromTo_size = 0; - term->window_update_pending = FALSE; + term->window_update_pending = false; term->bidi_cache_size = 0; term->pre_bidi_cache = term->post_bidi_cache = NULL; @@ -1792,7 +1792,7 @@ void term_size(Terminal *term, int newrows, int newcols, int newsavelines) if (newcols < 1) newcols = 1; deselect(term); - swap_screen(term, 0, FALSE, FALSE); + swap_screen(term, 0, false, false); term->alt_t = term->marg_t = 0; term->alt_b = term->marg_b = newrows - 1; @@ -1834,7 +1834,7 @@ void term_size(Terminal *term, int newrows, int newcols, int newsavelines) cline = delpos234(term->scrollback, --sblen); line = decompressline(cline, NULL); sfree(cline); - line->temporary = FALSE; /* reconstituted line is now real */ + line->temporary = false; /* reconstituted line is now real */ term->tempsblines -= 1; addpos234(term->screen, line, 0); term->curs.y += 1; @@ -1843,7 +1843,7 @@ void term_size(Terminal *term, int newrows, int newcols, int newsavelines) term->alt_savecurs.y += 1; } else { /* Add a new blank line at the bottom of the screen. */ - line = newline(term, newcols, FALSE); + line = newline(term, newcols, false); addpos234(term->screen, line, count234(term->screen)); } term->rows += 1; @@ -1885,7 +1885,7 @@ void term_size(Terminal *term, int newrows, int newcols, int newsavelines) /* Make a new displayed text buffer. */ newdisp = snewn(newrows, termline *); for (i = 0; i < newrows; i++) { - newdisp[i] = newline(term, newcols, FALSE); + newdisp[i] = newline(term, newcols, false); for (j = 0; j < newcols; j++) newdisp[i]->chars[j].attr = ATTR_INVALID; } @@ -1900,7 +1900,7 @@ void term_size(Terminal *term, int newrows, int newcols, int newsavelines) /* Make a new alternate screen. */ newalt = newtree234(NULL); for (i = 0; i < newrows; i++) { - line = newline(term, newcols, TRUE); + line = newline(term, newcols, true); addpos234(newalt, line, i); } if (term->alt_screen) { @@ -1915,7 +1915,7 @@ void term_size(Terminal *term, int newrows, int newcols, int newsavelines) { int i; for (i = (term->cols > 0 ? term->cols : 0); i < newcols; i++) - term->tabs[i] = (i % 8 == 0 ? TRUE : FALSE); + term->tabs[i] = (i % 8 == 0 ? true : false); } /* Check that the cursor positions are still valid. */ @@ -1944,13 +1944,13 @@ void term_size(Terminal *term, int newrows, int newcols, int newsavelines) if (term->alt_x >= newcols) term->alt_x = newcols - 1; term->alt_x = term->alt_y = 0; - term->wrapnext = term->alt_wnext = FALSE; + term->wrapnext = term->alt_wnext = false; term->rows = newrows; term->cols = newcols; term->savelines = newsavelines; - swap_screen(term, save_alt_which, FALSE, FALSE); + swap_screen(term, save_alt_which, false, false); update_sbar(term); term_update(term); @@ -1987,7 +1987,7 @@ static int find_last_nonempty_line(Terminal * term, tree234 * screen) } /* - * Swap screens. If `reset' is TRUE and we have been asked to + * Swap screens. If `reset' is true and we have been asked to * switch to the alternate screen, we must bring most of its * configuration from the main screen and erase the contents of the * alternate screen completely. (This is even true if we're already @@ -2001,7 +2001,7 @@ static void swap_screen(Terminal *term, int which, int reset, int keep_cur_pos) tree234 *ttr; if (!which) - reset = FALSE; /* do no weird resetting if which==0 */ + reset = false; /* do no weird resetting if which==0 */ if (which != term->alt_which) { term->alt_which = which; @@ -2084,7 +2084,7 @@ static void swap_screen(Terminal *term, int which, int reset, int keep_cur_pos) /* * Yes, this _is_ supposed to honour background-colour-erase. */ - erase_lots(term, FALSE, TRUE, TRUE); + erase_lots(term, false, true, true); } } @@ -2110,7 +2110,7 @@ static void check_selection(Terminal *term, pos from, pos to) /* * Scroll the screen. (`lines' is +ve for scrolling forward, -ve - * for backward.) `sb' is TRUE if the scrolling is permitted to + * for backward.) `sb' is true if the scrolling is permitted to * affect the scrollback buffer. */ static void scroll(Terminal *term, int topline, int botline, int lines, int sb) @@ -2119,7 +2119,7 @@ static void scroll(Terminal *term, int topline, int botline, int lines, int sb) int i, seltop, scrollwinsize; if (topline != 0 || term->alt_which != 0) - sb = FALSE; + sb = false; scrollwinsize = botline - topline + 1; @@ -2269,7 +2269,7 @@ static void move(Terminal *term, int x, int y, int marg_clip) y = term->rows - 1; term->curs.x = x; term->curs.y = y; - term->wrapnext = FALSE; + term->wrapnext = false; } /* @@ -2304,7 +2304,7 @@ static void save_cursor(Terminal *term, int save) * longer at the rightmost edge. */ if (term->wrapnext && term->curs.x < term->cols-1) - term->wrapnext = FALSE; + term->wrapnext = false; term->cset_attr[term->cset] = term->save_csattr; term->sco_acs = term->save_sco_acs; set_erase_char(term); @@ -2368,13 +2368,13 @@ static void erase_lots(Terminal *term, start.x = 0; end.y = term->curs.y + 1; end.x = 0; - erase_lattr = FALSE; + erase_lattr = false; } else { start.y = 0; start.x = 0; end.y = term->rows; end.x = 0; - erase_lattr = TRUE; + erase_lattr = true; } if (!from_begin) { start = term->curs; @@ -2406,7 +2406,7 @@ static void erase_lots(Terminal *term, scrolllines = find_last_nonempty_line(term, term->screen) + 1; } if (scrolllines > 0) - scroll(term, 0, scrolllines - 1, scrolllines, TRUE); + scroll(term, 0, scrolllines - 1, scrolllines, true); } else { termline *ldata = scrlineptr(start.y); while (poslt(start, end)) { @@ -2520,8 +2520,8 @@ static void toggle_mode(Terminal *term, int mode, int query, int state) case 2: /* DECANM: VT52 mode */ term->vt52_mode = !state; if (term->vt52_mode) { - term->blink_is_real = FALSE; - term->vt52_bold = FALSE; + term->blink_is_real = false; + term->vt52_bold = false; } else { term->blink_is_real = term->blinktext; } @@ -2535,7 +2535,7 @@ static void toggle_mode(Terminal *term, int mode, int query, int state) term->alt_t = term->marg_t = 0; term->alt_b = term->marg_b = term->rows - 1; move(term, 0, 0, 0); - erase_lots(term, FALSE, TRUE, TRUE); + erase_lots(term, false, true, true); break; case 5: /* DECSCNM: reverse video */ /* @@ -2546,7 +2546,7 @@ static void toggle_mode(Terminal *term, int mode, int query, int state) */ if (term->rvideo && !state) { /* This is an OFF, so set up a vbell */ - term_schedule_vbell(term, TRUE, term->rvbell_startpoint); + term_schedule_vbell(term, true, term->rvbell_startpoint); } else if (!term->rvideo && state) { /* This is an ON, so we notice the time and save it. */ term->rvbell_startpoint = GETTICKCOUNT(); @@ -2576,7 +2576,7 @@ static void toggle_mode(Terminal *term, int mode, int query, int state) case 47: /* alternate screen */ compatibility(OTHER); deselect(term); - swap_screen(term, term->no_alt_screen ? 0 : state, FALSE, FALSE); + swap_screen(term, term->no_alt_screen ? 0 : state, false, false); if (term->scroll_on_disp) term->disptop = 0; break; @@ -2597,7 +2597,7 @@ static void toggle_mode(Terminal *term, int mode, int query, int state) case 1047: /* alternate screen */ compatibility(OTHER); deselect(term); - swap_screen(term, term->no_alt_screen ? 0 : state, TRUE, TRUE); + swap_screen(term, term->no_alt_screen ? 0 : state, true, true); if (term->scroll_on_disp) term->disptop = 0; break; @@ -2612,14 +2612,14 @@ static void toggle_mode(Terminal *term, int mode, int query, int state) if (!state) seen_disp_event(term); compatibility(OTHER); deselect(term); - swap_screen(term, term->no_alt_screen ? 0 : state, TRUE, FALSE); + swap_screen(term, term->no_alt_screen ? 0 : state, true, false); if (!state && !term->no_alt_screen) save_cursor(term, state); if (term->scroll_on_disp) term->disptop = 0; break; case 2004: /* xterm bracketed paste */ - term->bracketed_paste = state ? TRUE : FALSE; + term->bracketed_paste = state ? true : false; break; } else switch (mode) { @@ -2729,7 +2729,7 @@ static void term_print_finish(Terminal *term) } printer_finish_job(term->print_job); term->print_job = NULL; - term->printing = term->only_printing = FALSE; + term->printing = term->only_printing = false; } static void term_display_graphic_char(Terminal *term, unsigned long c) @@ -2746,11 +2746,11 @@ static void term_display_graphic_char(Terminal *term, unsigned long c) if (term->wrapnext && term->wrap && width > 0) { cline->lattr |= LATTR_WRAPPED; if (term->curs.y == term->marg_b) - scroll(term, term->marg_t, term->marg_b, 1, TRUE); + scroll(term, term->marg_t, term->marg_b, 1, true); else if (term->curs.y < term->rows - 1) term->curs.y++; term->curs.x = 0; - term->wrapnext = FALSE; + term->wrapnext = false; cline = scrlineptr(term->curs.y); } if (term->insert && width > 0) @@ -2788,7 +2788,7 @@ static void term_display_graphic_char(Terminal *term, unsigned long c) cline->lattr |= LATTR_WRAPPED | LATTR_WRAPPED2; if (term->curs.y == term->marg_b) scroll(term, term->marg_t, term->marg_b, - 1, TRUE); + 1, true); else if (term->curs.y < term->rows - 1) term->curs.y++; term->curs.x = 0; @@ -2855,15 +2855,15 @@ static void term_display_graphic_char(Terminal *term, unsigned long c) term->curs.x++; if (term->curs.x == term->cols) { term->curs.x--; - term->wrapnext = TRUE; + term->wrapnext = true; if (term->wrap && term->vt52_mode) { cline->lattr |= LATTR_WRAPPED; if (term->curs.y == term->marg_b) - scroll(term, term->marg_t, term->marg_b, 1, TRUE); + scroll(term, term->marg_t, term->marg_b, 1, true); else if (term->curs.y < term->rows - 1) term->curs.y++; term->curs.x = 0; - term->wrapnext = FALSE; + term->wrapnext = false; } } seen_disp_event(term); @@ -3088,7 +3088,7 @@ static void term_out(Terminal *term) c = 0; else { term->termstate = SEEN_ESC; - term->esc_query = FALSE; + term->esc_query = false; c = '@' + (c & 0x1F); } } @@ -3097,7 +3097,7 @@ static void term_out(Terminal *term) if (c == '\177' && term->termstate < DO_CTRLS && has_compat(OTHER)) { if (term->curs.x && !term->wrapnext) term->curs.x--; - term->wrapnext = FALSE; + term->wrapnext = false; /* destructive backspace might be disabled */ if (!term->no_dbackspace) { check_boundary(term, term->curs.x, term->curs.y); @@ -3163,7 +3163,7 @@ static void term_out(Terminal *term) * last beep was more than s seconds ago, * leave overload mode. */ - term->beep_overloaded = FALSE; + term->beep_overloaded = false; } else if (term->bellovl && !term->beep_overloaded && term->nbeeps >= term->bellovl_n) { /* @@ -3171,7 +3171,7 @@ static void term_out(Terminal *term) * remaining in the queue, go into overload * mode. */ - term->beep_overloaded = TRUE; + term->beep_overloaded = true; } term->lastbeep = ticks; @@ -3182,7 +3182,7 @@ static void term_out(Terminal *term) win_bell(term->win, term->beep); if (term->beep == BELL_VISUAL) { - term_schedule_vbell(term, FALSE, 0); + term_schedule_vbell(term, false, 0); } } seen_disp_event(term); @@ -3195,7 +3195,7 @@ static void term_out(Terminal *term) else if (term->curs.x == 0 && term->curs.y > 0) term->curs.x = term->cols - 1, term->curs.y--; else if (term->wrapnext) - term->wrapnext = FALSE; + term->wrapnext = false; else term->curs.x--; seen_disp_event(term); @@ -3214,17 +3214,17 @@ static void term_out(Terminal *term) else { compatibility(ANSIMIN); term->termstate = SEEN_ESC; - term->esc_query = FALSE; + term->esc_query = false; } break; case '\015': /* CR: Carriage return */ term->curs.x = 0; - term->wrapnext = FALSE; + term->wrapnext = false; seen_disp_event(term); if (term->crhaslf) { if (term->curs.y == term->marg_b) - scroll(term, term->marg_t, term->marg_b, 1, TRUE); + scroll(term, term->marg_t, term->marg_b, 1, true); else if (term->curs.y < term->rows - 1) term->curs.y++; } @@ -3234,10 +3234,10 @@ static void term_out(Terminal *term) case '\014': /* FF: Form feed */ if (has_compat(SCOANSI)) { move(term, 0, 0, 0); - erase_lots(term, FALSE, FALSE, TRUE); + erase_lots(term, false, false, true); if (term->scroll_on_disp) term->disptop = 0; - term->wrapnext = FALSE; + term->wrapnext = false; seen_disp_event(term); break; } @@ -3245,12 +3245,12 @@ static void term_out(Terminal *term) compatibility(VT100); case '\012': /* LF: Line feed */ if (term->curs.y == term->marg_b) - scroll(term, term->marg_t, term->marg_b, 1, TRUE); + scroll(term, term->marg_t, term->marg_b, 1, true); else if (term->curs.y < term->rows - 1) term->curs.y++; if (term->lfhascr) term->curs.x = 0; - term->wrapnext = FALSE; + term->wrapnext = false; seen_disp_event(term); if (term->logctx) logtraffic(term->logctx, (unsigned char) c, LGTYP_ASCII); @@ -3313,7 +3313,7 @@ static void term_out(Terminal *term) term->termstate = SEEN_CSI; term->esc_nargs = 1; term->esc_args[0] = ARG_DEFAULT; - term->esc_query = FALSE; + term->esc_query = false; break; case ']': /* OSC: xterm escape sequences */ /* Compatibility is nasty here, xterm, linux, decterm yuk! */ @@ -3324,47 +3324,47 @@ static void term_out(Terminal *term) break; case '7': /* DECSC: save cursor */ compatibility(VT100); - save_cursor(term, TRUE); + save_cursor(term, true); break; case '8': /* DECRC: restore cursor */ compatibility(VT100); - save_cursor(term, FALSE); + save_cursor(term, false); seen_disp_event(term); break; case '=': /* DECKPAM: Keypad application mode */ compatibility(VT100); - term->app_keypad_keys = TRUE; + term->app_keypad_keys = true; break; case '>': /* DECKPNM: Keypad numeric mode */ compatibility(VT100); - term->app_keypad_keys = FALSE; + term->app_keypad_keys = false; break; case 'D': /* IND: exactly equivalent to LF */ compatibility(VT100); if (term->curs.y == term->marg_b) - scroll(term, term->marg_t, term->marg_b, 1, TRUE); + scroll(term, term->marg_t, term->marg_b, 1, true); else if (term->curs.y < term->rows - 1) term->curs.y++; - term->wrapnext = FALSE; + term->wrapnext = false; seen_disp_event(term); break; case 'E': /* NEL: exactly equivalent to CR-LF */ compatibility(VT100); term->curs.x = 0; if (term->curs.y == term->marg_b) - scroll(term, term->marg_t, term->marg_b, 1, TRUE); + scroll(term, term->marg_t, term->marg_b, 1, true); else if (term->curs.y < term->rows - 1) term->curs.y++; - term->wrapnext = FALSE; + term->wrapnext = false; seen_disp_event(term); break; case 'M': /* RI: reverse index - backwards LF */ compatibility(VT100); if (term->curs.y == term->marg_t) - scroll(term, term->marg_t, term->marg_b, -1, TRUE); + scroll(term, term->marg_t, term->marg_b, -1, true); else if (term->curs.y > 0) term->curs.y--; - term->wrapnext = FALSE; + term->wrapnext = false; seen_disp_event(term); break; case 'Z': /* DECID: terminal type query */ @@ -3375,7 +3375,7 @@ static void term_out(Terminal *term) break; case 'c': /* RIS: restore power-on settings */ compatibility(VT100); - power_on(term, TRUE); + power_on(term, true); if (term->ldisc) /* cause ldisc to notice changes */ ldisc_echoedit_update(term->ldisc); if (term->reset_132) { @@ -3389,7 +3389,7 @@ static void term_out(Terminal *term) break; case 'H': /* HTS: set a tab */ compatibility(VT100); - term->tabs[term->curs.x] = TRUE; + term->tabs[term->curs.x] = true; break; case ANSI('8', '#'): /* DECALN: fills screen with Es :-) */ @@ -3528,7 +3528,7 @@ static void term_out(Terminal *term) if (term->esc_query) term->esc_query = -1; else if (c == '?') - term->esc_query = TRUE; + term->esc_query = true; else term->esc_query = c; term->termstate = SEEN_CSI; @@ -3636,7 +3636,7 @@ static void term_out(Terminal *term) i++; if (i > 3) i = 0; - erase_lots(term, FALSE, !!(i & 2), !!(i & 1)); + erase_lots(term, false, !!(i & 2), !!(i & 1)); } } if (term->scroll_on_disp) @@ -3648,7 +3648,7 @@ static void term_out(Terminal *term) unsigned int i = def(term->esc_args[0], 0) + 1; if (i > 3) i = 0; - erase_lots(term, TRUE, !!(i & 2), !!(i & 1)); + erase_lots(term, true, !!(i & 2), !!(i & 1)); } seen_disp_event(term); break; @@ -3657,7 +3657,7 @@ static void term_out(Terminal *term) CLAMP(term->esc_args[0], term->rows); if (term->curs.y <= term->marg_b) scroll(term, term->curs.y, term->marg_b, - -def(term->esc_args[0], 1), FALSE); + -def(term->esc_args[0], 1), false); seen_disp_event(term); break; case 'M': /* DL: delete lines */ @@ -3666,7 +3666,7 @@ static void term_out(Terminal *term) if (term->curs.y <= term->marg_b) scroll(term, term->curs.y, term->marg_b, def(term->esc_args[0], 1), - TRUE); + true); seen_disp_event(term); break; case '@': /* ICH: insert chars */ @@ -3708,7 +3708,7 @@ static void term_out(Terminal *term) int i; for (i = 0; i < term->esc_nargs; i++) toggle_mode(term, term->esc_args[i], - term->esc_query, TRUE); + term->esc_query, true); } break; case 'i': /* MC: Media copy */ @@ -3720,7 +3720,7 @@ static void term_out(Terminal *term) if (term->esc_args[0] == 5 && (printer = conf_get_str(term->conf, CONF_printer))[0]) { - term->printing = TRUE; + term->printing = true; term->only_printing = !term->esc_query; term->print_state = 0; term_print_setup(term, printer); @@ -3737,18 +3737,18 @@ static void term_out(Terminal *term) int i; for (i = 0; i < term->esc_nargs; i++) toggle_mode(term, term->esc_args[i], - term->esc_query, FALSE); + term->esc_query, false); } break; case 'g': /* TBC: clear tabs */ compatibility(VT100); if (term->esc_nargs == 1) { if (term->esc_args[0] == 0) { - term->tabs[term->curs.x] = FALSE; + term->tabs[term->curs.x] = false; } else if (term->esc_args[0] == 3) { int i; for (i = 0; i < term->cols; i++) - term->tabs[i] = FALSE; + term->tabs[i] = false; } } break; @@ -3845,7 +3845,7 @@ static void term_out(Terminal *term) break; case 6: /* SCO light bkgrd */ compatibility(SCOANSI); - term->blink_is_real = FALSE; + term->blink_is_real = false; term->curr_attr |= ATTR_BLINK; term_schedule_tblink(term); break; @@ -3889,7 +3889,7 @@ static void term_out(Terminal *term) case 36: case 37: /* foreground */ - term->curr_truecolour.fg.enabled = FALSE; + term->curr_truecolour.fg.enabled = false; term->curr_attr &= ~ATTR_FGMASK; term->curr_attr |= (term->esc_args[i] - 30)<curr_truecolour.fg.enabled = FALSE; + term->curr_truecolour.fg.enabled = false; term->curr_attr &= ~ATTR_FGMASK; term->curr_attr |= ((term->esc_args[i] - 90 + 8) << ATTR_FGSHIFT); break; case 39: /* default-foreground */ - term->curr_truecolour.fg.enabled = FALSE; + term->curr_truecolour.fg.enabled = false; term->curr_attr &= ~ATTR_FGMASK; term->curr_attr |= ATTR_DEFFG; break; @@ -3923,7 +3923,7 @@ static void term_out(Terminal *term) case 46: case 47: /* background */ - term->curr_truecolour.bg.enabled = FALSE; + term->curr_truecolour.bg.enabled = false; term->curr_attr &= ~ATTR_BGMASK; term->curr_attr |= (term->esc_args[i] - 40)<curr_truecolour.bg.enabled = FALSE; + term->curr_truecolour.bg.enabled = false; term->curr_attr &= ~ATTR_BGMASK; term->curr_attr |= ((term->esc_args[i] - 100 + 8) << ATTR_BGSHIFT); break; case 49: /* default-background */ - term->curr_truecolour.bg.enabled = FALSE; + term->curr_truecolour.bg.enabled = false; term->curr_attr &= ~ATTR_BGMASK; term->curr_attr |= ATTR_DEFBG; break; @@ -4006,10 +4006,10 @@ static void term_out(Terminal *term) } break; case 's': /* save cursor */ - save_cursor(term, TRUE); + save_cursor(term, true); break; case 'u': /* restore cursor */ - save_cursor(term, FALSE); + save_cursor(term, false); seen_disp_event(term); break; case 't': /* DECSLPP: set page size - ie window height */ @@ -4037,10 +4037,10 @@ static void term_out(Terminal *term) char buf[80]; const char *p; case 1: - win_set_minimised(term->win, FALSE); + win_set_minimised(term->win, false); break; case 2: - win_set_minimised(term->win, TRUE); + win_set_minimised(term->win, true); break; case 3: if (term->esc_nargs >= 3) { @@ -4058,11 +4058,11 @@ static void term_out(Terminal *term) break; case 5: /* move to top */ - win_set_zorder(term->win, TRUE); + win_set_zorder(term->win, true); break; case 6: /* move to bottom */ - win_set_zorder(term->win, FALSE); + win_set_zorder(term->win, false); break; case 7: win_refresh(term->win); @@ -4082,7 +4082,7 @@ static void term_out(Terminal *term) if (term->esc_nargs >= 2) win_set_maximised( term->win, - term->esc_args[1] ? TRUE : FALSE); + term->esc_args[1] ? true : false); break; case 11: if (term->ldisc) @@ -4134,7 +4134,7 @@ static void term_out(Terminal *term) if (term->ldisc && term->remote_qtitle_action != TITLE_NONE) { if(term->remote_qtitle_action == TITLE_REAL) - p = win_get_title(term->win, TRUE); + p = win_get_title(term->win, true); else p = EMPTY_WINDOW_TITLE; len = strlen(p); @@ -4148,7 +4148,7 @@ static void term_out(Terminal *term) if (term->ldisc && term->remote_qtitle_action != TITLE_NONE) { if(term->remote_qtitle_action == TITLE_REAL) - p = win_get_title(term->win, FALSE); + p = win_get_title(term->win, false); else p = EMPTY_WINDOW_TITLE; len = strlen(p); @@ -4165,16 +4165,16 @@ static void term_out(Terminal *term) CLAMP(term->esc_args[0], term->rows); compatibility(SCOANSI); scroll(term, term->marg_t, term->marg_b, - def(term->esc_args[0], 1), TRUE); - term->wrapnext = FALSE; + def(term->esc_args[0], 1), true); + term->wrapnext = false; seen_disp_event(term); break; case 'T': /* SD: Scroll down */ CLAMP(term->esc_args[0], term->rows); compatibility(SCOANSI); scroll(term, term->marg_t, term->marg_b, - -def(term->esc_args[0], 1), TRUE); - term->wrapnext = FALSE; + -def(term->esc_args[0], 1), true); + term->wrapnext = false; seen_disp_event(term); break; case ANSI('|', '*'): /* DECSNLS */ @@ -4265,15 +4265,15 @@ static void term_out(Terminal *term) compatibility(SCOANSI); switch(term->esc_args[0]) { case 0: /* hide cursor */ - term->cursor_on = FALSE; + term->cursor_on = false; break; case 1: /* restore cursor */ - term->big_cursor = FALSE; - term->cursor_on = TRUE; + term->big_cursor = false; + term->cursor_on = true; break; case 2: /* block cursor */ - term->big_cursor = TRUE; - term->cursor_on = TRUE; + term->big_cursor = true; + term->cursor_on = true; break; } break; @@ -4287,14 +4287,14 @@ static void term_out(Terminal *term) compatibility(SCOANSI); if (term->esc_nargs >= 2) { if (term->esc_args[0] > term->esc_args[1]) - term->cursor_on = FALSE; + term->cursor_on = false; else - term->cursor_on = TRUE; + term->cursor_on = true; } break; case ANSI('D', '='): compatibility(SCOANSI); - term->blink_is_real = FALSE; + term->blink_is_real = false; term_schedule_tblink(term); if (term->esc_args[0]>=1) term->curr_attr |= ATTR_BLINK; @@ -4423,7 +4423,7 @@ static void term_out(Terminal *term) } break; case SEEN_OSC: - term->osc_w = FALSE; + term->osc_w = false; switch (c) { case 'P': /* Linux palette sequence */ term->termstate = SEEN_OSC_P; @@ -4436,7 +4436,7 @@ static void term_out(Terminal *term) break; case 'W': /* word-set */ term->termstate = SEEN_OSC_W; - term->osc_w = TRUE; + term->osc_w = true; break; case '0': case '1': @@ -4628,18 +4628,18 @@ static void term_out(Terminal *term) break; case 'I': if (term->curs.y == 0) - scroll(term, 0, term->rows - 1, -1, TRUE); + scroll(term, 0, term->rows - 1, -1, true); else if (term->curs.y > 0) term->curs.y--; - term->wrapnext = FALSE; + term->wrapnext = false; break; case 'J': - erase_lots(term, FALSE, FALSE, TRUE); + erase_lots(term, false, false, true); if (term->scroll_on_disp) term->disptop = 0; break; case 'K': - erase_lots(term, TRUE, FALSE, TRUE); + erase_lots(term, true, false, true); break; #if 0 case 'V': @@ -4660,17 +4660,17 @@ static void term_out(Terminal *term) ldisc_send(term->ldisc, "\033/Z", 3, 0); break; case '=': - term->app_keypad_keys = TRUE; + term->app_keypad_keys = true; break; case '>': - term->app_keypad_keys = FALSE; + term->app_keypad_keys = false; break; case '<': /* XXX This should switch to VT100 mode not current or default * VT mode. But this will only have effect in a VT220+ * emulation. */ - term->vt52_mode = FALSE; + term->vt52_mode = false; term->blink_is_real = term->blinktext; term_schedule_tblink(term); break; @@ -4690,19 +4690,19 @@ static void term_out(Terminal *term) case 'E': /* compatibility(ATARI) */ move(term, 0, 0, 0); - erase_lots(term, FALSE, FALSE, TRUE); + erase_lots(term, false, false, true); if (term->scroll_on_disp) term->disptop = 0; break; case 'L': /* compatibility(ATARI) */ if (term->curs.y <= term->marg_b) - scroll(term, term->curs.y, term->marg_b, -1, FALSE); + scroll(term, term->curs.y, term->marg_b, -1, false); break; case 'M': /* compatibility(ATARI) */ if (term->curs.y <= term->marg_b) - scroll(term, term->curs.y, term->marg_b, 1, TRUE); + scroll(term, term->curs.y, term->marg_b, 1, true); break; case 'b': /* compatibility(ATARI) */ @@ -4714,29 +4714,29 @@ static void term_out(Terminal *term) break; case 'd': /* compatibility(ATARI) */ - erase_lots(term, FALSE, TRUE, FALSE); + erase_lots(term, false, true, false); if (term->scroll_on_disp) term->disptop = 0; break; case 'e': /* compatibility(ATARI) */ - term->cursor_on = TRUE; + term->cursor_on = true; break; case 'f': /* compatibility(ATARI) */ - term->cursor_on = FALSE; + term->cursor_on = false; break; /* case 'j': Save cursor position - broken on ST */ /* case 'k': Restore cursor position */ case 'l': /* compatibility(ATARI) */ - erase_lots(term, TRUE, TRUE, TRUE); + erase_lots(term, true, true, true); term->curs.x = 0; - term->wrapnext = FALSE; + term->wrapnext = false; break; case 'o': /* compatibility(ATARI) */ - erase_lots(term, TRUE, TRUE, FALSE); + erase_lots(term, true, true, false); break; case 'p': /* compatibility(ATARI) */ @@ -4757,7 +4757,7 @@ static void term_out(Terminal *term) case 'R': /* compatibility(OTHER) */ - term->vt52_bold = FALSE; + term->vt52_bold = false; term->curr_attr = ATTR_DEFAULT; term->curr_truecolour.fg = optionalrgb_none; term->curr_truecolour.bg = optionalrgb_none; @@ -4773,12 +4773,12 @@ static void term_out(Terminal *term) break; case 'U': /* compatibility(VI50) */ - term->vt52_bold = TRUE; + term->vt52_bold = true; term->curr_attr |= ATTR_BOLD; break; case 'T': /* compatibility(VI50) */ - term->vt52_bold = FALSE; + term->vt52_bold = false; term->curr_attr &= ~ATTR_BOLD; break; #endif @@ -4830,7 +4830,7 @@ static void term_out(Terminal *term) */ static void parse_optionalrgb(optionalrgb *out, unsigned *values) { - out->enabled = TRUE; + out->enabled = true; out->r = values[0] < 256 ? values[0] : 0; out->g = values[1] < 256 ? values[1] : 0; out->b = values[2] < 256 ? values[2] : 0; @@ -4847,22 +4847,22 @@ static int term_bidi_cache_hit(Terminal *term, int line, int i; if (!term->pre_bidi_cache) - return FALSE; /* cache doesn't even exist yet! */ + return false; /* cache doesn't even exist yet! */ if (line >= term->bidi_cache_size) - return FALSE; /* cache doesn't have this many lines */ + return false; /* cache doesn't have this many lines */ if (!term->pre_bidi_cache[line].chars) - return FALSE; /* cache doesn't contain _this_ line */ + return false; /* cache doesn't contain _this_ line */ if (term->pre_bidi_cache[line].width != width) - return FALSE; /* line is wrong width */ + return false; /* line is wrong width */ for (i = 0; i < width; i++) if (!termchars_equal(term->pre_bidi_cache[line].chars+i, lbefore+i)) - return FALSE; /* line doesn't match cache */ + return false; /* line doesn't match cache */ - return TRUE; /* it didn't match. */ + return true; /* it didn't match. */ } static void term_bidi_cache_store(Terminal *term, int line, termchar *lbefore, @@ -5191,7 +5191,7 @@ static void do_paint(Terminal *term) selected = (posPle(term->selstart, scrpos) && posPlt(scrpos, term->selend)); } else - selected = FALSE; + selected = false; tattr = (tattr ^ rv ^ (selected ? ATTR_REVERSE : 0)); @@ -5246,11 +5246,11 @@ static void do_paint(Terminal *term) * with fonts that overflow their character cells. */ laststart = 0; - dirtyrect = FALSE; + dirtyrect = false; for (j = 0; j < term->cols; j++) { if (term->disptext[i]->chars[j].attr & DATTR_STARTRUN) { laststart = j; - dirtyrect = FALSE; + dirtyrect = false; } if (term->disptext[i]->chars[j].chr != newline[j].chr || @@ -5262,7 +5262,7 @@ static void do_paint(Terminal *term) for (k = laststart; k < j; k++) term->disptext[i]->chars[k].attr |= ATTR_INVALID; - dirtyrect = TRUE; + dirtyrect = true; } } @@ -5287,19 +5287,19 @@ static void do_paint(Terminal *term) tchar = newline[j].chr; if ((term->disptext[i]->chars[j].attr ^ tattr) & ATTR_WIDE) - dirty_line = TRUE; + dirty_line = true; break_run = ((tattr ^ attr) & term->attr_mask) != 0; if (!truecolour_equal(newline[j].truecolour, tc)) - break_run = TRUE; + break_run = true; #ifdef USES_VTLINE_HACK /* Special hack for VT100 Linedraw glyphs */ if ((tchar >= 0x23BA && tchar <= 0x23BD) || (j > 0 && (newline[j-1].chr >= 0x23BA && newline[j-1].chr <= 0x23BD))) - break_run = TRUE; + break_run = true; #endif /* @@ -5307,21 +5307,21 @@ static void do_paint(Terminal *term) * same CSET, if that CSET is a magic one. */ if (CSET_OF(tchar) != cset) - break_run = TRUE; + break_run = true; /* * Break on both sides of any combined-character cell. */ if (d->cc_next != 0 || (j > 0 && d[-1].cc_next != 0)) - break_run = TRUE; + break_run = true; if (!term->ucsdata->dbcs_screenfont && !dirty_line) { if (term->disptext[i]->chars[j].chr == tchar && (term->disptext[i]->chars[j].attr &~ DATTR_MASK) == tattr) - break_run = TRUE; + break_run = true; else if (!dirty_run && ccount == 1) - break_run = TRUE; + break_run = true; } if (break_run) { @@ -5342,11 +5342,11 @@ static void do_paint(Terminal *term) dirty_run = dirty_line; } - do_copy = FALSE; + do_copy = false; if (!termchars_equal_override(&term->disptext[i]->chars[j], d, tchar, tattr)) { - do_copy = TRUE; - dirty_run = TRUE; + do_copy = true; + dirty_run = true; } if (ccount+2 > chlen) { @@ -5420,7 +5420,7 @@ static void do_paint(Terminal *term) */ assert(!(i == our_curs_y && j == our_curs_x)); if (!termchars_equal(&term->disptext[i]->chars[j], d)) - dirty_run = TRUE; + dirty_run = true; copy_termchar(term->disptext[i], j, d); } } @@ -5575,7 +5575,7 @@ static void clipme(Terminal *term, pos top, pos bottom, int rect, int desel, old_top_x = top.x; /* needed for rect==1 */ while (poslt(top, bottom)) { - int nl = FALSE; + int nl = false; termline *ldata = lineptr(top.y); pos nlpos; @@ -5600,7 +5600,7 @@ static void clipme(Terminal *term, pos top, pos bottom, int rect, int desel, poslt(top, nlpos)) decpos(nlpos); if (poslt(nlpos, bottom)) - nl = TRUE; + nl = true; } else if (ldata->lattr & LATTR_WRAPPED2) { /* Ignore the last char on the line in a WRAPPED2 line. */ decpos(nlpos); @@ -5722,10 +5722,10 @@ static void clipme(Terminal *term, pos top, pos bottom, int rect, int desel, /* Finally, transfer all that to the clipboard(s). */ { int i; - int clip_local = FALSE; + int clip_local = false; for (i = 0; i < n_clipboards; i++) { if (clipboards[i] == CLIP_LOCAL) { - clip_local = TRUE; + clip_local = true; } else if (clipboards[i] != CLIP_NULL) { win_clip_write( term->win, clipboards[i], buf.textbuf, buf.attrbuf, @@ -5757,7 +5757,7 @@ void term_copyall(Terminal *term, const int *clipboards, int n_clipboards) top.x = 0; bottom.y = find_last_nonempty_line(term, screen); bottom.x = term->cols; - clipme(term, top, bottom, 0, TRUE, clipboards, n_clipboards); + clipme(term, top, bottom, 0, true, clipboards, n_clipboards); } static void paste_from_clip_local(void *vterm) @@ -5775,7 +5775,7 @@ void term_request_copy(Terminal *term, const int *clipboards, int n_clipboards) win_clip_write(term->win, clipboards[i], term->last_selected_text, term->last_selected_attr, term->last_selected_tc, term->last_selected_len, - FALSE); + false); } } } @@ -6229,23 +6229,23 @@ void term_mouse(Terminal *term, Mouse_Button braw, Mouse_Button bcooked, switch (braw) { case MBT_LEFT: encstate = 0x00; /* left button down */ - wheel = FALSE; + wheel = false; break; case MBT_MIDDLE: encstate = 0x01; - wheel = FALSE; + wheel = false; break; case MBT_RIGHT: encstate = 0x02; - wheel = FALSE; + wheel = false; break; case MBT_WHEEL_UP: encstate = 0x40; - wheel = TRUE; + wheel = true; break; case MBT_WHEEL_DOWN: encstate = 0x41; - wheel = TRUE; + wheel = true; break; default: return; @@ -6412,7 +6412,7 @@ void term_mouse(Terminal *term, Mouse_Button braw, Mouse_Button bcooked, * data to the clipboard. */ clipme(term, term->selstart, term->selend, - (term->seltype == RECTANGULAR), FALSE, + (term->seltype == RECTANGULAR), false, term->mouse_select_clipboards, term->n_mouse_select_clipboards); term->selstate = SELECTED; @@ -6512,13 +6512,13 @@ int term_ldisc(Terminal *term, int option) return term->term_echoing; if (option == LD_EDIT) return term->term_editing; - return FALSE; + return false; } static void term_added_data(Terminal *term) { if (!term->in_term_out) { - term->in_term_out = TRUE; + term->in_term_out = true; term_reset_cblink(term); /* * During drag-selects, we do not process terminal input, @@ -6527,7 +6527,7 @@ static void term_added_data(Terminal *term) */ if (term->selstate != DRAGGING) term_out(term); - term->in_term_out = FALSE; + term->in_term_out = false; } } diff --git a/terminal.h b/terminal.h index b63d42e9..d569f5f4 100644 --- a/terminal.h +++ b/terminal.h @@ -52,7 +52,7 @@ struct termline { int cols; /* number of real columns on the line */ int size; /* number of allocated termchars * (cc-lists may make this > cols) */ - int temporary; /* TRUE if decompressed from scrollback */ + int temporary; /* true if decompressed from scrollback */ int cc_free; /* offset to first cc in free list */ struct termchar *chars; }; @@ -166,7 +166,7 @@ struct terminal_tag { int esc_nargs; int esc_query; #define ANSI(x,y) ((x)+((y)<<8)) -#define ANSI_QUE(x) ANSI(x,TRUE) +#define ANSI_QUE(x) ANSI(x,true) #define OSC_STR_MAX 2048 int osc_strlen; diff --git a/testbn.c b/testbn.c index 0bc555ee..29f6b753 100644 --- a/testbn.c +++ b/testbn.c @@ -37,7 +37,7 @@ void queue_idempotent_callback(IdempotentCallback *ic) { assert(0); } #define fromxdigit(c) ( (c)>'9' ? ((c)&0xDF) - 'A' + 10 : (c) - '0' ) /* For Unix in particular, but harmless if this main() is reused elsewhere */ -const int buildinfo_gtk_relevant = FALSE; +const int buildinfo_gtk_relevant = false; int main(int argc, char **argv) { @@ -215,7 +215,7 @@ int main(int argc, char **argv) answer_q = bigdiv(n, d); answer_r = bigmod(n, d); - fail = FALSE; + fail = false; if (bignum_cmp(expect_q, answer_q) != 0) { char *as = bignum_decimal(n); char *bs = bignum_decimal(d); @@ -224,7 +224,7 @@ int main(int argc, char **argv) printf("%d: fail: %s / %s gave %s expected %s\n", line, as, bs, cs, ds); - fail = TRUE; + fail = true; sfree(as); sfree(bs); @@ -239,7 +239,7 @@ int main(int argc, char **argv) printf("%d: fail: %s mod %s gave %s expected %s\n", line, as, bs, cs, ds); - fail = TRUE; + fail = true; sfree(as); sfree(bs); diff --git a/timing.c b/timing.c index 696c1e1d..0aad374a 100644 --- a/timing.c +++ b/timing.c @@ -176,7 +176,7 @@ int run_timers(unsigned long anow, unsigned long *next) first = (struct timer *)index234(timers, 0); if (!first) - return FALSE; /* no timers remaining */ + return false; /* no timers remaining */ if (find234(timer_contexts, first->ctx, NULL) == NULL) { /* @@ -200,7 +200,7 @@ int run_timers(unsigned long anow, unsigned long *next) * future. Return how long it has yet to go. */ *next = first->now; - return TRUE; + return true; } } } diff --git a/unix/gtkapp.c b/unix/gtkapp.c index 2629e684..a9f6b02c 100644 --- a/unix/gtkapp.c +++ b/unix/gtkapp.c @@ -88,7 +88,7 @@ I suppose I'll have to look into OS X code signing. char *x_get_default(const char *key) { return NULL; } -const int buildinfo_gtk_relevant = TRUE; +const int buildinfo_gtk_relevant = true; #if !GTK_CHECK_VERSION(3,0,0) /* This front end only works in GTK 3. If that's not what we've got, @@ -275,7 +275,7 @@ void window_setup_error(const char *errmsg) create_message_box(NULL, "Error creating session window", errmsg, string_width("Some sort of fiddly error message that " "might be technical"), - TRUE, &buttons_ok, window_setup_error_callback, NULL); + true, &buttons_ok, window_setup_error_callback, NULL); } static void activate(GApplication *app, @@ -319,7 +319,7 @@ int main(int argc, char **argv) /* Call the function in ux{putty,pterm}.c to do app-type * specific setup */ extern void setup(int); - setup(FALSE); /* FALSE means we are not a one-session process */ + setup(false); /* false means we are not a one-session process */ } if (argc > 1) { diff --git a/unix/gtkask.c b/unix/gtkask.c index 5b45d342..defc98f0 100644 --- a/unix/gtkask.c +++ b/unix/gtkask.c @@ -122,7 +122,7 @@ static gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) } else { #if GTK_CHECK_VERSION(2,0,0) if (gtk_im_context_filter_keypress(ctx->imc, event)) - return TRUE; + return true; #endif if (event->type == GDK_KEY_PRESS) { @@ -158,7 +158,7 @@ static gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) } } } - return TRUE; + return true; } #if GTK_CHECK_VERSION(2,0,0) @@ -177,7 +177,7 @@ static gint configure_area(GtkWidget *widget, GdkEventConfigure *event, ctx->width = event->width; ctx->height = event->height; gtk_widget_queue_draw(widget); - return TRUE; + return true; } #ifdef DRAW_DEFAULT_CAIRO @@ -193,7 +193,7 @@ static void askpass_redraw_gdk(GdkWindow *win, struct drawing_area_ctx *ctx) { GdkGC *gc = gdk_gc_new(win); gdk_gc_set_foreground(gc, &ctx->cols[ctx->state]); - gdk_draw_rectangle(win, gc, TRUE, 0, 0, ctx->width, ctx->height); + gdk_draw_rectangle(win, gc, true, 0, 0, ctx->width, ctx->height); gdk_gc_unref(gc); } #endif @@ -203,7 +203,7 @@ static gint draw_area(GtkWidget *widget, cairo_t *cr, gpointer data) { struct drawing_area_ctx *ctx = (struct drawing_area_ctx *)data; askpass_redraw_cairo(cr, ctx); - return TRUE; + return true; } #else static gint expose_area(GtkWidget *widget, GdkEventExpose *event, @@ -219,7 +219,7 @@ static gint expose_area(GtkWidget *widget, GdkEventExpose *event, askpass_redraw_gdk(gtk_widget_get_window(ctx->area), ctx); #endif - return TRUE; + return true; } #endif @@ -245,7 +245,7 @@ static gboolean try_grab_keyboard(gpointer vctx) ctx->seat = seat; ret = gdk_seat_grab(seat, gdkw, GDK_SEAT_CAPABILITY_KEYBOARD, - TRUE, NULL, NULL, NULL, NULL); + true, NULL, NULL, NULL, NULL); /* * For some reason GDK 3.22 hides the GDK window as a side effect @@ -281,7 +281,7 @@ static gboolean try_grab_keyboard(gpointer vctx) ret = gdk_device_grab(ctx->keyboard, gtk_widget_get_window(ctx->dialog), GDK_OWNERSHIP_NONE, - TRUE, + true, GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK, NULL, GDK_CURRENT_TIME); @@ -290,7 +290,7 @@ static gboolean try_grab_keyboard(gpointer vctx) * It's much simpler in GTK 1 and 2! */ ret = gdk_keyboard_grab(gtk_widget_get_window(ctx->dialog), - FALSE, GDK_CURRENT_TIME); + false, GDK_CURRENT_TIME); #endif if (ret != GDK_GRAB_SUCCESS) goto fail; @@ -323,7 +323,7 @@ static gboolean try_grab_keyboard(gpointer vctx) gtk_widget_queue_draw(ctx->drawingareas[i].area); } - return FALSE; + return false; fail: /* @@ -347,7 +347,7 @@ static gboolean try_grab_keyboard(gpointer vctx) } else { g_timeout_add(1000/8, try_grab_keyboard, ctx); } - return FALSE; + return false; } void realize(GtkWidget *widget, gpointer vctx) @@ -389,12 +389,12 @@ static const char *gtk_askpass_setup(struct askpass_ctx *ctx, ctx->promptlabel = gtk_label_new(prompt_text); align_label_left(GTK_LABEL(ctx->promptlabel)); gtk_widget_show(ctx->promptlabel); - gtk_label_set_line_wrap(GTK_LABEL(ctx->promptlabel), TRUE); + gtk_label_set_line_wrap(GTK_LABEL(ctx->promptlabel), true); #if GTK_CHECK_VERSION(3,0,0) gtk_label_set_width_chars(GTK_LABEL(ctx->promptlabel), 48); #endif our_dialog_add_to_content_area(GTK_WINDOW(ctx->dialog), - ctx->promptlabel, TRUE, TRUE, 0); + ctx->promptlabel, true, true, 0); #if GTK_CHECK_VERSION(2,0,0) ctx->imc = gtk_im_multicontext_new(); #endif @@ -406,7 +406,7 @@ static const char *gtk_askpass_setup(struct askpass_ctx *ctx, ctx->cols[1].red = ctx->cols[1].green = ctx->cols[1].blue = 0; ctx->cols[2].red = ctx->cols[2].green = ctx->cols[2].blue = 0x8000; gdk_colormap_alloc_colors(ctx->colmap, ctx->cols, 2, - FALSE, TRUE, success); + false, true, success); if (!success[0] || !success[1]) return "unable to allocate colours"; } @@ -426,7 +426,7 @@ static const char *gtk_askpass_setup(struct askpass_ctx *ctx, * piece of template text. */ gtk_widget_set_size_request(ctx->drawingareas[i].area, 32, 32); gtk_box_pack_end(action_area, ctx->drawingareas[i].area, - TRUE, TRUE, 5); + true, true, 5); g_signal_connect(G_OBJECT(ctx->drawingareas[i].area), "configure_event", G_CALLBACK(configure_area), @@ -459,10 +459,10 @@ static const char *gtk_askpass_setup(struct askpass_ctx *ctx, * the prompt label at random, and we'll use gtk_grab_add to * ensure key events go to it. */ - gtk_widget_set_sensitive(ctx->dialog, TRUE); + gtk_widget_set_sensitive(ctx->dialog, true); #if GTK_CHECK_VERSION(2,0,0) - gtk_window_set_keep_above(GTK_WINDOW(ctx->dialog), TRUE); + gtk_window_set_keep_above(GTK_WINDOW(ctx->dialog), true); #endif /* @@ -503,14 +503,14 @@ static void gtk_askpass_cleanup(struct askpass_ctx *ctx) static int setup_gtk(const char *display) { - static int gtk_initialised = FALSE; + static int gtk_initialised = false; int argc; char *real_argv[3]; char **argv = real_argv; int ret; if (gtk_initialised) - return TRUE; + return true; argc = 0; argv[argc++] = dupstr("dummy"); @@ -524,7 +524,7 @@ static int setup_gtk(const char *display) return ret; } -const int buildinfo_gtk_relevant = TRUE; +const int buildinfo_gtk_relevant = true; char *gtk_askpass_main(const char *display, const char *wintitle, const char *prompt, int *success) @@ -537,22 +537,22 @@ char *gtk_askpass_main(const char *display, const char *wintitle, /* In case gtk_init hasn't been called yet by the program */ if (!setup_gtk(display)) { - *success = FALSE; + *success = false; return dupstr("unable to initialise GTK"); } if ((err = gtk_askpass_setup(ctx, wintitle, prompt)) != NULL) { - *success = FALSE; + *success = false; return dupprintf("%s", err); } gtk_main(); gtk_askpass_cleanup(ctx); if (ctx->passphrase) { - *success = TRUE; + *success = true; return ctx->passphrase; } else { - *success = FALSE; + *success = false; return ctx->error_message; } } @@ -577,7 +577,7 @@ int main(int argc, char **argv) gtk_init(&argc, &argv); if (argc != 2) { - success = FALSE; + success = false; ret = dupprintf("usage: %s ", argv[0]); } else { srand(time(NULL)); diff --git a/unix/gtkcols.c b/unix/gtkcols.c index 60e39441..fe8005f5 100644 --- a/unix/gtkcols.c +++ b/unix/gtkcols.c @@ -3,6 +3,7 @@ */ #include +#include "defs.h" #include "gtkcompat.h" #include "gtkcols.h" @@ -157,7 +158,7 @@ static void columns_class_init(ColumnsClass *klass) static void columns_init(Columns *cols) { - gtk_widget_set_has_window(GTK_WIDGET(cols), FALSE); + gtk_widget_set_has_window(GTK_WIDGET(cols), false); cols->children = NULL; cols->spacing = 0; @@ -222,7 +223,7 @@ static void columns_map(GtkWidget *widget) g_return_if_fail(IS_COLUMNS(widget)); cols = COLUMNS(widget); - gtk_widget_set_mapped(GTK_WIDGET(cols), TRUE); + gtk_widget_set_mapped(GTK_WIDGET(cols), true); for (children = cols->children; children && (child = children->data); @@ -243,7 +244,7 @@ static void columns_unmap(GtkWidget *widget) g_return_if_fail(IS_COLUMNS(widget)); cols = COLUMNS(widget); - gtk_widget_set_mapped(GTK_WIDGET(cols), FALSE); + gtk_widget_set_mapped(GTK_WIDGET(cols), false); for (children = cols->children; children && (child = children->data); @@ -285,9 +286,9 @@ static gint columns_expose(GtkWidget *widget, GdkEventExpose *event) GList *children; GdkEventExpose child_event; - g_return_val_if_fail(widget != NULL, FALSE); - g_return_val_if_fail(IS_COLUMNS(widget), FALSE); - g_return_val_if_fail(event != NULL, FALSE); + g_return_val_if_fail(widget != NULL, false); + g_return_val_if_fail(IS_COLUMNS(widget), false); + g_return_val_if_fail(event != NULL, false); if (GTK_WIDGET_DRAWABLE(widget)) { cols = COLUMNS(widget); @@ -304,7 +305,7 @@ static gint columns_expose(GtkWidget *widget, GdkEventExpose *event) gtk_widget_event(child->widget, (GdkEvent *)&child_event); } } - return FALSE; + return false; } #endif @@ -438,7 +439,7 @@ void columns_set_cols(Columns *cols, gint ncols, const gint *percentages) childdata->widget = NULL; childdata->ncols = ncols; childdata->percentages = g_new(gint, ncols); - childdata->force_left = FALSE; + childdata->force_left = false; for (i = 0; i < ncols; i++) childdata->percentages[i] = percentages[i]; @@ -459,7 +460,7 @@ void columns_add(Columns *cols, GtkWidget *child, childdata->widget = child; childdata->colstart = colstart; childdata->colspan = colspan; - childdata->force_left = FALSE; + childdata->force_left = false; childdata->same_height_as = NULL; childdata->percentages = NULL; @@ -506,7 +507,7 @@ void columns_force_left_align(Columns *cols, GtkWidget *widget) child = columns_find_child(cols, widget); g_return_if_fail(child != NULL); - child->force_left = TRUE; + child->force_left = true; if (gtk_widget_get_visible(widget)) gtk_widget_queue_resize(GTK_WIDGET(cols)); } @@ -563,14 +564,14 @@ static gint columns_focus(FOCUS_METHOD_SUPERCLASS *super, GtkDirectionType dir) GList *pos; GtkWidget *focuschild; - g_return_val_if_fail(super != NULL, FALSE); - g_return_val_if_fail(IS_COLUMNS(super), FALSE); + g_return_val_if_fail(super != NULL, false); + g_return_val_if_fail(IS_COLUMNS(super), false); cols = COLUMNS(super); if (!gtk_widget_is_drawable(GTK_WIDGET(cols)) || !gtk_widget_is_sensitive(GTK_WIDGET(cols))) - return FALSE; + return false; if (!gtk_widget_get_can_focus(GTK_WIDGET(cols)) && (dir == GTK_DIR_TAB_FORWARD || dir == GTK_DIR_TAB_BACKWARD)) { @@ -593,16 +594,16 @@ static gint columns_focus(FOCUS_METHOD_SUPERCLASS *super, GtkDirectionType dir) GTK_IS_CONTAINER(child) && !gtk_widget_has_focus(child)) { if (CHILD_FOCUS(child, dir)) - return TRUE; + return true; } } } else if (gtk_widget_is_drawable(child)) { if (GTK_IS_CONTAINER(child)) { if (CHILD_FOCUS(child, dir)) - return TRUE; + return true; } else if (gtk_widget_get_can_focus(child)) { gtk_widget_grab_focus(child); - return TRUE; + return true; } } @@ -612,7 +613,7 @@ static gint columns_focus(FOCUS_METHOD_SUPERCLASS *super, GtkDirectionType dir) pos = pos->prev; } - return FALSE; + return false; } else return columns_inherited_focus(super, dir); } @@ -668,7 +669,7 @@ static gint columns_compute_width(Columns *cols, widget_dim_fn_t get_width) printf("label %p '%s' wrap=%s: ", child->widget, gtk_label_get_text(GTK_LABEL(child->widget)), (gtk_label_get_line_wrap(GTK_LABEL(child->widget)) - ? "TRUE" : "FALSE")); + ? "true" : "false")); else printf("widget %p: ", child->widget); { diff --git a/unix/gtkcomm.c b/unix/gtkcomm.c index b29bd7ed..15da36d5 100644 --- a/unix/gtkcomm.c +++ b/unix/gtkcomm.c @@ -88,7 +88,7 @@ gboolean fd_input_func(GIOChannel *source, GIOCondition condition, if (condition & G_IO_OUT) select_result(sourcefd, 2); - return TRUE; + return true; } #else void fd_input_func(gpointer data, gint sourcefd, GdkInputCondition condition) @@ -173,11 +173,11 @@ static gint timer_trigger(gpointer data) } /* - * Returning FALSE means 'don't call this timer again', which + * Returning false means 'don't call this timer again', which * _should_ be redundant given that we removed it above, but just - * in case, return FALSE anyway. + * in case, return false anyway. */ - return FALSE; + return false; } void timer_change_notify(unsigned long next) @@ -215,10 +215,10 @@ static gint idle_toplevel_callback_func(gpointer data) */ if (!toplevel_callback_pending() && idle_fn_scheduled) { g_source_remove(toplevel_callback_idle_id); - idle_fn_scheduled = FALSE; + idle_fn_scheduled = false; } - return TRUE; + return true; } static void notify_toplevel_callback(void *vctx) @@ -226,7 +226,7 @@ static void notify_toplevel_callback(void *vctx) if (!idle_fn_scheduled) { toplevel_callback_idle_id = g_idle_add(idle_toplevel_callback_func, NULL); - idle_fn_scheduled = TRUE; + idle_fn_scheduled = true; } } diff --git a/unix/gtkcompat.h b/unix/gtkcompat.h index fe070720..b34eda10 100644 --- a/unix/gtkcompat.h +++ b/unix/gtkcompat.h @@ -200,7 +200,7 @@ #if GTK_CHECK_VERSION(3,0,0) #define gtk_hseparator_new() gtk_separator_new(GTK_ORIENTATION_HORIZONTAL) /* Fortunately, my hboxes and vboxes never actually set homogeneous to - * TRUE, so I can just wrap these deprecated constructors with a macro + * true, so I can just wrap these deprecated constructors with a macro * without also having to arrange a call to gtk_box_set_homogeneous. */ #define gtk_hbox_new(homogeneous, spacing) \ gtk_box_new(GTK_ORIENTATION_HORIZONTAL, spacing) diff --git a/unix/gtkdlg.c b/unix/gtkdlg.c index 39c91c61..d988f9fb 100644 --- a/unix/gtkdlg.c +++ b/unix/gtkdlg.c @@ -197,7 +197,7 @@ static void dlg_init(struct dlgparam *dp) { dp->byctrl = newtree234(uctrl_cmp_byctrl); dp->bywidget = newtree234(uctrl_cmp_bywidget); - dp->coloursel_result.ok = FALSE; + dp->coloursel_result.ok = false; dp->window = dp->cancelbutton = NULL; #if !GTK_CHECK_VERSION(2,0,0) dp->treeitems = NULL; @@ -265,7 +265,7 @@ void dlg_radiobutton_set(union control *ctrl, dlgparam *dp, int which) struct uctrl *uc = dlg_find_byctrl(dp, ctrl); assert(uc->ctrl->generic.type == CTRL_RADIO); assert(uc->buttons != NULL); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(uc->buttons[which]), TRUE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(uc->buttons[which]), true); } int dlg_radiobutton_get(union control *ctrl, dlgparam *dp) @@ -790,17 +790,17 @@ void dlg_listbox_select(union control *ctrl, dlgparam *dp, int index) items = gtk_container_children(GTK_CONTAINER(uc->list)); nitems = g_list_length(items); if (nitems > 0) { - int modified = FALSE; + int modified = false; g_list_free(items); newtop = uc->adj->lower + (uc->adj->upper - uc->adj->lower) * index / nitems; newbot = uc->adj->lower + (uc->adj->upper - uc->adj->lower) * (index+1) / nitems; if (uc->adj->value > newtop) { - modified = TRUE; + modified = true; uc->adj->value = newtop; } else if (uc->adj->value < newbot - uc->adj->page_size) { - modified = TRUE; + modified = true; uc->adj->value = newbot - uc->adj->page_size; } if (modified) @@ -824,7 +824,7 @@ void dlg_listbox_select(union control *ctrl, dlgparam *dp, int index) path = gtk_tree_path_new_from_indices(index, -1); gtk_tree_selection_select_path(treesel, path); gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(uc->treeview), - path, NULL, FALSE, 0.0, 0.0); + path, NULL, false, 0.0, 0.0); gtk_tree_path_free(path); return; } @@ -1063,7 +1063,7 @@ void dlg_error_msg(dlgparam *dp, const char *msg) create_message_box( dp->window, "Error", msg, string_width("Some sort of text about a config-box error message"), - FALSE, &buttons_ok, trivial_post_dialog_fn, NULL); + false, &buttons_ok, trivial_post_dialog_fn, NULL); } /* @@ -1104,7 +1104,7 @@ void dlg_coloursel_start(union control *ctrl, dlgparam *dp, int r, int g, int b) GtkWidget *coloursel = gtk_color_chooser_dialog_new("Select a colour", GTK_WINDOW(dp->window)); - gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(coloursel), FALSE); + gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(coloursel), false); #else GtkWidget *okbutton, *cancelbutton; GtkWidget *coloursel = @@ -1112,12 +1112,12 @@ void dlg_coloursel_start(union control *ctrl, dlgparam *dp, int r, int g, int b) GtkColorSelectionDialog *ccs = GTK_COLOR_SELECTION_DIALOG(coloursel); GtkColorSelection *cs = GTK_COLOR_SELECTION (gtk_color_selection_dialog_get_color_selection(ccs)); - gtk_color_selection_set_has_opacity_control(cs, FALSE); + gtk_color_selection_set_has_opacity_control(cs, false); #endif - dp->coloursel_result.ok = FALSE; + dp->coloursel_result.ok = false; - gtk_window_set_modal(GTK_WINDOW(coloursel), TRUE); + gtk_window_set_modal(GTK_WINDOW(coloursel), true); #if GTK_CHECK_VERSION(3,0,0) { @@ -1214,7 +1214,7 @@ static gboolean widget_focus(GtkWidget *widget, GdkEventFocus *event, dp->currfocus = focus; } - return FALSE; + return false; } static void button_clicked(GtkButton *button, gpointer data) @@ -1251,7 +1251,7 @@ static gboolean editbox_key(GtkWidget *widget, GdkEventKey *event, event, &return_val); return return_val; } - return FALSE; + return false; } static void editbox_changed(GtkEditable *ed, gpointer data) @@ -1269,7 +1269,7 @@ static gboolean editbox_lostfocus(GtkWidget *ed, GdkEventFocus *event, struct dlgparam *dp = (struct dlgparam *)data; struct uctrl *uc = dlg_find_bywidget(dp, GTK_WIDGET(ed)); uc->ctrl->generic.handler(uc->ctrl, dp, dp->data, EVENT_REFRESH); - return FALSE; + return false; } #if !GTK_CHECK_VERSION(2,0,0) @@ -1366,22 +1366,22 @@ static gboolean listitem_key(GtkWidget *item, GdkEventKey *event, g_list_free(chead); } - return TRUE; + return true; } - return FALSE; + return false; } static gboolean listitem_single_key(GtkWidget *item, GdkEventKey *event, gpointer data) { - return listitem_key(item, event, data, FALSE); + return listitem_key(item, event, data, false); } static gboolean listitem_multi_key(GtkWidget *item, GdkEventKey *event, gpointer data) { - return listitem_key(item, event, data, TRUE); + return listitem_key(item, event, data, true); } static gboolean listitem_button_press(GtkWidget *item, GdkEventButton *event, @@ -1395,7 +1395,7 @@ static gboolean listitem_button_press(GtkWidget *item, GdkEventButton *event, case GDK_2BUTTON_PRESS: uc->nclicks = 2; break; case GDK_3BUTTON_PRESS: uc->nclicks = 3; break; } - return FALSE; + return false; } static gboolean listitem_button_release(GtkWidget *item, GdkEventButton *event, @@ -1405,9 +1405,9 @@ static gboolean listitem_button_release(GtkWidget *item, GdkEventButton *event, struct uctrl *uc = dlg_find_bywidget(dp, GTK_WIDGET(item)); if (uc->nclicks>1) { uc->ctrl->generic.handler(uc->ctrl, dp, dp->data, EVENT_ACTION); - return TRUE; + return true; } - return FALSE; + return false; } static void list_selchange(GtkList *list, gpointer data) @@ -1497,7 +1497,7 @@ static gboolean draglist_valchange(gpointer data) sfree(ctx); - return FALSE; + return false; } static void listbox_reorder(GtkTreeModel *treemodel, GtkTreePath *path, @@ -1626,9 +1626,9 @@ static void colourchoose_response(GtkDialog *dialog, dp->coloursel_result.r = (int) (255 * rgba.red); dp->coloursel_result.g = (int) (255 * rgba.green); dp->coloursel_result.b = (int) (255 * rgba.blue); - dp->coloursel_result.ok = TRUE; + dp->coloursel_result.ok = true; } else { - dp->coloursel_result.ok = FALSE; + dp->coloursel_result.ok = false; } uc->ctrl->generic.handler(uc->ctrl, dp, dp->data, EVENT_CALLBACK); @@ -1667,7 +1667,7 @@ static void coloursel_ok(GtkButton *button, gpointer data) dp->coloursel_result.b = (int) (255 * cvals[2]); } #endif - dp->coloursel_result.ok = TRUE; + dp->coloursel_result.ok = true; uc->ctrl->generic.handler(uc->ctrl, dp, dp->data, EVENT_CALLBACK); } @@ -1676,7 +1676,7 @@ static void coloursel_cancel(GtkButton *button, gpointer data) struct dlgparam *dp = (struct dlgparam *)data; gpointer coloursel = g_object_get_data(G_OBJECT(button), "user-data"); struct uctrl *uc = g_object_get_data(G_OBJECT(coloursel), "user-data"); - dp->coloursel_result.ok = FALSE; + dp->coloursel_result.ok = false; uc->ctrl->generic.handler(uc->ctrl, dp, dp->data, EVENT_CALLBACK); } @@ -1697,7 +1697,7 @@ static void filefont_clicked(GtkButton *button, gpointer data) STANDARD_CANCEL_LABEL, GTK_RESPONSE_CANCEL, STANDARD_OPEN_LABEL, GTK_RESPONSE_ACCEPT, (const gchar *)NULL); - gtk_window_set_modal(GTK_WINDOW(filechoose), TRUE); + gtk_window_set_modal(GTK_WINDOW(filechoose), true); g_object_set_data(G_OBJECT(filechoose), "user-data", (gpointer)uc); g_signal_connect(G_OBJECT(filechoose), "response", G_CALLBACK(filechoose_response), (gpointer)dp); @@ -1705,7 +1705,7 @@ static void filefont_clicked(GtkButton *button, gpointer data) #else GtkWidget *filesel = gtk_file_selection_new(uc->ctrl->fileselect.title); - gtk_window_set_modal(GTK_WINDOW(filesel), TRUE); + gtk_window_set_modal(GTK_WINDOW(filesel), true); g_object_set_data (G_OBJECT(GTK_FILE_SELECTION(filesel)->ok_button), "user-data", (gpointer)filesel); @@ -1735,7 +1735,7 @@ static void filefont_clicked(GtkButton *button, gpointer data) gchar *spacings[] = { "c", "m", NULL }; GtkWidget *fontsel = gtk_font_selection_dialog_new("Select a font"); - gtk_window_set_modal(GTK_WINDOW(fontsel), TRUE); + gtk_window_set_modal(GTK_WINDOW(fontsel), true); gtk_font_selection_dialog_set_filter (GTK_FONT_SELECTION_DIALOG(fontsel), GTK_FONT_FILTER_BASE, GTK_FONT_ALL, @@ -1792,7 +1792,7 @@ static void filefont_clicked(GtkButton *button, gpointer data) unifontsel *fontsel = unifontsel_new("Select a font"); - gtk_window_set_modal(fontsel->window, TRUE); + gtk_window_set_modal(fontsel->window, true); unifontsel_set_name(fontsel, fontname); g_object_set_data(G_OBJECT(fontsel->ok_button), @@ -1877,7 +1877,7 @@ GtkWidget *layout_ctrls(struct dlgparam *dp, struct Shortcuts *scs, for (i = 0; i < s->ncontrols; i++) { union control *ctrl = s->ctrls[i]; struct uctrl *uc; - int left = FALSE; + int left = false; GtkWidget *w = NULL; switch (ctrl->generic.type) { @@ -1919,7 +1919,7 @@ GtkWidget *layout_ctrls(struct dlgparam *dp, struct Shortcuts *scs, case CTRL_BUTTON: w = gtk_button_new_with_label(ctrl->generic.label); if (win) { - gtk_widget_set_can_default(w, TRUE); + gtk_widget_set_can_default(w, true); if (ctrl->button.isdefault) gtk_window_set_default(win, w); if (ctrl->button.iscancel) @@ -1940,7 +1940,7 @@ GtkWidget *layout_ctrls(struct dlgparam *dp, struct Shortcuts *scs, G_CALLBACK(widget_focus), dp); shortcut_add(scs, gtk_bin_get_child(GTK_BIN(w)), ctrl->checkbox.shortcut, SHORTCUT_UCTRL, uc); - left = TRUE; + left = true; break; case CTRL_RADIO: /* @@ -2011,7 +2011,7 @@ GtkWidget *layout_ctrls(struct dlgparam *dp, struct Shortcuts *scs, * GTK 1 combo box. */ w = gtk_combo_new(); - gtk_combo_set_value_in_list(GTK_COMBO(w), FALSE, TRUE); + gtk_combo_set_value_in_list(GTK_COMBO(w), false, true); uc->entry = GTK_COMBO(w)->entry; uc->list = GTK_COMBO(w)->list; signalobject = uc->entry; @@ -2033,7 +2033,7 @@ GtkWidget *layout_ctrls(struct dlgparam *dp, struct Shortcuts *scs, } else { w = gtk_entry_new(); if (ctrl->editbox.password) - gtk_entry_set_visibility(GTK_ENTRY(w), FALSE); + gtk_entry_set_visibility(GTK_ENTRY(w), false); uc->entry = w; signalobject = w; } @@ -2226,7 +2226,7 @@ GtkWidget *layout_ctrls(struct dlgparam *dp, struct Shortcuts *scs, * column to look at in the list model). */ cr = gtk_cell_renderer_text_new(); - gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(w), cr, TRUE); + gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(w), cr, true); gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(w), cr, "text", 1, NULL); @@ -2337,7 +2337,7 @@ GtkWidget *layout_ctrls(struct dlgparam *dp, struct Shortcuts *scs, (GTK_TREE_MODEL(uc->listmodel)); g_object_set_data(G_OBJECT(uc->listmodel), "user-data", (gpointer)w); - gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(w), FALSE); + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(w), false); sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(w)); gtk_tree_selection_set_mode (sel, ctrl->listbox.multisel ? GTK_SELECTION_MULTIPLE : @@ -2351,7 +2351,7 @@ GtkWidget *layout_ctrls(struct dlgparam *dp, struct Shortcuts *scs, G_CALLBACK(listbox_selchange), dp); if (ctrl->listbox.draglist) { - gtk_tree_view_set_reorderable(GTK_TREE_VIEW(w), TRUE); + gtk_tree_view_set_reorderable(GTK_TREE_VIEW(w), true); g_signal_connect(G_OBJECT(uc->listmodel), "row-inserted", G_CALLBACK(listbox_reorder), dp); } @@ -2375,7 +2375,7 @@ GtkWidget *layout_ctrls(struct dlgparam *dp, struct Shortcuts *scs, if (!ctrl->listbox.hscroll) { g_object_set(G_OBJECT(cellrend), "ellipsize", PANGO_ELLIPSIZE_END, - "ellipsize-set", TRUE, + "ellipsize-set", true, (const char *)NULL); } column = gtk_tree_view_column_new_with_attributes @@ -2482,7 +2482,7 @@ GtkWidget *layout_ctrls(struct dlgparam *dp, struct Shortcuts *scs, uc->text = w = gtk_label_new(uc->ctrl->generic.label); #endif align_label_left(GTK_LABEL(w)); - gtk_label_set_line_wrap(GTK_LABEL(w), TRUE); + gtk_label_set_line_wrap(GTK_LABEL(w), true); break; } @@ -2570,10 +2570,10 @@ static int tree_grab_focus(struct dlgparam *dp) } if (f >= 0) - return FALSE; + return false; else { gtk_widget_grab_focus(dp->currtreeitem); - return TRUE; + return true; } } @@ -2584,7 +2584,7 @@ gint tree_focus(GtkContainer *container, GtkDirectionType direction, g_signal_stop_emission_by_name(G_OBJECT(container), "focus"); /* - * If there's a focused treeitem, we return FALSE to cause the + * If there's a focused treeitem, we return false to cause the * focus to move on to some totally other control. If not, we * focus the selected one. */ @@ -2598,7 +2598,7 @@ int win_key_press(GtkWidget *widget, GdkEventKey *event, gpointer data) if (event->keyval == GDK_KEY_Escape && dp->cancelbutton) { g_signal_emit_by_name(G_OBJECT(dp->cancelbutton), "clicked"); - return TRUE; + return true; } if ((event->state & GDK_MOD1_MASK) && @@ -2713,7 +2713,7 @@ int win_key_press(GtkWidget *widget, GdkEventKey *event, gpointer data) } } - return FALSE; + return false; } #if !GTK_CHECK_VERSION(2,0,0) @@ -2742,10 +2742,10 @@ int tree_key_press(GtkWidget *widget, GdkEventKey *event, gpointer data) */ { GtkWidget *w = dp->treeitems[i]; - int vis = TRUE; + int vis = true; while (w && (GTK_IS_TREE_ITEM(w) || GTK_IS_TREE(w))) { if (!GTK_WIDGET_VISIBLE(w)) { - vis = FALSE; + vis = false; break; } w = w->parent; @@ -2762,7 +2762,7 @@ int tree_key_press(GtkWidget *widget, GdkEventKey *event, gpointer data) g_signal_emit_by_name(G_OBJECT(dp->treeitems[j]), "toggle"); gtk_widget_grab_focus(dp->treeitems[j]); } - return TRUE; + return true; } /* @@ -2772,15 +2772,15 @@ int tree_key_press(GtkWidget *widget, GdkEventKey *event, gpointer data) if (event->keyval == GDK_Left || event->keyval == GDK_KP_Left) { g_signal_stop_emission_by_name(G_OBJECT(widget), "key_press_event"); gtk_tree_item_collapse(GTK_TREE_ITEM(widget)); - return TRUE; + return true; } if (event->keyval == GDK_Right || event->keyval == GDK_KP_Right) { g_signal_stop_emission_by_name(G_OBJECT(widget), "key_press_event"); gtk_tree_item_expand(GTK_TREE_ITEM(widget)); - return TRUE; + return true; } - return FALSE; + return false; } #endif @@ -2935,15 +2935,15 @@ GtkWidget *create_config_box(const char *title, Conf *conf, gtk_setup_config_box(dp->ctrlbox, midsession, window); gtk_window_set_title(GTK_WINDOW(window), title); - hbox = gtk_hbox_new(FALSE, 4); - our_dialog_add_to_content_area(GTK_WINDOW(window), hbox, TRUE, TRUE, 0); + hbox = gtk_hbox_new(false, 4); + our_dialog_add_to_content_area(GTK_WINDOW(window), hbox, true, true, 0); gtk_container_set_border_width(GTK_CONTAINER(hbox), 10); gtk_widget_show(hbox); - vbox = gtk_vbox_new(FALSE, 4); - gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0); + vbox = gtk_vbox_new(false, 4); + gtk_box_pack_start(GTK_BOX(hbox), vbox, false, false, 0); gtk_widget_show(vbox); cols = columns_new(4); - gtk_box_pack_start(GTK_BOX(vbox), cols, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), cols, false, false, 0); gtk_widget_show(cols); label = gtk_label_new("Category:"); columns_add(COLUMNS(cols), label, 0, 1); @@ -2954,7 +2954,7 @@ GtkWidget *create_config_box(const char *title, Conf *conf, treestore = gtk_tree_store_new (TREESTORE_NUM, G_TYPE_STRING, G_TYPE_INT); tree = gtk_tree_view_new_with_model(GTK_TREE_MODEL(treestore)); - gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(tree), FALSE); + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(tree), false); treerenderer = gtk_cell_renderer_text_new(); treecolumn = gtk_tree_view_column_new_with_attributes ("Label", treerenderer, "text", 0, NULL); @@ -2972,11 +2972,11 @@ GtkWidget *create_config_box(const char *title, Conf *conf, G_CALLBACK(widget_focus), dp); shortcut_add(&scs, label, 'g', SHORTCUT_TREE, tree); gtk_widget_show(treescroll); - gtk_box_pack_start(GTK_BOX(vbox), treescroll, TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(vbox), treescroll, true, true, 0); panels = gtk_notebook_new(); - gtk_notebook_set_show_tabs(GTK_NOTEBOOK(panels), FALSE); - gtk_notebook_set_show_border(GTK_NOTEBOOK(panels), FALSE); - gtk_box_pack_start(GTK_BOX(hbox), panels, TRUE, TRUE, 0); + gtk_notebook_set_show_tabs(GTK_NOTEBOOK(panels), false); + gtk_notebook_set_show_border(GTK_NOTEBOOK(panels), false); + gtk_box_pack_start(GTK_BOX(hbox), panels, true, true, 0); gtk_widget_show(panels); panelvbox = NULL; @@ -3023,7 +3023,7 @@ GtkWidget *create_config_box(const char *title, Conf *conf, first = (panelvbox == NULL); - panelvbox = gtk_vbox_new(FALSE, 4); + panelvbox = gtk_vbox_new(false, 4); gtk_widget_show(panelvbox); gtk_notebook_append_page(GTK_NOTEBOOK(panels), panelvbox, NULL); @@ -3076,7 +3076,7 @@ GtkWidget *create_config_box(const char *title, Conf *conf, */ gtk_tree_view_expand_row(GTK_TREE_VIEW(tree), selparams[nselparams].treepath, - FALSE); + false); } else { selparams[nselparams].treepath = NULL; } @@ -3117,7 +3117,7 @@ GtkWidget *create_config_box(const char *title, Conf *conf, } w = layout_ctrls(dp, &selparams[nselparams-1].shortcuts, s, NULL); - gtk_box_pack_start(GTK_BOX(panelvbox), w, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(panelvbox), w, false, false, 0); gtk_widget_show(w); } } @@ -3330,7 +3330,7 @@ GtkWidget *create_message_box( I(button->value)); c->generic.column = index++; if (button->type > 0) - c->button.isdefault = TRUE; + c->button.isdefault = true; /* We always arrange that _some_ button is labelled as * 'iscancel', so that pressing Escape will always cause @@ -3342,7 +3342,7 @@ GtkWidget *create_message_box( * that really is just showing a _message_ and not even asking * a question) then that will be picked. */ if (button->type == min_type) - c->button.iscancel = TRUE; + c->button.iscancel = true; } s1 = ctrl_getset(dp->ctrlbox, "x", "", ""); @@ -3356,7 +3356,7 @@ GtkWidget *create_message_box( w1 = layout_ctrls(dp, &scs, s1, GTK_WINDOW(window)); gtk_container_set_border_width(GTK_CONTAINER(w1), 10); gtk_widget_set_size_request(w1, minwid+20, -1); - our_dialog_add_to_content_area(GTK_WINDOW(window), w1, TRUE, TRUE, 0); + our_dialog_add_to_content_area(GTK_WINDOW(window), w1, true, true, 0); gtk_widget_show(w1); dp->shortcuts = &scs; @@ -3367,7 +3367,7 @@ GtkWidget *create_message_box( if (selectable) { #if GTK_CHECK_VERSION(2,0,0) struct uctrl *uc = dlg_find_byctrl(dp, textctrl); - gtk_label_set_selectable(GTK_LABEL(uc->text), TRUE); + gtk_label_set_selectable(GTK_LABEL(uc->text), true); /* * GTK selectable labels have a habit of selecting their @@ -3523,7 +3523,7 @@ int gtk_seat_verify_ssh_host_key( mainwin = GTK_WIDGET(gtk_seat_get_window(seat)); msgbox = create_message_box( - mainwin, "PuTTY Security Alert", text, string_width(fingerprint), TRUE, + mainwin, "PuTTY Security Alert", text, string_width(fingerprint), true, &buttons_hostkey, verify_ssh_host_key_result_callback, result_ctx); register_dialog(seat, DIALOG_SLOT_NETWORK_PROMPT, msgbox); @@ -3584,7 +3584,7 @@ int gtk_seat_confirm_weak_crypto_primitive( msgbox = create_message_box( mainwin, "PuTTY Security Alert", text, string_width("Reasonably long line of text as a width template"), - FALSE, &buttons_yn, simple_prompt_result_callback, result_ctx); + false, &buttons_yn, simple_prompt_result_callback, result_ctx); register_dialog(seat, result_ctx->dialog_slot, msgbox); sfree(text); @@ -3621,7 +3621,7 @@ int gtk_seat_confirm_weak_cached_hostkey( mainwin, "PuTTY Security Alert", text, string_width("is ecdsa-nistp521, which is below the configured" " warning threshold."), - FALSE, &buttons_yn, simple_prompt_result_callback, result_ctx); + false, &buttons_yn, simple_prompt_result_callback, result_ctx); register_dialog(seat, result_ctx->dialog_slot, msgbox); sfree(text); @@ -3642,7 +3642,7 @@ void nonfatal_message_box(void *window, const char *msg) create_message_box( window, title, msg, string_width("REASONABLY LONG LINE OF TEXT FOR BASIC SANITY"), - FALSE, &buttons_ok, trivial_post_dialog_fn, NULL); + false, &buttons_ok, trivial_post_dialog_fn, NULL); sfree(title); } @@ -3683,7 +3683,7 @@ static void licence_clicked(GtkButton *button, gpointer data) create_message_box(aboutbox, title, LICENCE_TEXT("\n\n"), string_width("LONGISH LINE OF TEXT SO THE LICENCE" " BOX ISN'T EXCESSIVELY TALL AND THIN"), - TRUE, &buttons_ok, trivial_post_dialog_fn, NULL); + true, &buttons_ok, trivial_post_dialog_fn, NULL); sfree(title); } @@ -3705,17 +3705,17 @@ void about_box(void *window) sfree(title); w = gtk_button_new_with_label("Close"); - gtk_widget_set_can_default(w, TRUE); + gtk_widget_set_can_default(w, true); gtk_window_set_default(GTK_WINDOW(aboutbox), w); action_area = our_dialog_make_action_hbox(GTK_WINDOW(aboutbox)); - gtk_box_pack_end(action_area, w, FALSE, FALSE, 0); + gtk_box_pack_end(action_area, w, false, false, 0); g_signal_connect(G_OBJECT(w), "clicked", G_CALLBACK(about_close_clicked), NULL); gtk_widget_show(w); w = gtk_button_new_with_label("View Licence"); - gtk_widget_set_can_default(w, TRUE); - gtk_box_pack_end(action_area, w, FALSE, FALSE, 0); + gtk_widget_set_can_default(w, true); + gtk_box_pack_end(action_area, w, false, false, 0); g_signal_connect(G_OBJECT(w), "clicked", G_CALLBACK(licence_clicked), NULL); gtk_widget_show(w); @@ -3729,11 +3729,11 @@ void about_box(void *window) w = gtk_label_new(label_text); gtk_label_set_justify(GTK_LABEL(w), GTK_JUSTIFY_CENTER); #if GTK_CHECK_VERSION(2,0,0) - gtk_label_set_selectable(GTK_LABEL(w), TRUE); + gtk_label_set_selectable(GTK_LABEL(w), true); #endif sfree(label_text); } - our_dialog_add_to_content_area(GTK_WINDOW(aboutbox), w, FALSE, FALSE, 0); + our_dialog_add_to_content_area(GTK_WINDOW(aboutbox), w, false, false, 0); #if GTK_CHECK_VERSION(2,0,0) /* * Same precautions against initial select-all as in @@ -3901,7 +3901,7 @@ gint eventlog_selection_clear(GtkWidget *widget, GdkEventSelection *seldata, sfree(es->seldata); es->sellen = 0; es->seldata = NULL; - return TRUE; + return true; } void showeventlog(eventlog_stuff *es, void *parentwin) @@ -3931,7 +3931,7 @@ void showeventlog(eventlog_stuff *es, void *parentwin) c = ctrl_pushbutton(s0, "Close", 'c', HELPCTX(no_help), eventlog_ok_handler, P(NULL)); c->button.column = 1; - c->button.isdefault = TRUE; + c->button.isdefault = true; s1 = ctrl_getset(es->eventbox, "x", "", ""); es->listctrl = c = ctrl_listbox(s1, NULL, NO_SHORTCUT, HELPCTX(no_help), @@ -3957,7 +3957,7 @@ void showeventlog(eventlog_stuff *es, void *parentwin) ("LINE OF TEXT GIVING WIDTH OF EVENT LOG IS " "QUITE LONG 'COS SSH LOG ENTRIES ARE WIDE"), -1); - our_dialog_add_to_content_area(GTK_WINDOW(window), w1, TRUE, TRUE, 0); + our_dialog_add_to_content_area(GTK_WINDOW(window), w1, true, true, 0); gtk_widget_show(w1); es->dp.data = es; @@ -4086,7 +4086,7 @@ int gtkdlg_askappend(Seat *seat, Filename *filename, msgbox = create_message_box( mainwin, mbtitle, message, string_width("LINE OF TEXT SUITABLE FOR THE ASKAPPEND WIDTH"), - FALSE, &buttons_append, simple_prompt_result_callback, result_ctx); + false, &buttons_append, simple_prompt_result_callback, result_ctx); register_dialog(seat, result_ctx->dialog_slot, msgbox); sfree(message); diff --git a/unix/gtkfont.c b/unix/gtkfont.c index 3dbf16f0..074b61f9 100644 --- a/unix/gtkfont.c +++ b/unix/gtkfont.c @@ -448,8 +448,8 @@ static unifont *x11font_create(GtkWidget *widget, const char *name, charset_encoding = XInternAtom(disp, "CHARSET_ENCODING", False); pubcs = realcs = CS_NONE; - sixteen_bit = FALSE; - variable = TRUE; + sixteen_bit = false; + variable = true; if (XGetFontProperty(xfs, charset_registry, ®istry_ret) && XGetFontProperty(xfs, charset_encoding, &encoding_ret)) { @@ -467,7 +467,7 @@ static unifont *x11font_create(GtkWidget *widget, const char *name, * into 16-bit Unicode. */ if (!strcasecmp(encoding, "iso10646-1")) { - sixteen_bit = TRUE; + sixteen_bit = true; pubcs = realcs = CS_UTF8; } @@ -496,7 +496,7 @@ static unifont *x11font_create(GtkWidget *widget, const char *name, spc = XGetAtomName(disp, (Atom)spacing_ret); if (spc && strchr("CcMm", spc[0])) - variable = FALSE; + variable = false; } xfont = snew(struct x11font); @@ -506,7 +506,7 @@ static unifont *x11font_create(GtkWidget *widget, const char *name, xfont->u.descent = xfs->descent; xfont->u.height = xfont->u.ascent + xfont->u.descent; xfont->u.public_charset = pubcs; - xfont->u.want_fallback = TRUE; + xfont->u.want_fallback = true; #ifdef DRAW_TEXT_GDK xfont->u.preferred_drawtype = DRAWTYPE_GDK; #elif defined DRAW_TEXT_CAIRO @@ -525,7 +525,7 @@ static unifont *x11font_create(GtkWidget *widget, const char *name, for (i = 0; i < lenof(xfont->fonts); i++) { xfont->fonts[i].xfs = NULL; - xfont->fonts[i].allocated = FALSE; + xfont->fonts[i].allocated = false; #ifdef DRAW_TEXT_CAIRO xfont->fonts[i].glyphcache = NULL; xfont->fonts[i].nglyphs = 0; @@ -534,7 +534,7 @@ static unifont *x11font_create(GtkWidget *widget, const char *name, #endif } xfont->fonts[0].xfs = xfs; - xfont->fonts[0].allocated = TRUE; + xfont->fonts[0].allocated = true; return &xfont->u; } @@ -572,7 +572,7 @@ static void x11_alloc_subfont(struct x11font *xfont, int sfid) char *derived_name = x11_guess_derived_font_name (disp, xfont->fonts[0].xfs, sfid & 1, !!(sfid & 2)); xfont->fonts[sfid].xfs = XLoadQueryFont(disp, derived_name); - xfont->fonts[sfid].allocated = TRUE; + xfont->fonts[sfid].allocated = true; sfree(derived_name); /* Note that xfont->fonts[sfid].xfs may still be NULL, if XLQF failed. */ } @@ -597,7 +597,7 @@ static int x11font_has_glyph(unifont *font, wchar_t glyph) int sblen = wc_to_mb(xfont->real_charset, 0, &glyph, 1, sbstring, 2, "", NULL); if (sblen == 0 || !sbstring[0]) - return FALSE; /* not even in the charset */ + return false; /* not even in the charset */ return x11_font_has_glyph(xfont->fonts[0].xfs, 0, (unsigned char)sbstring[0]); @@ -862,14 +862,14 @@ static void x11font_really_draw_text( */ step = 1; nsteps = nchars; - centre = TRUE; + centre = true; } else { /* * In a fixed-pitch font, we can draw the whole lot in one go. */ step = nchars; nsteps = 1; - centre = FALSE; + centre = false; } dfns->setup(ctx, xfi, disp); @@ -1391,17 +1391,17 @@ static int pangofont_check_desc_makes_sense(PangoContext *ctx, #ifndef PANGO_PRE_1POINT6 map = pango_context_get_font_map(ctx); if (!map) - return FALSE; + return false; pango_font_map_list_families(map, &families, &nfamilies); #else pango_context_list_families(ctx, &families, &nfamilies); #endif - matched = FALSE; + matched = false; for (i = 0; i < nfamilies; i++) { if (!g_ascii_strcasecmp(pango_font_family_get_name(families[i]), pango_font_description_get_family(desc))) { - matched = TRUE; + matched = true; break; } } @@ -1454,7 +1454,7 @@ static unifont *pangofont_create_internal(GtkWidget *widget, pfont->u.ascent = PANGO_PIXELS(pango_font_metrics_get_ascent(metrics)); pfont->u.descent = PANGO_PIXELS(pango_font_metrics_get_descent(metrics)); pfont->u.height = pfont->u.ascent + pfont->u.descent; - pfont->u.want_fallback = FALSE; + pfont->u.want_fallback = false; #ifdef DRAW_TEXT_CAIRO pfont->u.preferred_drawtype = DRAWTYPE_CAIRO; #elif defined DRAW_TEXT_GDK @@ -1562,7 +1562,7 @@ static int pangofont_char_width(PangoLayout *layout, struct pangofont *pfont, static int pangofont_has_glyph(unifont *font, wchar_t glyph) { /* Pango implements font fallback, so assume it has everything */ - return TRUE; + return true; } #ifdef DRAW_TEXT_GDK @@ -1592,7 +1592,7 @@ static void pangofont_draw_internal(unifont_drawctx *ctx, unifont *font, PangoRectangle rect; char *utfstring, *utfptr; int utflen; - int shadowbold = FALSE; + int shadowbold = false; void (*draw_layout)(unifont_drawctx *ctx, gint x, gint y, PangoLayout *layout) = NULL; @@ -1616,7 +1616,7 @@ static void pangofont_draw_internal(unifont_drawctx *ctx, unifont *font, pango_layout_set_font_description(layout, pfont->desc); if (bold > pfont->bold) { if (pfont->shadowalways) - shadowbold = TRUE; + shadowbold = true; else { PangoFontDescription *desc2 = pango_font_description_copy_static(pfont->desc); @@ -1743,7 +1743,7 @@ static void pangofont_draw_text(unifont_drawctx *ctx, unifont *font, int wide, int bold, int cellwidth) { pangofont_draw_internal(ctx, font, x, y, string, len, wide, bold, - cellwidth, FALSE); + cellwidth, false); } static void pangofont_draw_combining(unifont_drawctx *ctx, unifont *font, @@ -1765,7 +1765,7 @@ static void pangofont_draw_combining(unifont_drawctx *ctx, unifont *font, len++; } pangofont_draw_internal(ctx, font, x, y, string, len, wide, bold, - cellwidth, TRUE); + cellwidth, true); sfree(tmpstring); } @@ -2234,7 +2234,7 @@ unifont *multifont_create(GtkWidget *widget, const char *name, mfont->u.descent = font->descent; mfont->u.height = font->height; mfont->u.public_charset = font->public_charset; - mfont->u.want_fallback = FALSE; /* shouldn't be needed, but just in case */ + mfont->u.want_fallback = false; /* shouldn't be needed, but just in case */ mfont->u.preferred_drawtype = font->preferred_drawtype; mfont->main = font; mfont->fallback = fallback; @@ -2456,8 +2456,8 @@ static void unifontsel_deselect(unifontsel_internal *fs) fs->selected = NULL; gtk_list_store_clear(fs->style_model); gtk_list_store_clear(fs->size_model); - gtk_widget_set_sensitive(fs->u.ok_button, FALSE); - gtk_widget_set_sensitive(fs->size_entry, FALSE); + gtk_widget_set_sensitive(fs->u.ok_button, false); + gtk_widget_set_sensitive(fs->size_entry, false); unifontsel_draw_preview_text(fs); } @@ -2469,7 +2469,7 @@ static void unifontsel_setup_familylist(unifontsel_internal *fs) int currflags = -1; fontinfo *info; - fs->inhibit_response = TRUE; + fs->inhibit_response = true; gtk_list_store_clear(fs->family_model); listindex = 0; @@ -2522,20 +2522,20 @@ static void unifontsel_setup_familylist(unifontsel_internal *fs) if (fs->selected && fs->selected->familyindex < 0) unifontsel_deselect(fs); - fs->inhibit_response = FALSE; + fs->inhibit_response = false; } static void unifontsel_setup_stylelist(unifontsel_internal *fs, int start, int end) { GtkTreeIter iter; - int i, listindex, minpos = -1, maxpos = -1, started = FALSE; + int i, listindex, minpos = -1, maxpos = -1, started = false; char *currcs = NULL, *currstyle = NULL; fontinfo *info; gtk_list_store_clear(fs->style_model); listindex = 0; - started = FALSE; + started = false; /* * Search through the font tree for anything matching our @@ -2563,12 +2563,12 @@ static void unifontsel_setup_stylelist(unifontsel_internal *fs, * We've either finished a style/charset, or started a * new one, or both. */ - started = TRUE; + started = true; if (currstyle) { gtk_list_store_append(fs->style_model, &iter); gtk_list_store_set(fs->style_model, &iter, 0, currstyle, 1, minpos, 2, maxpos+1, - 3, TRUE, 4, PANGO_WEIGHT_NORMAL, -1); + 3, true, 4, PANGO_WEIGHT_NORMAL, -1); listindex++; } if (info) { @@ -2577,7 +2577,7 @@ static void unifontsel_setup_stylelist(unifontsel_internal *fs, gtk_list_store_append(fs->style_model, &iter); gtk_list_store_set(fs->style_model, &iter, 0, info->charset, 1, -1, 2, -1, - 3, FALSE, 4, PANGO_WEIGHT_BOLD, -1); + 3, false, 4, PANGO_WEIGHT_BOLD, -1); listindex++; } currcs = info->charset; @@ -2664,7 +2664,7 @@ static void unifontsel_draw_preview_text_inner(unifont_drawctx *dctx, (GTK_WIDGET(fs->u.window), info->realname, fs->selsize); font = info->fontclass->create(GTK_WIDGET(fs->u.window), sizename ? sizename : info->realname, - FALSE, FALSE, 0, 0); + false, false, 0, 0); } else font = NULL; @@ -2715,11 +2715,11 @@ static void unifontsel_draw_preview_text_inner(unifont_drawctx *dctx, info->fontclass->draw_text(dctx, font, 0, font->ascent, L"bankrupt jilted showmen quiz convex fogey", - 41, FALSE, FALSE, font->width); + 41, false, false, font->width); info->fontclass->draw_text(dctx, font, 0, font->ascent + font->height, L"BANKRUPT JILTED SHOWMEN QUIZ CONVEX FOGEY", - 41, FALSE, FALSE, font->width); + 41, false, false, font->width); /* * The ordering of punctuation here is also selected * with some specific aims in mind. I put ` and ' @@ -2735,7 +2735,7 @@ static void unifontsel_draw_preview_text_inner(unifont_drawctx *dctx, info->fontclass->draw_text(dctx, font, 0, font->ascent + font->height * 2, L"0123456789!?,.:;<>()[]{}\\/`'\"+*-=~#_@|%&^$", - 42, FALSE, FALSE, font->width); + 42, false, false, font->width); info->fontclass->destroy(font); } @@ -2803,7 +2803,7 @@ static void unifontsel_draw_preview_text(unifontsel_internal *fs) #endif gdk_window_invalidate_rect(gtk_widget_get_window(fs->preview_area), - NULL, FALSE); + NULL, false); } static void unifontsel_select_font(unifontsel_internal *fs, @@ -2816,14 +2816,14 @@ static void unifontsel_select_font(unifontsel_internal *fs, GtkTreePath *treepath; GtkTreeIter iter; - fs->inhibit_response = TRUE; + fs->inhibit_response = true; fs->selected = info; fs->selsize = size; if (size_is_explicit) fs->intendedsize = size; - gtk_widget_set_sensitive(fs->u.ok_button, TRUE); + gtk_widget_set_sensitive(fs->u.ok_button, true); /* * Find the index of this fontinfo in the selorder list. @@ -2852,7 +2852,7 @@ static void unifontsel_select_font(unifontsel_internal *fs, (gtk_tree_view_get_selection(GTK_TREE_VIEW(fs->family_list)), treepath); gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(fs->family_list), - treepath, NULL, FALSE, 0.0, 0.0); + treepath, NULL, false, 0.0, 0.0); success = gtk_tree_model_get_iter(GTK_TREE_MODEL(fs->family_model), &iter, treepath); assert(success); @@ -2876,7 +2876,7 @@ static void unifontsel_select_font(unifontsel_internal *fs, (gtk_tree_view_get_selection(GTK_TREE_VIEW(fs->style_list)), treepath); gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(fs->style_list), - treepath, NULL, FALSE, 0.0, 0.0); + treepath, NULL, false, 0.0, 0.0); gtk_tree_model_get_iter(GTK_TREE_MODEL(fs->style_model), &iter, treepath); gtk_tree_path_free(treepath); @@ -2899,7 +2899,7 @@ static void unifontsel_select_font(unifontsel_internal *fs, (gtk_tree_view_get_selection(GTK_TREE_VIEW(fs->size_list)), treepath); gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(fs->size_list), - treepath, NULL, FALSE, 0.0, 0.0); + treepath, NULL, false, 0.0, 0.0); gtk_tree_path_free(treepath); size = info->size; } else { @@ -2908,9 +2908,9 @@ static void unifontsel_select_font(unifontsel_internal *fs, if (unifontsel_default_sizes[j] == size) { treepath = gtk_tree_path_new_from_indices(j, -1); gtk_tree_view_set_cursor(GTK_TREE_VIEW(fs->size_list), - treepath, NULL, FALSE); + treepath, NULL, false); gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(fs->size_list), - treepath, NULL, FALSE, 0.0, + treepath, NULL, false, 0.0, 0.0); gtk_tree_path_free(treepath); } @@ -2940,7 +2940,7 @@ static void unifontsel_select_font(unifontsel_internal *fs, unifontsel_draw_preview_text(fs); - fs->inhibit_response = FALSE; + fs->inhibit_response = false; } static void unifontsel_button_toggled(GtkToggleButton *tb, gpointer data) @@ -3125,7 +3125,7 @@ static void family_changed(GtkTreeSelection *treeselection, gpointer data) if (!info->size) fs->selsize = fs->intendedsize; /* font is scalable */ unifontsel_select_font(fs, info, info->size ? info->size : fs->selsize, - 1, FALSE); + 1, false); } static void style_changed(GtkTreeSelection *treeselection, gpointer data) @@ -3152,7 +3152,7 @@ static void style_changed(GtkTreeSelection *treeselection, gpointer data) if (!info->size) fs->selsize = fs->intendedsize; /* font is scalable */ unifontsel_select_font(fs, info, info->size ? info->size : fs->selsize, - 2, FALSE); + 2, false); } static void size_changed(GtkTreeSelection *treeselection, gpointer data) @@ -3171,7 +3171,7 @@ static void size_changed(GtkTreeSelection *treeselection, gpointer data) gtk_tree_model_get(treemodel, &treeiter, 1, &minval, 2, &size, -1); info = (fontinfo *)index234(fs->fonts_by_selorder, minval); - unifontsel_select_font(fs, info, info->size ? info->size : size, 3, TRUE); + unifontsel_select_font(fs, info, info->size ? info->size : size, 3, true); } static void size_entry_changed(GtkEditable *ed, gpointer data) @@ -3188,7 +3188,7 @@ static void size_entry_changed(GtkEditable *ed, gpointer data) if (size > 0) { assert(fs->selected->size == 0); - unifontsel_select_font(fs, fs->selected, size, 3, TRUE); + unifontsel_select_font(fs, fs->selected, size, 3, true); } } @@ -3212,7 +3212,7 @@ static void alias_resolve(GtkTreeView *treeview, GtkTreePath *path, struct fontinfo_realname_find f; newname = info->fontclass->canonify_fontname - (GTK_WIDGET(fs->u.window), info->realname, &newsize, &flags, TRUE); + (GTK_WIDGET(fs->u.window), info->realname, &newsize, &flags, true); f.realname = newname; f.flags = flags; @@ -3225,7 +3225,7 @@ static void alias_resolve(GtkTreeView *treeview, GtkTreePath *path, return; /* didn't change under canonification => not an alias */ unifontsel_select_font(fs, newinfo, newinfo->size ? newinfo->size : newsize, - 1, TRUE); + 1, true); } } @@ -3240,7 +3240,7 @@ static gint unifontsel_draw_area(GtkWidget *widget, cairo_t *cr, gpointer data) dctx.u.cairo.cr = cr; unifontsel_draw_preview_text_inner(&dctx, fs); - return TRUE; + return true; } #else static gint unifontsel_expose_area(GtkWidget *widget, GdkEventExpose *event, @@ -3262,7 +3262,7 @@ static gint unifontsel_expose_area(GtkWidget *widget, GdkEventExpose *event, unifontsel_draw_preview_text(fs); #endif - return TRUE; + return true; } #endif @@ -3295,9 +3295,9 @@ static gint unifontsel_configure_area(GtkWidget *widget, } #endif - gdk_window_invalidate_rect(gtk_widget_get_window(widget), NULL, FALSE); + gdk_window_invalidate_rect(gtk_widget_get_window(widget), NULL, false); - return TRUE; + return true; } unifontsel *unifontsel_new(const char *wintitle) @@ -3309,7 +3309,7 @@ unifontsel *unifontsel_new(const char *wintitle) int lists_height, preview_height, font_width, style_width, size_width; int i; - fs->inhibit_response = FALSE; + fs->inhibit_response = false; fs->selected = NULL; { @@ -3352,7 +3352,7 @@ unifontsel *unifontsel_new(const char *wintitle) table = gtk_grid_new(); gtk_grid_set_column_spacing(GTK_GRID(table), 8); #else - table = gtk_table_new(8, 3, FALSE); + table = gtk_table_new(8, 3, false); gtk_table_set_col_spacings(GTK_TABLE(table), 8); #endif gtk_widget_show(table); @@ -3375,14 +3375,14 @@ unifontsel *unifontsel_new(const char *wintitle) gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area (GTK_DIALOG(fs->u.window))), - w, TRUE, TRUE, 0); + w, true, true, 0); label = gtk_label_new_with_mnemonic("_Font:"); gtk_widget_show(label); align_label_left(GTK_LABEL(label)); #if GTK_CHECK_VERSION(3,0,0) gtk_grid_attach(GTK_GRID(table), label, 0, 0, 1, 1); - g_object_set(G_OBJECT(label), "hexpand", TRUE, (const char *)NULL); + g_object_set(G_OBJECT(label), "hexpand", true, (const char *)NULL); #else gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, GTK_FILL, 0, 0, 0); #endif @@ -3394,7 +3394,7 @@ unifontsel *unifontsel_new(const char *wintitle) */ model = gtk_list_store_new(3, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT); w = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model)); - gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(w), FALSE); + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(w), false); gtk_label_set_mnemonic_widget(GTK_LABEL(label), w); gtk_widget_show(w); column = gtk_tree_view_column_new_with_attributes @@ -3417,7 +3417,7 @@ unifontsel *unifontsel_new(const char *wintitle) gtk_widget_set_size_request(scroll, font_width, lists_height); #if GTK_CHECK_VERSION(3,0,0) gtk_grid_attach(GTK_GRID(table), scroll, 0, 1, 1, 2); - g_object_set(G_OBJECT(scroll), "expand", TRUE, (const char *)NULL); + g_object_set(G_OBJECT(scroll), "expand", true, (const char *)NULL); #else gtk_table_attach(GTK_TABLE(table), scroll, 0, 1, 1, 3, GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); @@ -3430,7 +3430,7 @@ unifontsel *unifontsel_new(const char *wintitle) align_label_left(GTK_LABEL(label)); #if GTK_CHECK_VERSION(3,0,0) gtk_grid_attach(GTK_GRID(table), label, 1, 0, 1, 1); - g_object_set(G_OBJECT(label), "hexpand", TRUE, (const char *)NULL); + g_object_set(G_OBJECT(label), "hexpand", true, (const char *)NULL); #else gtk_table_attach(GTK_TABLE(table), label, 1, 2, 0, 1, GTK_FILL, 0, 0, 0); #endif @@ -3445,7 +3445,7 @@ unifontsel *unifontsel_new(const char *wintitle) model = gtk_list_store_new(5, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT, G_TYPE_BOOLEAN, G_TYPE_INT); w = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model)); - gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(w), FALSE); + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(w), false); gtk_label_set_mnemonic_widget(GTK_LABEL(label), w); gtk_widget_show(w); column = gtk_tree_view_column_new_with_attributes @@ -3466,7 +3466,7 @@ unifontsel *unifontsel_new(const char *wintitle) gtk_widget_set_size_request(scroll, style_width, lists_height); #if GTK_CHECK_VERSION(3,0,0) gtk_grid_attach(GTK_GRID(table), scroll, 1, 1, 1, 2); - g_object_set(G_OBJECT(scroll), "expand", TRUE, (const char *)NULL); + g_object_set(G_OBJECT(scroll), "expand", true, (const char *)NULL); #else gtk_table_attach(GTK_TABLE(table), scroll, 1, 2, 1, 3, GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); @@ -3479,7 +3479,7 @@ unifontsel *unifontsel_new(const char *wintitle) align_label_left(GTK_LABEL(label)); #if GTK_CHECK_VERSION(3,0,0) gtk_grid_attach(GTK_GRID(table), label, 2, 0, 1, 1); - g_object_set(G_OBJECT(label), "hexpand", TRUE, (const char *)NULL); + g_object_set(G_OBJECT(label), "hexpand", true, (const char *)NULL); #else gtk_table_attach(GTK_TABLE(table), label, 2, 3, 0, 1, GTK_FILL, 0, 0, 0); #endif @@ -3495,7 +3495,7 @@ unifontsel *unifontsel_new(const char *wintitle) gtk_widget_show(w); #if GTK_CHECK_VERSION(3,0,0) gtk_grid_attach(GTK_GRID(table), w, 2, 1, 1, 1); - g_object_set(G_OBJECT(w), "hexpand", TRUE, (const char *)NULL); + g_object_set(G_OBJECT(w), "hexpand", true, (const char *)NULL); #else gtk_table_attach(GTK_TABLE(table), w, 2, 3, 1, 2, GTK_FILL, 0, 0, 0); #endif @@ -3504,7 +3504,7 @@ unifontsel *unifontsel_new(const char *wintitle) model = gtk_list_store_new(3, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT); w = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model)); - gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(w), FALSE); + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(w), false); gtk_widget_show(w); column = gtk_tree_view_column_new_with_attributes ("Size", gtk_cell_renderer_text_new(), @@ -3523,7 +3523,7 @@ unifontsel *unifontsel_new(const char *wintitle) GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); #if GTK_CHECK_VERSION(3,0,0) gtk_grid_attach(GTK_GRID(table), scroll, 2, 2, 1, 1); - g_object_set(G_OBJECT(scroll), "expand", TRUE, (const char *)NULL); + g_object_set(G_OBJECT(scroll), "expand", true, (const char *)NULL); #else gtk_table_attach(GTK_TABLE(table), scroll, 2, 3, 2, 3, GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); @@ -3545,9 +3545,9 @@ unifontsel *unifontsel_new(const char *wintitle) fs->preview_bg.red = fs->preview_bg.green = fs->preview_bg.blue = 0xFFFF; #if !GTK_CHECK_VERSION(3,0,0) gdk_colormap_alloc_color(gdk_colormap_get_system(), &fs->preview_fg, - FALSE, FALSE); + false, false); gdk_colormap_alloc_color(gdk_colormap_get_system(), &fs->preview_bg, - FALSE, FALSE); + false, false); #endif #if GTK_CHECK_VERSION(3,0,0) g_signal_connect(G_OBJECT(fs->preview_area), "draw", @@ -3584,7 +3584,7 @@ unifontsel *unifontsel_new(const char *wintitle) gtk_widget_show(w); #if GTK_CHECK_VERSION(3,0,0) gtk_grid_attach(GTK_GRID(table), w, 0, 3, 3, 1); - g_object_set(G_OBJECT(w), "expand", TRUE, (const char *)NULL); + g_object_set(G_OBJECT(w), "expand", true, (const char *)NULL); #else gtk_table_attach(GTK_TABLE(table), w, 0, 3, 3, 4, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 8); @@ -3607,7 +3607,7 @@ unifontsel *unifontsel_new(const char *wintitle) fs->filter_buttons[fs->n_filter_buttons++] = w; #if GTK_CHECK_VERSION(3,0,0) gtk_grid_attach(GTK_GRID(table), w, 0, 4, 3, 1); - g_object_set(G_OBJECT(w), "hexpand", TRUE, (const char *)NULL); + g_object_set(G_OBJECT(w), "hexpand", true, (const char *)NULL); #else gtk_table_attach(GTK_TABLE(table), w, 0, 3, 4, 5, GTK_FILL, 0, 0, 0); #endif @@ -3620,7 +3620,7 @@ unifontsel *unifontsel_new(const char *wintitle) fs->filter_buttons[fs->n_filter_buttons++] = w; #if GTK_CHECK_VERSION(3,0,0) gtk_grid_attach(GTK_GRID(table), w, 0, 5, 3, 1); - g_object_set(G_OBJECT(w), "hexpand", TRUE, (const char *)NULL); + g_object_set(G_OBJECT(w), "hexpand", true, (const char *)NULL); #else gtk_table_attach(GTK_TABLE(table), w, 0, 3, 5, 6, GTK_FILL, 0, 0, 0); #endif @@ -3633,7 +3633,7 @@ unifontsel *unifontsel_new(const char *wintitle) fs->filter_buttons[fs->n_filter_buttons++] = w; #if GTK_CHECK_VERSION(3,0,0) gtk_grid_attach(GTK_GRID(table), w, 0, 6, 3, 1); - g_object_set(G_OBJECT(w), "hexpand", TRUE, (const char *)NULL); + g_object_set(G_OBJECT(w), "hexpand", true, (const char *)NULL); #else gtk_table_attach(GTK_TABLE(table), w, 0, 3, 6, 7, GTK_FILL, 0, 0, 0); #endif @@ -3647,7 +3647,7 @@ unifontsel *unifontsel_new(const char *wintitle) fs->filter_buttons[fs->n_filter_buttons++] = w; #if GTK_CHECK_VERSION(3,0,0) gtk_grid_attach(GTK_GRID(table), w, 0, 7, 3, 1); - g_object_set(G_OBJECT(w), "hexpand", TRUE, (const char *)NULL); + g_object_set(G_OBJECT(w), "hexpand", true, (const char *)NULL); #else gtk_table_attach(GTK_TABLE(table), w, 0, 3, 7, 8, GTK_FILL, 0, 0, 0); #endif @@ -3673,7 +3673,7 @@ unifontsel *unifontsel_new(const char *wintitle) unifontsel_setup_familylist(fs); fs->selsize = fs->intendedsize = 13; /* random default */ - gtk_widget_set_sensitive(fs->u.ok_button, FALSE); + gtk_widget_set_sensitive(fs->u.ok_button, false); return &fs->u; } @@ -3716,7 +3716,7 @@ void unifontsel_set_name(unifontsel *fontsel, const char *fontname) fontname = unifont_do_prefix(fontname, &start, &end); for (i = start; i < end; i++) { fontname2 = unifont_types[i]->canonify_fontname - (GTK_WIDGET(fs->u.window), fontname, &size, &flags, FALSE); + (GTK_WIDGET(fs->u.window), fontname, &size, &flags, false); if (fontname2) break; } @@ -3754,7 +3754,7 @@ void unifontsel_set_name(unifontsel *fontsel, const char *fontname) * know everything we need to fill in all the fields in the * dialog. */ - unifontsel_select_font(fs, info, size, 0, TRUE); + unifontsel_select_font(fs, info, size, 0, true); } char *unifontsel_get_name(unifontsel *fontsel) diff --git a/unix/gtkmain.c b/unix/gtkmain.c index 8829dbfa..8e357525 100644 --- a/unix/gtkmain.c +++ b/unix/gtkmain.c @@ -554,7 +554,7 @@ GtkWidget *make_gtk_toplevel_window(GtkFrontend *frontend) return gtk_window_new(GTK_WINDOW_TOPLEVEL); } -const int buildinfo_gtk_relevant = TRUE; +const int buildinfo_gtk_relevant = true; struct post_initial_config_box_ctx { Conf *conf; @@ -594,7 +594,7 @@ int main(int argc, char **argv) /* Call the function in ux{putty,pterm}.c to do app-type * specific setup */ extern void setup(int); - setup(TRUE); /* TRUE means we are a one-session process */ + setup(true); /* true means we are a one-session process */ } progname = argv[0]; @@ -633,7 +633,7 @@ int main(int argc, char **argv) smemclr(argv[1], strlen(argv[1])); assert(!dup_check_launchable || conf_launchable(conf)); - need_config_box = FALSE; + need_config_box = false; } else { if (do_cmdline(argc, argv, 0, conf)) exit(1); /* pre-defaults pass to get -class */ @@ -646,7 +646,7 @@ int main(int argc, char **argv) if (cmdline_tooltype & TOOLTYPE_HOST_ARG) need_config_box = !cmdline_host_ok(conf); else - need_config_box = FALSE; + need_config_box = false; } if (need_config_box) { diff --git a/unix/gtkmisc.c b/unix/gtkmisc.c index e9fcaa75..05379415 100644 --- a/unix/gtkmisc.c +++ b/unix/gtkmisc.c @@ -130,7 +130,7 @@ void our_dialog_set_action_area(GtkWindow *dlg, GtkWidget *w) #if !GTK_CHECK_VERSION(2,0,0) gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->action_area), - w, TRUE, TRUE, 0); + w, true, true, 0); #elif !GTK_CHECK_VERSION(3,0,0) @@ -149,14 +149,14 @@ void our_dialog_set_action_area(GtkWindow *dlg, GtkWidget *w) #endif gtk_widget_show(align); gtk_box_pack_end(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dlg))), - align, FALSE, TRUE, 0); + align, false, true, 0); w = gtk_hseparator_new(); gtk_box_pack_end(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dlg))), - w, FALSE, TRUE, 0); + w, false, true, 0); gtk_widget_show(w); gtk_widget_hide(gtk_dialog_get_action_area(GTK_DIALOG(dlg))); - g_object_set(G_OBJECT(dlg), "has-separator", TRUE, (const char *)NULL); + g_object_set(G_OBJECT(dlg), "has-separator", true, (const char *)NULL); #else /* GTK 3 */ @@ -166,10 +166,10 @@ void our_dialog_set_action_area(GtkWindow *dlg, GtkWidget *w) GtkWidget *sep; g_object_set(G_OBJECT(w), "margin", 8, (const char *)NULL); - gtk_box_pack_end(vbox, w, FALSE, TRUE, 0); + gtk_box_pack_end(vbox, w, false, true, 0); sep = gtk_hseparator_new(); - gtk_box_pack_end(vbox, sep, FALSE, TRUE, 0); + gtk_box_pack_end(vbox, sep, false, true, 0); gtk_widget_show(sep); #endif diff --git a/unix/gtkwin.c b/unix/gtkwin.c index d56c1ee5..2887d071 100644 --- a/unix/gtkwin.c +++ b/unix/gtkwin.c @@ -231,7 +231,7 @@ static void common_connfatal_message_box( GtkWidget *dialog = create_message_box( inst->window, title, msg, string_width("REASONABLY LONG LINE OF TEXT FOR BASIC SANITY"), - FALSE, &buttons_ok, postfn, inst); + false, &buttons_ok, postfn, inst); register_dialog(&inst->seat, DIALOG_SLOT_CONNECTION_FATAL, dialog); sfree(title); } @@ -262,7 +262,7 @@ static void gtk_seat_connection_fatal(Seat *seat, const char *msg) common_connfatal_message_box(inst, msg, post_nonfatal_message_box); } - inst->exited = TRUE; /* suppress normal exit handling */ + inst->exited = true; /* suppress normal exit handling */ queue_toplevel_callback(connection_fatal_callback, inst); } @@ -317,7 +317,7 @@ static int gtk_seat_output(Seat *seat, int is_stderr, static int gtk_seat_eof(Seat *seat) { /* GtkFrontend *inst = container_of(seat, GtkFrontend, seat); */ - return TRUE; /* do respond to incoming EOF with outgoing */ + return true; /* do respond to incoming EOF with outgoing */ } static int gtk_seat_get_userpass_input(Seat *seat, prompts_t *p, @@ -341,7 +341,7 @@ static int gtk_seat_get_window_pixel_size(Seat *seat, int *w, int *h) { GtkFrontend *inst = container_of(seat, GtkFrontend, seat); win_get_pixels(&inst->termwin, w, h); - return TRUE; + return true; } static void gtk_seat_notify_remote_exit(Seat *seat); @@ -591,13 +591,13 @@ static int find_and_raise_dialog(GtkFrontend *inst, enum DialogSlot slot) { GtkWidget *dialog = inst->dialogs[slot]; if (!dialog) - return FALSE; + return false; #if GTK_CHECK_VERSION(2,0,0) gtk_window_deiconify(GTK_WINDOW(dialog)); #endif gdk_window_raise(gtk_widget_get_window(dialog)); - return TRUE; + return true; } /* @@ -619,10 +619,10 @@ static void warn_on_close_callback(void *vctx, int result) /* * Handle the 'delete window' event (e.g. user clicking the WM close - * button). The return value FALSE means the window should close, and - * TRUE means it shouldn't. + * button). The return value false means the window should close, and + * true means it shouldn't. * - * (That's counterintuitive, but really, in GTK terms, TRUE means 'I + * (That's counterintuitive, but really, in GTK terms, true means 'I * have done everything necessary to handle this event, so the default * handler need not do anything', i.e. 'suppress default handler', * i.e. 'do not close the window'.) @@ -641,13 +641,13 @@ gint delete_window(GtkWidget *widget, GdkEvent *event, GtkFrontend *inst) inst->window, title, "Are you sure you want to close this session?", string_width("Most of the width of the above text"), - FALSE, &buttons_yn, warn_on_close_callback, inst); + false, &buttons_yn, warn_on_close_callback, inst); register_dialog(&inst->seat, DIALOG_SLOT_WARN_ON_CLOSE, dialog); sfree(title); } - return TRUE; + return true; } - return FALSE; + return false; } static void update_mouseptr(GtkFrontend *inst) @@ -706,17 +706,17 @@ static void drawing_area_setup(GtkFrontend *inst, int width, int height) /* * We'll need to tell terminal.c about the resize below. */ - need_size = TRUE; + need_size = true; /* * And we must refresh the window's backing image. */ - inst->drawing_area_setup_needed = TRUE; + inst->drawing_area_setup_needed = true; } #if GTK_CHECK_VERSION(3,10,0) new_scale = gtk_widget_get_scale_factor(inst->area); if (new_scale != inst->scale) - inst->drawing_area_setup_needed = TRUE; + inst->drawing_area_setup_needed = true; #else new_scale = 1; #endif @@ -729,7 +729,7 @@ static void drawing_area_setup(GtkFrontend *inst, int width, int height) if (!inst->drawing_area_setup_needed) return; - inst->drawing_area_setup_needed = FALSE; + inst->drawing_area_setup_needed = false; inst->scale = new_scale; { @@ -794,7 +794,7 @@ static void drawing_area_setup_simple(GtkFrontend *inst) static void area_realised(GtkWidget *widget, GtkFrontend *inst) { - inst->drawing_area_realised = TRUE; + inst->drawing_area_realised = true; if (inst->drawing_area_realised && inst->drawing_area_got_size && inst->drawing_area_setup_needed) drawing_area_setup_simple(inst); @@ -803,7 +803,7 @@ static void area_realised(GtkWidget *widget, GtkFrontend *inst) static void area_size_allocate( GtkWidget *widget, GdkRectangle *alloc, GtkFrontend *inst) { - inst->drawing_area_got_size = TRUE; + inst->drawing_area_got_size = true; if (inst->drawing_area_realised && inst->drawing_area_got_size) drawing_area_setup(inst, alloc->width, alloc->height); } @@ -828,7 +828,7 @@ static gboolean area_configured( { GtkFrontend *inst = (GtkFrontend *)data; area_check_scale(inst); - return FALSE; + return false; } #endif @@ -909,7 +909,7 @@ static gint draw_area(GtkWidget *widget, cairo_t *cr, gpointer data) cairo_surface_set_device_scale(target_surface, orig_sx, orig_sy); } - return TRUE; + return true; } #else gint expose_area(GtkWidget *widget, GdkEventExpose *event, gpointer data) @@ -946,7 +946,7 @@ gint expose_area(GtkWidget *widget, GdkEventExpose *event, gpointer data) } #endif - return TRUE; + return true; } #endif @@ -974,11 +974,11 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) wchar_t ucsoutput[2]; int ucsval, start, end, special, output_charset, use_ucsoutput; int nethack_mode, app_keypad_mode; - int generated_something = FALSE; + int generated_something = false; #ifdef OSX_META_KEY_CONFIG if (event->state & inst->system_mod_mask) - return FALSE; /* let GTK process OS X Command key */ + return false; /* let GTK process OS X Command key */ #endif /* Remember the timestamp. */ @@ -986,7 +986,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) /* By default, nothing is generated. */ end = start = 0; - special = use_ucsoutput = FALSE; + special = use_ucsoutput = false; output_charset = CS_ISO8859_1; #ifdef KEY_EVENT_DIAGNOSTICS @@ -1058,7 +1058,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) "hardware_keycode=%d is_modifier=%s string=[%s]\n", type_string, keyval_string, state_string, (int)event->hardware_keycode, - event->is_modifier ? "TRUE" : "FALSE", + event->is_modifier ? "true" : "false", string_string)); sfree(type_string); @@ -1105,7 +1105,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) #ifdef KEY_EVENT_DIAGNOSTICS debug((" - key release accepted by IM\n")); #endif - return TRUE; + return true; } else { #ifdef KEY_EVENT_DIAGNOSTICS debug((" - key release not accepted by IM\n")); @@ -1179,7 +1179,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) debug((" - Ctrl->: increase font size\n")); #endif change_font_size(inst, +1); - return TRUE; + return true; } if (event->keyval == GDK_KEY_less && (event->state & GDK_CONTROL_MASK)) { @@ -1187,7 +1187,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) debug((" - Ctrl-<: increase font size\n")); #endif change_font_size(inst, -1); - return TRUE; + return true; } /* @@ -1201,7 +1201,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) debug((" - Ctrl-Shift-PgUp scroll\n")); #endif term_scroll(inst->term, 1, 0); - return TRUE; + return true; } if (event->keyval == GDK_KEY_Page_Up && (event->state & GDK_SHIFT_MASK)) { @@ -1209,7 +1209,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) debug((" - Shift-PgUp scroll\n")); #endif term_scroll(inst->term, 0, -inst->height/2); - return TRUE; + return true; } if (event->keyval == GDK_KEY_Page_Up && (event->state & GDK_CONTROL_MASK)) { @@ -1217,7 +1217,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) debug((" - Ctrl-PgUp scroll\n")); #endif term_scroll(inst->term, 0, -1); - return TRUE; + return true; } if (event->keyval == GDK_KEY_Page_Down && ((event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) == @@ -1226,7 +1226,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) debug((" - Ctrl-shift-PgDn scroll\n")); #endif term_scroll(inst->term, -1, 0); - return TRUE; + return true; } if (event->keyval == GDK_KEY_Page_Down && (event->state & GDK_SHIFT_MASK)) { @@ -1234,7 +1234,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) debug((" - Shift-PgDn scroll\n")); #endif term_scroll(inst->term, 0, +inst->height/2); - return TRUE; + return true; } if (event->keyval == GDK_KEY_Page_Down && (event->state & GDK_CONTROL_MASK)) { @@ -1242,7 +1242,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) debug((" - Ctrl-PgDn scroll\n")); #endif term_scroll(inst->term, 0, +1); - return TRUE; + return true; } /* @@ -1258,19 +1258,19 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) debug((" - Shift-Insert: paste from PRIMARY\n")); #endif term_request_paste(inst->term, CLIP_PRIMARY); - return TRUE; + return true; case CLIPUI_EXPLICIT: #ifdef KEY_EVENT_DIAGNOSTICS debug((" - Shift-Insert: paste from CLIPBOARD\n")); #endif term_request_paste(inst->term, CLIP_CLIPBOARD); - return TRUE; + return true; case CLIPUI_CUSTOM: #ifdef KEY_EVENT_DIAGNOSTICS debug((" - Shift-Insert: paste from custom clipboard\n")); #endif term_request_paste(inst->term, inst->clipboard_ctrlshiftins); - return TRUE; + return true; default: #ifdef KEY_EVENT_DIAGNOSTICS debug((" - Shift-Insert: no paste action\n")); @@ -1289,21 +1289,21 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) #ifdef KEY_EVENT_DIAGNOSTICS debug((" - Ctrl-Insert: non-copy to PRIMARY\n")); #endif - return TRUE; + return true; case CLIPUI_EXPLICIT: #ifdef KEY_EVENT_DIAGNOSTICS debug((" - Ctrl-Insert: copy to CLIPBOARD\n")); #endif term_request_copy(inst->term, clips_clipboard, lenof(clips_clipboard)); - return TRUE; + return true; case CLIPUI_CUSTOM: #ifdef KEY_EVENT_DIAGNOSTICS debug((" - Ctrl-Insert: copy to custom clipboard\n")); #endif term_request_copy(inst->term, &inst->clipboard_ctrlshiftins, 1); - return TRUE; + return true; default: #ifdef KEY_EVENT_DIAGNOSTICS debug((" - Ctrl-Insert: no copy action\n")); @@ -1335,7 +1335,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) debug((" - Ctrl-Shift-C: non-copy to PRIMARY\n")); #endif } - return TRUE; + return true; case CLIPUI_EXPLICIT: if (paste) { #ifdef KEY_EVENT_DIAGNOSTICS @@ -1349,7 +1349,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) #endif term_request_copy(inst->term, clips, lenof(clips)); } - return TRUE; + return true; case CLIPUI_CUSTOM: if (paste) { #ifdef KEY_EVENT_DIAGNOSTICS @@ -1364,12 +1364,12 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) term_request_copy(inst->term, &inst->clipboard_ctrlshiftcv, 1); } - return TRUE; + return true; } } - special = FALSE; - use_ucsoutput = FALSE; + special = false; + use_ucsoutput = false; nethack_mode = conf_get_int(inst->conf, CONF_nethack_keypad); app_keypad_mode = (inst->term->app_keypad_keys && @@ -1447,7 +1447,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) event->keyval == GDK_KEY_KP_Page_Up)) { /* nethack mode; do nothing */ } else { - int try_filter = TRUE; + int try_filter = true; #ifdef META_MANUAL_MASK if (event->state & META_MANUAL_MASK & inst->meta_mod_mask) { @@ -1462,7 +1462,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) debug((" - Meta modifier requiring manual intervention, " "suppressing IM filtering\n")); #endif - try_filter = FALSE; + try_filter = false; } #endif @@ -1474,7 +1474,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) #ifdef KEY_EVENT_DIAGNOSTICS debug((" - key press accepted by IM\n")); #endif - return TRUE; + return true; } else { #ifdef KEY_EVENT_DIAGNOSTICS debug((" - key press not accepted by IM\n")); @@ -1558,7 +1558,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) debug((" - keysym_to_unicode gave %04x\n", (unsigned)ucsoutput[1])); #endif - use_ucsoutput = TRUE; + use_ucsoutput = true; end = 2; } else { output[lenof(output)-1] = '\0'; @@ -1598,7 +1598,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) sfree(keyval_name); } #endif - use_ucsoutput = TRUE; + use_ucsoutput = true; end = 2; } } @@ -1613,7 +1613,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) debug((" - Ctrl-` special case, translating as 1c\n")); #endif output[1] = '\x1C'; - use_ucsoutput = FALSE; + use_ucsoutput = false; end = 2; } @@ -1664,7 +1664,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) #endif if (inst->backend) backend_special(inst->backend, SS_BRK, 0); - return TRUE; + return true; } /* We handle Return ourselves, because it needs to be flagged as @@ -1674,9 +1674,9 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) debug((" - Return special case, translating as 0d + special\n")); #endif output[1] = '\015'; - use_ucsoutput = FALSE; + use_ucsoutput = false; end = 2; - special = TRUE; + special = true; } /* Control-2, Control-Space and Control-@ are NUL */ @@ -1689,7 +1689,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) debug((" - Ctrl-{space,2,@} special case, translating as 00\n")); #endif output[1] = '\0'; - use_ucsoutput = FALSE; + use_ucsoutput = false; end = 2; } @@ -1702,7 +1702,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) #endif output[1] = '\240'; output_charset = CS_ISO8859_1; - use_ucsoutput = FALSE; + use_ucsoutput = false; end = 2; } @@ -1715,9 +1715,9 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) debug((" - Backspace, translating as %02x\n", (unsigned)output[1])); #endif - use_ucsoutput = FALSE; + use_ucsoutput = false; end = 2; - special = TRUE; + special = true; } /* For Shift Backspace, do opposite of what is configured. */ if (event->keyval == GDK_KEY_BackSpace && @@ -1728,9 +1728,9 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) debug((" - Shift-Backspace, translating as %02x\n", (unsigned)output[1])); #endif - use_ucsoutput = FALSE; + use_ucsoutput = false; end = 2; - special = TRUE; + special = true; } /* Shift-Tab is ESC [ Z */ @@ -1741,7 +1741,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) debug((" - Shift-Tab, translating as ESC [ Z\n")); #endif end = 1 + sprintf(output+1, "\033[Z"); - use_ucsoutput = FALSE; + use_ucsoutput = false; } /* And normal Tab is Tab, if the keymap hasn't already told us. * (Curiously, at least one version of the MacOS 10.5 X server @@ -1790,7 +1790,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) #ifdef KEY_EVENT_DIAGNOSTICS debug((" - Nethack-mode key")); #endif - use_ucsoutput = FALSE; + use_ucsoutput = false; goto done; } } @@ -1844,7 +1844,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) end = 1 + sprintf(output+1, "\033?%c", xkey); } else end = 1 + sprintf(output+1, "\033O%c", xkey); - use_ucsoutput = FALSE; + use_ucsoutput = false; #ifdef KEY_EVENT_DIAGNOSTICS debug((" - Application keypad mode key")); #endif @@ -1955,7 +1955,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) #ifdef KEY_EVENT_DIAGNOSTICS debug((" - VT52 mode small keypad key")); #endif - use_ucsoutput = FALSE; + use_ucsoutput = false; goto done; } @@ -1983,7 +1983,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) #ifdef KEY_EVENT_DIAGNOSTICS debug((" - SCO mode function key")); #endif - use_ucsoutput = FALSE; + use_ucsoutput = false; goto done; } if (funky_type == FUNKY_SCO && /* SCO small keypad */ @@ -1998,7 +1998,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) #ifdef KEY_EVENT_DIAGNOSTICS debug((" - SCO mode small keypad key")); #endif - use_ucsoutput = FALSE; + use_ucsoutput = false; goto done; } if ((inst->term->vt52_mode || funky_type == FUNKY_VT100P) && @@ -2021,7 +2021,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) end = 1 + sprintf(output+1, "\x1BO%c", code + 'P' - 11 - offt); } - use_ucsoutput = FALSE; + use_ucsoutput = false; goto done; } if (funky_type == FUNKY_LINUX && code >= 11 && code <= 15) { @@ -2029,7 +2029,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) #ifdef KEY_EVENT_DIAGNOSTICS debug((" - Linux mode F1-F5 function key")); #endif - use_ucsoutput = FALSE; + use_ucsoutput = false; goto done; } if (funky_type == FUNKY_XTERM && code >= 11 && code <= 14) { @@ -2045,7 +2045,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) #endif end = 1 + sprintf(output+1, "\x1BO%c", code + 'P' - 11); } - use_ucsoutput = FALSE; + use_ucsoutput = false; goto done; } if ((code == 1 || code == 4) && @@ -2054,7 +2054,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) debug((" - rxvt style Home/End")); #endif end = 1 + sprintf(output+1, code == 1 ? "\x1B[H" : "\x1BOw"); - use_ucsoutput = FALSE; + use_ucsoutput = false; goto done; } if (code) { @@ -2062,7 +2062,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) debug((" - ordinary function key encoding")); #endif end = 1 + sprintf(output+1, "\x1B[%d~", code); - use_ucsoutput = FALSE; + use_ucsoutput = false; goto done; } } @@ -2089,7 +2089,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) #ifdef KEY_EVENT_DIAGNOSTICS debug((" - arrow key")); #endif - use_ucsoutput = FALSE; + use_ucsoutput = false; goto done; } } @@ -2120,7 +2120,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) * should never matter. */ output[end] = '\0'; /* NUL-terminate */ - generated_something = TRUE; + generated_something = true; if (inst->ldisc) ldisc_send(inst->ldisc, output+start, -2, 1); } else if (!inst->direct_to_font) { @@ -2140,7 +2140,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) charset_to_localenc(output_charset), string_string)); sfree(string_string); #endif - generated_something = TRUE; + generated_something = true; if (inst->ldisc) lpage_send(inst->ldisc, output_charset, output+start, end-start, 1); @@ -2165,7 +2165,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) * We generated our own Unicode key data from the * keysym, so use that instead. */ - generated_something = TRUE; + generated_something = true; if (inst->ldisc) luni_send(inst->ldisc, ucsoutput+start, end-start, 1); } @@ -2189,7 +2189,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) string_string)); sfree(string_string); #endif - generated_something = TRUE; + generated_something = true; if (inst->ldisc) ldisc_send(inst->ldisc, output+start, end-start, 1); } @@ -2200,7 +2200,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) if (generated_something) key_pressed(inst); - return TRUE; + return true; } #if GTK_CHECK_VERSION(2,0,0) @@ -2260,7 +2260,7 @@ gboolean scroll_internal(GtkFrontend *inst, gdouble delta, guint state, term_scroll(inst->term, 0, scroll_lines); inst->cumulative_scroll -= scroll_lines; } - return TRUE; + return true; } else { int scroll_events = (int)(inst->cumulative_scroll / SCROLL_INCREMENT_LINES); @@ -2281,7 +2281,7 @@ gboolean scroll_internal(GtkFrontend *inst, gdouble delta, guint state, MA_CLICK, x, y, shift, ctrl, alt); } } - return TRUE; + return true; } } #endif @@ -2306,11 +2306,11 @@ static gboolean button_internal(GtkFrontend *inst, GdkEventButton *event) if (!raw_mouse_mode) { if (event->button == 4 && event->type == GDK_BUTTON_PRESS) { term_scroll(inst->term, 0, -SCROLL_INCREMENT_LINES); - return TRUE; + return true; } if (event->button == 5 && event->type == GDK_BUTTON_PRESS) { term_scroll(inst->term, 0, +SCROLL_INCREMENT_LINES); - return TRUE; + return true; } } @@ -2321,7 +2321,7 @@ static gboolean button_internal(GtkFrontend *inst, GdkEventButton *event) gtk_menu_popup(GTK_MENU(inst->menu), NULL, NULL, NULL, NULL, event->button, event->time); #endif - return TRUE; + return true; } if (event->button == 1) @@ -2335,18 +2335,18 @@ static gboolean button_internal(GtkFrontend *inst, GdkEventButton *event) else if (event->button == 5) button = MBT_WHEEL_DOWN; else - return FALSE; /* don't even know what button! */ + return false; /* don't even know what button! */ switch (event->type) { case GDK_BUTTON_PRESS: act = MA_CLICK; break; case GDK_BUTTON_RELEASE: act = MA_RELEASE; break; case GDK_2BUTTON_PRESS: act = MA_2CLK; break; case GDK_3BUTTON_PRESS: act = MA_3CLK; break; - default: return FALSE; /* don't know this event type */ + default: return false; /* don't know this event type */ } if (raw_mouse_mode && act != MA_CLICK && act != MA_RELEASE) - return TRUE; /* we ignore these in raw mouse mode */ + return true; /* we ignore these in raw mouse mode */ x = (event->x - inst->window_border) / inst->font_width; y = (event->y - inst->window_border) / inst->font_height; @@ -2354,7 +2354,7 @@ static gboolean button_internal(GtkFrontend *inst, GdkEventButton *event) term_mouse(inst->term, button, translate_button(button), act, x, y, shift, ctrl, alt); - return TRUE; + return true; } gboolean button_event(GtkWidget *widget, GdkEventButton *event, gpointer data) @@ -2378,7 +2378,7 @@ gboolean scroll_event(GtkWidget *widget, GdkEventScroll *event, gpointer data) if (gdk_event_get_scroll_deltas((GdkEvent *)event, &dx, &dy)) { return scroll_internal(inst, dy, event->state, event->x, event->y); } else - return FALSE; + return false; #else guint button; GdkEventButton *event_button; @@ -2389,7 +2389,7 @@ gboolean scroll_event(GtkWidget *widget, GdkEventScroll *event, gpointer data) else if (event->direction == GDK_SCROLL_DOWN) button = 5; else - return FALSE; + return false; event_button = (GdkEventButton *)gdk_event_new(GDK_BUTTON_PRESS); event_button->window = g_object_ref(event->window); @@ -2430,7 +2430,7 @@ gint motion_event(GtkWidget *widget, GdkEventMotion *event, gpointer data) else if (event->state & GDK_BUTTON3_MASK) button = MBT_RIGHT; else - return FALSE; /* don't even know what button! */ + return false; /* don't even know what button! */ x = (event->x - inst->window_border) / inst->font_width; y = (event->y - inst->window_border) / inst->font_height; @@ -2438,7 +2438,7 @@ gint motion_event(GtkWidget *widget, GdkEventMotion *event, gpointer data) term_mouse(inst->term, button, translate_button(button), MA_DRAG, x, y, shift, ctrl, alt); - return TRUE; + return true; } static void key_pressed(GtkFrontend *inst) @@ -2485,7 +2485,7 @@ static void gtk_seat_notify_remote_exit(Seat *seat) static void destroy_inst_connection(GtkFrontend *inst) { - inst->exited = TRUE; + inst->exited = true; if (inst->ldisc) { ldisc_free(inst->ldisc); inst->ldisc = NULL; @@ -2498,7 +2498,7 @@ static void destroy_inst_connection(GtkFrontend *inst) term_provide_backend(inst->term, NULL); if (inst->menu) { seat_update_specials_menu(&inst->seat); - gtk_widget_set_sensitive(inst->restartitem, TRUE); + gtk_widget_set_sensitive(inst->restartitem, true); } } @@ -2577,7 +2577,7 @@ gint focus_event(GtkWidget *widget, GdkEventFocus *event, gpointer data) term_set_focus(inst->term, event->in); term_update(inst->term); show_mouseptr(inst, 1); - return FALSE; + return false; } static void gtk_seat_set_busy_status(Seat *seat, BusyStatus status) @@ -2704,7 +2704,7 @@ static void real_palette_set(GtkFrontend *inst, int n, int r, int g, int b) gboolean success[1]; gdk_colormap_free_colors(inst->colmap, inst->cols + n, 1); gdk_colormap_alloc_colors(inst->colmap, inst->cols + n, 1, - FALSE, TRUE, success); + false, true, success); if (!success[0]) g_error("%s: couldn't allocate colour %d (#%02x%02x%02x)\n", appname, n, r, g, b); @@ -2776,11 +2776,11 @@ static int gtkwin_palette_get(TermWin *tw, int n, int *r, int *g, int *b) { GtkFrontend *inst = container_of(tw, GtkFrontend, termwin); if (n < 0 || n >= NALLCOLOURS) - return FALSE; + return false; *r = inst->cols[n].red >> 8; *g = inst->cols[n].green >> 8; *b = inst->cols[n].blue >> 8; - return TRUE; + return true; } static void gtkwin_palette_reset(TermWin *tw) @@ -2831,7 +2831,7 @@ static void gtkwin_palette_reset(TermWin *tw) { gboolean success[NALLCOLOURS]; gdk_colormap_alloc_colors(inst->colmap, inst->cols, NALLCOLOURS, - FALSE, TRUE, success); + false, true, success); for (i = 0; i < NALLCOLOURS; i++) { if (!success[i]) g_error("%s: couldn't allocate colour %d (#%02x%02x%02x)\n", @@ -2896,7 +2896,7 @@ int init_clipboard(GtkFrontend *inst) { set_clipboard_atom(inst, CLIP_PRIMARY, GDK_SELECTION_PRIMARY); set_clipboard_atom(inst, CLIP_CLIPBOARD, clipboard_atom); - return TRUE; + return true; } static void clipboard_provide_data(GtkClipboard *clipboard, @@ -3214,7 +3214,7 @@ static gint selection_clear(GtkWidget *widget, GdkEventSelection *seldata, inst, seldata->selection); if (!state) - return TRUE; + return true; term_lost_clipboard_ownership(inst->term, state->clipboard); if (state->pasteout_data) @@ -3229,7 +3229,7 @@ static gint selection_clear(GtkWidget *widget, GdkEventSelection *seldata, state->pasteout_data_ctext_len = 0; state->pasteout_data_utf8 = NULL; state->pasteout_data_utf8_len = 0; - return TRUE; + return true; } static void gtkwin_clip_request_paste(TermWin *tw, int clipboard) @@ -3506,7 +3506,7 @@ static void gtkwin_set_scrollbar(TermWin *tw, int total, int start, int page) GtkFrontend *inst = container_of(tw, GtkFrontend, termwin); if (!conf_get_int(inst->conf, CONF_scrollbar)) return; - inst->ignore_sbar = TRUE; + inst->ignore_sbar = true; gtk_adjustment_set_lower(inst->sbar_adjust, 0); gtk_adjustment_set_upper(inst->sbar_adjust, total); gtk_adjustment_set_value(inst->sbar_adjust, start); @@ -3516,7 +3516,7 @@ static void gtkwin_set_scrollbar(TermWin *tw, int total, int start, int page) #if !GTK_CHECK_VERSION(3,18,0) gtk_adjustment_changed(inst->sbar_adjust); #endif - inst->ignore_sbar = FALSE; + inst->ignore_sbar = false; } void scrollbar_moved(GtkAdjustment *adj, GtkFrontend *inst) @@ -3570,7 +3570,7 @@ static int gtkwin_setup_draw_ctx(TermWin *tw) GtkFrontend *inst = container_of(tw, GtkFrontend, termwin); if (!gtk_widget_get_window(inst->area)) - return FALSE; + return false; inst->uctx.type = inst->drawtype; #ifdef DRAW_TEXT_GDK @@ -3592,7 +3592,7 @@ static int gtkwin_setup_draw_ctx(TermWin *tw) cairo_setup_draw_ctx(inst); } #endif - return TRUE; + return true; } static void gtkwin_free_draw_ctx(TermWin *tw) @@ -3894,7 +3894,7 @@ static void draw_backing_rect(GtkFrontend *inst) w = inst->width * inst->font_width + 2*inst->window_border; h = inst->height * inst->font_height + 2*inst->window_border; - draw_set_colour(inst, 258, FALSE); + draw_set_colour(inst, 258, false); draw_rectangle(inst, 1, 0, 0, w, h); draw_update(inst, 0, 0, w, h); win_free_draw_ctx(&inst->termwin); @@ -4005,7 +4005,7 @@ static void do_text_internal( draw_stretch_before(inst, x*inst->font_width+inst->window_border, y*inst->font_height+inst->window_border, - rlen*widefactor*inst->font_width, TRUE, + rlen*widefactor*inst->font_width, true, inst->font_height, ((lattr & LATTR_MODE) != LATTR_WIDE), ((lattr & LATTR_MODE) == LATTR_BOT)); @@ -4015,7 +4015,7 @@ static void do_text_internal( draw_set_colour_rgb(inst, truecolour.bg, attr & ATTR_DIM); else draw_set_colour(inst, nbg, attr & ATTR_DIM); - draw_rectangle(inst, TRUE, + draw_rectangle(inst, true, x*inst->font_width+inst->window_border, y*inst->font_height+inst->window_border, rlen*widefactor*inst->font_width, inst->font_height); @@ -4055,7 +4055,7 @@ static void do_text_internal( draw_stretch_after(inst, x*inst->font_width+inst->window_border, y*inst->font_height+inst->window_border, - rlen*widefactor*inst->font_width, TRUE, + rlen*widefactor*inst->font_width, true, inst->font_height, ((lattr & LATTR_MODE) != LATTR_WIDE), ((lattr & LATTR_MODE) == LATTR_BOT)); @@ -4136,8 +4136,8 @@ static void gtkwin_draw_cursor( * if it's passive. */ if (passive) { - draw_set_colour(inst, 261, FALSE); - draw_rectangle(inst, FALSE, + draw_set_colour(inst, 261, false); + draw_rectangle(inst, false, x*inst->font_width+inst->window_border, y*inst->font_height+inst->window_border, len*widefactor*inst->font_width-1, @@ -4175,7 +4175,7 @@ static void gtkwin_draw_cursor( length = inst->font_height; } - draw_set_colour(inst, 261, FALSE); + draw_set_colour(inst, 261, false); if (passive) { for (i = 0; i < length; i++) { if (i % 2 == 0) { @@ -4255,9 +4255,9 @@ static int gtk_seat_get_windowid(Seat *seat, long *id) GtkFrontend *inst = container_of(seat, GtkFrontend, seat); GdkWindow *window = gtk_widget_get_window(inst->area); if (!GDK_IS_X11_WINDOW(window)) - return FALSE; + return false; *id = GDK_WINDOW_XID(window); - return TRUE; + return true; } #endif @@ -4276,7 +4276,7 @@ char *setup_fonts_ucs(GtkFrontend *inst) int i; fs = conf_get_fontspec(inst->conf, CONF_font); - fonts[0] = multifont_create(inst->area, fs->name, FALSE, FALSE, + fonts[0] = multifont_create(inst->area, fs->name, false, false, shadowboldoffset, shadowbold); if (!fonts[0]) { return dupprintf("unable to load font \"%s\"", fs->name); @@ -4286,7 +4286,7 @@ char *setup_fonts_ucs(GtkFrontend *inst) if (shadowbold || !fs->name[0]) { fonts[1] = NULL; } else { - fonts[1] = multifont_create(inst->area, fs->name, FALSE, TRUE, + fonts[1] = multifont_create(inst->area, fs->name, false, true, shadowboldoffset, shadowbold); if (!fonts[1]) { if (fonts[0]) @@ -4297,7 +4297,7 @@ char *setup_fonts_ucs(GtkFrontend *inst) fs = conf_get_fontspec(inst->conf, CONF_widefont); if (fs->name[0]) { - fonts[2] = multifont_create(inst->area, fs->name, TRUE, FALSE, + fonts[2] = multifont_create(inst->area, fs->name, true, false, shadowboldoffset, shadowbold); if (!fonts[2]) { for (i = 0; i < 2; i++) @@ -4313,7 +4313,7 @@ char *setup_fonts_ucs(GtkFrontend *inst) if (shadowbold || !fs->name[0]) { fonts[3] = NULL; } else { - fonts[3] = multifont_create(inst->area, fs->name, TRUE, TRUE, + fonts[3] = multifont_create(inst->area, fs->name, true, true, shadowboldoffset, shadowbold); if (!fonts[3]) { for (i = 0; i < 3; i++) @@ -4344,7 +4344,7 @@ char *setup_fonts_ucs(GtkFrontend *inst) * The font size has changed, so force the next call to * drawing_area_setup to regenerate the backing surface. */ - inst->drawing_area_setup_needed = TRUE; + inst->drawing_area_setup_needed = true; } inst->direct_to_font = init_ucs(&inst->ucsdata, @@ -4505,7 +4505,7 @@ void clear_scrollback_menuitem(GtkMenuItem *item, gpointer data) void reset_terminal_menuitem(GtkMenuItem *item, gpointer data) { GtkFrontend *inst = (GtkFrontend *)data; - term_pwron(inst->term, TRUE); + term_pwron(inst->term, true); if (inst->ldisc) ldisc_echoedit_update(inst->ldisc); } @@ -4580,7 +4580,7 @@ void setup_clipboards(GtkFrontend *inst, Terminal *term, Conf *conf) set_clipboard_atom(inst, CLIP_CUSTOM_1, gdk_atom_intern( conf_get_str(conf, CONF_mousepaste_custom), - FALSE)); + false)); break; default: term->mouse_paste_clipboard = CLIP_NULL; @@ -4589,7 +4589,7 @@ void setup_clipboards(GtkFrontend *inst, Terminal *term, Conf *conf) if (conf_get_int(conf, CONF_ctrlshiftins) == CLIPUI_CUSTOM) { GdkAtom atom = gdk_atom_intern( - conf_get_str(conf, CONF_ctrlshiftins_custom), FALSE); + conf_get_str(conf, CONF_ctrlshiftins_custom), false); struct clipboard_state *state = clipboard_from_atom(inst, atom); if (state) { inst->clipboard_ctrlshiftins = state->clipboard; @@ -4601,7 +4601,7 @@ void setup_clipboards(GtkFrontend *inst, Terminal *term, Conf *conf) if (conf_get_int(conf, CONF_ctrlshiftcv) == CLIPUI_CUSTOM) { GdkAtom atom = gdk_atom_intern( - conf_get_str(conf, CONF_ctrlshiftcv_custom), FALSE); + conf_get_str(conf, CONF_ctrlshiftcv_custom), false); struct clipboard_state *state = clipboard_from_atom(inst, atom); if (state) { inst->clipboard_ctrlshiftins = state->clipboard; @@ -4724,7 +4724,7 @@ static void after_change_settings_dialog(void *vctx, int retval) } } - need_size = FALSE; + need_size = false; /* * If the scrollbar needs to be shown, hidden, or moved @@ -4733,7 +4733,7 @@ static void after_change_settings_dialog(void *vctx, int retval) if (conf_get_int(oldconf, CONF_scrollbar) != conf_get_int(newconf, CONF_scrollbar)) { show_scrollbar(inst, conf_get_int(newconf, CONF_scrollbar)); - need_size = TRUE; + need_size = true; } if (conf_get_int(oldconf, CONF_scrollbar_on_left) != conf_get_int(newconf, CONF_scrollbar_on_left)) { @@ -4781,11 +4781,11 @@ static void after_change_settings_dialog(void *vctx, int retval) create_message_box( inst->window, "Font setup error", msgboxtext, string_width("Could not change fonts in terminal window:"), - FALSE, &buttons_ok, trivial_post_dialog_fn, NULL); + false, &buttons_ok, trivial_post_dialog_fn, NULL); sfree(msgboxtext); sfree(errmsg); } else { - need_size = TRUE; + need_size = true; } } @@ -4910,9 +4910,9 @@ void restart_session_menuitem(GtkMenuItem *item, gpointer data) if (!inst->backend) { logevent(inst->logctx, "----- Session restarted -----"); - term_pwron(inst->term, FALSE); + term_pwron(inst->term, false); start_backend(inst); - inst->exited = FALSE; + inst->exited = false; } } @@ -4973,7 +4973,7 @@ static void update_savedsess_menu(GtkMenuItem *menuitem, gpointer data) gtk_container_foreach(GTK_CONTAINER(inst->sessionsmenu), (GtkCallback)gtk_widget_destroy, NULL); - get_sesslist(&sesslist, TRUE); + get_sesslist(&sesslist, true); /* skip sesslist.sessions[0] == Default Settings */ for (i = 1; i < sesslist.nsessions; i++) { GtkWidget *menuitem = @@ -4992,11 +4992,11 @@ static void update_savedsess_menu(GtkMenuItem *menuitem, gpointer data) if (sesslist.nsessions <= 1) { GtkWidget *menuitem = gtk_menu_item_new_with_label("(No sessions)"); - gtk_widget_set_sensitive(menuitem, FALSE); + gtk_widget_set_sensitive(menuitem, false); gtk_container_add(GTK_CONTAINER(inst->sessionsmenu), menuitem); gtk_widget_show(menuitem); } - get_sesslist(&sesslist, FALSE); /* free up */ + get_sesslist(&sesslist, false); /* free up */ } void set_window_icon(GtkWidget *window, const char *const *const *icon, @@ -5125,7 +5125,7 @@ static void start_backend(GtkFrontend *inst) if (error) { char *msg = dupprintf("Unable to open connection to %s:\n%s", conf_dest(inst->conf), error); - inst->exited = TRUE; + inst->exited = true; seat_connection_fatal(&inst->seat, msg); sfree(msg); return; @@ -5146,7 +5146,7 @@ static void start_backend(GtkFrontend *inst) inst->ldisc = ldisc_create(inst->conf, inst->term, inst->backend, &inst->seat); - gtk_widget_set_sensitive(inst->restartitem, FALSE); + gtk_widget_set_sensitive(inst->restartitem, false); } #if GTK_CHECK_VERSION(2,0,0) @@ -5227,7 +5227,7 @@ void new_session_window(Conf *conf, const char *geometry_string) #if GTK_CHECK_VERSION(3,4,0) inst->cumulative_scroll = 0.0; #endif - inst->drawing_area_setup_needed = TRUE; + inst->drawing_area_setup_needed = true; inst->termwin.vt = >k_termwin_vt; inst->seat.vt = >k_seat_vt; @@ -5247,7 +5247,7 @@ void new_session_window(Conf *conf, const char *geometry_string) if (flags & (XValue | YValue)) { inst->xpos = x; inst->ypos = y; - inst->gotpos = TRUE; + inst->gotpos = true; inst->gravity = ((flags & XNegative ? 1 : 0) | (flags & YNegative ? 2 : 0)); } @@ -5255,11 +5255,11 @@ void new_session_window(Conf *conf, const char *geometry_string) #endif if (!compound_text_atom) - compound_text_atom = gdk_atom_intern("COMPOUND_TEXT", FALSE); + compound_text_atom = gdk_atom_intern("COMPOUND_TEXT", false); if (!utf8_string_atom) - utf8_string_atom = gdk_atom_intern("UTF8_STRING", FALSE); + utf8_string_atom = gdk_atom_intern("UTF8_STRING", false); if (!clipboard_atom) - clipboard_atom = gdk_atom_intern("CLIPBOARD", FALSE); + clipboard_atom = gdk_atom_intern("CLIPBOARD", false); inst->area = gtk_drawing_area_new(); gtk_widget_set_name(GTK_WIDGET(inst->area), "drawing-area"); @@ -5324,17 +5324,17 @@ void new_session_window(Conf *conf, const char *geometry_string) inst->sbar_adjust = GTK_ADJUSTMENT(gtk_adjustment_new(0,0,0,0,0,0)); inst->sbar = gtk_vscrollbar_new(inst->sbar_adjust); - inst->hbox = GTK_BOX(gtk_hbox_new(FALSE, 0)); + inst->hbox = GTK_BOX(gtk_hbox_new(false, 0)); /* * We always create the scrollbar; it remains invisible if * unwanted, so we can pop it up quickly if it suddenly becomes * desirable. */ if (conf_get_int(inst->conf, CONF_scrollbar_on_left)) - gtk_box_pack_start(inst->hbox, inst->sbar, FALSE, FALSE, 0); - gtk_box_pack_start(inst->hbox, inst->area, TRUE, TRUE, 0); + gtk_box_pack_start(inst->hbox, inst->sbar, false, false, 0); + gtk_box_pack_start(inst->hbox, inst->area, true, true, 0); if (!conf_get_int(inst->conf, CONF_scrollbar_on_left)) - gtk_box_pack_start(inst->hbox, inst->sbar, FALSE, FALSE, 0); + gtk_box_pack_start(inst->hbox, inst->sbar, false, false, 0); gtk_container_add(GTK_CONTAINER(inst->window), GTK_WIDGET(inst->hbox)); @@ -5500,7 +5500,7 @@ void new_session_window(Conf *conf, const char *geometry_string) MKMENUITEM("New Session...", new_session_menuitem); MKMENUITEM("Restart Session", restart_session_menuitem); inst->restartitem = menuitem; - gtk_widget_set_sensitive(inst->restartitem, FALSE); + gtk_widget_set_sensitive(inst->restartitem, false); MKMENUITEM("Duplicate Session", dup_session_menuitem); if (saved_sessions) { inst->sessionsmenu = gtk_menu_new(); @@ -5557,7 +5557,7 @@ void new_session_window(Conf *conf, const char *geometry_string) term_size(inst->term, inst->height, inst->width, conf_get_int(inst->conf, CONF_savelines)); - inst->exited = FALSE; + inst->exited = false; start_backend(inst); diff --git a/unix/unix.h b/unix/unix.h index 11f9b51d..48e727b6 100644 --- a/unix/unix.h +++ b/unix/unix.h @@ -133,7 +133,7 @@ unsigned long getticks(void); * is _not_ implicit but requires a specific UI action. This is at * odds with all other PuTTY front ends' defaults, but on OS X there * is no multi-decade precedent for PuTTY working the other way. */ -#define CLIPUI_DEFAULT_AUTOCOPY FALSE +#define CLIPUI_DEFAULT_AUTOCOPY false #define CLIPUI_DEFAULT_MOUSE CLIPUI_IMPLICIT #define CLIPUI_DEFAULT_INS CLIPUI_EXPLICIT #define MENU_CLIPBOARD CLIP_CLIPBOARD @@ -146,7 +146,7 @@ unsigned long getticks(void); #define CLIPNAME_EXPLICIT_OBJECT "CLIPBOARD" /* These defaults are the ones Unix PuTTY has historically had since * it was first thought of in 2002 */ -#define CLIPUI_DEFAULT_AUTOCOPY FALSE +#define CLIPUI_DEFAULT_AUTOCOPY false #define CLIPUI_DEFAULT_MOUSE CLIPUI_IMPLICIT #define CLIPUI_DEFAULT_INS CLIPUI_IMPLICIT #define MENU_CLIPBOARD CLIP_CLIPBOARD diff --git a/unix/ux_x11.c b/unix/ux_x11.c index 4df66d15..fb5c4949 100644 --- a/unix/ux_x11.c +++ b/unix/ux_x11.c @@ -22,13 +22,13 @@ void platform_get_x11_auth(struct X11Display *disp, Conf *conf) /* * Find the .Xauthority file. */ - needs_free = FALSE; + needs_free = false; xauthfile = getenv("XAUTHORITY"); if (!xauthfile) { xauthfile = getenv("HOME"); if (xauthfile) { xauthfile = dupcat(xauthfile, "/.Xauthority", NULL); - needs_free = TRUE; + needs_free = true; } } @@ -39,7 +39,7 @@ void platform_get_x11_auth(struct X11Display *disp, Conf *conf) } } -const int platform_uses_x11_unix_by_default = TRUE; +const int platform_uses_x11_unix_by_default = true; int platform_make_x11_server(Plug *plug, const char *progname, int mindisp, const char *screen_number_suffix, @@ -71,7 +71,7 @@ int platform_make_x11_server(Plug *plug, const char *progname, int mindisp, int addrtype = ADDRTYPE_IPV4; sockets[nsockets] = new_listener( - NULL, tcp_port, plug, FALSE, conf, addrtype); + NULL, tcp_port, plug, false, conf, addrtype); err = sk_socket_error(sockets[nsockets]); if (!err) { diff --git a/unix/uxagentc.c b/unix/uxagentc.c index 1e804a73..31829eb7 100644 --- a/unix/uxagentc.c +++ b/unix/uxagentc.c @@ -19,8 +19,8 @@ int agent_exists(void) { const char *p = getenv("SSH_AUTH_SOCK"); if (p && *p) - return TRUE; - return FALSE; + return true; + return false; } static tree234 *agent_pending_queries; diff --git a/unix/uxcons.c b/unix/uxcons.c index b44d34b8..e47a8003 100644 --- a/unix/uxcons.c +++ b/unix/uxcons.c @@ -21,7 +21,7 @@ #include "storage.h" #include "ssh.h" -int console_batch_mode = FALSE; +int console_batch_mode = false; static struct termios orig_termios_stderr; static int stderr_is_a_tty; @@ -30,7 +30,7 @@ void stderr_tty_init() { /* Ensure that if stderr is a tty, we can get it back to a sane state. */ if ((flags & FLAG_STDERR_TTY) && isatty(STDERR_FILENO)) { - stderr_is_a_tty = TRUE; + stderr_is_a_tty = true; tcgetattr(STDERR_FILENO, &orig_termios_stderr); } } diff --git a/unix/uxmisc.c b/unix/uxmisc.c index 320a6c9e..cfdc5598 100644 --- a/unix/uxmisc.c +++ b/unix/uxmisc.c @@ -343,7 +343,7 @@ int open_for_write_would_lose_data(const Filename *fn) * open the file for writing and report _that_ error, which is * likely to be more to the point. */ - return FALSE; + return false; } /* @@ -360,8 +360,8 @@ int open_for_write_would_lose_data(const Filename *fn) * information.) */ if (S_ISREG(st.st_mode) && st.st_size > 0) { - return TRUE; + return true; } - return FALSE; + return false; } diff --git a/unix/uxnet.c b/unix/uxnet.c index 92311fc9..9ca98faf 100644 --- a/unix/uxnet.c +++ b/unix/uxnet.c @@ -297,15 +297,15 @@ static int sk_nextaddr(SockAddr *addr, SockAddrStep *step) #ifndef NO_IPV6 if (step->ai && step->ai->ai_next) { step->ai = step->ai->ai_next; - return TRUE; + return true; } else - return FALSE; + return false; #else if (step->curraddr+1 < addr->naddresses) { step->curraddr++; - return TRUE; + return true; } else { - return FALSE; + return false; } #endif } @@ -365,9 +365,9 @@ static SockAddr sk_extractaddr_tmp( int sk_addr_needs_port(SockAddr *addr) { if (addr->superfamily == UNRESOLVED || addr->superfamily == UNIX) { - return FALSE; + return false; } else { - return TRUE; + return true; } } @@ -392,9 +392,9 @@ static int sockaddr_is_loopback(struct sockaddr *sa) return IN6_IS_ADDR_LOOPBACK(&u->sin6.sin6_addr); #endif case AF_UNIX: - return TRUE; + return true; default: - return FALSE; + return false; } } @@ -452,7 +452,7 @@ void sk_addrcopy(SockAddr *addr, char *buf) memcpy(buf, &((struct sockaddr_in6 *)step.ai->ai_addr)->sin6_addr, sizeof(struct in6_addr)); else - assert(FALSE); + assert(false); #else struct in_addr a; @@ -536,9 +536,9 @@ static Socket *sk_net_accept(accept_ctx_t ctx, Plug *plug) ret->frozen = 1; ret->localhost_only = 0; /* unused, but best init anyway */ ret->pending_error = 0; - ret->oobpending = FALSE; + ret->oobpending = false; ret->outgoingeof = EOF_NO; - ret->incomingeof = FALSE; + ret->incomingeof = false; ret->listener = 0; ret->parent = ret->child = NULL; ret->addr = NULL; @@ -601,7 +601,7 @@ static int try_connect(NetSocket *sock) cloexec(s); if (sock->oobinline) { - int b = TRUE; + int b = true; if (setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (void *) &b, sizeof(b)) < 0) { err = errno; @@ -611,7 +611,7 @@ static int try_connect(NetSocket *sock) } if (sock->nodelay) { - int b = TRUE; + int b = true; if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (void *) &b, sizeof(b)) < 0) { err = errno; @@ -621,7 +621,7 @@ static int try_connect(NetSocket *sock) } if (sock->keepalive) { - int b = TRUE; + int b = true; if (setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (void *) &b, sizeof(b)) < 0) { err = errno; @@ -779,9 +779,9 @@ Socket *sk_new(SockAddr *addr, int port, int privport, int oobinline, ret->localhost_only = 0; /* unused, but best init anyway */ ret->pending_error = 0; ret->parent = ret->child = NULL; - ret->oobpending = FALSE; + ret->oobpending = false; ret->outgoingeof = EOF_NO; - ret->incomingeof = FALSE; + ret->incomingeof = false; ret->listener = 0; ret->addr = addr; START_STEP(ret->addr, ret->step); @@ -833,9 +833,9 @@ Socket *sk_newlistener(const char *srcaddr, int port, Plug *plug, ret->localhost_only = local_host_only; ret->pending_error = 0; ret->parent = ret->child = NULL; - ret->oobpending = FALSE; + ret->oobpending = false; ret->outgoingeof = EOF_NO; - ret->incomingeof = FALSE; + ret->incomingeof = false; ret->listener = 1; ret->addr = NULL; ret->s = -1; @@ -1127,7 +1127,7 @@ void try_send(NetSocket *s) /* * Perfectly normal: we've sent all we can for the moment. */ - s->writable = FALSE; + s->writable = false; return; } else { /* @@ -1312,7 +1312,7 @@ static void net_select_result(int fd, int event) * when we get called for the readability event (which * should also occur). */ - s->oobpending = TRUE; + s->oobpending = true; break; case 1: /* readable; also acceptance */ if (s->listener) { @@ -1361,7 +1361,7 @@ static void net_select_result(int fd, int event) if (s->oobinline && s->oobpending) { atmark = 1; if (ioctl(s->s, SIOCATMARK, &atmark) == 0 && atmark) - s->oobpending = FALSE; /* clear this indicator */ + s->oobpending = false; /* clear this indicator */ } else atmark = 1; @@ -1375,7 +1375,7 @@ static void net_select_result(int fd, int event) if (ret < 0) { plug_closing(s->plug, strerror(errno), errno, 0); } else if (0 == ret) { - s->incomingeof = TRUE; /* stop trying to read now */ + s->incomingeof = true; /* stop trying to read now */ uxsel_tell(s); plug_closing(s->plug, NULL, 0, 0); } else { @@ -1668,12 +1668,12 @@ Socket *new_unix_listener(SockAddr *listenaddr, Plug *plug) ret->writable = 0; /* to start with */ ret->sending_oob = 0; ret->frozen = 0; - ret->localhost_only = TRUE; + ret->localhost_only = true; ret->pending_error = 0; ret->parent = ret->child = NULL; - ret->oobpending = FALSE; + ret->oobpending = false; ret->outgoingeof = EOF_NO; - ret->incomingeof = FALSE; + ret->incomingeof = false; ret->listener = 1; ret->addr = listenaddr; ret->s = -1; diff --git a/unix/uxpeer.c b/unix/uxpeer.c index 57bcfb88..8aaa3579 100644 --- a/unix/uxpeer.c +++ b/unix/uxpeer.c @@ -25,8 +25,8 @@ int so_peercred(int fd, int *pid, int *uid, int *gid) *pid = cr.pid; *uid = cr.uid; *gid = cr.gid; - return TRUE; + return true; } #endif - return FALSE; + return false; } diff --git a/unix/uxpgnt.c b/unix/uxpgnt.c index ca1be2fe..ac536843 100644 --- a/unix/uxpgnt.c +++ b/unix/uxpgnt.c @@ -113,7 +113,7 @@ void keylist_update(void) const char *const appname = "Pageant"; -static int time_to_die = FALSE; +static int time_to_die = false; /* Stub functions to permit linking against x11fwd.c. These never get * used, because in LIFE_X11 mode we connect to the X server using a @@ -121,29 +121,29 @@ static int time_to_die = FALSE; * forwarding too. */ void chan_remotely_opened_confirmation(Channel *chan) { } void chan_remotely_opened_failure(Channel *chan, const char *err) { } -int chan_default_want_close(Channel *chan, int s, int r) { return FALSE; } -int chan_no_exit_status(Channel *ch, int s) { return FALSE; } +int chan_default_want_close(Channel *chan, int s, int r) { return false; } +int chan_no_exit_status(Channel *ch, int s) { return false; } int chan_no_exit_signal(Channel *ch, ptrlen s, int c, ptrlen m) -{ return FALSE; } +{ return false; } int chan_no_exit_signal_numeric(Channel *ch, int s, int c, ptrlen m) -{ return FALSE; } -int chan_no_run_shell(Channel *chan) { return FALSE; } -int chan_no_run_command(Channel *chan, ptrlen command) { return FALSE; } -int chan_no_run_subsystem(Channel *chan, ptrlen subsys) { return FALSE; } +{ return false; } +int chan_no_run_shell(Channel *chan) { return false; } +int chan_no_run_command(Channel *chan, ptrlen command) { return false; } +int chan_no_run_subsystem(Channel *chan, ptrlen subsys) { return false; } int chan_no_enable_x11_forwarding( Channel *chan, int oneshot, ptrlen authproto, ptrlen authdata, - unsigned screen_number) { return FALSE; } -int chan_no_enable_agent_forwarding(Channel *chan) { return FALSE; } + unsigned screen_number) { return false; } +int chan_no_enable_agent_forwarding(Channel *chan) { return false; } int chan_no_allocate_pty( Channel *chan, ptrlen termtype, unsigned width, unsigned height, unsigned pixwidth, unsigned pixheight, struct ssh_ttymodes modes) -{ return FALSE; } -int chan_no_set_env(Channel *chan, ptrlen var, ptrlen value) { return FALSE; } -int chan_no_send_break(Channel *chan, unsigned length) { return FALSE; } -int chan_no_send_signal(Channel *chan, ptrlen signame) { return FALSE; } +{ return false; } +int chan_no_set_env(Channel *chan, ptrlen var, ptrlen value) { return false; } +int chan_no_send_break(Channel *chan, unsigned length) { return false; } +int chan_no_send_signal(Channel *chan, ptrlen signame) { return false; } int chan_no_change_window_size( Channel *chan, unsigned width, unsigned height, - unsigned pixwidth, unsigned pixheight) { return FALSE; } + unsigned pixwidth, unsigned pixheight) { return false; } void chan_no_request_response(Channel *chan, int success) {} /* @@ -159,7 +159,7 @@ static void x11_sent(Plug *plug, int bufsize) {} static void x11_closing(Plug *plug, const char *error_msg, int error_code, int calling_back) { - time_to_die = TRUE; + time_to_die = true; } struct X11Connection { Plug plug; @@ -306,10 +306,10 @@ int have_controlling_tty(void) perror("/dev/tty: open"); exit(1); } - return FALSE; + return false; } else { close(fd); - return TRUE; + return true; } } @@ -326,9 +326,9 @@ static char *askpass_tty(const char *prompt) { int ret; prompts_t *p = new_prompts(); - p->to_server = FALSE; + p->to_server = false; p->name = dupstr("Pageant passphrase prompt"); - add_prompt(p, dupcat(prompt, ": ", (const char *)NULL), FALSE); + add_prompt(p, dupcat(prompt, ": ", (const char *)NULL), false); ret = console_get_userpass_input(p); assert(ret >= 0); @@ -400,7 +400,7 @@ static int unix_add_keyfile(const char *filename_str) int status, ret; char *err; - ret = TRUE; + ret = true; /* * Try without a passphrase. @@ -410,7 +410,7 @@ static int unix_add_keyfile(const char *filename_str) goto cleanup; } else if (status == PAGEANT_ACTION_FAILURE) { fprintf(stderr, "pageant: %s: %s\n", filename_str, err); - ret = FALSE; + ret = false; goto cleanup; } @@ -437,7 +437,7 @@ static int unix_add_keyfile(const char *filename_str) goto cleanup; } else if (status == PAGEANT_ACTION_FAILURE) { fprintf(stderr, "pageant: %s: %s\n", filename_str, err); - ret = FALSE; + ret = false; goto cleanup; } } @@ -476,9 +476,9 @@ int match_fingerprint_string(const char *string, const char *fingerprint) while (*string == ':') string++; while (*hash == ':') hash++; if (!*string) - return TRUE; + return true; if (tolower((unsigned char)*string) != tolower((unsigned char)*hash)) - return FALSE; + return false; string++; hash++; } @@ -502,8 +502,8 @@ struct pageant_pubkey *find_key(const char *string, char **retstr) { struct key_find_ctx actx, *ctx = &actx; struct pageant_pubkey key_in, *key_ret; - int try_file = TRUE, try_fp = TRUE, try_comment = TRUE; - int file_errors = FALSE; + int try_file = true, try_fp = true, try_comment = true; + int file_errors = false; /* * Trim off disambiguating prefixes telling us how to interpret @@ -511,17 +511,17 @@ struct pageant_pubkey *find_key(const char *string, char **retstr) */ if (!strncmp(string, "file:", 5)) { string += 5; - try_fp = try_comment = FALSE; - file_errors = TRUE; /* also report failure to load the file */ + try_fp = try_comment = false; + file_errors = true; /* also report failure to load the file */ } else if (!strncmp(string, "comment:", 8)) { string += 8; - try_file = try_fp = FALSE; + try_file = try_fp = false; } else if (!strncmp(string, "fp:", 3)) { string += 3; - try_file = try_comment = FALSE; + try_file = try_comment = false; } else if (!strncmp(string, "fingerprint:", 12)) { string += 12; - try_file = try_comment = FALSE; + try_file = try_comment = false; } /* @@ -632,7 +632,7 @@ void run_client(void) { const struct cmdline_key_action *act; struct pageant_pubkey *key; - int errors = FALSE; + int errors = false; char *retstr; if (!agent_exists()) { @@ -644,14 +644,14 @@ void run_client(void) switch (act->action) { case KEYACT_CLIENT_ADD: if (!unix_add_keyfile(act->filename)) - errors = TRUE; + errors = true; break; case KEYACT_CLIENT_LIST: if (pageant_enum_keys(key_list_callback, NULL, &retstr) == PAGEANT_ACTION_FAILURE) { fprintf(stderr, "pageant: listing keys: %s\n", retstr); sfree(retstr); - errors = TRUE; + errors = true; } break; case KEYACT_CLIENT_DEL: @@ -661,7 +661,7 @@ void run_client(void) fprintf(stderr, "pageant: deleting key '%s': %s\n", act->filename, retstr); sfree(retstr); - errors = TRUE; + errors = true; } if (key) pageant_pubkey_free(key); @@ -673,7 +673,7 @@ void run_client(void) fprintf(stderr, "pageant: finding key '%s': %s\n", act->filename, retstr); sfree(retstr); - errors = TRUE; + errors = true; } else { FILE *fp = stdout; /* FIXME: add a -o option? */ @@ -702,7 +702,7 @@ void run_client(void) if (pageant_delete_all_keys(&retstr) == PAGEANT_ACTION_FAILURE) { fprintf(stderr, "pageant: deleting all keys: %s\n", retstr); sfree(retstr); - errors = TRUE; + errors = true; } break; default: @@ -734,7 +734,7 @@ void run_agent(void) int fd; int i, fdcount, fdsize, fdstate; int termination_pid = -1; - int errors = FALSE; + int errors = false; Conf *conf; const struct cmdline_key_action *act; @@ -749,7 +749,7 @@ void run_agent(void) for (act = keyact_head; act; act = act->next) { assert(act->action == KEYACT_AGENT_LOAD); if (!unix_add_keyfile(act->filename)) - errors = TRUE; + errors = true; } if (errors) exit(1); @@ -811,13 +811,13 @@ void run_agent(void) smemclr(greeting, greetinglen); sfree(greeting); - pageant_fork_and_print_env(FALSE); + pageant_fork_and_print_env(false); } else if (life == LIFE_TTY) { schedule_timer(TTY_LIFE_POLL_INTERVAL, tty_life_timer, &dummy_timer_ctx); - pageant_fork_and_print_env(TRUE); + pageant_fork_and_print_env(true); } else if (life == LIFE_PERM) { - pageant_fork_and_print_env(FALSE); + pageant_fork_and_print_env(false); } else if (life == LIFE_DEBUG) { pageant_print_env(getpid()); pageant_logfp = stdout; @@ -840,8 +840,8 @@ void run_agent(void) perror("fork"); exit(1); } else if (pid == 0) { - setenv("SSH_AUTH_SOCK", socketname, TRUE); - setenv("SSH_AGENT_PID", dupprintf("%d", (int)agentpid), TRUE); + setenv("SSH_AUTH_SOCK", socketname, true); + setenv("SSH_AGENT_PID", dupprintf("%d", (int)agentpid), true); execvp(exec_args[0], exec_args); perror("exec"); _exit(127); @@ -945,7 +945,7 @@ void run_agent(void) * clean up and leave. */ if (!have_controlling_tty()) { - time_to_die = TRUE; + time_to_die = true; break; } } @@ -977,7 +977,7 @@ void run_agent(void) if (pid <= 0) break; if (pid == termination_pid) - time_to_die = TRUE; + time_to_die = true; } } @@ -998,7 +998,7 @@ void run_agent(void) int main(int argc, char **argv) { - int doing_opts = TRUE; + int doing_opts = true; keyact curr_keyact = KEYACT_AGENT_LOAD; const char *standalone_askpass_prompt = NULL; @@ -1063,7 +1063,7 @@ int main(int argc, char **argv) exit(1); } } else if (!strcmp(p, "--")) { - doing_opts = FALSE; + doing_opts = false; } } else { /* @@ -1120,19 +1120,19 @@ int main(int argc, char **argv) * actions of KEYACT_AGENT_* type. */ { - int has_agent_actions = FALSE; - int has_client_actions = FALSE; - int has_lifetime = FALSE; + int has_agent_actions = false; + int has_client_actions = false; + int has_lifetime = false; const struct cmdline_key_action *act; for (act = keyact_head; act; act = act->next) { if (is_agent_action(act->action)) - has_agent_actions = TRUE; + has_agent_actions = true; else - has_client_actions = TRUE; + has_client_actions = true; } if (life != LIFE_UNSPEC) - has_lifetime = TRUE; + has_lifetime = true; if (has_lifetime && has_client_actions) { fprintf(stderr, "pageant: client key actions (-a, -d, -D, -l, -L)" diff --git a/unix/uxplink.c b/unix/uxplink.c index 6b7da66c..dad746d9 100644 --- a/unix/uxplink.c +++ b/unix/uxplink.c @@ -38,7 +38,7 @@ void cmdline_error(const char *fmt, ...) exit(1); } -static int local_tty = FALSE; /* do we have a local tty? */ +static int local_tty = false; /* do we have a local tty? */ static Backend *backend; static Conf *conf; @@ -79,7 +79,7 @@ char *x_get_default(const char *key) } int term_ldisc(Terminal *term, int mode) { - return FALSE; + return false; } static void plink_echoedit_update(Seat *seat, int echo, int edit) { @@ -353,11 +353,11 @@ static int plink_output(Seat *seat, int is_stderr, const void *data, int len) { if (is_stderr) { bufchain_add(&stderr_data, data, len); - return try_output(TRUE); + return try_output(true); } else { assert(outgoingeof == EOF_NO); bufchain_add(&stdout_data, data, len); - return try_output(FALSE); + return try_output(false); } } @@ -365,8 +365,8 @@ static int plink_eof(Seat *seat) { assert(outgoingeof == EOF_NO); outgoingeof = EOF_PENDING; - try_output(FALSE); - return FALSE; /* do not respond to incoming EOF with outgoing */ + try_output(false); + return false; /* do not respond to incoming EOF with outgoing */ } static int plink_get_userpass_input(Seat *seat, prompts_t *p, bufchain *input) @@ -546,10 +546,10 @@ static void version(void) void frontend_net_error_pending(void) {} -const int share_can_be_downstream = TRUE; -const int share_can_be_upstream = TRUE; +const int share_can_be_downstream = true; +const int share_can_be_upstream = true; -const int buildinfo_gtk_relevant = FALSE; +const int buildinfo_gtk_relevant = false; int main(int argc, char **argv) { @@ -560,7 +560,7 @@ int main(int argc, char **argv) int exitcode; int errors; int use_subsystem = 0; - int just_test_share_exists = FALSE; + int just_test_share_exists = false; unsigned long now; struct winsize size; const struct BackendVtable *backvt; @@ -591,7 +591,7 @@ int main(int argc, char **argv) */ conf = conf_new(); do_defaults(NULL, conf); - loaded_session = FALSE; + loaded_session = false; default_protocol = conf_get_int(conf, CONF_protocol); default_port = conf_get_int(conf, CONF_port); errors = 0; @@ -645,7 +645,7 @@ int main(int argc, char **argv) provide_xrm_string(*++argv); } } else if (!strcmp(p, "-shareexists")) { - just_test_share_exists = TRUE; + just_test_share_exists = true; } else if (!strcmp(p, "-fuzznet")) { conf_set_int(conf, CONF_proxy_type, PROXY_FUZZ); conf_set_str(conf, CONF_proxy_telnet_command, "%host"); @@ -674,7 +674,7 @@ int main(int argc, char **argv) /* change trailing blank to NUL */ conf_set_str(conf, CONF_remote_cmd, command); conf_set_str(conf, CONF_remote_cmd2, ""); - conf_set_int(conf, CONF_nopty, TRUE); /* command => no tty */ + conf_set_int(conf, CONF_nopty, true); /* command => no tty */ break; /* done with cmdline */ } else { @@ -713,7 +713,7 @@ int main(int argc, char **argv) * Apply subsystem status. */ if (use_subsystem) - conf_set_int(conf, CONF_ssh_subsys, TRUE); + conf_set_int(conf, CONF_ssh_subsys, true); if (!*conf_get_str(conf, CONF_remote_cmd) && !*conf_get_str(conf, CONF_remote_cmd2) && @@ -772,7 +772,7 @@ int main(int argc, char **argv) !conf_get_int(conf, CONF_x11_forward) && !conf_get_int(conf, CONF_agentfwd) && !conf_get_str_nthstrkey(conf, CONF_portfwd, 0)) - conf_set_int(conf, CONF_ssh_simple, TRUE); + conf_set_int(conf, CONF_ssh_simple, true); if (just_test_share_exists) { if (!backvt->test_for_upstream) { @@ -823,7 +823,7 @@ int main(int argc, char **argv) local_tty = (tcgetattr(STDIN_FILENO, &orig_termios) == 0); atexit(cleanup_termios); seat_echoedit_update(plink_seat, 1, 1); - sending = FALSE; + sending = false; now = GETTICKCOUNT(); while (1) { @@ -958,7 +958,7 @@ int main(int argc, char **argv) exit(1); } else if (ret == 0) { backend_special(backend, SS_EOF, 0); - sending = FALSE; /* send nothing further after this */ + sending = false; /* send nothing further after this */ } else { if (local_tty) from_tty(buf, ret); @@ -969,11 +969,11 @@ int main(int argc, char **argv) } if (FD_ISSET(STDOUT_FILENO, &wset)) { - backend_unthrottle(backend, try_output(FALSE)); + backend_unthrottle(backend, try_output(false)); } if (FD_ISSET(STDERR_FILENO, &wset)) { - backend_unthrottle(backend, try_output(TRUE)); + backend_unthrottle(backend, try_output(true)); } run_toplevel_callbacks(); diff --git a/unix/uxpterm.c b/unix/uxpterm.c index c7325722..b4d66924 100644 --- a/unix/uxpterm.c +++ b/unix/uxpterm.c @@ -11,7 +11,7 @@ const char *const appname = "pterm"; const int use_event_log = 0; /* pterm doesn't need it */ const int new_session = 0, saved_sessions = 0; /* or these */ const int dup_check_launchable = 0; /* no need to check host name in conf */ -const int use_pty_argv = TRUE; +const int use_pty_argv = true; const struct BackendVtable *select_backend(Conf *conf) { diff --git a/unix/uxpty.c b/unix/uxpty.c index b3fe0f83..6b9f3555 100644 --- a/unix/uxpty.c +++ b/unix/uxpty.c @@ -285,10 +285,10 @@ static void sigchld_handler(int signum) static void pty_setup_sigchld_handler(void) { - static int setup = FALSE; + static int setup = false; if (!setup) { putty_signal(SIGCHLD, sigchld_handler); - setup = TRUE; + setup = true; } } @@ -455,7 +455,7 @@ void pty_pre_init(void) pty_setup_sigchld_handler(); pty->master_fd = pty->slave_fd = -1; #ifndef OMIT_UTMP - pty_stamped_utmp = FALSE; + pty_stamped_utmp = false; #endif if (geteuid() != getuid() || getegid() != getgid()) { @@ -597,7 +597,7 @@ static void pty_real_select_result(Pty *pty, int fd, int event, int status) { char buf[4096]; int ret; - int finished = FALSE; + int finished = false; if (event < 0) { /* @@ -608,7 +608,7 @@ static void pty_real_select_result(Pty *pty, int fd, int event, int status) /* * The primary child process died. */ - pty->child_dead = TRUE; + pty->child_dead = true; del234(ptys_by_pid, pty); pty->exit_code = status; @@ -625,7 +625,7 @@ static void pty_real_select_result(Pty *pty, int fd, int event, int status) * or make configurable if necessary. */ if (pty->master_fd >= 0) - finished = TRUE; + finished = true; } } else { if (event == 1) { @@ -667,7 +667,7 @@ static void pty_real_select_result(Pty *pty, int fd, int event, int status) * usage model would precisely _not_ be for the * pterm window to hang around! */ - finished = TRUE; + finished = true; pty_try_wait(); /* one last effort to collect exit code */ if (!pty->child_dead) pty->exit_code = 0; @@ -696,7 +696,7 @@ static void pty_real_select_result(Pty *pty, int fd, int event, int status) pty_close(pty); - pty->finished = TRUE; + pty->finished = true; /* * This is a slight layering-violation sort of hack: only @@ -862,7 +862,7 @@ Backend *pty_backend_create( pty = new_pty_struct(); pty->master_fd = pty->slave_fd = -1; #ifndef OMIT_UTMP - pty_stamped_utmp = FALSE; + pty_stamped_utmp = false; #endif } for (i = 0; i < 6; i++) @@ -1193,8 +1193,8 @@ Backend *pty_backend_create( _exit(127); } else { pty->child_pid = pid; - pty->child_dead = FALSE; - pty->finished = FALSE; + pty->child_dead = false; + pty->finished = false; if (pty->slave_fd > 0) close(pty->slave_fd); if (!ptys_by_pid) @@ -1248,7 +1248,7 @@ static const char *pty_init(Seat *seat, Backend **backend_handle, cmd = pty_argv[0]; *backend_handle= pty_backend_create( - seat, logctx, conf, pty_argv, cmd, modes, FALSE); + seat, logctx, conf, pty_argv, cmd, modes, false); *realhost = dupstr(""); return NULL; } @@ -1327,7 +1327,7 @@ static void pty_try_write(Pty *pty) uxsel_del(pty->master_i); close(pty->master_i); pty->master_i = -1; - pty->pending_eof = FALSE; + pty->pending_eof = false; } pty_uxsel_setup(pty); @@ -1427,7 +1427,7 @@ static void pty_special(Backend *be, SessionSpecialCode code, int arg) if (code == SS_EOF) { if (pty->master_i >= 0 && pty->master_i != pty->master_fd) { - pty->pending_eof = TRUE; + pty->pending_eof = true; pty_try_write(pty); } return; @@ -1473,7 +1473,7 @@ static const SessionSpecial *pty_get_specials(Backend *be) static int pty_connected(Backend *be) { /* Pty *pty = container_of(be, Pty, backend); */ - return TRUE; + return true; } static int pty_sendok(Backend *be) diff --git a/unix/uxputty.c b/unix/uxputty.c index fdfa6c21..a583f878 100644 --- a/unix/uxputty.c +++ b/unix/uxputty.c @@ -20,7 +20,7 @@ /* * Stubs to avoid uxpty.c needing to be linked in. */ -const int use_pty_argv = FALSE; +const int use_pty_argv = false; char **pty_argv; /* never used */ char *pty_osx_envrestore_prefix; @@ -48,7 +48,7 @@ const struct BackendVtable *select_backend(Conf *conf) void initial_config_box(Conf *conf, post_dialog_fn_t after, void *afterctx) { char *title = dupcat(appname, " Configuration", NULL); - create_config_box(title, conf, FALSE, 0, after, afterctx); + create_config_box(title, conf, false, 0, after, afterctx); sfree(title); } @@ -73,8 +73,8 @@ char *platform_get_x_display(void) { return dupstr(display); } -const int share_can_be_downstream = TRUE; -const int share_can_be_upstream = TRUE; +const int share_can_be_downstream = true; +const int share_can_be_upstream = true; void setup(int single) { diff --git a/unix/uxser.c b/unix/uxser.c index 2f9251b7..5be7cdf8 100644 --- a/unix/uxser.c +++ b/unix/uxser.c @@ -294,7 +294,7 @@ static const char *serial_init(Seat *seat, Backend **backend_handle, serial->seat = seat; serial->logctx = logctx; - serial->finished = FALSE; + serial->finished = false; serial->inbufsize = 0; bufchain_init(&serial->output_data); @@ -361,7 +361,7 @@ static void serial_select_result(int fd, int event) Serial *serial; char buf[4096]; int ret; - int finished = FALSE; + int finished = false; serial = find234(serial_by_fd, &fd, serial_find_by_fd); @@ -377,7 +377,7 @@ static void serial_select_result(int fd, int event) * to the idea that there might be two-way devices we * can treat _like_ serial ports which can return EOF. */ - finished = TRUE; + finished = true; } else if (ret < 0) { #ifdef EAGAIN if (errno == EAGAIN) @@ -403,7 +403,7 @@ static void serial_select_result(int fd, int event) if (finished) { serial_close(serial); - serial->finished = TRUE; + serial->finished = true; seat_notify_remote_exit(serial->seat); } diff --git a/unix/uxserver.c b/unix/uxserver.c index dbf5815a..c42afc1e 100644 --- a/unix/uxserver.c +++ b/unix/uxserver.c @@ -173,7 +173,7 @@ unsigned auth_methods(AuthPolicy *ap) } int auth_none(AuthPolicy *ap, ptrlen username) { - return FALSE; + return false; } int auth_password(AuthPolicy *ap, ptrlen username, ptrlen password, ptrlen *new_password_opt) @@ -211,9 +211,9 @@ int auth_publickey(AuthPolicy *ap, ptrlen username, ptrlen public_blob) struct AuthPolicy_ssh2_pubkey *iter; for (iter = ap->ssh2keys; iter; iter = iter->next) { if (ptrlen_eq_ptrlen(public_blob, iter->public_blob)) - return TRUE; + return true; } - return FALSE; + return false; } struct RSAKey *auth_publickey_ssh1( AuthPolicy *ap, ptrlen username, Bignum rsa_modulus) @@ -237,9 +237,9 @@ AuthKbdInt *auth_kbdint_prompts(AuthPolicy *ap, ptrlen username) aki->nprompts = 2; aki->prompts = snewn(aki->nprompts, AuthKbdIntPrompt); aki->prompts[0].prompt = dupstr("Echoey prompt: "); - aki->prompts[0].echo = TRUE; + aki->prompts[0].echo = true; aki->prompts[1].prompt = dupstr("Silent prompt: "); - aki->prompts[1].echo = FALSE; + aki->prompts[1].echo = false; return aki; case 1: aki->title = dupstr("Zero-prompt step"); @@ -286,7 +286,7 @@ int auth_ssh1int_response(AuthPolicy *ap, ptrlen response) } int auth_successful(AuthPolicy *ap, ptrlen username, unsigned method) { - return TRUE; + return true; } static void safety_warning(FILE *fp) @@ -319,13 +319,13 @@ static void show_version_and_exit(void) exit(0); } -const int buildinfo_gtk_relevant = FALSE; +const int buildinfo_gtk_relevant = false; -static int finished = FALSE; +static int finished = false; void server_instance_terminated(void) { /* FIXME: change policy here if we're running in a listening loop */ - finished = TRUE; + finished = true; } static int longoptarg(const char *arg, const char *expected, @@ -333,21 +333,21 @@ static int longoptarg(const char *arg, const char *expected, { int len = strlen(expected); if (memcmp(arg, expected, len)) - return FALSE; + return false; if (arg[len] == '=') { *val = arg + len + 1; - return TRUE; + return true; } else if (arg[len] == '\0') { if (--*argcp > 0) { *val = *++*argvp; - return TRUE; + return true; } else { fprintf(stderr, "%s: option %s expects an argument\n", appname, expected); exit(1); } } - return FALSE; + return false; } extern const SftpServerVtable unix_live_sftpserver_vt; @@ -393,7 +393,7 @@ int main(int argc, char **argv) } else if (!strcmp(arg, "--version")) { show_version_and_exit(); } else if (!strcmp(arg, "--verbose") || !strcmp(arg, "-v")) { - verbose = TRUE; + verbose = true; } else if (longoptarg(arg, "--hostkey", &val, &argc, &argv)) { Filename *keyfile; int keytype; diff --git a/unix/uxsftp.c b/unix/uxsftp.c index 275c38b1..328b335a 100644 --- a/unix/uxsftp.c +++ b/unix/uxsftp.c @@ -37,7 +37,7 @@ void platform_get_x11_auth(struct X11Display *display, Conf *conf) { /* Do nothing, therefore no auth. */ } -const int platform_uses_x11_unix_by_default = TRUE; +const int platform_uses_x11_unix_by_default = true; /* * Default settings that are specific to PSFTP. @@ -415,12 +415,12 @@ char *stripslashes(const char *str, int local) int vet_filename(const char *name) { if (strchr(name, '/')) - return FALSE; + return false; if (name[0] == '.' && (!name[1] || (name[1] == '.' && !name[2]))) - return FALSE; + return false; - return TRUE; + return true; } int create_directory(const char *name) @@ -444,7 +444,7 @@ static int ssh_sftp_do_select(int include_stdin, int no_fds_ok) int fd, fdstate, rwx, ret, maxfd; unsigned long now = GETTICKCOUNT(); unsigned long next; - int done_something = FALSE; + int done_something = false; fdlist = NULL; fdcount = fdsize = 0; @@ -555,7 +555,7 @@ static int ssh_sftp_do_select(int include_stdin, int no_fds_ok) */ int ssh_sftp_loop_iteration(void) { - return ssh_sftp_do_select(FALSE, FALSE); + return ssh_sftp_do_select(false, false); } /* @@ -573,7 +573,7 @@ char *ssh_sftp_get_cmdline(const char *prompt, int no_fds_ok) buflen = bufsize = 0; while (1) { - ret = ssh_sftp_do_select(TRUE, no_fds_ok); + ret = ssh_sftp_do_select(true, no_fds_ok); if (ret < 0) { printf("connection died\n"); sfree(buf); @@ -608,7 +608,7 @@ void frontend_net_error_pending(void) {} void platform_psftp_pre_conn_setup(void) {} -const int buildinfo_gtk_relevant = FALSE; +const int buildinfo_gtk_relevant = false; /* * Main program: do platform-specific initialisation and then call diff --git a/unix/uxsftpserver.c b/unix/uxsftpserver.c index 8b59b3ab..7cfee950 100644 --- a/unix/uxsftpserver.c +++ b/unix/uxsftpserver.c @@ -107,12 +107,12 @@ static int uss_decode_handle( unsigned char handlebuf[8]; if (handle.len != 8) - return FALSE; + return false; memcpy(handlebuf, handle.ptr, 8); des_decrypt_xdmauth(uss->handlekey, handlebuf, 8); *index = toint(GET_32BIT(handlebuf)); *seq = GET_32BIT(handlebuf + 4); - return TRUE; + return true; } static void uss_return_new_handle( @@ -126,12 +126,12 @@ static void uss_return_new_handle( uss->fdsopen = sresize(uss->fdsopen, uss->fdsize, int); while (old_size < uss->fdsize) { uss->fdseqs[old_size] = 0; - uss->fdsopen[old_size] = FALSE; + uss->fdsopen[old_size] = false; old_size++; } } assert(!uss->fdsopen[fd]); - uss->fdsopen[fd] = TRUE; + uss->fdsopen[fd] = true; if (++uss->fdseqs[fd] == USS_DIRHANDLE_SEQ) uss->fdseqs[fd] = 0; uss_return_handle_raw(uss, reply, fd, uss->fdseqs[fd]); @@ -286,7 +286,7 @@ static void uss_close(SftpServer *srv, SftpReplyBuilder *reply, } else if ((fd = uss_lookup_fd(uss, reply, handle)) >= 0) { close(fd); assert(0 <= fd && fd <= uss->fdsize); - uss->fdsopen[fd] = FALSE; + uss->fdsopen[fd] = false; fxp_reply_ok(reply); } /* if both failed, uss_lookup_fd will have filled in an error response */ @@ -424,20 +424,20 @@ static void uss_fstat(SftpServer *srv, SftpReplyBuilder *reply, { \ if (attrs.flags & SSH_FILEXFER_ATTR_SIZE) \ if (api_prefix(truncate)(api_arg, attrs.size) < 0) \ - success = FALSE; \ + success = false; \ if (attrs.flags & SSH_FILEXFER_ATTR_UIDGID) \ if (api_prefix(chown)(api_arg, attrs.uid, attrs.gid) < 0) \ - success = FALSE; \ + success = false; \ if (attrs.flags & SSH_FILEXFER_ATTR_PERMISSIONS) \ if (api_prefix(chmod)(api_arg, attrs.permissions) < 0) \ - success = FALSE; \ + success = false; \ if (attrs.flags & SSH_FILEXFER_ATTR_ACMODTIME) { \ struct timeval tv[2]; \ tv[0].tv_sec = attrs.atime; \ tv[1].tv_sec = attrs.mtime; \ tv[0].tv_usec = tv[1].tv_usec = 0; \ if (api_prefix(utimes)(api_arg, tv) < 0) \ - success = FALSE; \ + success = false; \ } \ } while (0) @@ -450,7 +450,7 @@ static void uss_setstat(SftpServer *srv, SftpReplyBuilder *reply, UnixSftpServer *uss = container_of(srv, UnixSftpServer, srv); char *pathstr = mkstr(path); - int success = TRUE; + int success = true; SETSTAT_GUTS(PATH_PREFIX, pathstr, attrs, success); free(pathstr); @@ -470,7 +470,7 @@ static void uss_fsetstat(SftpServer *srv, SftpReplyBuilder *reply, if ((fd = uss_lookup_fd(uss, reply, handle)) < 0) return; - int success = TRUE; + int success = true; SETSTAT_GUTS(FD_PREFIX, fd, attrs, success); if (!success) { diff --git a/unix/uxucs.c b/unix/uxucs.c index edaca92c..92961eaa 100644 --- a/unix/uxucs.c +++ b/unix/uxucs.c @@ -96,7 +96,7 @@ int wc_to_mb(int codepage, int flags, const wchar_t *wcstr, int wclen, } /* - * Return value is TRUE if pterm is to run in direct-to-font mode. + * Return value is true if pterm is to run in direct-to-font mode. */ int init_ucs(struct unicode_data *ucsdata, char *linecharset, int utf8_override, int font_charset, int vtmode) diff --git a/windows/sizetip.c b/windows/sizetip.c index 4f0a195f..a0fd415f 100644 --- a/windows/sizetip.c +++ b/windows/sizetip.c @@ -20,7 +20,7 @@ static LRESULT CALLBACK SizeTipWndProc(HWND hWnd, UINT nMsg, switch (nMsg) { case WM_ERASEBKGND: - return TRUE; + return true; case WM_PAINT: { @@ -80,7 +80,7 @@ static LRESULT CALLBACK SizeTipWndProc(HWND hWnd, UINT nMsg, SetWindowPos(hWnd, NULL, 0, 0, sz.cx + 6, sz.cy + 6, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE); - InvalidateRect(hWnd, NULL, FALSE); + InvalidateRect(hWnd, NULL, false); DeleteDC(hdc); } diff --git a/windows/wincapi.c b/windows/wincapi.c index 2bd03470..fbaf58e2 100644 --- a/windows/wincapi.c +++ b/windows/wincapi.c @@ -11,12 +11,12 @@ int got_crypt(void) { - static int attempted = FALSE; + static int attempted = false; static int successful; static HMODULE crypt; if (!attempted) { - attempted = TRUE; + attempted = true; crypt = load_system32_dll("crypt32.dll"); successful = crypt && #ifdef COVERITY diff --git a/windows/wincfg.c b/windows/wincfg.c index 8131883c..ec9b7e3d 100644 --- a/windows/wincfg.c +++ b/windows/wincfg.c @@ -157,7 +157,7 @@ void win_setup_config_box(struct controlbox *b, HWND *hwndp, int has_help, } } ctrl_filesel(s, "Custom sound file to play as a bell:", NO_SHORTCUT, - FILTER_WAVE_FILES, FALSE, "Select bell sound file", + FILTER_WAVE_FILES, false, "Select bell sound file", HELPCTX(bell_style), conf_filesel_handler, I(CONF_bell_wavefile)); @@ -396,7 +396,7 @@ void win_setup_config_box(struct controlbox *b, HWND *hwndp, int has_help, if (!midsession && backend_vt_from_proto(PROT_SSH)) { s = ctrl_getset(b, "Connection/SSH/X11", "x11", "X11 forwarding"); ctrl_filesel(s, "X authority file for local display", 't', - NULL, FALSE, "Select X authority file", + NULL, false, "Select X authority file", HELPCTX(ssh_tunnels_xauthority), conf_filesel_handler, I(CONF_xauthfile)); } diff --git a/windows/wincons.c b/windows/wincons.c index 9a542571..b01b1637 100644 --- a/windows/wincons.c +++ b/windows/wincons.c @@ -11,7 +11,7 @@ #include "storage.h" #include "ssh.h" -int console_batch_mode = FALSE; +int console_batch_mode = false; /* * Clean up and exit. diff --git a/windows/winctrls.c b/windows/winctrls.c index 1b51598f..2a3a093f 100644 --- a/windows/winctrls.c +++ b/windows/winctrls.c @@ -92,7 +92,7 @@ HWND doctl(struct ctlpos *cp, RECT r, ctl = CreateWindowEx(exstyle, wclass, wtext, wstyle, r.left, r.top, r.right, r.bottom, cp->hwnd, (HMENU)(ULONG_PTR)wid, hinst, NULL); - SendMessage(ctl, WM_SETFONT, cp->font, MAKELPARAM(TRUE, 0)); + SendMessage(ctl, WM_SETFONT, cp->font, MAKELPARAM(true, 0)); if (!strcmp(wclass, "LISTBOX")) { /* @@ -981,7 +981,7 @@ static void pl_moveitem(HWND hwnd, int listid, int src, int dst) SendDlgItemMessage (hwnd, listid, LB_GETTEXT, src, (LPARAM) txt); val = SendDlgItemMessage (hwnd, listid, LB_GETITEMDATA, src, 0); /* Deselect old location. */ - SendDlgItemMessage (hwnd, listid, LB_SETSEL, FALSE, src); + SendDlgItemMessage (hwnd, listid, LB_SETSEL, false, src); /* Delete it at the old location. */ SendDlgItemMessage (hwnd, listid, LB_DELETESTRING, src, 0); /* Insert it at new location. */ @@ -1014,14 +1014,14 @@ int pl_itemfrompt(HWND hwnd, POINT cursor, BOOL scroll) ret = p_LBItemFromPt(hwnd, cursor, scroll); if (ret == -1) return ret; - ret = p_LBItemFromPt(hwnd, cursor, FALSE); + ret = p_LBItemFromPt(hwnd, cursor, false); updist = downdist = 0; for (i = 1; i < 4096 && (!updist || !downdist); i++) { uppoint = downpoint = cursor; uppoint.y -= i; downpoint.y += i; - upitem = p_LBItemFromPt(hwnd, uppoint, FALSE); - downitem = p_LBItemFromPt(hwnd, downpoint, FALSE); + upitem = p_LBItemFromPt(hwnd, uppoint, false); + downitem = p_LBItemFromPt(hwnd, downpoint, false); if (!updist && upitem != ret) updist = i; if (!downdist && downitem != ret) @@ -1036,7 +1036,7 @@ int pl_itemfrompt(HWND hwnd, POINT cursor, BOOL scroll) * Handler for prefslist above. * * Return value has bit 0 set if the dialog box procedure needs to - * return TRUE from handling this message; it has bit 1 set if a + * return true from handling this message; it has bit 1 set if a * change may have been made in the contents of the list. */ int handle_prefslist(struct prefslist *hdl, @@ -1062,10 +1062,10 @@ int handle_prefslist(struct prefslist *hdl, SendDlgItemMessage(hwnd, hdl->listid, LB_ADDSTRING, 0, (LPARAM) ""); - hdl->srcitem = p_LBItemFromPt(dlm->hWnd, dlm->ptCursor, TRUE); + hdl->srcitem = p_LBItemFromPt(dlm->hWnd, dlm->ptCursor, true); hdl->dragging = 0; /* XXX hack Q183115 */ - SetWindowLongPtr(hwnd, DWLP_MSGRESULT, TRUE); + SetWindowLongPtr(hwnd, DWLP_MSGRESULT, true); ret |= 1; break; case DL_CANCELDRAG: p_DrawInsert(hwnd, dlm->hWnd, -1); /* Clear arrow */ @@ -1075,7 +1075,7 @@ int handle_prefslist(struct prefslist *hdl, ret |= 1; break; case DL_DRAGGING: hdl->dragging = 1; - dest = pl_itemfrompt(dlm->hWnd, dlm->ptCursor, TRUE); + dest = pl_itemfrompt(dlm->hWnd, dlm->ptCursor, true); if (dest > hdl->dummyitem) dest = hdl->dummyitem; p_DrawInsert (hwnd, dlm->hWnd, dest); if (dest >= 0) @@ -1085,7 +1085,7 @@ int handle_prefslist(struct prefslist *hdl, ret |= 1; break; case DL_DROPPED: if (hdl->dragging) { - dest = pl_itemfrompt(dlm->hWnd, dlm->ptCursor, TRUE); + dest = pl_itemfrompt(dlm->hWnd, dlm->ptCursor, true); if (dest > hdl->dummyitem) dest = hdl->dummyitem; p_DrawInsert (hwnd, dlm->hWnd, -1); } @@ -1211,7 +1211,7 @@ void winctrl_add_shortcuts(struct dlgparam *dp, struct winctrl *c) if (c->shortcuts[i] != NO_SHORTCUT) { unsigned char s = tolower((unsigned char)c->shortcuts[i]); assert(!dp->shortcuts[s]); - dp->shortcuts[s] = TRUE; + dp->shortcuts[s] = true; } } @@ -1222,7 +1222,7 @@ void winctrl_rem_shortcuts(struct dlgparam *dp, struct winctrl *c) if (c->shortcuts[i] != NO_SHORTCUT) { unsigned char s = tolower((unsigned char)c->shortcuts[i]); assert(dp->shortcuts[s]); - dp->shortcuts[s] = FALSE; + dp->shortcuts[s] = false; } } @@ -1780,7 +1780,7 @@ int winctrl_handle_command(struct dlgparam *dp, UINT msg, r.top + (r.bottom-r.top-s.cy)/2, (char *)c->data, strlen((char *)c->data)); - return TRUE; + return true; } ctrl = c->ctrl; @@ -1797,7 +1797,7 @@ int winctrl_handle_command(struct dlgparam *dp, UINT msg, * subsequent code can test dp->coloursel_wanted(). */ ret = 0; - dp->coloursel_wanted = FALSE; + dp->coloursel_wanted = false; /* * Now switch on the control type and the message. @@ -1933,7 +1933,7 @@ int winctrl_handle_command(struct dlgparam *dp, UINT msg, of.lpstrFileTitle = NULL; of.lpstrTitle = ctrl->fileselect.title; of.Flags = 0; - if (request_file(NULL, &of, FALSE, ctrl->fileselect.for_writing)) { + if (request_file(NULL, &of, false, ctrl->fileselect.for_writing)) { SetDlgItemText(dp->hwnd, c->base_id + 1, filename); ctrl->generic.handler(ctrl, dp, dp->data, EVENT_VALCHANGE); } @@ -2008,9 +2008,9 @@ int winctrl_handle_command(struct dlgparam *dp, UINT msg, (unsigned char) (cc.rgbResult >> 8) & 0xFF; dp->coloursel_result.b = (unsigned char) (cc.rgbResult >> 16) & 0xFF; - dp->coloursel_result.ok = TRUE; + dp->coloursel_result.ok = true; } else - dp->coloursel_result.ok = FALSE; + dp->coloursel_result.ok = false; ctrl->generic.handler(ctrl, dp, dp->data, EVENT_CALLBACK); } @@ -2019,7 +2019,7 @@ int winctrl_handle_command(struct dlgparam *dp, UINT msg, /* * This function can be called to produce context help on a - * control. Returns TRUE if it has actually launched some help. + * control. Returns true if it has actually launched some help. */ int winctrl_context_help(struct dlgparam *dp, HWND hwnd, int id) { @@ -2340,7 +2340,7 @@ void dlg_update_start(union control *ctrl, dlgparam *dp) { struct winctrl *c = dlg_findbyctrl(dp, ctrl); if (c && c->ctrl->generic.type == CTRL_LISTBOX) { - SendDlgItemMessage(dp->hwnd, c->base_id+1, WM_SETREDRAW, FALSE, 0); + SendDlgItemMessage(dp->hwnd, c->base_id+1, WM_SETREDRAW, false, 0); } } @@ -2349,8 +2349,8 @@ void dlg_update_done(union control *ctrl, dlgparam *dp) struct winctrl *c = dlg_findbyctrl(dp, ctrl); if (c && c->ctrl->generic.type == CTRL_LISTBOX) { HWND hw = GetDlgItem(dp->hwnd, c->base_id+1); - SendMessage(hw, WM_SETREDRAW, TRUE, 0); - InvalidateRect(hw, NULL, TRUE); + SendMessage(hw, WM_SETREDRAW, true, 0); + InvalidateRect(hw, NULL, true); } } @@ -2408,7 +2408,7 @@ void dlg_error_msg(dlgparam *dp, const char *msg) */ void dlg_end(dlgparam *dp, int value) { - dp->ended = TRUE; + dp->ended = true; dp->endresult = value; } @@ -2441,7 +2441,7 @@ void dlg_refresh(union control *ctrl, dlgparam *dp) void dlg_coloursel_start(union control *ctrl, dlgparam *dp, int r, int g, int b) { - dp->coloursel_wanted = TRUE; + dp->coloursel_wanted = true; dp->coloursel_result.r = r; dp->coloursel_result.g = g; dp->coloursel_result.b = b; @@ -2482,7 +2482,7 @@ void dlg_auto_set_fixed_pitch_flag(dlgparam *dp) quality = conf_get_int(conf, CONF_font_quality); fs = conf_get_fontspec(conf, CONF_font); - hfont = CreateFont(0, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, + hfont = CreateFont(0, 0, 0, 0, FW_DONTCARE, false, false, false, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, FONT_QUALITY(quality), FIXED_PITCH | FF_DONTCARE, fs->name); @@ -2491,7 +2491,7 @@ void dlg_auto_set_fixed_pitch_flag(dlgparam *dp) /* Note that the TMPF_FIXED_PITCH bit is defined upside down :-( */ is_var = (tm.tmPitchAndFamily & TMPF_FIXED_PITCH); } else { - is_var = FALSE; /* assume it's basically normal */ + is_var = false; /* assume it's basically normal */ } if (hdc) ReleaseDC(NULL, hdc); @@ -2499,7 +2499,7 @@ void dlg_auto_set_fixed_pitch_flag(dlgparam *dp) DeleteObject(hfont); if (is_var) - dp->fixed_pitch_fonts = FALSE; + dp->fixed_pitch_fonts = false; } int dlg_get_fixed_pitch_flag(dlgparam *dp) @@ -2516,12 +2516,12 @@ void dp_init(struct dlgparam *dp) { dp->nctrltrees = 0; dp->data = NULL; - dp->ended = FALSE; + dp->ended = false; dp->focused = dp->lastfocused = NULL; memset(dp->shortcuts, 0, sizeof(dp->shortcuts)); dp->hwnd = NULL; dp->wintitle = dp->errtitle = NULL; - dp->fixed_pitch_fonts = TRUE; + dp->fixed_pitch_fonts = true; } void dp_add_tree(struct dlgparam *dp, struct winctrls *wc) diff --git a/windows/windlg.c b/windows/windlg.c index 6dae33f9..d20cd805 100644 --- a/windows/windlg.c +++ b/windows/windlg.c @@ -156,14 +156,14 @@ static INT_PTR CALLBACK LogProc(HWND hwnd, UINT msg, memcpy(p, sel_nl, sizeof(sel_nl)); p += sizeof(sel_nl); } - write_aclip(CLIP_SYSTEM, clipdata, size, TRUE); + write_aclip(CLIP_SYSTEM, clipdata, size, true); sfree(clipdata); } sfree(selitems); for (i = 0; i < (ninitial + ncircular); i++) SendDlgItemMessage(hwnd, IDN_LIST, LB_SETSEL, - FALSE, i); + false, i); } } return 0; @@ -230,7 +230,7 @@ static INT_PTR CALLBACK AboutProc(HWND hwnd, UINT msg, switch (LOWORD(wParam)) { case IDOK: case IDCANCEL: - EndDialog(hwnd, TRUE); + EndDialog(hwnd, true); return 0; case IDA_LICENCE: EnableWindow(hwnd, 0); @@ -249,7 +249,7 @@ static INT_PTR CALLBACK AboutProc(HWND hwnd, UINT msg, } return 0; case WM_CLOSE: - EndDialog(hwnd, TRUE); + EndDialog(hwnd, true); return 0; } return 0; @@ -428,7 +428,7 @@ static INT_PTR CALLBACK GenericMainDlgProc(HWND hwnd, UINT msg, MoveWindow(hwnd, (rs.right + rs.left + rd.left - rd.right) / 2, (rs.bottom + rs.top + rd.top - rd.bottom) / 2, - rd.right - rd.left, rd.bottom - rd.top, TRUE); + rd.right - rd.left, rd.bottom - rd.top, true); } /* @@ -451,7 +451,7 @@ static INT_PTR CALLBACK GenericMainDlgProc(HWND hwnd, UINT msg, hwnd, (HMENU) IDCX_TVSTATIC, hinst, NULL); font = SendMessage(hwnd, WM_GETFONT, 0, 0); - SendMessage(tvstatic, WM_SETFONT, font, MAKELPARAM(TRUE, 0)); + SendMessage(tvstatic, WM_SETFONT, font, MAKELPARAM(true, 0)); r.left = 3; r.right = r.left + 95; @@ -468,7 +468,7 @@ static INT_PTR CALLBACK GenericMainDlgProc(HWND hwnd, UINT msg, hwnd, (HMENU) IDCX_TREEVIEW, hinst, NULL); font = SendMessage(hwnd, WM_GETFONT, 0, 0); - SendMessage(treeview, WM_SETFONT, font, MAKELPARAM(TRUE, 0)); + SendMessage(treeview, WM_SETFONT, font, MAKELPARAM(true, 0)); tvfaff.treeview = treeview; memset(tvfaff.lastat, 0, sizeof(tvfaff.lastat)); } @@ -594,7 +594,7 @@ static INT_PTR CALLBACK GenericMainDlgProc(HWND hwnd, UINT msg, i = TreeView_GetSelection(((LPNMHDR) lParam)->hwndFrom); - SendMessage (hwnd, WM_SETREDRAW, FALSE, 0); + SendMessage (hwnd, WM_SETREDRAW, false, 0); item.hItem = i; item.pszText = buffer; @@ -623,8 +623,8 @@ static INT_PTR CALLBACK GenericMainDlgProc(HWND hwnd, UINT msg, dlg_refresh(NULL, &dp); /* set up control values */ - SendMessage (hwnd, WM_SETREDRAW, TRUE, 0); - InvalidateRect (hwnd, NULL, TRUE); + SendMessage (hwnd, WM_SETREDRAW, true, 0); + InvalidateRect (hwnd, NULL, true); SetFocus(((LPNMHDR) lParam)->hwndFrom); /* ensure focus stays */ return 0; @@ -698,8 +698,8 @@ int do_config(void) int ret; ctrlbox = ctrl_new_box(); - setup_config_box(ctrlbox, FALSE, 0, 0); - win_setup_config_box(ctrlbox, &dp.hwnd, has_help(), FALSE, 0); + setup_config_box(ctrlbox, false, 0, 0); + win_setup_config_box(ctrlbox, &dp.hwnd, has_help(), false, 0); dp_init(&dp); winctrl_init(&ctrls_base); winctrl_init(&ctrls_panel); @@ -709,7 +709,7 @@ int do_config(void) dp.errtitle = dupprintf("%s Error", appname); dp.data = conf; dlg_auto_set_fixed_pitch_flag(&dp); - dp.shortcuts['g'] = TRUE; /* the treeview: `Cate&gory' */ + dp.shortcuts['g'] = true; /* the treeview: `Cate&gory' */ ret = SaneDialogBox(hinst, MAKEINTRESOURCE(IDD_MAINBOX), NULL, @@ -732,8 +732,8 @@ int do_reconfig(HWND hwnd, int protcfginfo) ctrlbox = ctrl_new_box(); protocol = conf_get_int(conf, CONF_protocol); - setup_config_box(ctrlbox, TRUE, protocol, protcfginfo); - win_setup_config_box(ctrlbox, &dp.hwnd, has_help(), TRUE, protocol); + setup_config_box(ctrlbox, true, protocol, protcfginfo); + win_setup_config_box(ctrlbox, &dp.hwnd, has_help(), true, protocol); dp_init(&dp); winctrl_init(&ctrls_base); winctrl_init(&ctrls_panel); @@ -743,7 +743,7 @@ int do_reconfig(HWND hwnd, int protcfginfo) dp.errtitle = dupprintf("%s Error", appname); dp.data = conf; dlg_auto_set_fixed_pitch_flag(&dp); - dp.shortcuts['g'] = TRUE; /* the treeview: `Cate&gory' */ + dp.shortcuts['g'] = true; /* the treeview: `Cate&gory' */ ret = SaneDialogBox(hinst, MAKEINTRESOURCE(IDD_MAINBOX), NULL, GenericMainDlgProc); diff --git a/windows/window.c b/windows/window.c index 5a6ddb7a..50bca70e 100644 --- a/windows/window.c +++ b/windows/window.c @@ -130,7 +130,7 @@ static Backend *backend; static struct unicode_data ucsdata; static int session_closed; -static int reconfiguring = FALSE; +static int reconfiguring = false; static const SessionSpecial *specials = NULL; static HMENU specials_menu = NULL; @@ -292,8 +292,8 @@ static const TermWinVtable windows_termwin_vt = { static TermWin wintw[1]; static HDC wintw_hdc; -const int share_can_be_downstream = TRUE; -const int share_can_be_upstream = TRUE; +const int share_can_be_downstream = true; +const int share_can_be_upstream = true; static int is_utf8(void) { @@ -318,7 +318,7 @@ char *win_seat_get_ttymode(Seat *seat, const char *mode) int win_seat_get_window_pixel_size(Seat *seat, int *x, int *y) { win_get_pixels(wintw, x, y); - return TRUE; + return true; } static int win_seat_output(Seat *seat, int is_stderr, const void *, int); @@ -416,7 +416,7 @@ static void start_backend(void) DeleteMenu(popup_menus[i].menu, IDM_RESTART, MF_BYCOMMAND); } - session_closed = FALSE; + session_closed = false; } static void close_session(void *ignored_context) @@ -424,7 +424,7 @@ static void close_session(void *ignored_context) char morestuff[100]; int i; - session_closed = TRUE; + session_closed = true; sprintf(morestuff, "%.70s (inactive)", appname); win_set_icon_title(wintw, morestuff); win_set_title(wintw, morestuff); @@ -511,7 +511,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) */ { char *p; - int special_launchable_argument = FALSE; + int special_launchable_argument = false; default_protocol = be_default_protocol; /* Find the appropriate default port. */ @@ -542,7 +542,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) (!p[2] || p[2] == '@' || p[2] == '&')) { /* &R restrict-acl prefix */ restrict_process_acl(); - restricted_acl = TRUE; + restricted_acl = true; p += 2; } @@ -562,7 +562,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) if (!conf_launchable(conf) && !do_config()) { cleanup_exit(0); } - special_launchable_argument = TRUE; + special_launchable_argument = true; } else if (*p == '&') { /* * An initial & means we've been given a command line @@ -585,7 +585,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) } else if (!do_config()) { cleanup_exit(0); } - special_launchable_argument = TRUE; + special_launchable_argument = true; } else if (!*p) { /* Do-nothing case for an empty command line - or rather, * for a command line that's empty _after_ we strip off @@ -792,7 +792,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) si.nMax = term->rows - 1; si.nPage = term->rows; si.nPos = 0; - SetScrollInfo(hwnd, SB_VERT, &si, FALSE); + SetScrollInfo(hwnd, SB_VERT, &si, false); } /* @@ -810,13 +810,13 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) int j; char *str; - popup_menus[SYSMENU].menu = GetSystemMenu(hwnd, FALSE); + popup_menus[SYSMENU].menu = GetSystemMenu(hwnd, false); popup_menus[CTXMENU].menu = CreatePopupMenu(); AppendMenu(popup_menus[CTXMENU].menu, MF_ENABLED, IDM_COPY, "&Copy"); AppendMenu(popup_menus[CTXMENU].menu, MF_ENABLED, IDM_PASTE, "&Paste"); savedsess_menu = CreateMenu(); - get_sesslist(&sesslist, TRUE); + get_sesslist(&sesslist, true); update_savedsess_menu(); for (j = 0; j < lenof(popup_menus); j++) { @@ -907,7 +907,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) handles = handle_get_events(&nhandles); - n = MsgWaitForMultipleObjects(nhandles, handles, FALSE, + n = MsgWaitForMultipleObjects(nhandles, handles, false, timeout, QS_ALLINPUT); if ((unsigned)(n - WAIT_OBJECT_0) < (unsigned)nhandles) { @@ -1122,8 +1122,8 @@ static void win_seat_update_specials_menu(Seat *seat) static void update_mouse_pointer(void) { LPTSTR curstype = NULL; - int force_visible = FALSE; - static int forced_visible = FALSE; + int force_visible = false; + static int forced_visible = false; switch (busy_status) { case BUSY_NOT: if (send_raw_mouse) @@ -1133,11 +1133,11 @@ static void update_mouse_pointer(void) break; case BUSY_WAITING: curstype = IDC_APPSTARTING; /* this may be an abuse */ - force_visible = TRUE; + force_visible = true; break; case BUSY_CPU: curstype = IDC_WAIT; - force_visible = TRUE; + force_visible = true; break; default: assert(0); @@ -1323,9 +1323,9 @@ static void init_palette(void) } pal = CreatePalette(logpal); if (pal) { - SelectPalette(hdc, pal, FALSE); + SelectPalette(hdc, pal, false); RealizePalette(hdc); - SelectPalette(hdc, GetStockObject(DEFAULT_PALETTE), FALSE); + SelectPalette(hdc, GetStockObject(DEFAULT_PALETTE), false); } } ReleaseDC(hwnd, hdc); @@ -1388,7 +1388,7 @@ static void general_textout(HDC hdc, int x, int y, CONST RECT *lprc, CONST INT *lpDx, int opaque) { int i, j, xp, xn; - int bkmode = 0, got_bkmode = FALSE; + int bkmode = 0, got_bkmode = false; xp = xn = x; @@ -1421,9 +1421,9 @@ static void general_textout(HDC hdc, int x, int y, CONST RECT *lprc, xp = xn; bkmode = GetBkMode(hdc); - got_bkmode = TRUE; + got_bkmode = true; SetBkMode(hdc, TRANSPARENT); - opaque = FALSE; + opaque = false; } if (got_bkmode) @@ -1442,8 +1442,8 @@ static int get_font_width(HDC hdc, const TEXTMETRIC *tm) ABCFLOAT widths[LAST-FIRST + 1]; int j; - font_varpitch = TRUE; - font_dualwidth = TRUE; + font_varpitch = true; + font_dualwidth = true; if (GetCharABCWidthsFloat(hdc, FIRST, LAST, widths)) { ret = 0; for (j = 0; j < lenof(widths); j++) { @@ -1494,7 +1494,7 @@ static void init_fonts(int pick_width, int pick_height) bold_font_mode = conf_get_int(conf, CONF_bold_style) & 1 ? BOLD_FONT : BOLD_NONE; - bold_colours = conf_get_int(conf, CONF_bold_style) & 2 ? TRUE : FALSE; + bold_colours = conf_get_int(conf, CONF_bold_style) & 2 ? true : false; und_mode = UND_FONT; font = conf_get_fontspec(conf, CONF_font); @@ -1521,12 +1521,12 @@ static void init_fonts(int pick_width, int pick_height) quality = conf_get_int(conf, CONF_font_quality); #define f(i,c,w,u) \ - fonts[i] = CreateFont (font_height, font_width, 0, 0, w, FALSE, u, FALSE, \ + fonts[i] = CreateFont (font_height, font_width, 0, 0, w, false, u, false, \ c, OUT_DEFAULT_PRECIS, \ CLIP_DEFAULT_PRECIS, FONT_QUALITY(quality), \ FIXED_PITCH | FF_DONTCARE, font->name) - f(FONT_NORMAL, font->charset, fw_dontcare, FALSE); + f(FONT_NORMAL, font->charset, fw_dontcare, false); SelectObject(hdc, fonts[FONT_NORMAL]); GetTextMetrics(hdc, &tm); @@ -1535,11 +1535,11 @@ static void init_fonts(int pick_width, int pick_height) /* Note that the TMPF_FIXED_PITCH bit is defined upside down :-( */ if (!(tm.tmPitchAndFamily & TMPF_FIXED_PITCH)) { - font_varpitch = FALSE; + font_varpitch = false; font_dualwidth = (tm.tmAveCharWidth != tm.tmMaxCharWidth); } else { - font_varpitch = TRUE; - font_dualwidth = TRUE; + font_varpitch = true; + font_dualwidth = true; } if (pick_width == 0 || pick_height == 0) { font_height = tm.tmHeight; @@ -1570,7 +1570,7 @@ static void init_fonts(int pick_width, int pick_height) ucsdata.dbcs_screenfont = (cpinfo.MaxCharSize > 1); } - f(FONT_UNDERLINE, font->charset, fw_dontcare, TRUE); + f(FONT_UNDERLINE, font->charset, fw_dontcare, true); /* * Some fonts, e.g. 9-pt Courier, draw their underlines @@ -1604,11 +1604,11 @@ static void init_fonts(int pick_width, int pick_height) SetBkColor(und_dc, RGB(0, 0, 0)); SetBkMode(und_dc, OPAQUE); ExtTextOut(und_dc, 0, 0, ETO_OPAQUE, NULL, " ", 1, NULL); - gotit = FALSE; + gotit = false; for (i = 0; i < font_height; i++) { c = GetPixel(und_dc, font_width / 2, i); if (c != RGB(0, 0, 0)) - gotit = TRUE; + gotit = true; } SelectObject(und_dc, und_oldbm); DeleteObject(und_bm); @@ -1621,7 +1621,7 @@ static void init_fonts(int pick_width, int pick_height) } if (bold_font_mode == BOLD_FONT) { - f(FONT_BOLD, font->charset, fw_bold, FALSE); + f(FONT_BOLD, font->charset, fw_bold, false); } #undef f @@ -1685,7 +1685,7 @@ static void another_font(int fontno) c = font->charset; w = fw_dontcare; - u = FALSE; + u = false; s = font->name; x = font_width; @@ -1698,13 +1698,13 @@ static void another_font(int fontno) if (fontno & FONT_BOLD) w = fw_bold; if (fontno & FONT_UNDERLINE) - u = TRUE; + u = true; quality = conf_get_int(conf, CONF_font_quality); fonts[fontno] = CreateFont(font_height * (1 + !!(fontno & FONT_HIGH)), x, 0, 0, w, - FALSE, u, FALSE, c, OUT_DEFAULT_PRECIS, + false, u, false, c, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, FONT_QUALITY(quality), DEFAULT_PITCH | FF_DONTCARE, s); @@ -1776,7 +1776,7 @@ static void wintw_request_resize(TermWin *tw, int w, int h) } else reset_window(0); - InvalidateRect(hwnd, NULL, TRUE); + InvalidateRect(hwnd, NULL, true); } static void reset_window(int reinit) { @@ -1826,7 +1826,7 @@ static void reset_window(int reinit) { offset_height != (win_height-font_height*term->rows)/2) ){ offset_width = (win_width-font_width*term->cols)/2; offset_height = (win_height-font_height*term->rows)/2; - InvalidateRect(hwnd, NULL, TRUE); + InvalidateRect(hwnd, NULL, true); #ifdef RDB_DEBUG_PATCH debug((27, "reset_window() -> Reposition terminal")); #endif @@ -1847,7 +1847,7 @@ static void reset_window(int reinit) { init_fonts(win_width/term->cols, win_height/term->rows); offset_width = (win_width-font_width*term->cols)/2; offset_height = (win_height-font_height*term->rows)/2; - InvalidateRect(hwnd, NULL, TRUE); + InvalidateRect(hwnd, NULL, true); #ifdef RDB_DEBUG_PATCH debug((25, "reset_window() -> Z font resize to (%d, %d)", font_width, font_height)); @@ -1863,7 +1863,7 @@ static void reset_window(int reinit) { conf_get_int(conf, CONF_savelines)); offset_width = (win_width-font_width*term->cols)/2; offset_height = (win_height-font_height*term->rows)/2; - InvalidateRect(hwnd, NULL, TRUE); + InvalidateRect(hwnd, NULL, true); #ifdef RDB_DEBUG_PATCH debug((27, "reset_window() -> Zoomed term_size")); #endif @@ -1897,7 +1897,7 @@ static void reset_window(int reinit) { SWP_NOMOVE | SWP_NOZORDER); } - InvalidateRect(hwnd, NULL, TRUE); + InvalidateRect(hwnd, NULL, true); return; } @@ -1956,7 +1956,7 @@ static void reset_window(int reinit) { font_height*term->rows + extra_height, SWP_NOMOVE | SWP_NOZORDER); - InvalidateRect(hwnd, NULL, TRUE); + InvalidateRect(hwnd, NULL, true); #ifdef RDB_DEBUG_PATCH debug((27, "reset_window() -> window resize to (%d,%d)", font_width*term->cols + extra_width, @@ -1980,7 +1980,7 @@ static void reset_window(int reinit) { extra_width = wr.right - wr.left - cr.right + cr.left +offset_width*2; extra_height = wr.bottom - wr.top - cr.bottom + cr.top+offset_height*2; - InvalidateRect(hwnd, NULL, TRUE); + InvalidateRect(hwnd, NULL, true); #ifdef RDB_DEBUG_PATCH debug((25, "reset_window() -> font resize to (%d,%d)", font_width, font_height)); @@ -2049,9 +2049,9 @@ static void show_mouseptr(int show) if (!conf_get_int(conf, CONF_hide_mouseptr)) show = 1; /* override if this feature disabled */ if (cursor_visible && !show) - ShowCursor(FALSE); + ShowCursor(false); else if (!cursor_visible && show) - ShowCursor(TRUE); + ShowCursor(true); cursor_visible = show; } @@ -2060,12 +2060,12 @@ static int is_alt_pressed(void) BYTE keystate[256]; int r = GetKeyboardState(keystate); if (!r) - return FALSE; + return false; if (keystate[VK_MENU] & 0x80) - return TRUE; + return true; if (keystate[VK_RMENU] & 0x80) - return TRUE; - return FALSE; + return true; + return false; } static int resizing; @@ -2084,7 +2084,7 @@ static void win_seat_notify_remote_exit(Seat *seat) PostQuitMessage(0); } else { queue_toplevel_callback(close_session, NULL); - session_closed = TRUE; + session_closed = true; /* exitcode == INT_MAX indicates that the connection was closed * by a fatal error, so an error box will be coming our way and * we should not generate this informational one. */ @@ -2128,14 +2128,14 @@ static HDC make_hdc(void) if (!hdc) return NULL; - SelectPalette(hdc, pal, FALSE); + SelectPalette(hdc, pal, false); return hdc; } static void free_hdc(HDC hdc) { assert(hwnd); - SelectPalette(hdc, GetStockObject(DEFAULT_PALETTE), FALSE); + SelectPalette(hdc, GetStockObject(DEFAULT_PALETTE), false); ReleaseDC(hwnd, hdc); } @@ -2143,10 +2143,10 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { HDC hdc; - static int ignore_clip = FALSE; - static int need_backend_resize = FALSE; - static int fullscr_on_max = FALSE; - static int processed_resize = FALSE; + static int ignore_clip = false; + static int need_backend_resize = false; + static int fullscr_on_max = false; + static int processed_resize = false; static UINT last_mousemove = 0; int resize_action; @@ -2186,8 +2186,8 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, if ((HMENU)wParam == savedsess_menu) { /* About to pop up Saved Sessions sub-menu. * Refresh the session list. */ - get_sesslist(&sesslist, FALSE); /* free */ - get_sesslist(&sesslist, TRUE); + get_sesslist(&sesslist, false); /* free */ + get_sesslist(&sesslist, true); update_savedsess_menu(); return 0; } @@ -2231,7 +2231,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, sa.nLength = sizeof(sa); sa.lpSecurityDescriptor = NULL; - sa.bInheritHandle = TRUE; + sa.bInheritHandle = true; filemap = CreateFileMapping(INVALID_HANDLE_VALUE, &sa, PAGE_READWRITE, @@ -2245,7 +2245,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, } strbuf_free(serbuf); - inherit_handles = TRUE; + inherit_handles = true; cl = dupprintf("putty %s&%p:%u", argprefix, filemap, (unsigned)size); } else if (wParam == IDM_SAVEDSESS) { @@ -2254,14 +2254,14 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, if (sessno < (unsigned)sesslist.nsessions) { const char *session = sesslist.sessions[sessno]; cl = dupprintf("putty %s@%s", argprefix, session); - inherit_handles = FALSE; + inherit_handles = false; } else break; } else /* IDM_NEWSESS */ { cl = dupprintf("putty%s%s", *argprefix ? " " : "", argprefix); - inherit_handles = FALSE; + inherit_handles = false; } GetModuleFileName(NULL, b, sizeof(b) - 1); @@ -2286,7 +2286,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, if (!backend) { lp_eventlog(default_logpolicy, "----- Session restarted -----"); - term_pwron(term, FALSE); + term_pwron(term, false); start_backend(); } @@ -2300,7 +2300,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, if (reconfiguring) break; else - reconfiguring = TRUE; + reconfiguring = true; /* * Copy the current window title into the stored @@ -2314,7 +2314,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, reconfig_result = do_reconfig(hwnd, backend ? backend_cfg_info(backend) : 0); - reconfiguring = FALSE; + reconfiguring = false; if (!reconfig_result) { conf_free(prev_conf); break; @@ -2472,7 +2472,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, init_lvl = 2; } - InvalidateRect(hwnd, NULL, TRUE); + InvalidateRect(hwnd, NULL, true); reset_window(init_lvl); conf_free(prev_conf); @@ -2491,7 +2491,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, term_clrsb(term); break; case IDM_RESET: - term_pwron(term, TRUE); + term_pwron(term, true); if (ldisc) ldisc_echoedit_update(ldisc); break; @@ -2719,7 +2719,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, case WM_DESTROYCLIPBOARD: if (!ignore_clip) term_lost_clipboard_ownership(term, CLIP_SYSTEM); - ignore_clip = FALSE; + ignore_clip = false; return 0; case WM_PAINT: { @@ -2728,7 +2728,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, HideCaret(hwnd); hdc = BeginPaint(hwnd, &p); if (pal) { - SelectPalette(hdc, pal, TRUE); + SelectPalette(hdc, pal, true); RealizePalette(hdc); } @@ -2838,7 +2838,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, } return 0; case WM_SETFOCUS: - term_set_focus(term, TRUE); + term_set_focus(term, true); CreateCaret(hwnd, caretbm, font_width, font_height); ShowCaret(hwnd); flash_window(0); /* stop */ @@ -2847,7 +2847,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, break; case WM_KILLFOCUS: show_mouseptr(1); - term_set_focus(term, FALSE); + term_set_focus(term, false); DestroyCaret(); caret_x = caret_y = -1; /* ensure caret is replaced next time */ term_update(term); @@ -2857,12 +2857,12 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, debug((27, "WM_ENTERSIZEMOVE")); #endif EnableSizeTip(1); - resizing = TRUE; - need_backend_resize = FALSE; + resizing = true; + need_backend_resize = false; break; case WM_EXITSIZEMOVE: EnableSizeTip(0); - resizing = FALSE; + resizing = false; #ifdef RDB_DEBUG_PATCH debug((27, "WM_EXITSIZEMOVE")); #endif @@ -2870,7 +2870,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, term_size(term, conf_get_int(conf, CONF_height), conf_get_int(conf, CONF_width), conf_get_int(conf, CONF_savelines)); - InvalidateRect(hwnd, NULL, TRUE); + InvalidateRect(hwnd, NULL, true); } break; case WM_SIZING: @@ -2900,8 +2900,8 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, conf_set_int(conf, CONF_height, term->rows); conf_set_int(conf, CONF_width, term->cols); - InvalidateRect(hwnd, NULL, TRUE); - need_backend_resize = TRUE; + InvalidateRect(hwnd, NULL, true); + need_backend_resize = true; } width = r->right - r->left - extra_width; @@ -2967,7 +2967,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, } /* break; (never reached) */ case WM_FULLSCR_ON_MAX: - fullscr_on_max = TRUE; + fullscr_on_max = true; break; case WM_MOVE: sys_cursor_update(); @@ -2990,7 +2990,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, if (wParam == SIZE_RESTORED || wParam == SIZE_MAXIMIZED) SetWindowText(hwnd, window_name); if (wParam == SIZE_RESTORED) { - processed_resize = FALSE; + processed_resize = false; clear_full_screen(); if (processed_resize) { /* @@ -3003,8 +3003,8 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, } } if (wParam == SIZE_MAXIMIZED && fullscr_on_max) { - fullscr_on_max = FALSE; - processed_resize = FALSE; + fullscr_on_max = false; + processed_resize = false; make_full_screen(); if (processed_resize) { /* @@ -3017,7 +3017,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, } } - processed_resize = TRUE; + processed_resize = true; if (resize_action == RESIZE_DISABLED) { /* A resize, well it better be a minimize. */ @@ -3048,7 +3048,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, * arise in maximisation as well via the Aero * snap UI. */ - need_backend_resize = TRUE; + need_backend_resize = true; conf_set_int(conf, CONF_height, h); conf_set_int(conf, CONF_width, w); } else { @@ -3087,7 +3087,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, * getting sent down the connection during an NT * opaque drag.) */ - need_backend_resize = TRUE; + need_backend_resize = true; conf_set_int(conf, CONF_height, h); conf_set_int(conf, CONF_width, w); } else { @@ -3154,10 +3154,10 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, if (RealizePalette(hdc) > 0) UpdateColors(hdc); free_hdc(hdc); - return TRUE; + return true; } } - return FALSE; + return false; case WM_KEYDOWN: case WM_SYSKEYDOWN: case WM_KEYUP: @@ -3470,7 +3470,7 @@ static void do_text_internal( int text_adjust = 0; int xoffset = 0; int maxlen, remaining, opaque; - int is_cursor = FALSE; + int is_cursor = false; static int *lpDx = NULL; static int lpDx_len = 0; int *lpDx_maybe; @@ -3497,7 +3497,7 @@ static void do_text_internal( attr &= ~(ATTR_REVERSE|ATTR_BLINK|ATTR_COLOURS|ATTR_DIM); /* cursor fg and bg */ attr |= (260 << ATTR_FGSHIFT) | (261 << ATTR_BGSHIFT); - is_cursor = TRUE; + is_cursor = true; } nfont = 0; @@ -3666,7 +3666,7 @@ static void do_text_internal( maxlen = len; } - opaque = TRUE; /* start by erasing the rectangle */ + opaque = true; /* start by erasing the rectangle */ for (remaining = len; remaining > 0; text += len, remaining -= len, x += char_width * len2) { len = (maxlen < remaining ? maxlen : remaining); @@ -3831,7 +3831,7 @@ static void do_text_internal( * rectangle. */ SetBkMode(wintw_hdc, TRANSPARENT); - opaque = FALSE; + opaque = false; } if (lattr != LATTR_TOP && (force_manual_underline || (und_mode == UND_LINE @@ -4975,7 +4975,7 @@ static void wintw_set_scrollbar(TermWin *tw, int total, int start, int page) si.nPage = page; si.nPos = start; if (hwnd) - SetScrollInfo(hwnd, SB_VERT, &si, TRUE); + SetScrollInfo(hwnd, SB_VERT, &si, true); } static int wintw_setup_draw_ctx(TermWin *tw) @@ -5007,11 +5007,11 @@ static void real_palette_set(int n, int r, int g, int b) static int wintw_palette_get(TermWin *tw, int n, int *r, int *g, int *b) { if (n < 0 || n >= NALLCOLOURS) - return FALSE; + return false; *r = colours_rgb[n].r; *g = colours_rgb[n].g; *b = colours_rgb[n].b; - return TRUE; + return true; } static void wintw_palette_set(TermWin *tw, int n, int r, int g, int b) @@ -5031,7 +5031,7 @@ static void wintw_palette_set(TermWin *tw, int n, int r, int g, int b) /* If Default Background changes, we need to ensure any * space between the text area and the window border is * redrawn. */ - InvalidateRect(hwnd, NULL, TRUE); + InvalidateRect(hwnd, NULL, true); } } @@ -5060,7 +5060,7 @@ static void wintw_palette_reset(TermWin *tw) } else { /* Default Background may have changed. Ensure any space between * text area and window border is redrawn. */ - InvalidateRect(hwnd, NULL, TRUE); + InvalidateRect(hwnd, NULL, true); } } @@ -5083,7 +5083,7 @@ void write_aclip(int clipboard, char *data, int len, int must_deselect) GlobalUnlock(clipdata); if (!must_deselect) - SendMessage(hwnd, WM_IGNORE_CLIP, TRUE, 0); + SendMessage(hwnd, WM_IGNORE_CLIP, true, 0); if (OpenClipboard(hwnd)) { EmptyClipboard(); @@ -5093,7 +5093,7 @@ void write_aclip(int clipboard, char *data, int len, int must_deselect) GlobalFree(clipdata); if (!must_deselect) - SendMessage(hwnd, WM_IGNORE_CLIP, FALSE, 0); + SendMessage(hwnd, WM_IGNORE_CLIP, false, 0); } typedef struct _rgbindex { @@ -5511,7 +5511,7 @@ static void wintw_clip_write( GlobalUnlock(clipdata2); if (!must_deselect) - SendMessage(hwnd, WM_IGNORE_CLIP, TRUE, 0); + SendMessage(hwnd, WM_IGNORE_CLIP, true, 0); if (OpenClipboard(hwnd)) { EmptyClipboard(); @@ -5526,7 +5526,7 @@ static void wintw_clip_write( } if (!must_deselect) - SendMessage(hwnd, WM_IGNORE_CLIP, FALSE, 0); + SendMessage(hwnd, WM_IGNORE_CLIP, false, 0); } static DWORD WINAPI clipboard_read_threadfunc(void *param) @@ -5653,7 +5653,7 @@ static BOOL flash_window_ex(DWORD dwFlags, UINT uCount, DWORD dwTimeout) return (*p_FlashWindowEx)(&fi); } else - return FALSE; /* shrug */ + return false; /* shrug */ } static void flash_window(int mode); @@ -5685,7 +5685,7 @@ static void flash_window(int mode) if (p_FlashWindowEx) flash_window_ex(FLASHW_STOP, 0, 0); else - FlashWindow(hwnd, FALSE); + FlashWindow(hwnd, false); } } else if (mode == 2) { @@ -5704,7 +5704,7 @@ static void flash_window(int mode) 0 /* system cursor blink rate */); /* No need to schedule timer */ } else { - FlashWindow(hwnd, TRUE); + FlashWindow(hwnd, true); next_flash = schedule_timer(450, flash_window_timer, hwnd); } } @@ -5712,7 +5712,7 @@ static void flash_window(int mode) } else if ((mode == 1) && (beep_ind == B_IND_FLASH)) { /* maintain */ if (flashing && !p_FlashWindowEx) { - FlashWindow(hwnd, TRUE); /* toggle */ + FlashWindow(hwnd, true); /* toggle */ next_flash = schedule_timer(450, flash_window_timer, hwnd); } } @@ -5825,7 +5825,7 @@ static void wintw_set_zorder(TermWin *tw, int top) */ static void wintw_refresh(TermWin *tw) { - InvalidateRect(hwnd, NULL, TRUE); + InvalidateRect(hwnd, NULL, true); } /* @@ -5887,10 +5887,10 @@ static const char *wintw_get_title(TermWin *tw, int icon) static int is_full_screen() { if (!IsZoomed(hwnd)) - return FALSE; + return false; if (GetWindowLongPtr(hwnd, GWL_STYLE) & WS_CAPTION) - return FALSE; - return TRUE; + return false; + return true; } /* Get the rect/size of a full screen window using the nearest available @@ -5907,7 +5907,7 @@ static int get_fullscreen_rect(RECT * ss) /* structure copy */ *ss = mi.rcMonitor; - return TRUE; + return true; #else /* could also use code like this: ss->left = ss->top = 0; @@ -6017,7 +6017,7 @@ static int win_seat_output(Seat *seat, int is_stderr, static int win_seat_eof(Seat *seat) { - return TRUE; /* do respond to incoming EOF with outgoing */ + return true; /* do respond to incoming EOF with outgoing */ } static int win_seat_get_userpass_input( diff --git a/windows/winhandl.c b/windows/winhandl.c index cfd62987..88c375cd 100644 --- a/windows/winhandl.c +++ b/windows/winhandl.c @@ -119,7 +119,7 @@ static DWORD WINAPI handle_input_threadfunc(void *param) if (ctx->flags & HANDLE_FLAG_OVERLAPPED) { povl = &ovl; - oev = CreateEvent(NULL, TRUE, FALSE, NULL); + oev = CreateEvent(NULL, true, false, NULL); } else { povl = NULL; } @@ -141,7 +141,7 @@ static DWORD WINAPI handle_input_threadfunc(void *param) ctx->readerr = 0; if (povl && !readret && ctx->readerr == ERROR_IO_PENDING) { WaitForSingleObject(povl->hEvent, INFINITE); - readret = GetOverlappedResult(ctx->h, povl, &ctx->len, FALSE); + readret = GetOverlappedResult(ctx->h, povl, &ctx->len, false); if (!readret) ctx->readerr = GetLastError(); else @@ -223,7 +223,7 @@ static void handle_throttle(struct handle_input *ctx, int backlog) */ if (backlog < MAX_BACKLOG) { SetEvent(ctx->ev_from_main); - ctx->busy = TRUE; + ctx->busy = true; } } @@ -288,7 +288,7 @@ static DWORD WINAPI handle_output_threadfunc(void *param) if (ctx->flags & HANDLE_FLAG_OVERLAPPED) { povl = &ovl; - oev = CreateEvent(NULL, TRUE, FALSE, NULL); + oev = CreateEvent(NULL, true, false, NULL); } else { povl = NULL; } @@ -318,7 +318,7 @@ static DWORD WINAPI handle_output_threadfunc(void *param) ctx->writeerr = 0; if (povl && !writeret && GetLastError() == ERROR_IO_PENDING) { writeret = GetOverlappedResult(ctx->h, povl, - &ctx->lenwritten, TRUE); + &ctx->lenwritten, true); if (!writeret) ctx->writeerr = GetLastError(); else @@ -354,7 +354,7 @@ static void handle_try_output(struct handle_output *ctx) ctx->buffer = senddata; ctx->len = sendlen; SetEvent(ctx->ev_from_main); - ctx->busy = TRUE; + ctx->busy = true; } else if (!ctx->busy && bufchain_size(&ctx->queued_data) == 0 && ctx->outgoingeof == EOF_PENDING) { CloseHandle(ctx->h); @@ -440,12 +440,12 @@ struct handle *handle_input_new(HANDLE handle, handle_inputfn_t gotdata, h->type = HT_INPUT; h->u.i.h = handle; - h->u.i.ev_to_main = CreateEvent(NULL, FALSE, FALSE, NULL); - h->u.i.ev_from_main = CreateEvent(NULL, FALSE, FALSE, NULL); + h->u.i.ev_to_main = CreateEvent(NULL, false, false, NULL); + h->u.i.ev_from_main = CreateEvent(NULL, false, false, NULL); h->u.i.gotdata = gotdata; - h->u.i.defunct = FALSE; - h->u.i.moribund = FALSE; - h->u.i.done = FALSE; + h->u.i.defunct = false; + h->u.i.moribund = false; + h->u.i.done = false; h->u.i.privdata = privdata; h->u.i.flags = flags; @@ -455,7 +455,7 @@ struct handle *handle_input_new(HANDLE handle, handle_inputfn_t gotdata, CreateThread(NULL, 0, handle_input_threadfunc, &h->u.i, 0, &in_threadid); - h->u.i.busy = TRUE; + h->u.i.busy = true; return h; } @@ -468,12 +468,12 @@ struct handle *handle_output_new(HANDLE handle, handle_outputfn_t sentdata, h->type = HT_OUTPUT; h->u.o.h = handle; - h->u.o.ev_to_main = CreateEvent(NULL, FALSE, FALSE, NULL); - h->u.o.ev_from_main = CreateEvent(NULL, FALSE, FALSE, NULL); - h->u.o.busy = FALSE; - h->u.o.defunct = FALSE; - h->u.o.moribund = FALSE; - h->u.o.done = FALSE; + h->u.o.ev_to_main = CreateEvent(NULL, false, false, NULL); + h->u.o.ev_from_main = CreateEvent(NULL, false, false, NULL); + h->u.o.busy = false; + h->u.o.defunct = false; + h->u.o.moribund = false; + h->u.o.done = false; h->u.o.privdata = privdata; bufchain_init(&h->u.o.queued_data); h->u.o.outgoingeof = EOF_NO; @@ -499,13 +499,13 @@ struct handle *handle_add_foreign_event(HANDLE event, h->u.f.h = INVALID_HANDLE_VALUE; h->u.f.ev_to_main = event; h->u.f.ev_from_main = INVALID_HANDLE_VALUE; - h->u.f.defunct = TRUE; /* we have no thread in the first place */ - h->u.f.moribund = FALSE; - h->u.f.done = FALSE; + h->u.f.defunct = true; /* we have no thread in the first place */ + h->u.f.moribund = false; + h->u.f.done = false; h->u.f.privdata = NULL; h->u.f.callback = callback; h->u.f.ctx = ctx; - h->u.f.busy = TRUE; + h->u.f.busy = true; if (!handles_by_evtomain) handles_by_evtomain = newtree234(handle_cmp_evtomain); @@ -592,7 +592,7 @@ void handle_free(struct handle *h) * we set the moribund flag, which will be noticed next time * an operation completes. */ - h->u.g.moribund = TRUE; + h->u.g.moribund = true; } else if (h->u.g.defunct) { /* * There isn't even a subthread; we can go straight to @@ -605,9 +605,9 @@ void handle_free(struct handle *h) * to die. Set the moribund flag to indicate that it will * want destroying after that. */ - h->u.g.moribund = TRUE; - h->u.g.done = TRUE; - h->u.g.busy = TRUE; + h->u.g.moribund = true; + h->u.g.done = true; + h->u.g.busy = true; SetEvent(h->u.g.ev_from_main); } } @@ -642,8 +642,8 @@ void handle_got_event(HANDLE event) if (h->u.g.done) { handle_destroy(h); } else { - h->u.g.done = TRUE; - h->u.g.busy = TRUE; + h->u.g.done = true; + h->u.g.busy = true; SetEvent(h->u.g.ev_from_main); } return; @@ -653,7 +653,7 @@ void handle_got_event(HANDLE event) int backlog; case HT_INPUT: - h->u.i.busy = FALSE; + h->u.i.busy = false; /* * A signal on an input handle means data has arrived. @@ -662,7 +662,7 @@ void handle_got_event(HANDLE event) /* * EOF, or (nearly equivalently) read error. */ - h->u.i.defunct = TRUE; + h->u.i.defunct = true; h->u.i.gotdata(h, NULL, -h->u.i.readerr); } else { backlog = h->u.i.gotdata(h, h->u.i.buffer, h->u.i.len); @@ -671,7 +671,7 @@ void handle_got_event(HANDLE event) break; case HT_OUTPUT: - h->u.o.busy = FALSE; + h->u.o.busy = false; /* * A signal on an output handle means we have completed a @@ -684,7 +684,7 @@ void handle_got_event(HANDLE event) * and mark the thread as defunct (because the output * thread is terminating by now). */ - h->u.o.defunct = TRUE; + h->u.o.defunct = true; h->u.o.sentdata(h, -h->u.o.writeerr); } else { bufchain_consume(&h->u.o.queued_data, h->u.o.lenwritten); diff --git a/windows/winhelp.c b/windows/winhelp.c index daf92ed9..03444236 100644 --- a/windows/winhelp.c +++ b/windows/winhelp.c @@ -42,10 +42,10 @@ void init_help(void) help_path = NULL; strcpy(r, PUTTY_HELP_CONTENTS); if ( (fp = fopen(b, "r")) != NULL) { - help_has_contents = TRUE; + help_has_contents = true; fclose(fp); } else - help_has_contents = FALSE; + help_has_contents = false; #ifndef NO_HTMLHELP strcpy(r, PUTTY_CHM_FILE); @@ -120,7 +120,7 @@ void launch_help(HWND hwnd, const char *topic) help_has_contents ? HELP_FINDER : HELP_CONTENTS, 0); } } - requested_help = TRUE; + requested_help = true; } void quit_help(HWND hwnd) @@ -134,6 +134,6 @@ void quit_help(HWND hwnd) if (help_path) { WinHelp(hwnd, help_path, HELP_QUIT, 0); } - requested_help = FALSE; + requested_help = false; } } diff --git a/windows/winhsock.c b/windows/winhsock.c index 27e1e0c5..fdc225b4 100644 --- a/windows/winhsock.c +++ b/windows/winhsock.c @@ -118,7 +118,7 @@ static void sk_handle_close(Socket *s) HandleSocket *hs = container_of(s, HandleSocket, sock); if (hs->defer_close) { - hs->deferred_close = TRUE; + hs->deferred_close = true; return; } @@ -185,10 +185,10 @@ static void handle_socket_unfreeze(void *hsv) * Hand it off to the plug. Be careful of re-entrance - that might * have the effect of trying to close this socket. */ - hs->defer_close = TRUE; + hs->defer_close = true; plug_receive(hs->plug, 0, data, len); bufchain_consume(&hs->inputdata, len); - hs->defer_close = FALSE; + hs->defer_close = false; if (hs->deferred_close) { sk_handle_close(&hs->sock); return; @@ -346,7 +346,7 @@ Socket *make_handle_socket(HANDLE send_H, HANDLE recv_H, HANDLE stderr_H, hs->stderr_h = handle_input_new(hs->stderr_H, handle_stderr, hs, flags); - hs->defer_close = hs->deferred_close = FALSE; + hs->defer_close = hs->deferred_close = false; return &hs->sock; } diff --git a/windows/winjump.c b/windows/winjump.c index e42ba275..dccdb93d 100644 --- a/windows/winjump.c +++ b/windows/winjump.c @@ -492,7 +492,7 @@ static void update_jumplist_from_registry(void) IObjectArray *array = NULL; IShellLink *link = NULL; IObjectArray *pRemoved = NULL; - int need_abort = FALSE; + int need_abort = false; /* * Create an ICustomDestinationList: the top-level object which @@ -513,7 +513,7 @@ static void update_jumplist_from_registry(void) if (!SUCCEEDED(pCDL->lpVtbl->BeginList(pCDL, &num_items, COMPTR(IObjectArray, &pRemoved)))) goto cleanup; - need_abort = TRUE; + need_abort = true; if (!SUCCEEDED(pRemoved->lpVtbl->GetCount(pRemoved, &nremoved))) nremoved = 0; @@ -543,7 +543,7 @@ static void update_jumplist_from_registry(void) /* * Check that the link isn't in the user-removed list. */ - for (i = 0, found = FALSE; i < nremoved && !found; i++) { + for (i = 0, found = false; i < nremoved && !found; i++) { IShellLink *rlink; if (SUCCEEDED(pRemoved->lpVtbl->GetAt (pRemoved, i, COMPTR(IShellLink, &rlink)))) { @@ -553,7 +553,7 @@ static void update_jumplist_from_registry(void) SUCCEEDED(rlink->lpVtbl->GetDescription (rlink, desc2, sizeof(desc2)-1)) && !strcmp(desc1, desc2)) { - found = TRUE; + found = true; } rlink->lpVtbl->Release(rlink); } @@ -656,7 +656,7 @@ static void update_jumplist_from_registry(void) * Commit the jump list. */ pCDL->lpVtbl->CommitList(pCDL); - need_abort = FALSE; + need_abort = false; /* * Clean up. @@ -738,12 +738,12 @@ BOOL set_explicit_app_user_model_id() { if (p_SetCurrentProcessExplicitAppUserModelID(L"SimonTatham.PuTTY") == S_OK) { - return TRUE; + return true; } - return FALSE; + return false; } /* Function doesn't exist, which is ok for Pre-7 systems */ - return TRUE; + return true; } diff --git a/windows/winmisc.c b/windows/winmisc.c index 4a53757e..6bdbedee 100644 --- a/windows/winmisc.c +++ b/windows/winmisc.c @@ -81,12 +81,12 @@ char *get_username(void) { DWORD namelen; char *user; - int got_username = FALSE; + int got_username = false; DECL_WINDOWS_FUNCTION(static, BOOLEAN, GetUserNameExA, (EXTENDED_NAME_FORMAT, LPSTR, PULONG)); { - static int tried_usernameex = FALSE; + static int tried_usernameex = false; if (!tried_usernameex) { /* Not available on Win9x, so load dynamically */ HMODULE secur32 = load_system32_dll("secur32.dll"); @@ -97,7 +97,7 @@ char *get_username(void) HMODULE sspicli = load_system32_dll("sspicli.dll"); (void)sspicli; /* squash compiler warning about unused variable */ GET_WINDOWS_FUNCTION(secur32, GetUserNameExA); - tried_usernameex = TRUE; + tried_usernameex = true; } } @@ -125,7 +125,7 @@ char *get_username(void) if (!got_username) { /* Fall back to local user name */ namelen = 0; - if (GetUserName(NULL, &namelen) == FALSE) { + if (GetUserName(NULL, &namelen) == false) { /* * Apparently this doesn't work at least on Windows XP SP2. * Thus assume a maximum of 256. It will fail again if it @@ -604,7 +604,7 @@ int open_for_write_would_lose_data(const Filename *fn) * let the subsequent attempt to open the file for real give a * more useful error message. */ - return FALSE; + return false; } if (attrs.dwFileAttributes & (FILE_ATTRIBUTE_DEVICE | FILE_ATTRIBUTE_DIRECTORY)) { @@ -613,7 +613,7 @@ int open_for_write_would_lose_data(const Filename *fn) * opening it for writing will not cause truncation. (It may * not _succeed_ either, but that's not our problem here!) */ - return FALSE; + return false; } if (attrs.nFileSizeHigh == 0 && attrs.nFileSizeLow == 0) { /* @@ -622,7 +622,7 @@ int open_for_write_would_lose_data(const Filename *fn) * opening it for writing won't truncate any data away because * there's nothing to truncate anyway. */ - return FALSE; + return false; } - return TRUE; + return true; } diff --git a/windows/winnet.c b/windows/winnet.c index e320397d..44092bbb 100644 --- a/windows/winnet.c +++ b/windows/winnet.c @@ -213,14 +213,14 @@ int sk_startup(int hi, int lo) winsock_ver = MAKEWORD(hi, lo); if (p_WSAStartup(winsock_ver, &wsadata)) { - return FALSE; + return false; } if (LOBYTE(wsadata.wVersion) != LOBYTE(winsock_ver)) { - return FALSE; + return false; } - return TRUE; + return true; } /* Actually define this function pointer, which won't have been @@ -524,9 +524,9 @@ SockAddr *sk_namelookup(const char *host, char **canonicalname, #ifndef NO_IPV6 ret->ais = NULL; #endif - ret->namedpipe = FALSE; + ret->namedpipe = false; ret->addresses = NULL; - ret->resolved = FALSE; + ret->resolved = false; ret->refcount = 1; *realhost = '\0'; @@ -549,7 +549,7 @@ SockAddr *sk_namelookup(const char *host, char **canonicalname, sfree(trimmed_host); } if (err == 0) - ret->resolved = TRUE; + ret->resolved = true; } else #endif { @@ -558,7 +558,7 @@ SockAddr *sk_namelookup(const char *host, char **canonicalname, * (NOTE: we don't use gethostbyname as a fallback!) */ if ( (h = p_gethostbyname(host)) ) - ret->resolved = TRUE; + ret->resolved = true; else err = p_WSAGetLastError(); } @@ -614,7 +614,7 @@ SockAddr *sk_namelookup(const char *host, char **canonicalname, ret->addresses = snewn(1, unsigned long); ret->naddresses = 1; ret->addresses[0] = p_ntohl(a); - ret->resolved = TRUE; + ret->resolved = true; strncpy(realhost, host, sizeof(realhost)); } realhost[lenof(realhost)-1] = '\0'; @@ -627,11 +627,11 @@ SockAddr *sk_nonamelookup(const char *host) { SockAddr *ret = snew(SockAddr); ret->error = NULL; - ret->resolved = FALSE; + ret->resolved = false; #ifndef NO_IPV6 ret->ais = NULL; #endif - ret->namedpipe = FALSE; + ret->namedpipe = false; ret->addresses = NULL; ret->naddresses = 0; ret->refcount = 1; @@ -644,11 +644,11 @@ SockAddr *sk_namedpipe_addr(const char *pipename) { SockAddr *ret = snew(SockAddr); ret->error = NULL; - ret->resolved = FALSE; + ret->resolved = false; #ifndef NO_IPV6 ret->ais = NULL; #endif - ret->namedpipe = TRUE; + ret->namedpipe = true; ret->addresses = NULL; ret->naddresses = 0; ret->refcount = 1; @@ -663,16 +663,16 @@ int sk_nextaddr(SockAddr *addr, SockAddrStep *step) if (step->ai) { if (step->ai->ai_next) { step->ai = step->ai->ai_next; - return TRUE; + return true; } else - return FALSE; + return false; } #endif if (step->curraddr+1 < addr->naddresses) { step->curraddr++; - return TRUE; + return true; } else { - return FALSE; + return false; } } @@ -741,7 +741,7 @@ static SockAddr sk_extractaddr_tmp( int sk_addr_needs_port(SockAddr *addr) { - return addr->namedpipe ? FALSE : TRUE; + return addr->namedpipe ? false : true; } int sk_hostname_is_local(const char *name) @@ -851,7 +851,7 @@ void sk_addrcopy(SockAddr *addr, char *buf) memcpy(buf, &((struct sockaddr_in6 *)step.ai->ai_addr)->sin6_addr, sizeof(struct in6_addr)); else - assert(FALSE); + assert(false); } else #endif if (family == AF_INET) { @@ -1015,17 +1015,17 @@ static DWORD try_connect(NetSocket *sock) SetHandleInformation((HANDLE)s, HANDLE_FLAG_INHERIT, 0); if (sock->oobinline) { - BOOL b = TRUE; + BOOL b = true; p_setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (void *) &b, sizeof(b)); } if (sock->nodelay) { - BOOL b = TRUE; + BOOL b = true; p_setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (void *) &b, sizeof(b)); } if (sock->keepalive) { - BOOL b = TRUE; + BOOL b = true; p_setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (void *) &b, sizeof(b)); } @@ -1470,7 +1470,7 @@ void try_send(NetSocket *s) * a small number - so we check that case and treat * it just like WSAEWOULDBLOCK.) */ - s->writable = FALSE; + s->writable = false; return; } else { /* diff --git a/windows/winnoise.c b/windows/winnoise.c index 1dd0481b..b2305d26 100644 --- a/windows/winnoise.c +++ b/windows/winnoise.c @@ -21,7 +21,7 @@ static HMODULE wincrypt_module = NULL; int win_read_random(void *buf, unsigned wanted) { - int toret = FALSE; + int toret = false; HCRYPTPROV crypt_provider; if (!wincrypt_module) { diff --git a/windows/winnpc.c b/windows/winnpc.c index 624757a4..f5bffbf7 100644 --- a/windows/winnpc.c +++ b/windows/winnpc.c @@ -80,7 +80,7 @@ Socket *new_named_pipe_client(const char *pipename, Plug *plug) LocalFree(psd); - return make_handle_socket(pipehandle, pipehandle, NULL, plug, TRUE); + return make_handle_socket(pipehandle, pipehandle, NULL, plug, true); } #endif /* !defined NO_SECURITY */ diff --git a/windows/winnps.c b/windows/winnps.c index 3e6904f3..5ea141fa 100644 --- a/windows/winnps.c +++ b/windows/winnps.c @@ -80,7 +80,7 @@ static int create_named_pipe(NamedPipeServerSocket *ps, int first_instance) memset(&sa, 0, sizeof(sa)); sa.nLength = sizeof(sa); sa.lpSecurityDescriptor = ps->psd; - sa.bInheritHandle = FALSE; + sa.bInheritHandle = false; ps->pipehandle = CreateNamedPipe (/* lpName */ @@ -117,7 +117,7 @@ static Socket *named_pipe_accept(accept_ctx_t ctx, Plug *plug) { HANDLE conn = (HANDLE)ctx.p; - return make_handle_socket(conn, conn, NULL, plug, TRUE); + return make_handle_socket(conn, conn, NULL, plug, true); } /* @@ -136,7 +136,7 @@ static void named_pipe_accept_loop(NamedPipeServerSocket *ps, if (got_one_already) { /* If we were called with a connection already waiting, * skip this step. */ - got_one_already = FALSE; + got_one_already = false; error = 0; } else { /* @@ -173,7 +173,7 @@ static void named_pipe_accept_loop(NamedPipeServerSocket *ps, CloseHandle(conn); } - if (!create_named_pipe(ps, FALSE)) { + if (!create_named_pipe(ps, false)) { error = GetLastError(); } else { /* @@ -196,7 +196,7 @@ static void named_pipe_accept_loop(NamedPipeServerSocket *ps, static void named_pipe_connect_callback(void *vps) { NamedPipeServerSocket *ps = (NamedPipeServerSocket *)vps; - named_pipe_accept_loop(ps, TRUE); + named_pipe_accept_loop(ps, true); } /* @@ -234,18 +234,18 @@ Socket *new_named_pipe_listener(const char *pipename, Plug *plug) goto cleanup; } - if (!create_named_pipe(ret, TRUE)) { + if (!create_named_pipe(ret, true)) { ret->error = dupprintf("unable to create named pipe '%s': %s", pipename, win_strerror(GetLastError())); goto cleanup; } memset(&ret->connect_ovl, 0, sizeof(ret->connect_ovl)); - ret->connect_ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + ret->connect_ovl.hEvent = CreateEvent(NULL, true, false, NULL); ret->callback_handle = handle_add_foreign_event(ret->connect_ovl.hEvent, named_pipe_connect_callback, ret); - named_pipe_accept_loop(ret, FALSE); + named_pipe_accept_loop(ret, false); cleanup: return &ret->sock; diff --git a/windows/winpgen.c b/windows/winpgen.c index 11b438dc..0c90838e 100644 --- a/windows/winpgen.c +++ b/windows/winpgen.c @@ -171,7 +171,7 @@ static INT_PTR CALLBACK PassphraseProc(HWND hwnd, UINT msg, MoveWindow(hwnd, (rs.right + rs.left + rd.left - rd.right) / 2, (rs.bottom + rs.top + rd.top - rd.bottom) / 2, - rd.right - rd.left, rd.bottom - rd.top, TRUE); + rd.right - rd.left, rd.bottom - rd.top, true); } p = (struct PassphraseProcStruct *) lParam; @@ -233,7 +233,7 @@ static int prompt_keyfile(HWND hwnd, char *dlgtitle, of.lpstrFileTitle = NULL; of.lpstrTitle = dlgtitle; of.Flags = 0; - return request_file(NULL, &of, FALSE, save); + return request_file(NULL, &of, false, save); } /* @@ -256,7 +256,7 @@ static INT_PTR CALLBACK LicenceProc(HWND hwnd, UINT msg, MoveWindow(hwnd, (rs.right + rs.left + rd.left - rd.right) / 2, (rs.bottom + rs.top + rd.top - rd.bottom) / 2, - rd.right - rd.left, rd.bottom - rd.top, TRUE); + rd.right - rd.left, rd.bottom - rd.top, true); } SetDlgItemText(hwnd, 1000, LICENCE_TEXT("\r\n\r\n")); @@ -296,7 +296,7 @@ static INT_PTR CALLBACK AboutProc(HWND hwnd, UINT msg, MoveWindow(hwnd, (rs.right + rs.left + rd.left - rd.right) / 2, (rs.bottom + rs.top + rd.top - rd.bottom) / 2, - rd.right - rd.left, rd.bottom - rd.top, TRUE); + rd.right - rd.left, rd.bottom - rd.top, true); } { @@ -493,9 +493,9 @@ void ui_set_state(HWND hwnd, struct MainDlgState *state, int status) switch (status) { case 0: /* no key */ - hidemany(hwnd, nokey_ids, FALSE); - hidemany(hwnd, generating_ids, TRUE); - hidemany(hwnd, gotkey_ids, TRUE); + hidemany(hwnd, nokey_ids, false); + hidemany(hwnd, generating_ids, true); + hidemany(hwnd, gotkey_ids, true); EnableWindow(GetDlgItem(hwnd, IDC_GENERATE), 1); EnableWindow(GetDlgItem(hwnd, IDC_LOAD), 1); EnableWindow(GetDlgItem(hwnd, IDC_SAVE), 0); @@ -526,9 +526,9 @@ void ui_set_state(HWND hwnd, struct MainDlgState *state, int status) MF_GRAYED|MF_BYCOMMAND); break; case 1: /* generating key */ - hidemany(hwnd, nokey_ids, TRUE); - hidemany(hwnd, generating_ids, FALSE); - hidemany(hwnd, gotkey_ids, TRUE); + hidemany(hwnd, nokey_ids, true); + hidemany(hwnd, generating_ids, false); + hidemany(hwnd, gotkey_ids, true); EnableWindow(GetDlgItem(hwnd, IDC_GENERATE), 0); EnableWindow(GetDlgItem(hwnd, IDC_LOAD), 0); EnableWindow(GetDlgItem(hwnd, IDC_SAVE), 0); @@ -559,9 +559,9 @@ void ui_set_state(HWND hwnd, struct MainDlgState *state, int status) MF_GRAYED|MF_BYCOMMAND); break; case 2: - hidemany(hwnd, nokey_ids, TRUE); - hidemany(hwnd, generating_ids, TRUE); - hidemany(hwnd, gotkey_ids, FALSE); + hidemany(hwnd, nokey_ids, true); + hidemany(hwnd, generating_ids, true); + hidemany(hwnd, gotkey_ids, false); EnableWindow(GetDlgItem(hwnd, IDC_GENERATE), 1); EnableWindow(GetDlgItem(hwnd, IDC_LOAD), 1); EnableWindow(GetDlgItem(hwnd, IDC_SAVE), 1); @@ -739,7 +739,7 @@ void load_key_file(HWND hwnd, struct MainDlgState *state, if (type == SSH_KEYTYPE_SSH1) { char *fingerprint, *savecomment; - state->ssh2 = FALSE; + state->ssh2 = false; state->commentptr = &state->key.comment; state->key = newkey1; @@ -764,7 +764,7 @@ void load_key_file(HWND hwnd, struct MainDlgState *state, char *fp; char *savecomment; - state->ssh2 = TRUE; + state->ssh2 = true; state->commentptr = &state->ssh2key.comment; state->ssh2key = *newkey2; /* structure copy */ @@ -789,7 +789,7 @@ void load_key_file(HWND hwnd, struct MainDlgState *state, * the key data. */ ui_set_state(hwnd, state, 2); - state->key_exists = TRUE; + state->key_exists = true; /* * If the user has imported a foreign key @@ -841,7 +841,7 @@ static void start_generating_key(HWND hwnd, struct MainDlgState *state) MB_OK | MB_ICONERROR); sfree(params); } else { - state->generation_thread_exists = TRUE; + state->generation_thread_exists = true; } } @@ -871,10 +871,10 @@ static INT_PTR CALLBACK MainDlgProc(HWND hwnd, UINT msg, (LPARAM) LoadIcon(hinst, MAKEINTRESOURCE(200))); state = snew(struct MainDlgState); - state->generation_thread_exists = FALSE; - state->collecting_entropy = FALSE; + state->generation_thread_exists = false; + state->collecting_entropy = false; state->entropy = NULL; - state->key_exists = FALSE; + state->key_exists = false; SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR) state); { HMENU menu, menu1; @@ -935,7 +935,7 @@ static INT_PTR CALLBACK MainDlgProc(HWND hwnd, UINT msg, MoveWindow(hwnd, (rs.right + rs.left + rd.left - rd.right) / 2, (rs.bottom + rs.top + rd.top - rd.bottom) / 2, - rd.right - rd.left, rd.bottom - rd.top, TRUE); + rd.right - rd.left, rd.bottom - rd.top, true); } { @@ -1012,7 +1012,7 @@ static INT_PTR CALLBACK MainDlgProc(HWND hwnd, UINT msg, endbox(&cp); } ui_set_key_type(hwnd, state, IDC_KEYSSH2RSA); - SetDlgItemInt(hwnd, IDC_BITS, DEFAULT_KEY_BITS, FALSE); + SetDlgItemInt(hwnd, IDC_BITS, DEFAULT_KEY_BITS, false); SendDlgItemMessage(hwnd, IDC_CURVE, CB_SETCURSEL, DEFAULT_CURVE_INDEX, 0); @@ -1049,7 +1049,7 @@ static INT_PTR CALLBACK MainDlgProc(HWND hwnd, UINT msg, random_add_heavynoise(state->entropy, state->entropy_size); smemclr(state->entropy, state->entropy_size); sfree(state->entropy); - state->collecting_entropy = FALSE; + state->collecting_entropy = false; start_generating_key(hwnd, state); } @@ -1114,7 +1114,7 @@ static INT_PTR CALLBACK MainDlgProc(HWND hwnd, UINT msg, unsigned raw_entropy_required; unsigned char *raw_entropy_buf; BOOL ok; - state->key_bits = GetDlgItemInt(hwnd, IDC_BITS, &ok, FALSE); + state->key_bits = GetDlgItemInt(hwnd, IDC_BITS, &ok, false); if (!ok) state->key_bits = DEFAULT_KEY_BITS; { @@ -1147,7 +1147,7 @@ static INT_PTR CALLBACK MainDlgProc(HWND hwnd, UINT msg, if (ret != IDOK) break; state->key_bits = DEFAULT_KEY_BITS; - SetDlgItemInt(hwnd, IDC_BITS, DEFAULT_KEY_BITS, FALSE); + SetDlgItemInt(hwnd, IDC_BITS, DEFAULT_KEY_BITS, false); } else if ((state->keytype == RSA || state->keytype == DSA) && state->key_bits < DEFAULT_KEY_BITS) { char *message = dupprintf @@ -1201,8 +1201,8 @@ static INT_PTR CALLBACK MainDlgProc(HWND hwnd, UINT msg, ui_set_state(hwnd, state, 1); SetDlgItemText(hwnd, IDC_GENERATING, entropy_msg); - state->key_exists = FALSE; - state->collecting_entropy = TRUE; + state->key_exists = false; + state->collecting_entropy = true; state->entropy_got = 0; state->entropy_size = (state->entropy_required * @@ -1392,8 +1392,8 @@ static INT_PTR CALLBACK MainDlgProc(HWND hwnd, UINT msg, return 0; case WM_DONEKEY: state = (struct MainDlgState *) GetWindowLongPtr(hwnd, GWLP_USERDATA); - state->generation_thread_exists = FALSE; - state->key_exists = TRUE; + state->generation_thread_exists = false; + state->key_exists = true; SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETRANGE, 0, MAKELPARAM(0, PROGRESSRANGE)); SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETPOS, PROGRESSRANGE, 0); diff --git a/windows/winpgnt.c b/windows/winpgnt.c index b5e9fcbb..bae72174 100644 --- a/windows/winpgnt.c +++ b/windows/winpgnt.c @@ -58,7 +58,7 @@ static HMENU systray_menu, session_menu; static int already_running; static char *putty_path; -static int restrict_putty_acl = FALSE; +static int restrict_putty_acl = false; /* CWD for "add key" file requester. */ static filereq *keypath = NULL; @@ -222,7 +222,7 @@ static INT_PTR CALLBACK PassphraseProc(HWND hwnd, UINT msg, MoveWindow(hwnd, (rs.right + rs.left + rd.left - rd.right) / 2, (rs.bottom + rs.top + rd.top - rd.bottom) / 2, - rd.right - rd.left, rd.bottom - rd.top, TRUE); + rd.right - rd.left, rd.bottom - rd.top, true); } SetForegroundWindow(hwnd); @@ -467,7 +467,7 @@ static void prompt_add_keyfile(void) of.lpstrFileTitle = NULL; of.lpstrTitle = "Select Private Key File"; of.Flags = OFN_ALLOWMULTISELECT | OFN_EXPLORER; - if (request_file(keypath, &of, TRUE, FALSE)) { + if (request_file(keypath, &of, true, false)) { if(strlen(filelist) > of.nFileOffset) { /* Only one filename returned? */ Filename *fn = filename_from_str(filelist); @@ -520,7 +520,7 @@ static INT_PTR CALLBACK KeyListProc(HWND hwnd, UINT msg, MoveWindow(hwnd, (rs.right + rs.left + rd.left - rd.right) / 2, (rs.bottom + rs.top + rd.top - rd.bottom) / 2, - rd.right - rd.left, rd.bottom - rd.top, TRUE); + rd.right - rd.left, rd.bottom - rd.top, true); } if (has_help()) @@ -715,7 +715,7 @@ static void update_sessions(void) mii.fState = MFS_ENABLED; mii.wID = (index_menu * 16) + IDM_SESSIONS_BASE; mii.dwTypeData = session_name; - InsertMenuItem(session_menu, index_menu, TRUE, &mii); + InsertMenuItem(session_menu, index_menu, true, &mii); index_menu++; } index_key++; @@ -729,7 +729,7 @@ static void update_sessions(void) mii.fType = MFT_STRING; mii.fState = MFS_GRAYED; mii.dwTypeData = _T("(No sessions)"); - InsertMenuItem(session_menu, index_menu, TRUE, &mii); + InsertMenuItem(session_menu, index_menu, true, &mii); } } @@ -748,7 +748,7 @@ PSID get_default_sid(void) PSECURITY_DESCRIPTOR psd = NULL; PSID sid = NULL, copy = NULL, ret = NULL; - if ((proc = OpenProcess(MAXIMUM_ALLOWED, FALSE, + if ((proc = OpenProcess(MAXIMUM_ALLOWED, false, GetCurrentProcessId())) == NULL) goto cleanup; @@ -795,7 +795,7 @@ static void pageant_reply_BinarySink_write( memcpy(rep->buf + rep->len, data, len); rep->len += len; } else { - rep->overflowed = TRUE; + rep->overflowed = true; } } @@ -821,7 +821,7 @@ static char *answer_filemapping_message(const char *mapname) debug(("mapname = \"%s\"\n", mapname)); #endif - maphandle = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, mapname); + maphandle = OpenFileMapping(FILE_MAP_ALL_ACCESS, false, mapname); if (maphandle == NULL || maphandle == INVALID_HANDLE_VALUE) { err = dupprintf("OpenFileMapping(\"%s\"): %s", mapname, win_strerror(GetLastError())); @@ -928,7 +928,7 @@ static char *answer_filemapping_message(const char *mapname) reply.buf = (char *)mapaddr + 4; reply.size = mapsize - 4; reply.len = 0; - reply.overflowed = FALSE; + reply.overflowed = false; BinarySink_INIT(&reply, pageant_reply_BinarySink_write); if (msglen > mapsize - 4) { @@ -939,7 +939,7 @@ static char *answer_filemapping_message(const char *mapname) (unsigned char *)mapaddr + 4, msglen, NULL, NULL); if (reply.overflowed) { reply.len = 0; - reply.overflowed = FALSE; + reply.overflowed = false; pageant_failure_msg(BinarySink_UPCAST(&reply), "output would overflow message buffer", NULL, NULL); @@ -993,7 +993,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, PostMessage(hwnd, WM_SYSTRAY2, cursorpos.x, cursorpos.y); } else if (lParam == WM_LBUTTONDBLCLK) { /* Run the default menu item. */ - UINT menuitem = GetMenuDefaultItem(systray_menu, FALSE, 0); + UINT menuitem = GetMenuDefaultItem(systray_menu, false, 0); if (menuitem != -1) PostMessage(hwnd, WM_COMMAND, menuitem, 0); } @@ -1085,7 +1085,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, mii.fMask = MIIM_TYPE; mii.cch = MAX_PATH; mii.dwTypeData = buf; - GetMenuItemInfo(session_menu, wParam, FALSE, &mii); + GetMenuItemInfo(session_menu, wParam, false, &mii); param[0] = '\0'; if (restrict_putty_acl) strcat(param, "&R"); @@ -1258,7 +1258,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) restrict_process_acl(); } else if (!strcmp(argv[i], "-restrict-putty-acl") || !strcmp(argv[i], "-restrict_putty_acl")) { - restrict_putty_acl = TRUE; + restrict_putty_acl = true; } else if (!strcmp(argv[i], "-c")) { /* * If we see `-c', then the rest of the @@ -1274,7 +1274,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) Filename *fn = filename_from_str(argv[i]); win_add_keyfile(fn); filename_free(fn); - added_keys = TRUE; + added_keys = true; } } @@ -1356,7 +1356,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) initial_menuitems_count = GetMenuItemCount(session_menu); /* Set the default menu item. */ - SetMenuDefaultItem(systray_menu, IDM_VIEWKEYS, FALSE); + SetMenuDefaultItem(systray_menu, IDM_VIEWKEYS, false); ShowWindow(hwnd, SW_HIDE); diff --git a/windows/winpgntc.c b/windows/winpgntc.c index c6607715..d079c9b9 100644 --- a/windows/winpgntc.c +++ b/windows/winpgntc.c @@ -20,9 +20,9 @@ int agent_exists(void) HWND hwnd; hwnd = FindWindow("Pageant", "Pageant"); if (!hwnd) - return FALSE; + return false; else - return TRUE; + return true; } void agent_cancel_query(agent_pending_query *q) @@ -75,9 +75,9 @@ agent_pending_query *agent_query( if (psd) { if (p_InitializeSecurityDescriptor (psd, SECURITY_DESCRIPTOR_REVISION) && - p_SetSecurityDescriptorOwner(psd, usersid, FALSE)) { + p_SetSecurityDescriptorOwner(psd, usersid, false)) { sa.nLength = sizeof(sa); - sa.bInheritHandle = TRUE; + sa.bInheritHandle = true; sa.lpSecurityDescriptor = psd; psa = &sa; } else { diff --git a/windows/winplink.c b/windows/winplink.c index d2a7b80e..b777443a 100644 --- a/windows/winplink.c +++ b/windows/winplink.c @@ -42,7 +42,7 @@ static Conf *conf; int term_ldisc(Terminal *term, int mode) { - return FALSE; + return false; } static void plink_echoedit_update(Seat *seat, int echo, int edit) { @@ -75,7 +75,7 @@ static int plink_output(Seat *seat, int is_stderr, const void *data, int len) static int plink_eof(Seat *seat) { handle_write_eof(stdout_handle); - return FALSE; /* do not respond to incoming EOF with outgoing */ + return false; /* do not respond to incoming EOF with outgoing */ } static int plink_get_userpass_input(Seat *seat, prompts_t *p, bufchain *input) @@ -254,8 +254,8 @@ void stdouterr_sent(struct handle *h, int new_backlog) } } -const int share_can_be_downstream = TRUE; -const int share_can_be_upstream = TRUE; +const int share_can_be_downstream = true; +const int share_can_be_upstream = true; int main(int argc, char **argv) { @@ -265,7 +265,7 @@ int main(int argc, char **argv) int exitcode; int errors; int use_subsystem = 0; - int just_test_share_exists = FALSE; + int just_test_share_exists = false; unsigned long now, next, then; const struct BackendVtable *vt; @@ -292,7 +292,7 @@ int main(int argc, char **argv) */ conf = conf_new(); do_defaults(NULL, conf); - loaded_session = FALSE; + loaded_session = false; default_protocol = conf_get_int(conf, CONF_protocol); default_port = conf_get_int(conf, CONF_port); errors = 0; @@ -336,7 +336,7 @@ int main(int argc, char **argv) pgp_fingerprints(); exit(1); } else if (!strcmp(p, "-shareexists")) { - just_test_share_exists = TRUE; + just_test_share_exists = true; } else if (*p != '-') { char *command; int cmdlen, cmdsize; @@ -362,7 +362,7 @@ int main(int argc, char **argv) /* change trailing blank to NUL */ conf_set_str(conf, CONF_remote_cmd, command); conf_set_str(conf, CONF_remote_cmd2, ""); - conf_set_int(conf, CONF_nopty, TRUE); /* command => no tty */ + conf_set_int(conf, CONF_nopty, true); /* command => no tty */ break; /* done with cmdline */ } else { @@ -389,7 +389,7 @@ int main(int argc, char **argv) * Apply subsystem status. */ if (use_subsystem) - conf_set_int(conf, CONF_ssh_subsys, TRUE); + conf_set_int(conf, CONF_ssh_subsys, true); if (!*conf_get_str(conf, CONF_remote_cmd) && !*conf_get_str(conf, CONF_remote_cmd2) && @@ -422,7 +422,7 @@ int main(int argc, char **argv) !conf_get_int(conf, CONF_x11_forward) && !conf_get_int(conf, CONF_agentfwd) && !conf_get_str_nthstrkey(conf, CONF_portfwd, 0)) - conf_set_int(conf, CONF_ssh_simple, TRUE); + conf_set_int(conf, CONF_ssh_simple, true); logctx = log_init(default_logpolicy, conf); @@ -446,7 +446,7 @@ int main(int argc, char **argv) /* * Start up the connection. */ - netevent = CreateEvent(NULL, FALSE, FALSE, NULL); + netevent = CreateEvent(NULL, false, false, NULL); { const char *error; char *realhost; @@ -488,7 +488,7 @@ int main(int argc, char **argv) main_thread_id = GetCurrentThreadId(); - sending = FALSE; + sending = false; now = GETTICKCOUNT(); @@ -501,7 +501,7 @@ int main(int argc, char **argv) if (!sending && backend_sendok(backend)) { stdin_handle = handle_input_new(inhandle, stdin_gotdata, NULL, 0); - sending = TRUE; + sending = true; } if (toplevel_callback_pending()) { @@ -523,7 +523,7 @@ int main(int argc, char **argv) handles = handle_get_events(&nhandles); handles = sresize(handles, nhandles+1, HANDLE); handles[nhandles] = netevent; - n = MsgWaitForMultipleObjects(nhandles+1, handles, FALSE, ticks, + n = MsgWaitForMultipleObjects(nhandles+1, handles, false, ticks, QS_POSTMESSAGE); if ((unsigned)(n - WAIT_OBJECT_0) < (unsigned)nhandles) { handle_got_event(handles[n - WAIT_OBJECT_0]); diff --git a/windows/winprint.c b/windows/winprint.c index 083f6e1c..cb9184ba 100644 --- a/windows/winprint.c +++ b/windows/winprint.c @@ -32,7 +32,7 @@ DECL_WINDOWS_FUNCTION(static, BOOL, WritePrinter, static void init_winfuncs(void) { - static int initialised = FALSE; + static int initialised = false; if (initialised) return; { @@ -53,7 +53,7 @@ static void init_winfuncs(void) GET_WINDOWS_FUNCTION_PP(winspool_module, EndPagePrinter); GET_WINDOWS_FUNCTION_PP(winspool_module, WritePrinter); } - initialised = TRUE; + initialised = true; } static int printer_add_enum(int param, DWORD level, char **buffer, @@ -80,11 +80,11 @@ static int printer_add_enum(int param, DWORD level, char **buffer, if (p_EnumPrinters(param, NULL, level, (LPBYTE)((*buffer)+offset), needed, &needed, &nprinters) == 0) - return FALSE; + return false; *nprinters_ptr += nprinters; - return TRUE; + return true; } printer_enum *printer_start_enum(int *nprinters_ptr) diff --git a/windows/winproxy.c b/windows/winproxy.c index d0a8884b..c83e2b4f 100644 --- a/windows/winproxy.c +++ b/windows/winproxy.c @@ -48,7 +48,7 @@ Socket *platform_new_connection(SockAddr *addr, const char *hostname, */ sa.nLength = sizeof(sa); sa.lpSecurityDescriptor = NULL; /* default */ - sa.bInheritHandle = TRUE; + sa.bInheritHandle = true; if (!CreatePipe(&us_from_cmd, &cmd_to_us, &sa, 0)) { sfree(cmd); return new_error_socket_fmt( @@ -91,7 +91,7 @@ Socket *platform_new_connection(SockAddr *addr, const char *hostname, si.hStdInput = cmd_from_us; si.hStdOutput = cmd_to_us; si.hStdError = cmd_err_to_us; - CreateProcess(NULL, cmd, NULL, NULL, TRUE, + CreateProcess(NULL, cmd, NULL, NULL, true, CREATE_NO_WINDOW | NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi); CloseHandle(pi.hProcess); @@ -106,5 +106,5 @@ Socket *platform_new_connection(SockAddr *addr, const char *hostname, CloseHandle(cmd_err_to_us); return make_handle_socket(us_to_cmd, us_from_cmd, us_from_cmd_err, - plug, FALSE); + plug, false); } diff --git a/windows/winsecur.c b/windows/winsecur.c index 76dcae91..656c327a 100644 --- a/windows/winsecur.c +++ b/windows/winsecur.c @@ -18,12 +18,12 @@ static PSID worldsid, networksid, usersid; int got_advapi(void) { - static int attempted = FALSE; + static int attempted = false; static int successful; static HMODULE advapi; if (!attempted) { - attempted = TRUE; + attempted = true; advapi = load_system32_dll("advapi32.dll"); successful = advapi && GET_WINDOWS_FUNCTION(advapi, GetSecurityInfo) && @@ -50,7 +50,7 @@ PSID get_user_sid(void) if (!got_advapi()) goto cleanup; - if ((proc = OpenProcess(MAXIMUM_ALLOWED, FALSE, + if ((proc = OpenProcess(MAXIMUM_ALLOWED, false, GetCurrentProcessId())) == NULL) goto cleanup; @@ -104,7 +104,7 @@ int getsids(char **error) #pragma clang diagnostic pop #endif - int ret = FALSE; + int ret = false; *error = NULL; @@ -135,7 +135,7 @@ int getsids(char **error) } } - ret = TRUE; + ret = true; cleanup: return ret; @@ -149,7 +149,7 @@ int make_private_security_descriptor(DWORD permissions, { EXPLICIT_ACCESS ea[3]; int acl_err; - int ret = FALSE; + int ret = false; *psd = NULL; @@ -197,19 +197,19 @@ int make_private_security_descriptor(DWORD permissions, goto cleanup; } - if (!SetSecurityDescriptorOwner(*psd, usersid, FALSE)) { + if (!SetSecurityDescriptorOwner(*psd, usersid, false)) { *error = dupprintf("unable to set owner in security descriptor: %s", win_strerror(GetLastError())); goto cleanup; } - if (!SetSecurityDescriptorDacl(*psd, TRUE, *acl, FALSE)) { + if (!SetSecurityDescriptorDacl(*psd, true, *acl, false)) { *error = dupprintf("unable to set DACL in security descriptor: %s", win_strerror(GetLastError())); goto cleanup; } - ret = TRUE; + ret = true; cleanup: if (!ret) { @@ -232,7 +232,7 @@ static int really_restrict_process_acl(char **error) { EXPLICIT_ACCESS ea[2]; int acl_err; - int ret=FALSE; + int ret=false; PACL acl = NULL; static const DWORD nastyace=WRITE_DAC | WRITE_OWNER | @@ -279,7 +279,7 @@ static int really_restrict_process_acl(char **error) } - ret=TRUE; + ret=true; cleanup: if (!ret) { @@ -317,7 +317,7 @@ void restrict_process_acl(void) #if !defined NO_SECURITY ret = really_restrict_process_acl(&error); #else - ret = FALSE; + ret = false; error = dupstr("ACL restrictions not compiled into this binary"); #endif if (!ret) diff --git a/windows/winsecur.h b/windows/winsecur.h index a56f7fb8..dd4da9ee 100644 --- a/windows/winsecur.h +++ b/windows/winsecur.h @@ -46,9 +46,9 @@ PSID get_user_sid(void); * servers, i.e. allowing access only to the current user id and also * only local (i.e. not over SMB) connections. * - * If this function returns TRUE, then 'psd' and 'acl' will have been + * If this function returns true, then 'psd' and 'acl' will have been * filled in with memory allocated using LocalAlloc (and hence must be - * freed later using LocalFree). If it returns FALSE, then instead + * freed later using LocalFree). If it returns false, then instead * 'error' has been filled with a dynamically allocated error message. */ int make_private_security_descriptor(DWORD permissions, diff --git a/windows/winser.c b/windows/winser.c index 3fba2989..d848c20c 100644 --- a/windows/winser.c +++ b/windows/winser.c @@ -107,18 +107,18 @@ static const char *serial_configure(Serial *serial, HANDLE serport, Conf *conf) /* * Boilerplate. */ - dcb.fBinary = TRUE; + dcb.fBinary = true; dcb.fDtrControl = DTR_CONTROL_ENABLE; - dcb.fDsrSensitivity = FALSE; - dcb.fTXContinueOnXoff = FALSE; - dcb.fOutX = FALSE; - dcb.fInX = FALSE; - dcb.fErrorChar = FALSE; - dcb.fNull = FALSE; + dcb.fDsrSensitivity = false; + dcb.fTXContinueOnXoff = false; + dcb.fOutX = false; + dcb.fInX = false; + dcb.fErrorChar = false; + dcb.fNull = false; dcb.fRtsControl = RTS_CONTROL_ENABLE; - dcb.fAbortOnError = FALSE; - dcb.fOutxCtsFlow = FALSE; - dcb.fOutxDsrFlow = FALSE; + dcb.fAbortOnError = false; + dcb.fOutxCtsFlow = false; + dcb.fOutxDsrFlow = false; /* * Configurable parameters. @@ -151,17 +151,17 @@ static const char *serial_configure(Serial *serial, HANDLE serport, Conf *conf) str = "no"; break; case SER_FLOW_XONXOFF: - dcb.fOutX = dcb.fInX = TRUE; + dcb.fOutX = dcb.fInX = true; str = "XON/XOFF"; break; case SER_FLOW_RTSCTS: dcb.fRtsControl = RTS_CONTROL_HANDSHAKE; - dcb.fOutxCtsFlow = TRUE; + dcb.fOutxCtsFlow = true; str = "RTS/CTS"; break; case SER_FLOW_DSRDTR: dcb.fDtrControl = DTR_CONTROL_HANDSHAKE; - dcb.fOutxDsrFlow = TRUE; + dcb.fOutxDsrFlow = true; str = "DSR/DTR"; break; } @@ -204,7 +204,7 @@ static const char *serial_init(Seat *seat, Backend **backend_handle, serial->port = INVALID_HANDLE_VALUE; serial->out = serial->in = NULL; serial->bufsize = 0; - serial->break_in_progress = FALSE; + serial->break_in_progress = false; serial->backend.vt = &serial_backend; *backend_handle = &serial->backend; @@ -329,7 +329,7 @@ static void serbreak_timer(void *ctx, unsigned long now) if (now == serial->clearbreak_time && serial->port) { ClearCommBreak(serial->port); - serial->break_in_progress = FALSE; + serial->break_in_progress = false; logevent(serial->logctx, "Finished serial break"); } } @@ -356,7 +356,7 @@ static void serial_special(Backend *be, SessionSpecialCode code, int arg) */ serial->clearbreak_time = schedule_timer(TICKSPERSEC * 2 / 5, serbreak_timer, serial); - serial->break_in_progress = TRUE; + serial->break_in_progress = true; } return; diff --git a/windows/winsftp.c b/windows/winsftp.c index 06531529..c85c6c8f 100644 --- a/windows/winsftp.c +++ b/windows/winsftp.c @@ -25,7 +25,7 @@ void platform_get_x11_auth(struct X11Display *display, Conf *conf) { /* Do nothing, therefore no auth. */ } -const int platform_uses_x11_unix_by_default = TRUE; +const int platform_uses_x11_unix_by_default = true; /* ---------------------------------------------------------------------- * File access abstraction. @@ -440,12 +440,12 @@ void finish_wildcard_matching(WildcardMatcher *dir) int vet_filename(const char *name) { if (strchr(name, '/') || strchr(name, '\\') || strchr(name, ':')) - return FALSE; + return false; if (!name[strspn(name, ".")]) /* entirely composed of dots */ - return FALSE; + return false; - return TRUE; + return true; } int create_directory(const char *name) @@ -479,7 +479,7 @@ char *do_select(SOCKET skt, int startup) if (startup) { events = (FD_CONNECT | FD_READ | FD_WRITE | FD_OOB | FD_CLOSE | FD_ACCEPT); - netevent = CreateEvent(NULL, FALSE, FALSE, NULL); + netevent = CreateEvent(NULL, false, false, NULL); } else { events = 0; } @@ -534,7 +534,7 @@ int do_eventsel_loop(HANDLE other_event) else otherindex = -1; - n = WaitForMultipleObjects(nallhandles, handles, FALSE, ticks); + n = WaitForMultipleObjects(nallhandles, handles, false, ticks); if ((unsigned)(n - WAIT_OBJECT_0) < (unsigned)nhandles) { handle_got_event(handles[n - WAIT_OBJECT_0]); @@ -721,7 +721,7 @@ char *ssh_sftp_get_cmdline(const char *prompt, int no_fds_ok) * Create a second thread to read from stdin. Process network * and timing events until it terminates. */ - ctx->event = CreateEvent(NULL, FALSE, FALSE, NULL); + ctx->event = CreateEvent(NULL, false, false, NULL); ctx->line = NULL; hThread = CreateThread(NULL, 0, command_read_thread, ctx, 0, &threadid); diff --git a/windows/winshare.c b/windows/winshare.c index af4bc974..864dd9c6 100644 --- a/windows/winshare.c +++ b/windows/winshare.c @@ -161,9 +161,9 @@ int platform_ssh_share(const char *pi_name, Conf *conf, memset(&sa, 0, sizeof(sa)); sa.nLength = sizeof(sa); sa.lpSecurityDescriptor = psd; - sa.bInheritHandle = FALSE; + sa.bInheritHandle = false; - mutex = CreateMutex(&sa, FALSE, mutexname); + mutex = CreateMutex(&sa, false, mutexname); if (!mutex) { *logtext = dupprintf("CreateMutex(\"%s\") failed: %s", diff --git a/windows/winstore.c b/windows/winstore.c index 7c4be074..52f9b337 100644 --- a/windows/winstore.c +++ b/windows/winstore.c @@ -24,7 +24,7 @@ static const char *const puttystr = PUTTY_REG_POS "\\Sessions"; static const char hex[16] = "0123456789ABCDEF"; -static int tried_shgetfolderpath = FALSE; +static int tried_shgetfolderpath = false; static HMODULE shell32_module = NULL; DECL_WINDOWS_FUNCTION(static, HRESULT, SHGetFolderPathA, (HWND, int, HANDLE, DWORD, LPSTR)); @@ -511,7 +511,7 @@ static int try_random_seed(char const *path, int action, HANDLE *ret) win_strerror(GetLastError())); } *ret = INVALID_HANDLE_VALUE; - return FALSE; /* so we'll do the next ones too */ + return false; /* so we'll do the next ones too */ } *ret = CreateFile(path, @@ -576,7 +576,7 @@ static HANDLE access_random_seed(int action) * so stuff that. */ shell32_module = load_system32_dll("shell32.dll"); GET_WINDOWS_FUNCTION(shell32_module, SHGetFolderPathA); - tried_shgetfolderpath = TRUE; + tried_shgetfolderpath = true; } if (p_SHGetFolderPathA) { if (SUCCEEDED(p_SHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, diff --git a/windows/winstuff.h b/windows/winstuff.h index 0a55be89..d71663c3 100644 --- a/windows/winstuff.h +++ b/windows/winstuff.h @@ -622,7 +622,7 @@ BOOL set_explicit_app_user_model_id(); /* * Exports from winnoise.c. */ -int win_read_random(void *buf, unsigned wanted); /* returns TRUE on success */ +int win_read_random(void *buf, unsigned wanted); /* returns true on success */ /* * Extra functions in winstore.c over and above the interface in @@ -654,7 +654,7 @@ char *get_jumplist_registry_entries(void); #define CLIPNAME_EXPLICIT "System clipboard" #define CLIPNAME_EXPLICIT_OBJECT "system clipboard" /* These defaults are the ones PuTTY has historically had */ -#define CLIPUI_DEFAULT_AUTOCOPY TRUE +#define CLIPUI_DEFAULT_AUTOCOPY true #define CLIPUI_DEFAULT_MOUSE CLIPUI_EXPLICIT #define CLIPUI_DEFAULT_INS CLIPUI_EXPLICIT diff --git a/windows/winx11.c b/windows/winx11.c index b8c7fa7d..eb15b39a 100644 --- a/windows/winx11.c +++ b/windows/winx11.c @@ -16,4 +16,4 @@ void platform_get_x11_auth(struct X11Display *disp, Conf *conf) x11_get_auth_from_authfile(disp, xauthpath); } -const int platform_uses_x11_unix_by_default = FALSE; +const int platform_uses_x11_unix_by_default = false; diff --git a/x11fwd.c b/x11fwd.c index 287003fd..4f1bb45c 100644 --- a/x11fwd.c +++ b/x11fwd.c @@ -209,7 +209,7 @@ struct X11Display *x11_setup_display(const char *display, Conf *conf, */ if (localcopy[0] == '/') { disp->unixsocketpath = localcopy; - disp->unixdomain = TRUE; + disp->unixdomain = true; disp->hostname = NULL; disp->displaynum = -1; disp->screennum = 0; @@ -258,7 +258,7 @@ struct X11Display *x11_setup_display(const char *display, Conf *conf, else if (!*hostname || !strcmp(hostname, "unix")) disp->unixdomain = platform_uses_x11_unix_by_default; else - disp->unixdomain = FALSE; + disp->unixdomain = false; if (!disp->hostname && !disp->unixdomain) disp->hostname = dupstr("localhost"); @@ -310,7 +310,7 @@ struct X11Display *x11_setup_display(const char *display, Conf *conf, sk_addr_free(ux); } else { sk_addr_free(disp->addr); - disp->unixdomain = TRUE; + disp->unixdomain = true; disp->addr = ux; /* Fill in the rest in a moment */ } @@ -469,7 +469,7 @@ void x11_get_auth_from_authfile(struct X11Display *disp, ptrlen addr, protoname, data; char *displaynum_string; int displaynum; - int ideal_match = FALSE; + int ideal_match = false; char *ourhostname; /* A maximally sized (wildly implausible) .Xauthority record @@ -527,7 +527,7 @@ void x11_get_auth_from_authfile(struct X11Display *disp, BinarySource_BARE_INIT(src, buf, size); while (!ideal_match) { - int match = FALSE; + int match = false; if (src->pos >= MAX_RECORD_SIZE) { size -= src->pos; @@ -597,7 +597,7 @@ void x11_get_auth_from_authfile(struct X11Display *disp, char buf[4]; sk_addrcopy(disp->addr, buf); if (addr.len == 4 && !memcmp(addr.ptr, buf, 4)) { - match = TRUE; + match = true; /* If this is a "localhost" entry, note it down * but carry on looking for a Unix-domain entry. */ ideal_match = !localhost; @@ -610,7 +610,7 @@ void x11_get_auth_from_authfile(struct X11Display *disp, char buf[16]; sk_addrcopy(disp->addr, buf); if (addr.len == 16 && !memcmp(addr.ptr, buf, 16)) { - match = TRUE; + match = true; ideal_match = !localhost; } } @@ -620,7 +620,7 @@ void x11_get_auth_from_authfile(struct X11Display *disp, && ourhostname && ptrlen_eq_string(addr, ourhostname)) /* A matching Unix-domain socket is always the best * match. */ - match = ideal_match = TRUE; + match = ideal_match = true; break; } @@ -660,7 +660,7 @@ void x11_format_auth_for_authfile( put_uint16(bs, 6); /* indicates IPv6 */ put_stringpl_xauth(bs, make_ptrlen(ipv6buf, 16)); } else { - assert(FALSE && "Bad address type in x11_format_auth_for_authfile"); + assert(false && "Bad address type in x11_format_auth_for_authfile"); } { @@ -720,7 +720,7 @@ static void x11_receive(Plug *plug, int urgent, char *data, int len) struct X11Connection *xconn = container_of( plug, struct X11Connection, plug); - xconn->no_data_sent_to_x_client = FALSE; + xconn->no_data_sent_to_x_client = false; sshfwd_write(xconn->c, data, len); } @@ -811,8 +811,8 @@ Channel *x11_new_channel(tree234 *authtree, SshChannel *c, xconn->authtree = authtree; xconn->verified = 0; xconn->data_read = 0; - xconn->input_wanted = TRUE; - xconn->no_data_sent_to_x_client = TRUE; + xconn->input_wanted = true; + xconn->no_data_sent_to_x_client = true; xconn->c = c; /* @@ -882,7 +882,7 @@ static void x11_send_init_error(struct X11Connection *xconn, memcpy(reply + 8, full_message, msglen); sshfwd_write(xconn->c, reply, 8 + msgsize); sshfwd_write_eof(xconn->c); - xconn->no_data_sent_to_x_client = FALSE; + xconn->no_data_sent_to_x_client = false; sfree(reply); sfree(full_message); } @@ -898,9 +898,9 @@ static int x11_parse_ip(const char *addr_string, unsigned long *ip) if (addr_string && 4 == sscanf(addr_string, "%d.%d.%d.%d", i+0, i+1, i+2, i+3)) { *ip = (i[0] << 24) | (i[1] << 16) | (i[2] << 8) | i[3]; - return TRUE; + return true; } else { - return FALSE; + return false; } } From 5691805cbd4147ac861dd93f5784cea7edde8384 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Mon, 29 Oct 2018 20:02:21 +0000 Subject: [PATCH 587/607] Introduce a conf value type of bool. It's not actually used anywhere yet, though. This is just adding the accessor functions, which will enforce a rigorous separation between conf keys typed as int and as bool. --- conf.c | 38 +++++++++++++++++++++++++++++++++++++- putty.h | 2 ++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/conf.c b/conf.c index a8578b10..8eee8447 100644 --- a/conf.c +++ b/conf.c @@ -13,7 +13,9 @@ /* * Enumeration of types used in keys and values. */ -typedef enum { TYPE_NONE, TYPE_INT, TYPE_STR, TYPE_FILENAME, TYPE_FONT } Type; +typedef enum { + TYPE_NONE, TYPE_BOOL, TYPE_INT, TYPE_STR, TYPE_FILENAME, TYPE_FONT +} Type; /* * Arrays which allow us to look up the subkey and value types for a @@ -51,6 +53,7 @@ struct constkey { struct value { union { + bool boolval; int intval; char *stringval; Filename *fileval; @@ -171,6 +174,9 @@ static void free_value(struct value *val, int type) static void copy_value(struct value *to, struct value *from, int type) { switch (type) { + case TYPE_BOOL: + to->u.boolval = from->u.boolval; + break; case TYPE_INT: to->u.intval = from->u.intval; break; @@ -256,6 +262,19 @@ Conf *conf_copy(Conf *oldconf) return newconf; } +bool conf_get_bool(Conf *conf, int primary) +{ + struct key key; + struct conf_entry *entry; + + assert(subkeytypes[primary] == TYPE_NONE); + assert(valuetypes[primary] == TYPE_BOOL); + key.primary = primary; + entry = find234(conf->tree, &key, NULL); + assert(entry); + return entry->value.u.boolval; +} + int conf_get_int(Conf *conf, int primary) { struct key key; @@ -384,6 +403,17 @@ FontSpec *conf_get_fontspec(Conf *conf, int primary) return entry->value.u.fontval; } +void conf_set_bool(Conf *conf, int primary, bool value) +{ + struct conf_entry *entry = snew(struct conf_entry); + + assert(subkeytypes[primary] == TYPE_NONE); + assert(valuetypes[primary] == TYPE_BOOL); + entry->key.primary = primary; + entry->value.u.boolval = value; + conf_insert(conf, entry); +} + void conf_set_int(Conf *conf, int primary, int value) { struct conf_entry *entry = snew(struct conf_entry); @@ -486,6 +516,9 @@ void conf_serialise(BinarySink *bs, Conf *conf) break; } switch (valuetypes[entry->key.primary]) { + case TYPE_BOOL: + put_bool(bs, entry->value.u.boolval); + break; case TYPE_INT: put_uint32(bs, entry->value.u.intval); break; @@ -532,6 +565,9 @@ int conf_deserialise(Conf *conf, BinarySource *src) } switch (valuetypes[entry->key.primary]) { + case TYPE_BOOL: + entry->value.u.boolval = get_bool(src); + break; case TYPE_INT: entry->value.u.intval = toint(get_uint32(src)); break; diff --git a/putty.h b/putty.h index 0212d083..13129bb5 100644 --- a/putty.h +++ b/putty.h @@ -1410,6 +1410,7 @@ void conf_free(Conf *conf); Conf *conf_copy(Conf *oldconf); void conf_copy_into(Conf *dest, Conf *src); /* Mandatory accessor functions: enforce by assertion that keys exist. */ +bool conf_get_bool(Conf *conf, int key); int conf_get_int(Conf *conf, int key); int conf_get_int_int(Conf *conf, int key, int subkey); char *conf_get_str(Conf *conf, int key); /* result still owned by conf */ @@ -1426,6 +1427,7 @@ char *conf_get_str_strs(Conf *conf, int key, char *subkeyin, char **subkeyout); /* Return the nth string subkey in a list. Owned by conf. NULL if beyond end */ char *conf_get_str_nthstrkey(Conf *conf, int key, int n); /* Functions to set entries in configuration. Always copy their inputs. */ +void conf_set_bool(Conf *conf, int key, bool value); void conf_set_int(Conf *conf, int key, int value); void conf_set_int_int(Conf *conf, int key, int subkey, int value); void conf_set_str(Conf *conf, int key, const char *value); From 1378bb049ab6c62fe0b852dcedc81d7b1474a23f Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Mon, 29 Oct 2018 19:57:31 +0000 Subject: [PATCH 588/607] Switch some Conf settings over to being bool. I think this is the full set of things that ought logically to be boolean. One annoyance is that quite a few radio-button controls in config.c address Conf fields that are now bool rather than int, which means that the shared handler function can't just access them all with conf_{get,set}_int. Rather than back out the rigorous separation of int and bool in conf.c itself, I've just added a similar alternative handler function for the bool-typed ones. --- cmdline.c | 26 +-- config.c | 72 +++++--- fuzzterm.c | 7 +- ldisc.c | 4 +- logging.c | 2 +- mainchan.c | 10 +- portfwd.c | 4 +- proxy.c | 2 +- pscp.c | 18 +- psftp.c | 14 +- putty.h | 250 ++++++++++++++-------------- settings.c | 397 +++++++++++++++++++++++---------------------- ssh.c | 22 +-- ssh1connection.c | 2 +- ssh1login.c | 8 +- ssh2connection.c | 4 +- ssh2transport.c | 22 +-- sshserver.c | 4 +- sshshare.c | 6 +- telnet.c | 4 +- terminal.c | 114 ++++++------- unix/gtkmain.c | 14 +- unix/gtkwin.c | 87 +++++----- unix/uxpgnt.c | 1 + unix/uxplink.c | 19 ++- unix/uxpty.c | 6 +- unix/uxserver.c | 5 + unix/uxsftp.c | 5 + windows/windefs.c | 5 + windows/window.c | 88 +++++----- windows/winplink.c | 14 +- 31 files changed, 658 insertions(+), 578 deletions(-) diff --git a/cmdline.c b/cmdline.c index 5e94e866..ea084e45 100644 --- a/cmdline.c +++ b/cmdline.c @@ -594,7 +594,7 @@ int cmdline_process_param(const char *p, char *value, fclose(fp); conf_set_str(conf, CONF_remote_cmd, command); conf_set_str(conf, CONF_remote_cmd2, ""); - conf_set_int(conf, CONF_nopty, true); /* command => no terminal */ + conf_set_bool(conf, CONF_nopty, true); /* command => no terminal */ sfree(command); } if (!strcmp(p, "-P")) { @@ -626,78 +626,78 @@ int cmdline_process_param(const char *p, char *value, RETURN(1); UNAVAILABLE_IN(TOOLTYPE_NONNETWORK); SAVEABLE(0); - conf_set_int(conf, CONF_tryagent, true); + conf_set_bool(conf, CONF_tryagent, true); } if (!strcmp(p, "-noagent") || !strcmp(p, "-nopagent") || !strcmp(p, "-nopageant")) { RETURN(1); UNAVAILABLE_IN(TOOLTYPE_NONNETWORK); SAVEABLE(0); - conf_set_int(conf, CONF_tryagent, false); + conf_set_bool(conf, CONF_tryagent, false); } if (!strcmp(p, "-share")) { RETURN(1); UNAVAILABLE_IN(TOOLTYPE_NONNETWORK); SAVEABLE(0); - conf_set_int(conf, CONF_ssh_connection_sharing, true); + conf_set_bool(conf, CONF_ssh_connection_sharing, true); } if (!strcmp(p, "-noshare")) { RETURN(1); UNAVAILABLE_IN(TOOLTYPE_NONNETWORK); SAVEABLE(0); - conf_set_int(conf, CONF_ssh_connection_sharing, false); + conf_set_bool(conf, CONF_ssh_connection_sharing, false); } if (!strcmp(p, "-A")) { RETURN(1); UNAVAILABLE_IN(TOOLTYPE_FILETRANSFER | TOOLTYPE_NONNETWORK); SAVEABLE(0); - conf_set_int(conf, CONF_agentfwd, 1); + conf_set_bool(conf, CONF_agentfwd, true); } if (!strcmp(p, "-a")) { RETURN(1); UNAVAILABLE_IN(TOOLTYPE_FILETRANSFER | TOOLTYPE_NONNETWORK); SAVEABLE(0); - conf_set_int(conf, CONF_agentfwd, 0); + conf_set_bool(conf, CONF_agentfwd, false); } if (!strcmp(p, "-X")) { RETURN(1); UNAVAILABLE_IN(TOOLTYPE_FILETRANSFER | TOOLTYPE_NONNETWORK); SAVEABLE(0); - conf_set_int(conf, CONF_x11_forward, 1); + conf_set_bool(conf, CONF_x11_forward, true); } if (!strcmp(p, "-x")) { RETURN(1); UNAVAILABLE_IN(TOOLTYPE_FILETRANSFER | TOOLTYPE_NONNETWORK); SAVEABLE(0); - conf_set_int(conf, CONF_x11_forward, 0); + conf_set_bool(conf, CONF_x11_forward, false); } if (!strcmp(p, "-t")) { RETURN(1); UNAVAILABLE_IN(TOOLTYPE_FILETRANSFER | TOOLTYPE_NONNETWORK); SAVEABLE(1); /* lower priority than -m */ - conf_set_int(conf, CONF_nopty, 0); + conf_set_bool(conf, CONF_nopty, false); } if (!strcmp(p, "-T")) { RETURN(1); UNAVAILABLE_IN(TOOLTYPE_FILETRANSFER | TOOLTYPE_NONNETWORK); SAVEABLE(1); - conf_set_int(conf, CONF_nopty, 1); + conf_set_bool(conf, CONF_nopty, true); } if (!strcmp(p, "-N")) { RETURN(1); UNAVAILABLE_IN(TOOLTYPE_FILETRANSFER | TOOLTYPE_NONNETWORK); SAVEABLE(0); - conf_set_int(conf, CONF_ssh_no_shell, 1); + conf_set_bool(conf, CONF_ssh_no_shell, true); } if (!strcmp(p, "-C")) { RETURN(1); UNAVAILABLE_IN(TOOLTYPE_NONNETWORK); SAVEABLE(0); - conf_set_int(conf, CONF_compression, 1); + conf_set_bool(conf, CONF_compression, true); } if (!strcmp(p, "-1")) { diff --git a/config.c b/config.c index 3205b862..a4e3f778 100644 --- a/config.c +++ b/config.c @@ -43,11 +43,39 @@ void conf_radiobutton_handler(union control *ctrl, dlgparam *dlg, } } +void conf_radiobutton_bool_handler(union control *ctrl, dlgparam *dlg, + void *data, int event) +{ + int button; + Conf *conf = (Conf *)data; + + /* + * Same as conf_radiobutton_handler, but using conf_set_bool in + * place of conf_set_int, because it's dealing with a bool-typed + * config option. + */ + if (event == EVENT_REFRESH) { + int val = conf_get_bool(conf, ctrl->radio.context.i); + for (button = 0; button < ctrl->radio.nbuttons; button++) + if (val == ctrl->radio.buttondata[button].i) + break; + /* We expected that `break' to happen, in all circumstances. */ + assert(button < ctrl->radio.nbuttons); + dlg_radiobutton_set(ctrl, dlg, button); + } else if (event == EVENT_VALCHANGE) { + button = dlg_radiobutton_get(ctrl, dlg); + assert(button >= 0 && button < ctrl->radio.nbuttons); + conf_set_bool(conf, ctrl->radio.context.i, + ctrl->radio.buttondata[button].i); + } +} + #define CHECKBOX_INVERT (1<<30) void conf_checkbox_handler(union control *ctrl, dlgparam *dlg, void *data, int event) { - int key, invert; + int key; + bool invert; Conf *conf = (Conf *)data; /* @@ -68,10 +96,10 @@ void conf_checkbox_handler(union control *ctrl, dlgparam *dlg, */ if (event == EVENT_REFRESH) { - int val = conf_get_int(conf, key); + bool val = conf_get_bool(conf, key); dlg_checkbox_set(ctrl, dlg, (!val ^ !invert)); } else if (event == EVENT_VALCHANGE) { - conf_set_int(conf, key, !dlg_checkbox_get(ctrl,dlg) ^ !invert); + conf_set_bool(conf, key, !dlg_checkbox_get(ctrl,dlg) ^ !invert); } } @@ -328,9 +356,9 @@ static void numeric_keypad_handler(union control *ctrl, dlgparam *dlg, * handler, but it has to handle two fields in Conf. */ if (event == EVENT_REFRESH) { - if (conf_get_int(conf, CONF_nethack_keypad)) + if (conf_get_bool(conf, CONF_nethack_keypad)) button = 2; - else if (conf_get_int(conf, CONF_app_keypad)) + else if (conf_get_bool(conf, CONF_app_keypad)) button = 1; else button = 0; @@ -340,11 +368,11 @@ static void numeric_keypad_handler(union control *ctrl, dlgparam *dlg, button = dlg_radiobutton_get(ctrl, dlg); assert(button >= 0 && button < ctrl->radio.nbuttons); if (button == 2) { - conf_set_int(conf, CONF_app_keypad, false); - conf_set_int(conf, CONF_nethack_keypad, true); + conf_set_bool(conf, CONF_app_keypad, false); + conf_set_bool(conf, CONF_nethack_keypad, true); } else { - conf_set_int(conf, CONF_app_keypad, (button != 0)); - conf_set_int(conf, CONF_nethack_keypad, false); + conf_set_bool(conf, CONF_app_keypad, (button != 0)); + conf_set_bool(conf, CONF_nethack_keypad, false); } } } @@ -1701,14 +1729,14 @@ void setup_config_box(struct controlbox *b, int midsession, "Change the sequences sent by:"); ctrl_radiobuttons(s, "The Backspace key", 'b', 2, HELPCTX(keyboard_backspace), - conf_radiobutton_handler, + conf_radiobutton_bool_handler, I(CONF_bksp_is_delete), "Control-H", I(0), "Control-? (127)", I(1), NULL); ctrl_radiobuttons(s, "The Home and End keys", 'e', 2, HELPCTX(keyboard_homeend), - conf_radiobutton_handler, + conf_radiobutton_bool_handler, I(CONF_rxvt_homeend), - "Standard", I(0), "rxvt", I(1), NULL); + "Standard", I(false), "rxvt", I(true), NULL); ctrl_radiobuttons(s, "The Function keys and keypad", 'f', 3, HELPCTX(keyboard_funkeys), conf_radiobutton_handler, @@ -1720,7 +1748,7 @@ void setup_config_box(struct controlbox *b, int midsession, "Application keypad settings:"); ctrl_radiobuttons(s, "Initial state of cursor keys:", 'r', 3, HELPCTX(keyboard_appcursor), - conf_radiobutton_handler, + conf_radiobutton_bool_handler, I(CONF_app_cursor), "Normal", I(0), "Application", I(1), NULL); ctrl_radiobuttons(s, "Initial state of numeric keypad:", 'n', 3, @@ -1960,10 +1988,10 @@ void setup_config_box(struct controlbox *b, int midsession, "Default selection mode (Alt+drag does the other one):", NO_SHORTCUT, 2, HELPCTX(selection_rect), - conf_radiobutton_handler, + conf_radiobutton_bool_handler, I(CONF_rect_select), - "Normal", 'n', I(0), - "Rectangular block", 'r', I(1), NULL); + "Normal", 'n', I(false), + "Rectangular block", 'r', I(true), NULL); s = ctrl_getset(b, "Window/Selection", "clipboards", "Assign copy/paste actions to clipboards"); @@ -2142,7 +2170,7 @@ void setup_config_box(struct controlbox *b, int midsession, sfree(user); ctrl_radiobuttons(s, "When username is not specified:", 'n', 4, HELPCTX(connection_username_from_env), - conf_radiobutton_handler, + conf_radiobutton_bool_handler, I(CONF_username_from_env), "Prompt", I(false), userlabel, I(true), @@ -2281,15 +2309,15 @@ void setup_config_box(struct controlbox *b, int midsession, ctrl_radiobuttons(s, "Handling of OLD_ENVIRON ambiguity:", NO_SHORTCUT, 2, HELPCTX(telnet_oldenviron), - conf_radiobutton_handler, + conf_radiobutton_bool_handler, I(CONF_rfc_environ), - "BSD (commonplace)", 'b', I(0), - "RFC 1408 (unusual)", 'f', I(1), NULL); + "BSD (commonplace)", 'b', I(false), + "RFC 1408 (unusual)", 'f', I(true), NULL); ctrl_radiobuttons(s, "Telnet negotiation mode:", 't', 2, HELPCTX(telnet_passive), - conf_radiobutton_handler, + conf_radiobutton_bool_handler, I(CONF_passive_telnet), - "Passive", I(1), "Active", I(0), NULL); + "Passive", I(true), "Active", I(false), NULL); } ctrl_checkbox(s, "Keyboard sends Telnet special commands", 'k', HELPCTX(telnet_specialkeys), diff --git a/fuzzterm.c b/fuzzterm.c index 2e35677f..477dda58 100644 --- a/fuzzterm.c +++ b/fuzzterm.c @@ -25,7 +25,7 @@ int main(int argc, char **argv) conf = conf_new(); do_defaults(NULL, conf); init_ucs(&ucsdata, conf_get_str(conf, CONF_line_codepage), - conf_get_int(conf, CONF_utf8_override), + conf_get_bool(conf, CONF_utf8_override), CS_NONE, conf_get_int(conf, CONF_vtmode)); term = term_init(conf, &ucsdata, &termwin); @@ -188,6 +188,11 @@ char *platform_default_s(const char *name) return NULL; } +bool platform_default_b(const char *name, bool def) +{ + return def; +} + int platform_default_i(const char *name, int def) { return def; diff --git a/ldisc.c b/ldisc.c index 449e6659..1273d05d 100644 --- a/ldisc.c +++ b/ldisc.c @@ -103,8 +103,8 @@ Ldisc *ldisc_create(Conf *conf, Terminal *term, Backend *backend, Seat *seat) void ldisc_configure(Ldisc *ldisc, Conf *conf) { - ldisc->telnet_keyboard = conf_get_int(conf, CONF_telnet_keyboard); - ldisc->telnet_newline = conf_get_int(conf, CONF_telnet_newline); + ldisc->telnet_keyboard = conf_get_bool(conf, CONF_telnet_keyboard); + ldisc->telnet_newline = conf_get_bool(conf, CONF_telnet_newline); ldisc->protocol = conf_get_int(conf, CONF_protocol); ldisc->localecho = conf_get_int(conf, CONF_localecho); ldisc->localedit = conf_get_int(conf, CONF_localedit); diff --git a/logging.c b/logging.c index bf747b27..68bb8acf 100644 --- a/logging.c +++ b/logging.c @@ -102,7 +102,7 @@ static void logfopen_callback(void *vctx, int mode) } } - if (ctx->state == L_OPEN && conf_get_int(ctx->conf, CONF_logheader)) { + if (ctx->state == L_OPEN && conf_get_bool(ctx->conf, CONF_logheader)) { /* Write header line into log file. */ tm = ltime(); strftime(buf, 24, "%Y.%m.%d %H:%M:%S", &tm); diff --git a/mainchan.c b/mainchan.c index bf2deabb..ffbbb761 100644 --- a/mainchan.c +++ b/mainchan.c @@ -78,7 +78,7 @@ mainchan *mainchan_new( { mainchan *mc; - if (conf_get_int(conf, CONF_ssh_no_shell)) + if (conf_get_bool(conf, CONF_ssh_no_shell)) return NULL; /* no main channel at all */ mc = snew(mainchan); @@ -141,7 +141,7 @@ static void mainchan_open_confirmation(Channel *chan) struct X11FakeAuth *x11auth; int retry_cmd_now = false; - if (conf_get_int(mc->conf, CONF_x11_forward)) {; + if (conf_get_bool(mc->conf, CONF_x11_forward)) {; char *x11_setup_err; if ((x11disp = x11_setup_display( conf_get_str(mc->conf, CONF_x11_display), @@ -165,7 +165,7 @@ static void mainchan_open_confirmation(Channel *chan) mc->req_agent = true; } - if (!conf_get_int(mc->conf, CONF_nopty)) { + if (!conf_get_bool(mc->conf, CONF_nopty)) { sshfwd_request_pty( mc->sc, true, mc->conf, mc->term_width, mc->term_height); mc->req_pty = true; @@ -181,7 +181,7 @@ static void mainchan_open_confirmation(Channel *chan) ppl_logevent(("Sent %d environment variables", mc->n_req_env)); cmd = conf_get_str(mc->conf, CONF_remote_cmd); - if (conf_get_int(mc->conf, CONF_ssh_subsys)) { + if (conf_get_bool(mc->conf, CONF_ssh_subsys)) { retry_cmd_now = !sshfwd_start_subsystem(mc->sc, true, cmd); } else if (*cmd) { sshfwd_start_command(mc->sc, true, cmd); @@ -204,7 +204,7 @@ static void mainchan_open_confirmation(Channel *chan) static void mainchan_try_fallback_command(mainchan *mc) { const char *cmd = conf_get_str(mc->conf, CONF_remote_cmd2); - if (conf_get_int(mc->conf, CONF_ssh_subsys2)) { + if (conf_get_bool(mc->conf, CONF_ssh_subsys2)) { sshfwd_start_subsystem(mc->sc, true, cmd); } else { sshfwd_start_command(mc->sc, true, cmd); diff --git a/portfwd.c b/portfwd.c index c4a3210b..1515135d 100644 --- a/portfwd.c +++ b/portfwd.c @@ -587,7 +587,7 @@ static char *pfl_listen(const char *desthost, int destport, pl->cl = cl; pl->s = new_listener(srcaddr, port, &pl->plug, - !conf_get_int(conf, CONF_lport_acceptall), + !conf_get_bool(conf, CONF_lport_acceptall), conf, address_family); if ((err = sk_socket_error(pl->s)) != NULL) { char *err_ret = dupstr(err); @@ -1024,7 +1024,7 @@ void portfwdmgr_config(PortFwdManager *mgr, Conf *conf) if (pfr->saddr) { shost = pfr->saddr; - } else if (conf_get_int(conf, CONF_rport_acceptall)) { + } else if (conf_get_bool(conf, CONF_rport_acceptall)) { shost = ""; } else { shost = "localhost"; diff --git a/proxy.c b/proxy.c index 0e1eeeed..89d34952 100644 --- a/proxy.c +++ b/proxy.c @@ -283,7 +283,7 @@ int proxy_for_destination (SockAddr *addr, const char *hostname, * Check the host name and IP against the hard-coded * representations of `localhost'. */ - if (!conf_get_int(conf, CONF_even_proxy_localhost) && + if (!conf_get_bool(conf, CONF_even_proxy_localhost) && (sk_hostname_is_local(hostname) || (addr && sk_address_is_local(addr)))) return 0; /* do not proxy */ diff --git a/pscp.c b/pscp.c index 11f3f5c9..ebda4e01 100644 --- a/pscp.c +++ b/pscp.c @@ -437,9 +437,9 @@ static void do_cmd(char *host, char *user, char *cmd) * things like SCP and SFTP: agent forwarding, port forwarding, * X forwarding. */ - conf_set_int(conf, CONF_x11_forward, 0); - conf_set_int(conf, CONF_agentfwd, 0); - conf_set_int(conf, CONF_ssh_simple, true); + conf_set_bool(conf, CONF_x11_forward, false); + conf_set_bool(conf, CONF_agentfwd, false); + conf_set_bool(conf, CONF_ssh_simple, true); { char *key; while ((key = conf_get_str_nthstrkey(conf, CONF_portfwd, 0)) != NULL) @@ -457,12 +457,12 @@ static void do_cmd(char *host, char *user, char *cmd) /* First choice is SFTP subsystem. */ main_cmd_is_sftp = 1; conf_set_str(conf, CONF_remote_cmd, "sftp"); - conf_set_int(conf, CONF_ssh_subsys, true); + conf_set_bool(conf, CONF_ssh_subsys, true); if (try_scp) { /* Fallback is to use the provided scp command. */ fallback_cmd_is_sftp = 0; conf_set_str(conf, CONF_remote_cmd2, cmd); - conf_set_int(conf, CONF_ssh_subsys2, false); + conf_set_bool(conf, CONF_ssh_subsys2, false); } else { /* Since we're not going to try SCP, we may as well try * harder to find an SFTP server, since in the current @@ -475,15 +475,15 @@ static void do_cmd(char *host, char *user, char *cmd) "test -x /usr/local/lib/sftp-server &&" " exec /usr/local/lib/sftp-server\n" "exec sftp-server"); - conf_set_int(conf, CONF_ssh_subsys2, false); + conf_set_bool(conf, CONF_ssh_subsys2, false); } } else { /* Don't try SFTP at all; just try the scp command. */ main_cmd_is_sftp = 0; conf_set_str(conf, CONF_remote_cmd, cmd); - conf_set_int(conf, CONF_ssh_subsys, false); + conf_set_bool(conf, CONF_ssh_subsys, false); } - conf_set_int(conf, CONF_nopty, true); + conf_set_bool(conf, CONF_nopty, true); logctx = log_init(default_logpolicy, conf); @@ -493,7 +493,7 @@ static void do_cmd(char *host, char *user, char *cmd) conf_get_str(conf, CONF_host), conf_get_int(conf, CONF_port), &realhost, 0, - conf_get_int(conf, CONF_tcp_keepalives)); + conf_get_bool(conf, CONF_tcp_keepalives)); if (err != NULL) bump("ssh_init: %s", err); ssh_scp_init(); diff --git a/psftp.c b/psftp.c index 6ab158b9..84c81454 100644 --- a/psftp.c +++ b/psftp.c @@ -2761,9 +2761,9 @@ static int psftp_connect(char *userhost, char *user, int portnumber) * things like SCP and SFTP: agent forwarding, port forwarding, * X forwarding. */ - conf_set_int(conf, CONF_x11_forward, 0); - conf_set_int(conf, CONF_agentfwd, 0); - conf_set_int(conf, CONF_ssh_simple, true); + conf_set_bool(conf, CONF_x11_forward, false); + conf_set_bool(conf, CONF_agentfwd, false); + conf_set_bool(conf, CONF_ssh_simple, true); { char *key; while ((key = conf_get_str_nthstrkey(conf, CONF_portfwd, 0)) != NULL) @@ -2772,8 +2772,8 @@ static int psftp_connect(char *userhost, char *user, int portnumber) /* Set up subsystem name. */ conf_set_str(conf, CONF_remote_cmd, "sftp"); - conf_set_int(conf, CONF_ssh_subsys, true); - conf_set_int(conf, CONF_nopty, true); + conf_set_bool(conf, CONF_ssh_subsys, true); + conf_set_bool(conf, CONF_nopty, true); /* * Set up fallback option, for SSH-1 servers or servers with the @@ -2798,7 +2798,7 @@ static int psftp_connect(char *userhost, char *user, int portnumber) "test -x /usr/local/lib/sftp-server &&" " exec /usr/local/lib/sftp-server\n" "exec sftp-server"); - conf_set_int(conf, CONF_ssh_subsys2, false); + conf_set_bool(conf, CONF_ssh_subsys2, false); logctx = log_init(default_logpolicy, conf); @@ -2808,7 +2808,7 @@ static int psftp_connect(char *userhost, char *user, int portnumber) conf_get_str(conf, CONF_host), conf_get_int(conf, CONF_port), &realhost, 0, - conf_get_int(conf, CONF_tcp_keepalives)); + conf_get_bool(conf, CONF_tcp_keepalives)); if (err != NULL) { fprintf(stderr, "ssh_init: %s\n", err); return 1; diff --git a/putty.h b/putty.h index 13129bb5..f6898aab 100644 --- a/putty.h +++ b/putty.h @@ -1155,37 +1155,37 @@ void cleanup_exit(int); /* X(value-type, subkey-type, keyword) */ \ X(STR, NONE, host) \ X(INT, NONE, port) \ - X(INT, NONE, protocol) \ - X(INT, NONE, addressfamily) \ - X(INT, NONE, close_on_exit) \ - X(INT, NONE, warn_on_close) \ + X(INT, NONE, protocol) /* PROT_SSH, PROT_TELNET etc */ \ + X(INT, NONE, addressfamily) /* ADDRTYPE_IPV[46] or ADDRTYPE_UNSPEC */ \ + X(INT, NONE, close_on_exit) /* FORCE_ON, FORCE_OFF, AUTO */ \ + X(BOOL, NONE, warn_on_close) \ X(INT, NONE, ping_interval) /* in seconds */ \ - X(INT, NONE, tcp_nodelay) \ - X(INT, NONE, tcp_keepalives) \ + X(BOOL, NONE, tcp_nodelay) \ + X(BOOL, NONE, tcp_keepalives) \ X(STR, NONE, loghost) /* logical host being contacted, for host key check */ \ /* Proxy options */ \ X(STR, NONE, proxy_exclude_list) \ - X(INT, NONE, proxy_dns) \ - X(INT, NONE, even_proxy_localhost) \ - X(INT, NONE, proxy_type) \ + X(INT, NONE, proxy_dns) /* FORCE_ON, FORCE_OFF, AUTO */ \ + X(BOOL, NONE, even_proxy_localhost) \ + X(INT, NONE, proxy_type) /* PROXY_NONE, PROXY_SOCKS4, ... */ \ X(STR, NONE, proxy_host) \ X(INT, NONE, proxy_port) \ X(STR, NONE, proxy_username) \ X(STR, NONE, proxy_password) \ X(STR, NONE, proxy_telnet_command) \ - X(INT, NONE, proxy_log_to_term) \ + X(INT, NONE, proxy_log_to_term) /* FORCE_ON, FORCE_OFF, AUTO */ \ /* SSH options */ \ X(STR, NONE, remote_cmd) \ X(STR, NONE, remote_cmd2) /* fallback if remote_cmd fails; never loaded or saved */ \ - X(INT, NONE, nopty) \ - X(INT, NONE, compression) \ + X(BOOL, NONE, nopty) \ + X(BOOL, NONE, compression) \ X(INT, INT, ssh_kexlist) \ X(INT, INT, ssh_hklist) \ X(INT, NONE, ssh_rekey_time) /* in minutes */ \ X(STR, NONE, ssh_rekey_data) /* string encoding e.g. "100K", "2M", "1G" */ \ - X(INT, NONE, tryagent) \ - X(INT, NONE, agentfwd) \ - X(INT, NONE, change_username) /* allow username switching in SSH-2 */ \ + X(BOOL, NONE, tryagent) \ + X(BOOL, NONE, agentfwd) \ + X(BOOL, NONE, change_username) /* allow username switching in SSH-2 */ \ X(INT, INT, ssh_cipherlist) \ X(FILENAME, NONE, keyfile) \ /* \ @@ -1202,20 +1202,20 @@ void cleanup_exit(int); * downgrades PuTTY. So it's easier to use these numbers internally too. \ */ \ X(INT, NONE, sshprot) \ - X(INT, NONE, ssh2_des_cbc) /* "des-cbc" unrecommended SSH-2 cipher */ \ - X(INT, NONE, ssh_no_userauth) /* bypass "ssh-userauth" (SSH-2 only) */ \ - X(INT, NONE, ssh_show_banner) /* show USERAUTH_BANNERs (SSH-2 only) */ \ - X(INT, NONE, try_tis_auth) \ - X(INT, NONE, try_ki_auth) \ - X(INT, NONE, try_gssapi_auth) /* attempt gssapi auth via ssh userauth */ \ - X(INT, NONE, try_gssapi_kex) /* attempt gssapi auth via ssh kex */ \ - X(INT, NONE, gssapifwd) /* forward tgt via gss */ \ + X(BOOL, NONE, ssh2_des_cbc) /* "des-cbc" unrecommended SSH-2 cipher */ \ + X(BOOL, NONE, ssh_no_userauth) /* bypass "ssh-userauth" (SSH-2 only) */ \ + X(BOOL, NONE, ssh_show_banner) /* show USERAUTH_BANNERs (SSH-2 only) */ \ + X(BOOL, NONE, try_tis_auth) \ + X(BOOL, NONE, try_ki_auth) \ + X(BOOL, NONE, try_gssapi_auth) /* attempt gssapi auth via ssh userauth */ \ + X(BOOL, NONE, try_gssapi_kex) /* attempt gssapi auth via ssh kex */ \ + X(BOOL, NONE, gssapifwd) /* forward tgt via gss */ \ X(INT, NONE, gssapirekey) /* KEXGSS refresh interval (mins) */ \ X(INT, INT, ssh_gsslist) /* preference order for local GSS libs */ \ X(FILENAME, NONE, ssh_gss_custom) \ - X(INT, NONE, ssh_subsys) /* run a subsystem rather than a command */ \ - X(INT, NONE, ssh_subsys2) /* fallback to go with remote_cmd_ptr2 */ \ - X(INT, NONE, ssh_no_shell) /* avoid running a shell */ \ + X(BOOL, NONE, ssh_subsys) /* run a subsystem rather than a command */ \ + X(BOOL, NONE, ssh_subsys2) /* fallback to go with remote_cmd_ptr2 */ \ + X(BOOL, NONE, ssh_no_shell) /* avoid running a shell */ \ X(STR, NONE, ssh_nc_host) /* host to connect to in `nc' mode */ \ X(INT, NONE, ssh_nc_port) /* port to connect to in `nc' mode */ \ /* Telnet options */ \ @@ -1224,127 +1224,128 @@ void cleanup_exit(int); X(STR, STR, ttymodes) /* values are "Vvalue" or "A" */ \ X(STR, STR, environmt) \ X(STR, NONE, username) \ - X(INT, NONE, username_from_env) \ + X(BOOL, NONE, username_from_env) \ X(STR, NONE, localusername) \ - X(INT, NONE, rfc_environ) \ - X(INT, NONE, passive_telnet) \ + X(BOOL, NONE, rfc_environ) \ + X(BOOL, NONE, passive_telnet) \ /* Serial port options */ \ X(STR, NONE, serline) \ X(INT, NONE, serspeed) \ X(INT, NONE, serdatabits) \ X(INT, NONE, serstopbits) \ - X(INT, NONE, serparity) \ - X(INT, NONE, serflow) \ + X(INT, NONE, serparity) /* SER_PAR_NONE, SER_PAR_ODD, ... */ \ + X(INT, NONE, serflow) /* SER_FLOW_NONE, SER_FLOW_XONXOFF, ... */ \ /* Keyboard options */ \ - X(INT, NONE, bksp_is_delete) \ - X(INT, NONE, rxvt_homeend) \ - X(INT, NONE, funky_type) \ - X(INT, NONE, no_applic_c) /* totally disable app cursor keys */ \ - X(INT, NONE, no_applic_k) /* totally disable app keypad */ \ - X(INT, NONE, no_mouse_rep) /* totally disable mouse reporting */ \ - X(INT, NONE, no_remote_resize) /* disable remote resizing */ \ - X(INT, NONE, no_alt_screen) /* disable alternate screen */ \ - X(INT, NONE, no_remote_wintitle) /* disable remote retitling */ \ - X(INT, NONE, no_remote_clearscroll) /* disable ESC[3J */ \ - X(INT, NONE, no_dbackspace) /* disable destructive backspace */ \ - X(INT, NONE, no_remote_charset) /* disable remote charset config */ \ - X(INT, NONE, remote_qtitle_action) /* remote win title query action */ \ - X(INT, NONE, app_cursor) \ - X(INT, NONE, app_keypad) \ - X(INT, NONE, nethack_keypad) \ - X(INT, NONE, telnet_keyboard) \ - X(INT, NONE, telnet_newline) \ - X(INT, NONE, alt_f4) /* is it special? */ \ - X(INT, NONE, alt_space) /* is it special? */ \ - X(INT, NONE, alt_only) /* is it special? */ \ - X(INT, NONE, localecho) \ - X(INT, NONE, localedit) \ - X(INT, NONE, alwaysontop) \ - X(INT, NONE, fullscreenonaltenter) \ - X(INT, NONE, scroll_on_key) \ - X(INT, NONE, scroll_on_disp) \ - X(INT, NONE, erase_to_scrollback) \ - X(INT, NONE, compose_key) \ - X(INT, NONE, ctrlaltkeys) \ - X(INT, NONE, osx_option_meta) \ - X(INT, NONE, osx_command_meta) \ + X(BOOL, NONE, bksp_is_delete) \ + X(BOOL, NONE, rxvt_homeend) \ + X(INT, NONE, funky_type) /* FUNKY_XTERM, FUNKY_LINUX, ... */ \ + X(BOOL, NONE, no_applic_c) /* totally disable app cursor keys */ \ + X(BOOL, NONE, no_applic_k) /* totally disable app keypad */ \ + X(BOOL, NONE, no_mouse_rep) /* totally disable mouse reporting */ \ + X(BOOL, NONE, no_remote_resize) /* disable remote resizing */ \ + X(BOOL, NONE, no_alt_screen) /* disable alternate screen */ \ + X(BOOL, NONE, no_remote_wintitle) /* disable remote retitling */ \ + X(BOOL, NONE, no_remote_clearscroll) /* disable ESC[3J */ \ + X(BOOL, NONE, no_dbackspace) /* disable destructive backspace */ \ + X(BOOL, NONE, no_remote_charset) /* disable remote charset config */ \ + X(INT, NONE, remote_qtitle_action) /* remote win title query action + * (TITLE_NONE, TITLE_EMPTY, ...) */ \ + X(BOOL, NONE, app_cursor) \ + X(BOOL, NONE, app_keypad) \ + X(BOOL, NONE, nethack_keypad) \ + X(BOOL, NONE, telnet_keyboard) \ + X(BOOL, NONE, telnet_newline) \ + X(BOOL, NONE, alt_f4) /* is it special? */ \ + X(BOOL, NONE, alt_space) /* is it special? */ \ + X(BOOL, NONE, alt_only) /* is it special? */ \ + X(INT, NONE, localecho) /* FORCE_ON, FORCE_OFF, AUTO */ \ + X(INT, NONE, localedit) /* FORCE_ON, FORCE_OFF, AUTO */ \ + X(BOOL, NONE, alwaysontop) \ + X(BOOL, NONE, fullscreenonaltenter) \ + X(BOOL, NONE, scroll_on_key) \ + X(BOOL, NONE, scroll_on_disp) \ + X(BOOL, NONE, erase_to_scrollback) \ + X(BOOL, NONE, compose_key) \ + X(BOOL, NONE, ctrlaltkeys) \ + X(BOOL, NONE, osx_option_meta) \ + X(BOOL, NONE, osx_command_meta) \ X(STR, NONE, wintitle) /* initial window title */ \ /* Terminal options */ \ X(INT, NONE, savelines) \ - X(INT, NONE, dec_om) \ - X(INT, NONE, wrap_mode) \ - X(INT, NONE, lfhascr) \ + X(BOOL, NONE, dec_om) \ + X(BOOL, NONE, wrap_mode) \ + X(BOOL, NONE, lfhascr) \ X(INT, NONE, cursor_type) /* 0=block 1=underline 2=vertical */ \ - X(INT, NONE, blink_cur) \ - X(INT, NONE, beep) \ - X(INT, NONE, beep_ind) \ - X(INT, NONE, bellovl) /* bell overload protection active? */ \ + X(BOOL, NONE, blink_cur) \ + X(INT, NONE, beep) /* BELL_DISABLED, BELL_DEFAULT, ... */ \ + X(INT, NONE, beep_ind) /* B_IND_DISABLED, B_IND_FLASH, ... */ \ + X(BOOL, NONE, bellovl) /* bell overload protection active? */ \ X(INT, NONE, bellovl_n) /* number of bells to cause overload */ \ X(INT, NONE, bellovl_t) /* time interval for overload (seconds) */ \ X(INT, NONE, bellovl_s) /* period of silence to re-enable bell (s) */ \ X(FILENAME, NONE, bell_wavefile) \ - X(INT, NONE, scrollbar) \ - X(INT, NONE, scrollbar_in_fullscreen) \ - X(INT, NONE, resize_action) \ - X(INT, NONE, bce) \ - X(INT, NONE, blinktext) \ - X(INT, NONE, win_name_always) \ + X(BOOL, NONE, scrollbar) \ + X(BOOL, NONE, scrollbar_in_fullscreen) \ + X(INT, NONE, resize_action) /* RESIZE_TERM, RESIZE_DISABLED, ... */ \ + X(BOOL, NONE, bce) \ + X(BOOL, NONE, blinktext) \ + X(BOOL, NONE, win_name_always) \ X(INT, NONE, width) \ X(INT, NONE, height) \ X(FONT, NONE, font) \ - X(INT, NONE, font_quality) \ + X(INT, NONE, font_quality) /* FQ_DEFAULT, FQ_ANTIALIASED, ... */ \ X(FILENAME, NONE, logfilename) \ - X(INT, NONE, logtype) \ - X(INT, NONE, logxfovr) \ - X(INT, NONE, logflush) \ - X(INT, NONE, logheader) \ - X(INT, NONE, logomitpass) \ - X(INT, NONE, logomitdata) \ - X(INT, NONE, hide_mouseptr) \ - X(INT, NONE, sunken_edge) \ - X(INT, NONE, window_border) \ + X(INT, NONE, logtype) /* LGTYP_NONE, LGTYPE_ASCII, ... */ \ + X(INT, NONE, logxfovr) /* LGXF_OVR, LGXF_APN, LGXF_ASK */ \ + X(BOOL, NONE, logflush) \ + X(BOOL, NONE, logheader) \ + X(BOOL, NONE, logomitpass) \ + X(BOOL, NONE, logomitdata) \ + X(BOOL, NONE, hide_mouseptr) \ + X(BOOL, NONE, sunken_edge) \ + X(INT, NONE, window_border) /* in pixels */ \ X(STR, NONE, answerback) \ X(STR, NONE, printer) \ - X(INT, NONE, arabicshaping) \ - X(INT, NONE, bidi) \ + X(BOOL, NONE, arabicshaping) \ + X(BOOL, NONE, bidi) \ /* Colour options */ \ - X(INT, NONE, ansi_colour) \ - X(INT, NONE, xterm_256_colour) \ - X(INT, NONE, true_colour) \ - X(INT, NONE, system_colour) \ - X(INT, NONE, try_palette) \ - X(INT, NONE, bold_style) \ + X(BOOL, NONE, ansi_colour) \ + X(BOOL, NONE, xterm_256_colour) \ + X(BOOL, NONE, true_colour) \ + X(BOOL, NONE, system_colour) \ + X(BOOL, NONE, try_palette) \ + X(INT, NONE, bold_style) /* 1=font 2=colour (3=both) */ \ X(INT, INT, colours) \ /* Selection options */ \ - X(INT, NONE, mouse_is_xterm) \ - X(INT, NONE, rect_select) \ - X(INT, NONE, paste_controls) \ - X(INT, NONE, rawcnp) \ - X(INT, NONE, utf8linedraw) \ - X(INT, NONE, rtf_paste) \ - X(INT, NONE, mouse_override) \ + X(INT, NONE, mouse_is_xterm) /* 0=compromise 1=xterm 2=Windows */ \ + X(BOOL, NONE, rect_select) \ + X(BOOL, NONE, paste_controls) \ + X(BOOL, NONE, rawcnp) \ + X(BOOL, NONE, utf8linedraw) \ + X(BOOL, NONE, rtf_paste) \ + X(BOOL, NONE, mouse_override) \ X(INT, INT, wordness) \ - X(INT, NONE, mouseautocopy) \ - X(INT, NONE, mousepaste) \ - X(INT, NONE, ctrlshiftins) \ - X(INT, NONE, ctrlshiftcv) \ + X(BOOL, NONE, mouseautocopy) \ + X(INT, NONE, mousepaste) /* CLIPUI_IMPLICIT, CLIPUI_EXPLICIT, ... */ \ + X(INT, NONE, ctrlshiftins) /* CLIPUI_IMPLICIT, CLIPUI_EXPLICIT, ... */ \ + X(INT, NONE, ctrlshiftcv) /* CLIPUI_IMPLICIT, CLIPUI_EXPLICIT, ... */ \ X(STR, NONE, mousepaste_custom) \ X(STR, NONE, ctrlshiftins_custom) \ X(STR, NONE, ctrlshiftcv_custom) \ /* translations */ \ - X(INT, NONE, vtmode) \ + X(INT, NONE, vtmode) /* VT_XWINDOWS, VT_OEMANSI, ... */ \ X(STR, NONE, line_codepage) \ - X(INT, NONE, cjk_ambig_wide) \ - X(INT, NONE, utf8_override) \ - X(INT, NONE, xlat_capslockcyr) \ + X(BOOL, NONE, cjk_ambig_wide) \ + X(BOOL, NONE, utf8_override) \ + X(BOOL, NONE, xlat_capslockcyr) \ /* X11 forwarding */ \ - X(INT, NONE, x11_forward) \ + X(BOOL, NONE, x11_forward) \ X(STR, NONE, x11_display) \ - X(INT, NONE, x11_auth) \ + X(INT, NONE, x11_auth) /* X11_NO_AUTH, X11_MIT, X11_XDM */ \ X(FILENAME, NONE, xauthfile) \ /* port forwarding */ \ - X(INT, NONE, lport_acceptall) /* accept conns from hosts other than localhost */ \ - X(INT, NONE, rport_acceptall) /* same for remote forwarded ports (SSH-2 only) */ \ + X(BOOL, NONE, lport_acceptall) /* accept conns from hosts other than localhost */ \ + X(BOOL, NONE, rport_acceptall) /* same for remote forwarded ports (SSH-2 only) */ \ /* \ * Subkeys for 'portfwd' can have the following forms: \ * \ @@ -1356,7 +1357,7 @@ void cleanup_exit(int); * should be of the form 'host:port'. \ */ \ X(STR, STR, portfwd) \ - /* SSH bug compatibility modes */ \ + /* SSH bug compatibility modes. All FORCE_ON/FORCE_OFF/AUTO */ \ X(INT, NONE, sshbug_ignore1) \ X(INT, NONE, sshbug_plainpw1) \ X(INT, NONE, sshbug_rsa1) \ @@ -1375,10 +1376,10 @@ void cleanup_exit(int); * other than the main one, which means it can safely use a very \ * large window in SSH-2. \ */ \ - X(INT, NONE, ssh_simple) \ - X(INT, NONE, ssh_connection_sharing) \ - X(INT, NONE, ssh_connection_sharing_upstream) \ - X(INT, NONE, ssh_connection_sharing_downstream) \ + X(BOOL, NONE, ssh_simple) \ + X(BOOL, NONE, ssh_connection_sharing) \ + X(BOOL, NONE, ssh_connection_sharing_upstream) \ + X(BOOL, NONE, ssh_connection_sharing_downstream) \ /* * ssh_manual_hostkeys is conceptually a set rather than a * dictionary: the string subkeys are the important thing, and the @@ -1386,15 +1387,15 @@ void cleanup_exit(int); */ \ X(STR, STR, ssh_manual_hostkeys) \ /* Options for pterm. Should split out into platform-dependent part. */ \ - X(INT, NONE, stamp_utmp) \ - X(INT, NONE, login_shell) \ - X(INT, NONE, scrollbar_on_left) \ - X(INT, NONE, shadowbold) \ + X(BOOL, NONE, stamp_utmp) \ + X(BOOL, NONE, login_shell) \ + X(BOOL, NONE, scrollbar_on_left) \ + X(BOOL, NONE, shadowbold) \ X(FONT, NONE, boldfont) \ X(FONT, NONE, widefont) \ X(FONT, NONE, wideboldfont) \ - X(INT, NONE, shadowboldoffset) \ - X(INT, NONE, crhaslf) \ + X(INT, NONE, shadowboldoffset) /* in pixels */ \ + X(BOOL, NONE, crhaslf) \ X(STR, NONE, winclass) \ /* Now define the actual enum of option keywords using that macro. */ @@ -1494,6 +1495,7 @@ void registry_cleanup(void); * transferred to the caller, and must be freed. */ char *platform_default_s(const char *name); +bool platform_default_b(const char *name, bool def); int platform_default_i(const char *name, int def); Filename *platform_default_filename(const char *name); FontSpec *platform_default_fontspec(const char *name); diff --git a/settings.c b/settings.c index 73e8e319..e1b16918 100644 --- a/settings.c +++ b/settings.c @@ -97,7 +97,7 @@ char *get_remote_username(Conf *conf) char *username = conf_get_str(conf, CONF_username); if (*username) { return dupstr(username); - } else if (conf_get_int(conf, CONF_username_from_env)) { + } else if (conf_get_bool(conf, CONF_username_from_env)) { /* Use local username. */ return get_username(); /* might still be NULL */ } else { @@ -147,6 +147,18 @@ static void gppfile(settings_r *sesskey, const char *name, filename_free(result); } +static bool gppb_raw(settings_r *sesskey, const char *name, bool def) +{ + def = platform_default_b(name, def); + return sesskey ? read_setting_i(sesskey, name, def) != 0 : def; +} + +static void gppb(settings_r *sesskey, const char *name, int def, + Conf *conf, conf_BOOL_NONE primary) +{ + conf_set_bool(conf, primary, gppb_raw(sesskey, name, def)); +} + static int gppi_raw(settings_r *sesskey, const char *name, int def) { def = platform_default_i(name, def); @@ -455,6 +467,11 @@ static void wprefs(settings_w *sesskey, const char *name, sfree(buf); } +static void write_setting_b(settings_w *handle, const char *key, bool value) +{ + write_setting_i(handle, key, value ? 1 : 0); +} + static void write_clip_setting(settings_w *sesskey, const char *savekey, Conf *conf, int confkey, int strconfkey) { @@ -526,10 +543,10 @@ void save_open_settings(settings_w *sesskey, Conf *conf) write_setting_filename(sesskey, "LogFileName", conf_get_filename(conf, CONF_logfilename)); write_setting_i(sesskey, "LogType", conf_get_int(conf, CONF_logtype)); write_setting_i(sesskey, "LogFileClash", conf_get_int(conf, CONF_logxfovr)); - write_setting_i(sesskey, "LogFlush", conf_get_int(conf, CONF_logflush)); - write_setting_i(sesskey, "LogHeader", conf_get_int(conf, CONF_logheader)); - write_setting_i(sesskey, "SSHLogOmitPasswords", conf_get_int(conf, CONF_logomitpass)); - write_setting_i(sesskey, "SSHLogOmitData", conf_get_int(conf, CONF_logomitdata)); + write_setting_b(sesskey, "LogFlush", conf_get_bool(conf, CONF_logflush)); + write_setting_b(sesskey, "LogHeader", conf_get_bool(conf, CONF_logheader)); + write_setting_b(sesskey, "SSHLogOmitPasswords", conf_get_bool(conf, CONF_logomitpass)); + write_setting_b(sesskey, "SSHLogOmitData", conf_get_bool(conf, CONF_logomitdata)); p = "raw"; { const struct BackendVtable *vt = @@ -542,11 +559,11 @@ void save_open_settings(settings_w *sesskey, Conf *conf) /* The CloseOnExit numbers are arranged in a different order from * the standard FORCE_ON / FORCE_OFF / AUTO. */ write_setting_i(sesskey, "CloseOnExit", (conf_get_int(conf, CONF_close_on_exit)+2)%3); - write_setting_i(sesskey, "WarnOnClose", !!conf_get_int(conf, CONF_warn_on_close)); + write_setting_b(sesskey, "WarnOnClose", !!conf_get_bool(conf, CONF_warn_on_close)); write_setting_i(sesskey, "PingInterval", conf_get_int(conf, CONF_ping_interval) / 60); /* minutes */ write_setting_i(sesskey, "PingIntervalSecs", conf_get_int(conf, CONF_ping_interval) % 60); /* seconds */ - write_setting_i(sesskey, "TCPNoDelay", conf_get_int(conf, CONF_tcp_nodelay)); - write_setting_i(sesskey, "TCPKeepalives", conf_get_int(conf, CONF_tcp_keepalives)); + write_setting_b(sesskey, "TCPNoDelay", conf_get_bool(conf, CONF_tcp_nodelay)); + write_setting_b(sesskey, "TCPKeepalives", conf_get_bool(conf, CONF_tcp_keepalives)); write_setting_s(sesskey, "TerminalType", conf_get_str(conf, CONF_termtype)); write_setting_s(sesskey, "TerminalSpeed", conf_get_str(conf, CONF_termspeed)); wmap(sesskey, "TerminalModes", conf, CONF_ttymodes, true); @@ -557,7 +574,7 @@ void save_open_settings(settings_w *sesskey, Conf *conf) /* proxy settings */ write_setting_s(sesskey, "ProxyExcludeList", conf_get_str(conf, CONF_proxy_exclude_list)); write_setting_i(sesskey, "ProxyDNS", (conf_get_int(conf, CONF_proxy_dns)+2)%3); - write_setting_i(sesskey, "ProxyLocalhost", conf_get_int(conf, CONF_even_proxy_localhost)); + write_setting_b(sesskey, "ProxyLocalhost", conf_get_bool(conf, CONF_even_proxy_localhost)); write_setting_i(sesskey, "ProxyMethod", conf_get_int(conf, CONF_proxy_type)); write_setting_s(sesskey, "ProxyHost", conf_get_str(conf, CONF_proxy_host)); write_setting_i(sesskey, "ProxyPort", conf_get_int(conf, CONF_proxy_port)); @@ -567,79 +584,79 @@ void save_open_settings(settings_w *sesskey, Conf *conf) write_setting_i(sesskey, "ProxyLogToTerm", conf_get_int(conf, CONF_proxy_log_to_term)); wmap(sesskey, "Environment", conf, CONF_environmt, true); write_setting_s(sesskey, "UserName", conf_get_str(conf, CONF_username)); - write_setting_i(sesskey, "UserNameFromEnvironment", conf_get_int(conf, CONF_username_from_env)); + write_setting_b(sesskey, "UserNameFromEnvironment", conf_get_bool(conf, CONF_username_from_env)); write_setting_s(sesskey, "LocalUserName", conf_get_str(conf, CONF_localusername)); - write_setting_i(sesskey, "NoPTY", conf_get_int(conf, CONF_nopty)); - write_setting_i(sesskey, "Compression", conf_get_int(conf, CONF_compression)); - write_setting_i(sesskey, "TryAgent", conf_get_int(conf, CONF_tryagent)); - write_setting_i(sesskey, "AgentFwd", conf_get_int(conf, CONF_agentfwd)); - write_setting_i(sesskey, "GssapiFwd", conf_get_int(conf, CONF_gssapifwd)); - write_setting_i(sesskey, "ChangeUsername", conf_get_int(conf, CONF_change_username)); + write_setting_b(sesskey, "NoPTY", conf_get_bool(conf, CONF_nopty)); + write_setting_b(sesskey, "Compression", conf_get_bool(conf, CONF_compression)); + write_setting_b(sesskey, "TryAgent", conf_get_bool(conf, CONF_tryagent)); + write_setting_b(sesskey, "AgentFwd", conf_get_bool(conf, CONF_agentfwd)); + write_setting_b(sesskey, "GssapiFwd", conf_get_bool(conf, CONF_gssapifwd)); + write_setting_b(sesskey, "ChangeUsername", conf_get_bool(conf, CONF_change_username)); wprefs(sesskey, "Cipher", ciphernames, CIPHER_MAX, conf, CONF_ssh_cipherlist); wprefs(sesskey, "KEX", kexnames, KEX_MAX, conf, CONF_ssh_kexlist); wprefs(sesskey, "HostKey", hknames, HK_MAX, conf, CONF_ssh_hklist); write_setting_i(sesskey, "RekeyTime", conf_get_int(conf, CONF_ssh_rekey_time)); write_setting_i(sesskey, "GssapiRekey", conf_get_int(conf, CONF_gssapirekey)); write_setting_s(sesskey, "RekeyBytes", conf_get_str(conf, CONF_ssh_rekey_data)); - write_setting_i(sesskey, "SshNoAuth", conf_get_int(conf, CONF_ssh_no_userauth)); - write_setting_i(sesskey, "SshBanner", conf_get_int(conf, CONF_ssh_show_banner)); - write_setting_i(sesskey, "AuthTIS", conf_get_int(conf, CONF_try_tis_auth)); - write_setting_i(sesskey, "AuthKI", conf_get_int(conf, CONF_try_ki_auth)); - write_setting_i(sesskey, "AuthGSSAPI", conf_get_int(conf, CONF_try_gssapi_auth)); - write_setting_i(sesskey, "AuthGSSAPIKEX", conf_get_int(conf, CONF_try_gssapi_kex)); + write_setting_b(sesskey, "SshNoAuth", conf_get_bool(conf, CONF_ssh_no_userauth)); + write_setting_b(sesskey, "SshBanner", conf_get_bool(conf, CONF_ssh_show_banner)); + write_setting_b(sesskey, "AuthTIS", conf_get_bool(conf, CONF_try_tis_auth)); + write_setting_b(sesskey, "AuthKI", conf_get_bool(conf, CONF_try_ki_auth)); + write_setting_b(sesskey, "AuthGSSAPI", conf_get_bool(conf, CONF_try_gssapi_auth)); + write_setting_b(sesskey, "AuthGSSAPIKEX", conf_get_bool(conf, CONF_try_gssapi_kex)); #ifndef NO_GSSAPI wprefs(sesskey, "GSSLibs", gsslibkeywords, ngsslibs, conf, CONF_ssh_gsslist); write_setting_filename(sesskey, "GSSCustom", conf_get_filename(conf, CONF_ssh_gss_custom)); #endif - write_setting_i(sesskey, "SshNoShell", conf_get_int(conf, CONF_ssh_no_shell)); + write_setting_b(sesskey, "SshNoShell", conf_get_bool(conf, CONF_ssh_no_shell)); write_setting_i(sesskey, "SshProt", conf_get_int(conf, CONF_sshprot)); write_setting_s(sesskey, "LogHost", conf_get_str(conf, CONF_loghost)); - write_setting_i(sesskey, "SSH2DES", conf_get_int(conf, CONF_ssh2_des_cbc)); + write_setting_b(sesskey, "SSH2DES", conf_get_bool(conf, CONF_ssh2_des_cbc)); write_setting_filename(sesskey, "PublicKeyFile", conf_get_filename(conf, CONF_keyfile)); write_setting_s(sesskey, "RemoteCommand", conf_get_str(conf, CONF_remote_cmd)); - write_setting_i(sesskey, "RFCEnviron", conf_get_int(conf, CONF_rfc_environ)); - write_setting_i(sesskey, "PassiveTelnet", conf_get_int(conf, CONF_passive_telnet)); - write_setting_i(sesskey, "BackspaceIsDelete", conf_get_int(conf, CONF_bksp_is_delete)); - write_setting_i(sesskey, "RXVTHomeEnd", conf_get_int(conf, CONF_rxvt_homeend)); + write_setting_b(sesskey, "RFCEnviron", conf_get_bool(conf, CONF_rfc_environ)); + write_setting_b(sesskey, "PassiveTelnet", conf_get_bool(conf, CONF_passive_telnet)); + write_setting_b(sesskey, "BackspaceIsDelete", conf_get_bool(conf, CONF_bksp_is_delete)); + write_setting_b(sesskey, "RXVTHomeEnd", conf_get_bool(conf, CONF_rxvt_homeend)); write_setting_i(sesskey, "LinuxFunctionKeys", conf_get_int(conf, CONF_funky_type)); - write_setting_i(sesskey, "NoApplicationKeys", conf_get_int(conf, CONF_no_applic_k)); - write_setting_i(sesskey, "NoApplicationCursors", conf_get_int(conf, CONF_no_applic_c)); - write_setting_i(sesskey, "NoMouseReporting", conf_get_int(conf, CONF_no_mouse_rep)); - write_setting_i(sesskey, "NoRemoteResize", conf_get_int(conf, CONF_no_remote_resize)); - write_setting_i(sesskey, "NoAltScreen", conf_get_int(conf, CONF_no_alt_screen)); - write_setting_i(sesskey, "NoRemoteWinTitle", conf_get_int(conf, CONF_no_remote_wintitle)); - write_setting_i(sesskey, "NoRemoteClearScroll", conf_get_int(conf, CONF_no_remote_clearscroll)); + write_setting_b(sesskey, "NoApplicationKeys", conf_get_bool(conf, CONF_no_applic_k)); + write_setting_b(sesskey, "NoApplicationCursors", conf_get_bool(conf, CONF_no_applic_c)); + write_setting_b(sesskey, "NoMouseReporting", conf_get_bool(conf, CONF_no_mouse_rep)); + write_setting_b(sesskey, "NoRemoteResize", conf_get_bool(conf, CONF_no_remote_resize)); + write_setting_b(sesskey, "NoAltScreen", conf_get_bool(conf, CONF_no_alt_screen)); + write_setting_b(sesskey, "NoRemoteWinTitle", conf_get_bool(conf, CONF_no_remote_wintitle)); + write_setting_b(sesskey, "NoRemoteClearScroll", conf_get_bool(conf, CONF_no_remote_clearscroll)); write_setting_i(sesskey, "RemoteQTitleAction", conf_get_int(conf, CONF_remote_qtitle_action)); - write_setting_i(sesskey, "NoDBackspace", conf_get_int(conf, CONF_no_dbackspace)); - write_setting_i(sesskey, "NoRemoteCharset", conf_get_int(conf, CONF_no_remote_charset)); - write_setting_i(sesskey, "ApplicationCursorKeys", conf_get_int(conf, CONF_app_cursor)); - write_setting_i(sesskey, "ApplicationKeypad", conf_get_int(conf, CONF_app_keypad)); - write_setting_i(sesskey, "NetHackKeypad", conf_get_int(conf, CONF_nethack_keypad)); - write_setting_i(sesskey, "AltF4", conf_get_int(conf, CONF_alt_f4)); - write_setting_i(sesskey, "AltSpace", conf_get_int(conf, CONF_alt_space)); - write_setting_i(sesskey, "AltOnly", conf_get_int(conf, CONF_alt_only)); - write_setting_i(sesskey, "ComposeKey", conf_get_int(conf, CONF_compose_key)); - write_setting_i(sesskey, "CtrlAltKeys", conf_get_int(conf, CONF_ctrlaltkeys)); + write_setting_b(sesskey, "NoDBackspace", conf_get_bool(conf, CONF_no_dbackspace)); + write_setting_b(sesskey, "NoRemoteCharset", conf_get_bool(conf, CONF_no_remote_charset)); + write_setting_b(sesskey, "ApplicationCursorKeys", conf_get_bool(conf, CONF_app_cursor)); + write_setting_b(sesskey, "ApplicationKeypad", conf_get_bool(conf, CONF_app_keypad)); + write_setting_b(sesskey, "NetHackKeypad", conf_get_bool(conf, CONF_nethack_keypad)); + write_setting_b(sesskey, "AltF4", conf_get_bool(conf, CONF_alt_f4)); + write_setting_b(sesskey, "AltSpace", conf_get_bool(conf, CONF_alt_space)); + write_setting_b(sesskey, "AltOnly", conf_get_bool(conf, CONF_alt_only)); + write_setting_b(sesskey, "ComposeKey", conf_get_bool(conf, CONF_compose_key)); + write_setting_b(sesskey, "CtrlAltKeys", conf_get_bool(conf, CONF_ctrlaltkeys)); #ifdef OSX_META_KEY_CONFIG - write_setting_i(sesskey, "OSXOptionMeta", conf_get_int(conf, CONF_osx_option_meta)); - write_setting_i(sesskey, "OSXCommandMeta", conf_get_int(conf, CONF_osx_command_meta)); + write_setting_b(sesskey, "OSXOptionMeta", conf_get_bool(conf, CONF_osx_option_meta)); + write_setting_b(sesskey, "OSXCommandMeta", conf_get_bool(conf, CONF_osx_command_meta)); #endif - write_setting_i(sesskey, "TelnetKey", conf_get_int(conf, CONF_telnet_keyboard)); - write_setting_i(sesskey, "TelnetRet", conf_get_int(conf, CONF_telnet_newline)); + write_setting_b(sesskey, "TelnetKey", conf_get_bool(conf, CONF_telnet_keyboard)); + write_setting_b(sesskey, "TelnetRet", conf_get_bool(conf, CONF_telnet_newline)); write_setting_i(sesskey, "LocalEcho", conf_get_int(conf, CONF_localecho)); write_setting_i(sesskey, "LocalEdit", conf_get_int(conf, CONF_localedit)); write_setting_s(sesskey, "Answerback", conf_get_str(conf, CONF_answerback)); - write_setting_i(sesskey, "AlwaysOnTop", conf_get_int(conf, CONF_alwaysontop)); - write_setting_i(sesskey, "FullScreenOnAltEnter", conf_get_int(conf, CONF_fullscreenonaltenter)); - write_setting_i(sesskey, "HideMousePtr", conf_get_int(conf, CONF_hide_mouseptr)); - write_setting_i(sesskey, "SunkenEdge", conf_get_int(conf, CONF_sunken_edge)); + write_setting_b(sesskey, "AlwaysOnTop", conf_get_bool(conf, CONF_alwaysontop)); + write_setting_b(sesskey, "FullScreenOnAltEnter", conf_get_bool(conf, CONF_fullscreenonaltenter)); + write_setting_b(sesskey, "HideMousePtr", conf_get_bool(conf, CONF_hide_mouseptr)); + write_setting_b(sesskey, "SunkenEdge", conf_get_bool(conf, CONF_sunken_edge)); write_setting_i(sesskey, "WindowBorder", conf_get_int(conf, CONF_window_border)); write_setting_i(sesskey, "CurType", conf_get_int(conf, CONF_cursor_type)); - write_setting_i(sesskey, "BlinkCur", conf_get_int(conf, CONF_blink_cur)); + write_setting_b(sesskey, "BlinkCur", conf_get_bool(conf, CONF_blink_cur)); write_setting_i(sesskey, "Beep", conf_get_int(conf, CONF_beep)); write_setting_i(sesskey, "BeepInd", conf_get_int(conf, CONF_beep_ind)); write_setting_filename(sesskey, "BellWaveFile", conf_get_filename(conf, CONF_bell_wavefile)); - write_setting_i(sesskey, "BellOverload", conf_get_int(conf, CONF_bellovl)); + write_setting_b(sesskey, "BellOverload", conf_get_bool(conf, CONF_bellovl)); write_setting_i(sesskey, "BellOverloadN", conf_get_int(conf, CONF_bellovl_n)); write_setting_i(sesskey, "BellOverloadT", conf_get_int(conf, CONF_bellovl_t) #ifdef PUTTY_UNIX_H @@ -652,24 +669,24 @@ void save_open_settings(settings_w *sesskey, Conf *conf) #endif ); write_setting_i(sesskey, "ScrollbackLines", conf_get_int(conf, CONF_savelines)); - write_setting_i(sesskey, "DECOriginMode", conf_get_int(conf, CONF_dec_om)); - write_setting_i(sesskey, "AutoWrapMode", conf_get_int(conf, CONF_wrap_mode)); - write_setting_i(sesskey, "LFImpliesCR", conf_get_int(conf, CONF_lfhascr)); - write_setting_i(sesskey, "CRImpliesLF", conf_get_int(conf, CONF_crhaslf)); - write_setting_i(sesskey, "DisableArabicShaping", conf_get_int(conf, CONF_arabicshaping)); - write_setting_i(sesskey, "DisableBidi", conf_get_int(conf, CONF_bidi)); - write_setting_i(sesskey, "WinNameAlways", conf_get_int(conf, CONF_win_name_always)); + write_setting_b(sesskey, "DECOriginMode", conf_get_bool(conf, CONF_dec_om)); + write_setting_b(sesskey, "AutoWrapMode", conf_get_bool(conf, CONF_wrap_mode)); + write_setting_b(sesskey, "LFImpliesCR", conf_get_bool(conf, CONF_lfhascr)); + write_setting_b(sesskey, "CRImpliesLF", conf_get_bool(conf, CONF_crhaslf)); + write_setting_b(sesskey, "DisableArabicShaping", conf_get_bool(conf, CONF_arabicshaping)); + write_setting_b(sesskey, "DisableBidi", conf_get_bool(conf, CONF_bidi)); + write_setting_b(sesskey, "WinNameAlways", conf_get_bool(conf, CONF_win_name_always)); write_setting_s(sesskey, "WinTitle", conf_get_str(conf, CONF_wintitle)); write_setting_i(sesskey, "TermWidth", conf_get_int(conf, CONF_width)); write_setting_i(sesskey, "TermHeight", conf_get_int(conf, CONF_height)); write_setting_fontspec(sesskey, "Font", conf_get_fontspec(conf, CONF_font)); write_setting_i(sesskey, "FontQuality", conf_get_int(conf, CONF_font_quality)); write_setting_i(sesskey, "FontVTMode", conf_get_int(conf, CONF_vtmode)); - write_setting_i(sesskey, "UseSystemColours", conf_get_int(conf, CONF_system_colour)); - write_setting_i(sesskey, "TryPalette", conf_get_int(conf, CONF_try_palette)); - write_setting_i(sesskey, "ANSIColour", conf_get_int(conf, CONF_ansi_colour)); - write_setting_i(sesskey, "Xterm256Colour", conf_get_int(conf, CONF_xterm_256_colour)); - write_setting_i(sesskey, "TrueColour", conf_get_int(conf, CONF_true_colour)); + write_setting_b(sesskey, "UseSystemColours", conf_get_bool(conf, CONF_system_colour)); + write_setting_b(sesskey, "TryPalette", conf_get_bool(conf, CONF_try_palette)); + write_setting_b(sesskey, "ANSIColour", conf_get_bool(conf, CONF_ansi_colour)); + write_setting_b(sesskey, "Xterm256Colour", conf_get_bool(conf, CONF_xterm_256_colour)); + write_setting_b(sesskey, "TrueColour", conf_get_bool(conf, CONF_true_colour)); write_setting_i(sesskey, "BoldAsColour", conf_get_int(conf, CONF_bold_style)-1); for (i = 0; i < 22; i++) { @@ -681,13 +698,13 @@ void save_open_settings(settings_w *sesskey, Conf *conf) conf_get_int_int(conf, CONF_colours, i*3+2)); write_setting_s(sesskey, buf, buf2); } - write_setting_i(sesskey, "RawCNP", conf_get_int(conf, CONF_rawcnp)); - write_setting_i(sesskey, "UTF8linedraw", conf_get_int(conf, CONF_utf8linedraw)); - write_setting_i(sesskey, "PasteRTF", conf_get_int(conf, CONF_rtf_paste)); + write_setting_b(sesskey, "RawCNP", conf_get_bool(conf, CONF_rawcnp)); + write_setting_b(sesskey, "UTF8linedraw", conf_get_bool(conf, CONF_utf8linedraw)); + write_setting_b(sesskey, "PasteRTF", conf_get_bool(conf, CONF_rtf_paste)); write_setting_i(sesskey, "MouseIsXterm", conf_get_int(conf, CONF_mouse_is_xterm)); - write_setting_i(sesskey, "RectSelect", conf_get_int(conf, CONF_rect_select)); - write_setting_i(sesskey, "PasteControls", conf_get_int(conf, CONF_paste_controls)); - write_setting_i(sesskey, "MouseOverride", conf_get_int(conf, CONF_mouse_override)); + write_setting_b(sesskey, "RectSelect", conf_get_bool(conf, CONF_rect_select)); + write_setting_b(sesskey, "PasteControls", conf_get_bool(conf, CONF_paste_controls)); + write_setting_b(sesskey, "MouseOverride", conf_get_bool(conf, CONF_mouse_override)); for (i = 0; i < 256; i += 32) { char buf[20], buf2[256]; int j; @@ -700,8 +717,8 @@ void save_open_settings(settings_w *sesskey, Conf *conf) } write_setting_s(sesskey, buf, buf2); } - write_setting_i(sesskey, "MouseAutocopy", - conf_get_int(conf, CONF_mouseautocopy)); + write_setting_b(sesskey, "MouseAutocopy", + conf_get_bool(conf, CONF_mouseautocopy)); write_clip_setting(sesskey, "MousePaste", conf, CONF_mousepaste, CONF_mousepaste_custom); write_clip_setting(sesskey, "CtrlShiftIns", conf, @@ -709,24 +726,24 @@ void save_open_settings(settings_w *sesskey, Conf *conf) write_clip_setting(sesskey, "CtrlShiftCV", conf, CONF_ctrlshiftcv, CONF_ctrlshiftcv_custom); write_setting_s(sesskey, "LineCodePage", conf_get_str(conf, CONF_line_codepage)); - write_setting_i(sesskey, "CJKAmbigWide", conf_get_int(conf, CONF_cjk_ambig_wide)); - write_setting_i(sesskey, "UTF8Override", conf_get_int(conf, CONF_utf8_override)); + write_setting_b(sesskey, "CJKAmbigWide", conf_get_bool(conf, CONF_cjk_ambig_wide)); + write_setting_b(sesskey, "UTF8Override", conf_get_bool(conf, CONF_utf8_override)); write_setting_s(sesskey, "Printer", conf_get_str(conf, CONF_printer)); - write_setting_i(sesskey, "CapsLockCyr", conf_get_int(conf, CONF_xlat_capslockcyr)); - write_setting_i(sesskey, "ScrollBar", conf_get_int(conf, CONF_scrollbar)); - write_setting_i(sesskey, "ScrollBarFullScreen", conf_get_int(conf, CONF_scrollbar_in_fullscreen)); - write_setting_i(sesskey, "ScrollOnKey", conf_get_int(conf, CONF_scroll_on_key)); - write_setting_i(sesskey, "ScrollOnDisp", conf_get_int(conf, CONF_scroll_on_disp)); - write_setting_i(sesskey, "EraseToScrollback", conf_get_int(conf, CONF_erase_to_scrollback)); + write_setting_b(sesskey, "CapsLockCyr", conf_get_bool(conf, CONF_xlat_capslockcyr)); + write_setting_b(sesskey, "ScrollBar", conf_get_bool(conf, CONF_scrollbar)); + write_setting_b(sesskey, "ScrollBarFullScreen", conf_get_bool(conf, CONF_scrollbar_in_fullscreen)); + write_setting_b(sesskey, "ScrollOnKey", conf_get_bool(conf, CONF_scroll_on_key)); + write_setting_b(sesskey, "ScrollOnDisp", conf_get_bool(conf, CONF_scroll_on_disp)); + write_setting_b(sesskey, "EraseToScrollback", conf_get_bool(conf, CONF_erase_to_scrollback)); write_setting_i(sesskey, "LockSize", conf_get_int(conf, CONF_resize_action)); - write_setting_i(sesskey, "BCE", conf_get_int(conf, CONF_bce)); - write_setting_i(sesskey, "BlinkText", conf_get_int(conf, CONF_blinktext)); - write_setting_i(sesskey, "X11Forward", conf_get_int(conf, CONF_x11_forward)); + write_setting_b(sesskey, "BCE", conf_get_bool(conf, CONF_bce)); + write_setting_b(sesskey, "BlinkText", conf_get_bool(conf, CONF_blinktext)); + write_setting_b(sesskey, "X11Forward", conf_get_bool(conf, CONF_x11_forward)); write_setting_s(sesskey, "X11Display", conf_get_str(conf, CONF_x11_display)); write_setting_i(sesskey, "X11AuthType", conf_get_int(conf, CONF_x11_auth)); write_setting_filename(sesskey, "X11AuthFile", conf_get_filename(conf, CONF_xauthfile)); - write_setting_i(sesskey, "LocalPortAcceptAll", conf_get_int(conf, CONF_lport_acceptall)); - write_setting_i(sesskey, "RemotePortAcceptAll", conf_get_int(conf, CONF_rport_acceptall)); + write_setting_b(sesskey, "LocalPortAcceptAll", conf_get_bool(conf, CONF_lport_acceptall)); + write_setting_b(sesskey, "RemotePortAcceptAll", conf_get_bool(conf, CONF_rport_acceptall)); wmap(sesskey, "PortForwardings", conf, CONF_portfwd, true); write_setting_i(sesskey, "BugIgnore1", 2-conf_get_int(conf, CONF_sshbug_ignore1)); write_setting_i(sesskey, "BugPlainPW1", 2-conf_get_int(conf, CONF_sshbug_plainpw1)); @@ -741,13 +758,13 @@ void save_open_settings(settings_w *sesskey, Conf *conf) write_setting_i(sesskey, "BugOldGex2", 2-conf_get_int(conf, CONF_sshbug_oldgex2)); write_setting_i(sesskey, "BugWinadj", 2-conf_get_int(conf, CONF_sshbug_winadj)); write_setting_i(sesskey, "BugChanReq", 2-conf_get_int(conf, CONF_sshbug_chanreq)); - write_setting_i(sesskey, "StampUtmp", conf_get_int(conf, CONF_stamp_utmp)); - write_setting_i(sesskey, "LoginShell", conf_get_int(conf, CONF_login_shell)); - write_setting_i(sesskey, "ScrollbarOnLeft", conf_get_int(conf, CONF_scrollbar_on_left)); + write_setting_b(sesskey, "StampUtmp", conf_get_bool(conf, CONF_stamp_utmp)); + write_setting_b(sesskey, "LoginShell", conf_get_bool(conf, CONF_login_shell)); + write_setting_b(sesskey, "ScrollbarOnLeft", conf_get_bool(conf, CONF_scrollbar_on_left)); write_setting_fontspec(sesskey, "BoldFont", conf_get_fontspec(conf, CONF_boldfont)); write_setting_fontspec(sesskey, "WideFont", conf_get_fontspec(conf, CONF_widefont)); write_setting_fontspec(sesskey, "WideBoldFont", conf_get_fontspec(conf, CONF_wideboldfont)); - write_setting_i(sesskey, "ShadowBold", conf_get_int(conf, CONF_shadowbold)); + write_setting_b(sesskey, "ShadowBold", conf_get_bool(conf, CONF_shadowbold)); write_setting_i(sesskey, "ShadowBoldOffset", conf_get_int(conf, CONF_shadowboldoffset)); write_setting_s(sesskey, "SerialLine", conf_get_str(conf, CONF_serline)); write_setting_i(sesskey, "SerialSpeed", conf_get_int(conf, CONF_serspeed)); @@ -756,9 +773,9 @@ void save_open_settings(settings_w *sesskey, Conf *conf) write_setting_i(sesskey, "SerialParity", conf_get_int(conf, CONF_serparity)); write_setting_i(sesskey, "SerialFlowControl", conf_get_int(conf, CONF_serflow)); write_setting_s(sesskey, "WindowClass", conf_get_str(conf, CONF_winclass)); - write_setting_i(sesskey, "ConnectionSharing", conf_get_int(conf, CONF_ssh_connection_sharing)); - write_setting_i(sesskey, "ConnectionSharingUpstream", conf_get_int(conf, CONF_ssh_connection_sharing_upstream)); - write_setting_i(sesskey, "ConnectionSharingDownstream", conf_get_int(conf, CONF_ssh_connection_sharing_downstream)); + write_setting_b(sesskey, "ConnectionSharing", conf_get_bool(conf, CONF_ssh_connection_sharing)); + write_setting_b(sesskey, "ConnectionSharingUpstream", conf_get_bool(conf, CONF_ssh_connection_sharing_upstream)); + write_setting_b(sesskey, "ConnectionSharingDownstream", conf_get_bool(conf, CONF_ssh_connection_sharing_downstream)); wmap(sesskey, "SSHManualHostKeys", conf, CONF_ssh_manual_hostkeys, false); } @@ -779,7 +796,7 @@ void load_open_settings(settings_r *sesskey, Conf *conf) int i; char *prot; - conf_set_int(conf, CONF_ssh_subsys, 0); /* FIXME: load this properly */ + conf_set_bool(conf, CONF_ssh_subsys, false); /* FIXME: load this properly */ conf_set_str(conf, CONF_remote_cmd, ""); conf_set_str(conf, CONF_remote_cmd2, ""); conf_set_str(conf, CONF_ssh_nc_host, ""); @@ -788,10 +805,10 @@ void load_open_settings(settings_r *sesskey, Conf *conf) gppfile(sesskey, "LogFileName", conf, CONF_logfilename); gppi(sesskey, "LogType", 0, conf, CONF_logtype); gppi(sesskey, "LogFileClash", LGXF_ASK, conf, CONF_logxfovr); - gppi(sesskey, "LogFlush", 1, conf, CONF_logflush); - gppi(sesskey, "LogHeader", 1, conf, CONF_logheader); - gppi(sesskey, "SSHLogOmitPasswords", 1, conf, CONF_logomitpass); - gppi(sesskey, "SSHLogOmitData", 0, conf, CONF_logomitdata); + gppb(sesskey, "LogFlush", 1, conf, CONF_logflush); + gppb(sesskey, "LogHeader", 1, conf, CONF_logheader); + gppb(sesskey, "SSHLogOmitPasswords", 1, conf, CONF_logomitpass); + gppb(sesskey, "SSHLogOmitData", 0, conf, CONF_logomitdata); prot = gpps_raw(sesskey, "Protocol", "default"); conf_set_int(conf, CONF_protocol, default_protocol); @@ -811,7 +828,7 @@ void load_open_settings(settings_r *sesskey, Conf *conf) /* The CloseOnExit numbers are arranged in a different order from * the standard FORCE_ON / FORCE_OFF / AUTO. */ i = gppi_raw(sesskey, "CloseOnExit", 1); conf_set_int(conf, CONF_close_on_exit, (i+1)%3); - gppi(sesskey, "WarnOnClose", 1, conf, CONF_warn_on_close); + gppb(sesskey, "WarnOnClose", 1, conf, CONF_warn_on_close); { /* This is two values for backward compatibility with 0.50/0.51 */ int pingmin, pingsec; @@ -819,8 +836,8 @@ void load_open_settings(settings_r *sesskey, Conf *conf) pingsec = gppi_raw(sesskey, "PingIntervalSecs", 0); conf_set_int(conf, CONF_ping_interval, pingmin * 60 + pingsec); } - gppi(sesskey, "TCPNoDelay", 1, conf, CONF_tcp_nodelay); - gppi(sesskey, "TCPKeepalives", 0, conf, CONF_tcp_keepalives); + gppb(sesskey, "TCPNoDelay", 1, conf, CONF_tcp_nodelay); + gppb(sesskey, "TCPKeepalives", 0, conf, CONF_tcp_keepalives); gpps(sesskey, "TerminalType", "xterm", conf, CONF_termtype); gpps(sesskey, "TerminalSpeed", "38400,38400", conf, CONF_termspeed); if (gppmap(sesskey, "TerminalModes", conf, CONF_ttymodes)) { @@ -877,7 +894,7 @@ void load_open_settings(settings_r *sesskey, Conf *conf) /* proxy settings */ gpps(sesskey, "ProxyExcludeList", "", conf, CONF_proxy_exclude_list); i = gppi_raw(sesskey, "ProxyDNS", 1); conf_set_int(conf, CONF_proxy_dns, (i+1)%3); - gppi(sesskey, "ProxyLocalhost", 0, conf, CONF_even_proxy_localhost); + gppb(sesskey, "ProxyLocalhost", 0, conf, CONF_even_proxy_localhost); gppi(sesskey, "ProxyMethod", -1, conf, CONF_proxy_type); if (conf_get_int(conf, CONF_proxy_type) == -1) { int i; @@ -907,14 +924,14 @@ void load_open_settings(settings_r *sesskey, Conf *conf) gppi(sesskey, "ProxyLogToTerm", FORCE_OFF, conf, CONF_proxy_log_to_term); gppmap(sesskey, "Environment", conf, CONF_environmt); gpps(sesskey, "UserName", "", conf, CONF_username); - gppi(sesskey, "UserNameFromEnvironment", 0, conf, CONF_username_from_env); + gppb(sesskey, "UserNameFromEnvironment", 0, conf, CONF_username_from_env); gpps(sesskey, "LocalUserName", "", conf, CONF_localusername); - gppi(sesskey, "NoPTY", 0, conf, CONF_nopty); - gppi(sesskey, "Compression", 0, conf, CONF_compression); - gppi(sesskey, "TryAgent", 1, conf, CONF_tryagent); - gppi(sesskey, "AgentFwd", 0, conf, CONF_agentfwd); - gppi(sesskey, "ChangeUsername", 0, conf, CONF_change_username); - gppi(sesskey, "GssapiFwd", 0, conf, CONF_gssapifwd); + gppb(sesskey, "NoPTY", 0, conf, CONF_nopty); + gppb(sesskey, "Compression", 0, conf, CONF_compression); + gppb(sesskey, "TryAgent", 1, conf, CONF_tryagent); + gppb(sesskey, "AgentFwd", 0, conf, CONF_agentfwd); + gppb(sesskey, "ChangeUsername", 0, conf, CONF_change_username); + gppb(sesskey, "GssapiFwd", 0, conf, CONF_gssapifwd); gprefs(sesskey, "Cipher", "\0", ciphernames, CIPHER_MAX, conf, CONF_ssh_cipherlist); { @@ -979,33 +996,33 @@ void load_open_settings(settings_r *sesskey, Conf *conf) conf_set_int(conf, CONF_sshprot, sshprot); } gpps(sesskey, "LogHost", "", conf, CONF_loghost); - gppi(sesskey, "SSH2DES", 0, conf, CONF_ssh2_des_cbc); - gppi(sesskey, "SshNoAuth", 0, conf, CONF_ssh_no_userauth); - gppi(sesskey, "SshBanner", 1, conf, CONF_ssh_show_banner); - gppi(sesskey, "AuthTIS", 0, conf, CONF_try_tis_auth); - gppi(sesskey, "AuthKI", 1, conf, CONF_try_ki_auth); - gppi(sesskey, "AuthGSSAPI", 1, conf, CONF_try_gssapi_auth); - gppi(sesskey, "AuthGSSAPIKEX", 1, conf, CONF_try_gssapi_kex); + gppb(sesskey, "SSH2DES", 0, conf, CONF_ssh2_des_cbc); + gppb(sesskey, "SshNoAuth", 0, conf, CONF_ssh_no_userauth); + gppb(sesskey, "SshBanner", 1, conf, CONF_ssh_show_banner); + gppb(sesskey, "AuthTIS", 0, conf, CONF_try_tis_auth); + gppb(sesskey, "AuthKI", 1, conf, CONF_try_ki_auth); + gppb(sesskey, "AuthGSSAPI", 1, conf, CONF_try_gssapi_auth); + gppb(sesskey, "AuthGSSAPIKEX", 1, conf, CONF_try_gssapi_kex); #ifndef NO_GSSAPI gprefs(sesskey, "GSSLibs", "\0", gsslibkeywords, ngsslibs, conf, CONF_ssh_gsslist); gppfile(sesskey, "GSSCustom", conf, CONF_ssh_gss_custom); #endif - gppi(sesskey, "SshNoShell", 0, conf, CONF_ssh_no_shell); + gppb(sesskey, "SshNoShell", 0, conf, CONF_ssh_no_shell); gppfile(sesskey, "PublicKeyFile", conf, CONF_keyfile); gpps(sesskey, "RemoteCommand", "", conf, CONF_remote_cmd); - gppi(sesskey, "RFCEnviron", 0, conf, CONF_rfc_environ); - gppi(sesskey, "PassiveTelnet", 0, conf, CONF_passive_telnet); - gppi(sesskey, "BackspaceIsDelete", 1, conf, CONF_bksp_is_delete); - gppi(sesskey, "RXVTHomeEnd", 0, conf, CONF_rxvt_homeend); + gppb(sesskey, "RFCEnviron", 0, conf, CONF_rfc_environ); + gppb(sesskey, "PassiveTelnet", 0, conf, CONF_passive_telnet); + gppb(sesskey, "BackspaceIsDelete", 1, conf, CONF_bksp_is_delete); + gppb(sesskey, "RXVTHomeEnd", 0, conf, CONF_rxvt_homeend); gppi(sesskey, "LinuxFunctionKeys", 0, conf, CONF_funky_type); - gppi(sesskey, "NoApplicationKeys", 0, conf, CONF_no_applic_k); - gppi(sesskey, "NoApplicationCursors", 0, conf, CONF_no_applic_c); - gppi(sesskey, "NoMouseReporting", 0, conf, CONF_no_mouse_rep); - gppi(sesskey, "NoRemoteResize", 0, conf, CONF_no_remote_resize); - gppi(sesskey, "NoAltScreen", 0, conf, CONF_no_alt_screen); - gppi(sesskey, "NoRemoteWinTitle", 0, conf, CONF_no_remote_wintitle); - gppi(sesskey, "NoRemoteClearScroll", 0, conf, CONF_no_remote_clearscroll); + gppb(sesskey, "NoApplicationKeys", 0, conf, CONF_no_applic_k); + gppb(sesskey, "NoApplicationCursors", 0, conf, CONF_no_applic_c); + gppb(sesskey, "NoMouseReporting", 0, conf, CONF_no_mouse_rep); + gppb(sesskey, "NoRemoteResize", 0, conf, CONF_no_remote_resize); + gppb(sesskey, "NoAltScreen", 0, conf, CONF_no_alt_screen); + gppb(sesskey, "NoRemoteWinTitle", 0, conf, CONF_no_remote_wintitle); + gppb(sesskey, "NoRemoteClearScroll", 0, conf, CONF_no_remote_clearscroll); { /* Backward compatibility */ int no_remote_qtitle = gppi_raw(sesskey, "NoRemoteQTitle", 1); @@ -1016,37 +1033,37 @@ void load_open_settings(settings_r *sesskey, Conf *conf) no_remote_qtitle ? TITLE_EMPTY : TITLE_REAL, conf, CONF_remote_qtitle_action); } - gppi(sesskey, "NoDBackspace", 0, conf, CONF_no_dbackspace); - gppi(sesskey, "NoRemoteCharset", 0, conf, CONF_no_remote_charset); - gppi(sesskey, "ApplicationCursorKeys", 0, conf, CONF_app_cursor); - gppi(sesskey, "ApplicationKeypad", 0, conf, CONF_app_keypad); - gppi(sesskey, "NetHackKeypad", 0, conf, CONF_nethack_keypad); - gppi(sesskey, "AltF4", 1, conf, CONF_alt_f4); - gppi(sesskey, "AltSpace", 0, conf, CONF_alt_space); - gppi(sesskey, "AltOnly", 0, conf, CONF_alt_only); - gppi(sesskey, "ComposeKey", 0, conf, CONF_compose_key); - gppi(sesskey, "CtrlAltKeys", 1, conf, CONF_ctrlaltkeys); + gppb(sesskey, "NoDBackspace", 0, conf, CONF_no_dbackspace); + gppb(sesskey, "NoRemoteCharset", 0, conf, CONF_no_remote_charset); + gppb(sesskey, "ApplicationCursorKeys", 0, conf, CONF_app_cursor); + gppb(sesskey, "ApplicationKeypad", 0, conf, CONF_app_keypad); + gppb(sesskey, "NetHackKeypad", 0, conf, CONF_nethack_keypad); + gppb(sesskey, "AltF4", 1, conf, CONF_alt_f4); + gppb(sesskey, "AltSpace", 0, conf, CONF_alt_space); + gppb(sesskey, "AltOnly", 0, conf, CONF_alt_only); + gppb(sesskey, "ComposeKey", 0, conf, CONF_compose_key); + gppb(sesskey, "CtrlAltKeys", 1, conf, CONF_ctrlaltkeys); #ifdef OSX_META_KEY_CONFIG - gppi(sesskey, "OSXOptionMeta", 1, conf, CONF_osx_option_meta); - gppi(sesskey, "OSXCommandMeta", 0, conf, CONF_osx_command_meta); + gppb(sesskey, "OSXOptionMeta", 1, conf, CONF_osx_option_meta); + gppb(sesskey, "OSXCommandMeta", 0, conf, CONF_osx_command_meta); #endif - gppi(sesskey, "TelnetKey", 0, conf, CONF_telnet_keyboard); - gppi(sesskey, "TelnetRet", 1, conf, CONF_telnet_newline); + gppb(sesskey, "TelnetKey", 0, conf, CONF_telnet_keyboard); + gppb(sesskey, "TelnetRet", 1, conf, CONF_telnet_newline); gppi(sesskey, "LocalEcho", AUTO, conf, CONF_localecho); gppi(sesskey, "LocalEdit", AUTO, conf, CONF_localedit); gpps(sesskey, "Answerback", "PuTTY", conf, CONF_answerback); - gppi(sesskey, "AlwaysOnTop", 0, conf, CONF_alwaysontop); - gppi(sesskey, "FullScreenOnAltEnter", 0, conf, CONF_fullscreenonaltenter); - gppi(sesskey, "HideMousePtr", 0, conf, CONF_hide_mouseptr); - gppi(sesskey, "SunkenEdge", 0, conf, CONF_sunken_edge); + gppb(sesskey, "AlwaysOnTop", 0, conf, CONF_alwaysontop); + gppb(sesskey, "FullScreenOnAltEnter", 0, conf, CONF_fullscreenonaltenter); + gppb(sesskey, "HideMousePtr", 0, conf, CONF_hide_mouseptr); + gppb(sesskey, "SunkenEdge", 0, conf, CONF_sunken_edge); gppi(sesskey, "WindowBorder", 1, conf, CONF_window_border); gppi(sesskey, "CurType", 0, conf, CONF_cursor_type); - gppi(sesskey, "BlinkCur", 0, conf, CONF_blink_cur); + gppb(sesskey, "BlinkCur", 0, conf, CONF_blink_cur); /* pedantic compiler tells me I can't use conf, CONF_beep as an int * :-) */ gppi(sesskey, "Beep", 1, conf, CONF_beep); gppi(sesskey, "BeepInd", 0, conf, CONF_beep_ind); gppfile(sesskey, "BellWaveFile", conf, CONF_bell_wavefile); - gppi(sesskey, "BellOverload", 1, conf, CONF_bellovl); + gppb(sesskey, "BellOverload", 1, conf, CONF_bellovl); gppi(sesskey, "BellOverloadN", 5, conf, CONF_bellovl_n); i = gppi_raw(sesskey, "BellOverloadT", 2*TICKSPERSEC #ifdef PUTTY_UNIX_H @@ -1069,24 +1086,24 @@ void load_open_settings(settings_r *sesskey, Conf *conf) #endif ); gppi(sesskey, "ScrollbackLines", 2000, conf, CONF_savelines); - gppi(sesskey, "DECOriginMode", 0, conf, CONF_dec_om); - gppi(sesskey, "AutoWrapMode", 1, conf, CONF_wrap_mode); - gppi(sesskey, "LFImpliesCR", 0, conf, CONF_lfhascr); - gppi(sesskey, "CRImpliesLF", 0, conf, CONF_crhaslf); - gppi(sesskey, "DisableArabicShaping", 0, conf, CONF_arabicshaping); - gppi(sesskey, "DisableBidi", 0, conf, CONF_bidi); - gppi(sesskey, "WinNameAlways", 1, conf, CONF_win_name_always); + gppb(sesskey, "DECOriginMode", 0, conf, CONF_dec_om); + gppb(sesskey, "AutoWrapMode", 1, conf, CONF_wrap_mode); + gppb(sesskey, "LFImpliesCR", 0, conf, CONF_lfhascr); + gppb(sesskey, "CRImpliesLF", 0, conf, CONF_crhaslf); + gppb(sesskey, "DisableArabicShaping", 0, conf, CONF_arabicshaping); + gppb(sesskey, "DisableBidi", 0, conf, CONF_bidi); + gppb(sesskey, "WinNameAlways", 1, conf, CONF_win_name_always); gpps(sesskey, "WinTitle", "", conf, CONF_wintitle); gppi(sesskey, "TermWidth", 80, conf, CONF_width); gppi(sesskey, "TermHeight", 24, conf, CONF_height); gppfont(sesskey, "Font", conf, CONF_font); gppi(sesskey, "FontQuality", FQ_DEFAULT, conf, CONF_font_quality); gppi(sesskey, "FontVTMode", VT_UNICODE, conf, CONF_vtmode); - gppi(sesskey, "UseSystemColours", 0, conf, CONF_system_colour); - gppi(sesskey, "TryPalette", 0, conf, CONF_try_palette); - gppi(sesskey, "ANSIColour", 1, conf, CONF_ansi_colour); - gppi(sesskey, "Xterm256Colour", 1, conf, CONF_xterm_256_colour); - gppi(sesskey, "TrueColour", 1, conf, CONF_true_colour); + gppb(sesskey, "UseSystemColours", 0, conf, CONF_system_colour); + gppb(sesskey, "TryPalette", 0, conf, CONF_try_palette); + gppb(sesskey, "ANSIColour", 1, conf, CONF_ansi_colour); + gppb(sesskey, "Xterm256Colour", 1, conf, CONF_xterm_256_colour); + gppb(sesskey, "TrueColour", 1, conf, CONF_true_colour); i = gppi_raw(sesskey, "BoldAsColour", 1); conf_set_int(conf, CONF_bold_style, i+1); for (i = 0; i < 22; i++) { @@ -1108,13 +1125,13 @@ void load_open_settings(settings_r *sesskey, Conf *conf) } sfree(buf2); } - gppi(sesskey, "RawCNP", 0, conf, CONF_rawcnp); - gppi(sesskey, "UTF8linedraw", 0, conf, CONF_utf8linedraw); - gppi(sesskey, "PasteRTF", 0, conf, CONF_rtf_paste); + gppb(sesskey, "RawCNP", 0, conf, CONF_rawcnp); + gppb(sesskey, "UTF8linedraw", 0, conf, CONF_utf8linedraw); + gppb(sesskey, "PasteRTF", 0, conf, CONF_rtf_paste); gppi(sesskey, "MouseIsXterm", 0, conf, CONF_mouse_is_xterm); - gppi(sesskey, "RectSelect", 0, conf, CONF_rect_select); - gppi(sesskey, "PasteControls", 0, conf, CONF_paste_controls); - gppi(sesskey, "MouseOverride", 1, conf, CONF_mouse_override); + gppb(sesskey, "RectSelect", 0, conf, CONF_rect_select); + gppb(sesskey, "PasteControls", 0, conf, CONF_paste_controls); + gppb(sesskey, "MouseOverride", 1, conf, CONF_mouse_override); for (i = 0; i < 256; i += 32) { static const char *const defaults[] = { "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0", @@ -1141,7 +1158,7 @@ void load_open_settings(settings_r *sesskey, Conf *conf) } sfree(buf2); } - gppi(sesskey, "MouseAutocopy", CLIPUI_DEFAULT_AUTOCOPY, + gppb(sesskey, "MouseAutocopy", CLIPUI_DEFAULT_AUTOCOPY, conf, CONF_mouseautocopy); read_clip_setting(sesskey, "MousePaste", CLIPUI_DEFAULT_MOUSE, conf, CONF_mousepaste, CONF_mousepaste_custom); @@ -1154,25 +1171,25 @@ void load_open_settings(settings_r *sesskey, Conf *conf) * into a plausible default for the locale. */ gpps(sesskey, "LineCodePage", "", conf, CONF_line_codepage); - gppi(sesskey, "CJKAmbigWide", 0, conf, CONF_cjk_ambig_wide); - gppi(sesskey, "UTF8Override", 1, conf, CONF_utf8_override); + gppb(sesskey, "CJKAmbigWide", 0, conf, CONF_cjk_ambig_wide); + gppb(sesskey, "UTF8Override", 1, conf, CONF_utf8_override); gpps(sesskey, "Printer", "", conf, CONF_printer); - gppi(sesskey, "CapsLockCyr", 0, conf, CONF_xlat_capslockcyr); - gppi(sesskey, "ScrollBar", 1, conf, CONF_scrollbar); - gppi(sesskey, "ScrollBarFullScreen", 0, conf, CONF_scrollbar_in_fullscreen); - gppi(sesskey, "ScrollOnKey", 0, conf, CONF_scroll_on_key); - gppi(sesskey, "ScrollOnDisp", 1, conf, CONF_scroll_on_disp); - gppi(sesskey, "EraseToScrollback", 1, conf, CONF_erase_to_scrollback); + gppb(sesskey, "CapsLockCyr", 0, conf, CONF_xlat_capslockcyr); + gppb(sesskey, "ScrollBar", 1, conf, CONF_scrollbar); + gppb(sesskey, "ScrollBarFullScreen", 0, conf, CONF_scrollbar_in_fullscreen); + gppb(sesskey, "ScrollOnKey", 0, conf, CONF_scroll_on_key); + gppb(sesskey, "ScrollOnDisp", 1, conf, CONF_scroll_on_disp); + gppb(sesskey, "EraseToScrollback", 1, conf, CONF_erase_to_scrollback); gppi(sesskey, "LockSize", 0, conf, CONF_resize_action); - gppi(sesskey, "BCE", 1, conf, CONF_bce); - gppi(sesskey, "BlinkText", 0, conf, CONF_blinktext); - gppi(sesskey, "X11Forward", 0, conf, CONF_x11_forward); + gppb(sesskey, "BCE", 1, conf, CONF_bce); + gppb(sesskey, "BlinkText", 0, conf, CONF_blinktext); + gppb(sesskey, "X11Forward", 0, conf, CONF_x11_forward); gpps(sesskey, "X11Display", "", conf, CONF_x11_display); gppi(sesskey, "X11AuthType", X11_MIT, conf, CONF_x11_auth); gppfile(sesskey, "X11AuthFile", conf, CONF_xauthfile); - gppi(sesskey, "LocalPortAcceptAll", 0, conf, CONF_lport_acceptall); - gppi(sesskey, "RemotePortAcceptAll", 0, conf, CONF_rport_acceptall); + gppb(sesskey, "LocalPortAcceptAll", 0, conf, CONF_lport_acceptall); + gppb(sesskey, "RemotePortAcceptAll", 0, conf, CONF_rport_acceptall); gppmap(sesskey, "PortForwardings", conf, CONF_portfwd); i = gppi_raw(sesskey, "BugIgnore1", 0); conf_set_int(conf, CONF_sshbug_ignore1, 2-i); i = gppi_raw(sesskey, "BugPlainPW1", 0); conf_set_int(conf, CONF_sshbug_plainpw1, 2-i); @@ -1195,11 +1212,11 @@ void load_open_settings(settings_r *sesskey, Conf *conf) i = gppi_raw(sesskey, "BugOldGex2", 0); conf_set_int(conf, CONF_sshbug_oldgex2, 2-i); i = gppi_raw(sesskey, "BugWinadj", 0); conf_set_int(conf, CONF_sshbug_winadj, 2-i); i = gppi_raw(sesskey, "BugChanReq", 0); conf_set_int(conf, CONF_sshbug_chanreq, 2-i); - conf_set_int(conf, CONF_ssh_simple, false); - gppi(sesskey, "StampUtmp", 1, conf, CONF_stamp_utmp); - gppi(sesskey, "LoginShell", 1, conf, CONF_login_shell); - gppi(sesskey, "ScrollbarOnLeft", 0, conf, CONF_scrollbar_on_left); - gppi(sesskey, "ShadowBold", 0, conf, CONF_shadowbold); + conf_set_bool(conf, CONF_ssh_simple, false); + gppb(sesskey, "StampUtmp", 1, conf, CONF_stamp_utmp); + gppb(sesskey, "LoginShell", 1, conf, CONF_login_shell); + gppb(sesskey, "ScrollbarOnLeft", 0, conf, CONF_scrollbar_on_left); + gppb(sesskey, "ShadowBold", 0, conf, CONF_shadowbold); gppfont(sesskey, "BoldFont", conf, CONF_boldfont); gppfont(sesskey, "WideFont", conf, CONF_widefont); gppfont(sesskey, "WideBoldFont", conf, CONF_wideboldfont); @@ -1211,9 +1228,9 @@ void load_open_settings(settings_r *sesskey, Conf *conf) gppi(sesskey, "SerialParity", SER_PAR_NONE, conf, CONF_serparity); gppi(sesskey, "SerialFlowControl", SER_FLOW_XONXOFF, conf, CONF_serflow); gpps(sesskey, "WindowClass", "", conf, CONF_winclass); - gppi(sesskey, "ConnectionSharing", 0, conf, CONF_ssh_connection_sharing); - gppi(sesskey, "ConnectionSharingUpstream", 1, conf, CONF_ssh_connection_sharing_upstream); - gppi(sesskey, "ConnectionSharingDownstream", 1, conf, CONF_ssh_connection_sharing_downstream); + gppb(sesskey, "ConnectionSharing", 0, conf, CONF_ssh_connection_sharing); + gppb(sesskey, "ConnectionSharingUpstream", 1, conf, CONF_ssh_connection_sharing_upstream); + gppb(sesskey, "ConnectionSharingDownstream", 1, conf, CONF_ssh_connection_sharing_downstream); gppmap(sesskey, "SSHManualHostKeys", conf, CONF_ssh_manual_hostkeys); } diff --git a/ssh.c b/ssh.c index 808833ea..2a5dd85f 100644 --- a/ssh.c +++ b/ssh.c @@ -177,8 +177,8 @@ static void ssh_got_ssh_version(struct ssh_version_receiver *rcv, * ourselves), since then the assumption that we have only * one channel to worry about is not true after all. */ - int is_simple = - (conf_get_int(ssh->conf, CONF_ssh_simple) && !ssh->connshare); + bool is_simple = + (conf_get_bool(ssh->conf, CONF_ssh_simple) && !ssh->connshare); ssh->bpp = ssh2_bpp_new(ssh->logctx, &ssh->stats, false); ssh_connect_bpp(ssh); @@ -218,7 +218,7 @@ static void ssh_got_ssh_version(struct ssh_version_receiver *rcv, ssh_verstring_get_remote(old_bpp), &ssh->cl); ssh_connect_ppl(ssh, connection_layer); - if (conf_get_int(ssh->conf, CONF_ssh_no_userauth)) { + if (conf_get_bool(ssh->conf, CONF_ssh_no_userauth)) { userauth_layer = NULL; transport_child_layer = connection_layer; } else { @@ -227,12 +227,12 @@ static void ssh_got_ssh_version(struct ssh_version_receiver *rcv, userauth_layer = ssh2_userauth_new( connection_layer, ssh->savedhost, ssh->fullhostname, conf_get_filename(ssh->conf, CONF_keyfile), - conf_get_int(ssh->conf, CONF_tryagent), username, - conf_get_int(ssh->conf, CONF_change_username), - conf_get_int(ssh->conf, CONF_try_ki_auth), - conf_get_int(ssh->conf, CONF_try_gssapi_auth), - conf_get_int(ssh->conf, CONF_try_gssapi_kex), - conf_get_int(ssh->conf, CONF_gssapifwd), + conf_get_bool(ssh->conf, CONF_tryagent), username, + conf_get_bool(ssh->conf, CONF_change_username), + conf_get_bool(ssh->conf, CONF_try_ki_auth), + conf_get_bool(ssh->conf, CONF_try_gssapi_auth), + conf_get_bool(ssh->conf, CONF_try_gssapi_kex), + conf_get_bool(ssh->conf, CONF_gssapifwd), &ssh->gss_state); ssh_connect_ppl(ssh, userauth_layer); transport_child_layer = userauth_layer; @@ -781,8 +781,8 @@ static void ssh_throttle_all(Ssh *ssh, int enable, int bufsize) static void ssh_cache_conf_values(Ssh *ssh) { - ssh->pls.omit_passwords = conf_get_int(ssh->conf, CONF_logomitpass); - ssh->pls.omit_data = conf_get_int(ssh->conf, CONF_logomitdata); + ssh->pls.omit_passwords = conf_get_bool(ssh->conf, CONF_logomitpass); + ssh->pls.omit_data = conf_get_bool(ssh->conf, CONF_logomitdata); } /* diff --git a/ssh1connection.c b/ssh1connection.c index bdbc29b0..a7e09dfc 100644 --- a/ssh1connection.c +++ b/ssh1connection.c @@ -663,7 +663,7 @@ static int ssh1_agent_forwarding_permitted(ConnectionLayer *cl) { struct ssh1_connection_state *s = container_of(cl, struct ssh1_connection_state, cl); - return conf_get_int(s->conf, CONF_agentfwd) && agent_exists(); + return conf_get_bool(s->conf, CONF_agentfwd) && agent_exists(); } static void ssh1_connection_special_cmd(PacketProtocolLayer *ppl, diff --git a/ssh1login.c b/ssh1login.c index e58f4cd1..7efc068c 100644 --- a/ssh1login.c +++ b/ssh1login.c @@ -481,7 +481,7 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl) /* Check whether we're configured to try Pageant, and also whether * it's available. */ - s->try_agent_auth = (conf_get_int(s->conf, CONF_tryagent) && + s->try_agent_auth = (conf_get_bool(s->conf, CONF_tryagent) && agent_exists()); while (pktin->type == SSH1_SMSG_FAILURE) { @@ -793,7 +793,7 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl) */ s->cur_prompt = new_prompts(s->ppl.seat); - if (conf_get_int(s->conf, CONF_try_tis_auth) && + if (conf_get_bool(s->conf, CONF_try_tis_auth) && (s->supported_auths_mask & (1 << SSH1_AUTH_TIS)) && !s->tis_auth_refused) { s->pwpkt_type = SSH1_CMSG_AUTH_TIS_RESPONSE; @@ -842,7 +842,7 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl) ssh1_pkt_type(pktin->type)); return; } - } else if (conf_get_int(s->conf, CONF_try_tis_auth) && + } else if (conf_get_bool(s->conf, CONF_try_tis_auth) && (s->supported_auths_mask & (1 << SSH1_AUTH_CCARD)) && !s->ccard_auth_refused) { s->pwpkt_type = SSH1_CMSG_AUTH_CCARD_RESPONSE; @@ -1059,7 +1059,7 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl) ppl_logevent(("Authentication successful")); - if (conf_get_int(s->conf, CONF_compression)) { + if (conf_get_bool(s->conf, CONF_compression)) { ppl_logevent(("Requesting compression")); pkt = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_REQUEST_COMPRESSION); put_uint32(pkt, 6); /* gzip compression level */ diff --git a/ssh2connection.c b/ssh2connection.c index 04a44740..f717ae84 100644 --- a/ssh2connection.c +++ b/ssh2connection.c @@ -256,7 +256,7 @@ PacketProtocolLayer *ssh2_connection_new( * any at all channels (because our purpose is probably to be a * background port forwarder). */ - s->persistent = conf_get_int(s->conf, CONF_ssh_no_shell); + s->persistent = conf_get_bool(s->conf, CONF_ssh_no_shell); s->connshare = connshare; s->peer_verstring = dupstr(peer_verstring); @@ -1526,7 +1526,7 @@ static int ssh2_agent_forwarding_permitted(ConnectionLayer *cl) { struct ssh2_connection_state *s = container_of(cl, struct ssh2_connection_state, cl); - return conf_get_int(s->conf, CONF_agentfwd) && agent_exists(); + return conf_get_bool(s->conf, CONF_agentfwd) && agent_exists(); } static int ssh2_connection_get_specials( diff --git a/ssh2transport.c b/ssh2transport.c index c1f645c0..58886991 100644 --- a/ssh2transport.c +++ b/ssh2transport.c @@ -485,7 +485,7 @@ static void ssh2_write_kexinit_lists( preferred_ciphers[n_preferred_ciphers++] = &ssh2_blowfish; break; case CIPHER_DES: - if (conf_get_int(conf, CONF_ssh2_des_cbc)) + if (conf_get_bool(conf, CONF_ssh2_des_cbc)) preferred_ciphers[n_preferred_ciphers++] = &ssh2_des; break; case CIPHER_3DES: @@ -513,7 +513,7 @@ static void ssh2_write_kexinit_lists( /* * Set up preferred compression. */ - if (conf_get_int(conf, CONF_compression)) + if (conf_get_bool(conf, CONF_compression)) preferred_comp = &ssh_zlib; else preferred_comp = &ssh_comp_none; @@ -993,7 +993,7 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) * where the flag was set on the previous key exchange.) */ s->can_gssapi_keyex = false; - } else if (conf_get_int(s->conf, CONF_try_gssapi_kex)) { + } else if (conf_get_bool(s->conf, CONF_try_gssapi_kex)) { /* * We always check if we have GSS creds before we come up with * the kex algorithm list, otherwise future rekeys will fail @@ -1026,7 +1026,7 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) */ if (!s->got_session_id && (s->gss_status & GSS_CTXT_MAYFAIL) != 0) s->can_gssapi_keyex = 0; - s->gss_delegate = conf_get_int(s->conf, CONF_gssapifwd); + s->gss_delegate = conf_get_bool(s->conf, CONF_gssapifwd); } else { s->can_gssapi_keyex = false; } @@ -1676,8 +1676,8 @@ static void ssh2_transport_gss_update(struct ssh2_transport_state *s, */ if (s->shgss->libs->nlibraries == 0) return; - if (!conf_get_int(s->conf, CONF_try_gssapi_auth) && - !conf_get_int(s->conf, CONF_try_gssapi_kex)) + if (!conf_get_bool(s->conf, CONF_try_gssapi_auth) && + !conf_get_bool(s->conf, CONF_try_gssapi_kex)) return; /* Import server name and cache it */ @@ -1754,7 +1754,7 @@ static void ssh2_transport_gss_update(struct ssh2_transport_state *s, * refresh them. We must avoid setting GSS_CRED_UPDATED or * GSS_CTXT_EXPIRES when credential delegation is disabled. */ - if (conf_get_int(s->conf, CONF_gssapifwd) == 0) + if (conf_get_bool(s->conf, CONF_gssapifwd) == 0) return; if (s->gss_cred_expiry != GSS_NO_EXPIRATION && @@ -1918,8 +1918,8 @@ static void ssh2_transport_reconfigure(PacketProtocolLayer *ppl, Conf *conf) } } - if (conf_get_int(s->conf, CONF_compression) != - conf_get_int(conf, CONF_compression)) { + if (conf_get_bool(s->conf, CONF_compression) != + conf_get_bool(conf, CONF_compression)) { rekey_reason = "compression setting changed"; rekey_mandatory = true; } @@ -1930,8 +1930,8 @@ static void ssh2_transport_reconfigure(PacketProtocolLayer *ppl, Conf *conf) rekey_reason = "cipher settings changed"; rekey_mandatory = true; } - if (conf_get_int(s->conf, CONF_ssh2_des_cbc) != - conf_get_int(conf, CONF_ssh2_des_cbc)) { + if (conf_get_bool(s->conf, CONF_ssh2_des_cbc) != + conf_get_bool(conf, CONF_ssh2_des_cbc)) { rekey_reason = "cipher settings changed"; rekey_mandatory = true; } diff --git a/sshserver.c b/sshserver.c index f12ec5cd..a97dc86d 100644 --- a/sshserver.c +++ b/sshserver.c @@ -221,7 +221,7 @@ Plug *ssh_server_plug( srv->plug.vt = &ssh_server_plugvt; srv->conf = conf_copy(conf); srv->logctx = log_init(logpolicy, conf); - conf_set_int(srv->conf, CONF_ssh_no_shell, true); + conf_set_bool(srv->conf, CONF_ssh_no_shell, true); srv->nhostkeys = nhostkeys; srv->hostkeys = hostkeys; srv->hostkey1 = hostkey1; @@ -418,7 +418,7 @@ static void server_got_ssh_version(struct ssh_version_receiver *rcv, ssh2connection_server_configure(connection_layer, srv->sftpserver_vt); server_connect_ppl(srv, connection_layer); - if (conf_get_int(srv->conf, CONF_ssh_no_userauth)) { + if (conf_get_bool(srv->conf, CONF_ssh_no_userauth)) { userauth_layer = NULL; transport_child_layer = connection_layer; } else { diff --git a/sshshare.c b/sshshare.c index 227f213a..dd44a5c3 100644 --- a/sshshare.c +++ b/sshshare.c @@ -2077,12 +2077,12 @@ Socket *ssh_connection_sharing_init( Socket *sock, *toret = NULL; struct ssh_sharing_state *sharestate; - if (!conf_get_int(conf, CONF_ssh_connection_sharing)) + if (!conf_get_bool(conf, CONF_ssh_connection_sharing)) return NULL; /* do not share anything */ can_upstream = share_can_be_upstream && - conf_get_int(conf, CONF_ssh_connection_sharing_upstream); + conf_get_bool(conf, CONF_ssh_connection_sharing_upstream); can_downstream = share_can_be_downstream && - conf_get_int(conf, CONF_ssh_connection_sharing_downstream); + conf_get_bool(conf, CONF_ssh_connection_sharing_downstream); if (!can_upstream && !can_downstream) return NULL; diff --git a/telnet.c b/telnet.c index 5c7baa93..97bd8e5c 100644 --- a/telnet.c +++ b/telnet.c @@ -412,7 +412,7 @@ static void process_subneg(Telnet *telnet) logeventf(telnet->logctx, "server:\tSB %s SEND", telopt(telnet->sb_opt)); if (telnet->sb_opt == TELOPT_OLD_ENVIRON) { - if (conf_get_int(telnet->conf, CONF_rfc_environ)) { + if (conf_get_bool(telnet->conf, CONF_rfc_environ)) { value = RFC_VALUE; var = RFC_VAR; } else { @@ -746,7 +746,7 @@ static const char *telnet_init(Seat *seat, Backend **backend_handle, /* * Initialise option states. */ - if (conf_get_int(telnet->conf, CONF_passive_telnet)) { + if (conf_get_bool(telnet->conf, CONF_passive_telnet)) { const struct Opt *const *o; for (o = opts; *o; o++) diff --git a/terminal.c b/terminal.c index ff39968d..e99edea0 100644 --- a/terminal.c +++ b/terminal.c @@ -1286,11 +1286,11 @@ static void power_on(Terminal *term, int clear) for (i = 0; i < term->cols; i++) term->tabs[i] = (i % 8 == 0 ? true : false); } - term->alt_om = term->dec_om = conf_get_int(term->conf, CONF_dec_om); + term->alt_om = term->dec_om = conf_get_bool(term->conf, CONF_dec_om); term->alt_ins = term->insert = false; term->alt_wnext = term->wrapnext = term->save_wnext = term->alt_save_wnext = false; - term->alt_wrap = term->wrap = conf_get_int(term->conf, CONF_wrap_mode); + term->alt_wrap = term->wrap = conf_get_bool(term->conf, CONF_wrap_mode); term->alt_cset = term->cset = term->save_cset = term->alt_save_cset = 0; term->alt_utf = term->utf = term->save_utf = term->alt_save_utf = 0; term->utf_state = 0; @@ -1307,10 +1307,10 @@ static void power_on(Terminal *term, int clear) term->curr_truecolour.fg = term->curr_truecolour.bg = optionalrgb_none; term->save_truecolour = term->alt_save_truecolour = term->curr_truecolour; term->term_editing = term->term_echoing = false; - term->app_cursor_keys = conf_get_int(term->conf, CONF_app_cursor); - term->app_keypad_keys = conf_get_int(term->conf, CONF_app_keypad); - term->use_bce = conf_get_int(term->conf, CONF_bce); - term->blink_is_real = conf_get_int(term->conf, CONF_blinktext); + term->app_cursor_keys = conf_get_bool(term->conf, CONF_app_cursor); + term->app_keypad_keys = conf_get_bool(term->conf, CONF_app_keypad); + term->use_bce = conf_get_bool(term->conf, CONF_bce); + term->blink_is_real = conf_get_bool(term->conf, CONF_blinktext); term->erase_char = term->basic_erase_char; term->alt_which = 0; term_print_finish(term); @@ -1429,46 +1429,46 @@ static void set_erase_char(Terminal *term) */ void term_copy_stuff_from_conf(Terminal *term) { - term->ansi_colour = conf_get_int(term->conf, CONF_ansi_colour); - term->arabicshaping = conf_get_int(term->conf, CONF_arabicshaping); + term->ansi_colour = conf_get_bool(term->conf, CONF_ansi_colour); + term->arabicshaping = conf_get_bool(term->conf, CONF_arabicshaping); term->beep = conf_get_int(term->conf, CONF_beep); - term->bellovl = conf_get_int(term->conf, CONF_bellovl); + term->bellovl = conf_get_bool(term->conf, CONF_bellovl); term->bellovl_n = conf_get_int(term->conf, CONF_bellovl_n); term->bellovl_s = conf_get_int(term->conf, CONF_bellovl_s); term->bellovl_t = conf_get_int(term->conf, CONF_bellovl_t); - term->bidi = conf_get_int(term->conf, CONF_bidi); - term->bksp_is_delete = conf_get_int(term->conf, CONF_bksp_is_delete); - term->blink_cur = conf_get_int(term->conf, CONF_blink_cur); - term->blinktext = conf_get_int(term->conf, CONF_blinktext); - term->cjk_ambig_wide = conf_get_int(term->conf, CONF_cjk_ambig_wide); + term->bidi = conf_get_bool(term->conf, CONF_bidi); + term->bksp_is_delete = conf_get_bool(term->conf, CONF_bksp_is_delete); + term->blink_cur = conf_get_bool(term->conf, CONF_blink_cur); + term->blinktext = conf_get_bool(term->conf, CONF_blinktext); + term->cjk_ambig_wide = conf_get_bool(term->conf, CONF_cjk_ambig_wide); term->conf_height = conf_get_int(term->conf, CONF_height); term->conf_width = conf_get_int(term->conf, CONF_width); - term->crhaslf = conf_get_int(term->conf, CONF_crhaslf); - term->erase_to_scrollback = conf_get_int(term->conf, CONF_erase_to_scrollback); + term->crhaslf = conf_get_bool(term->conf, CONF_crhaslf); + term->erase_to_scrollback = conf_get_bool(term->conf, CONF_erase_to_scrollback); term->funky_type = conf_get_int(term->conf, CONF_funky_type); - term->lfhascr = conf_get_int(term->conf, CONF_lfhascr); - term->logflush = conf_get_int(term->conf, CONF_logflush); + term->lfhascr = conf_get_bool(term->conf, CONF_lfhascr); + term->logflush = conf_get_bool(term->conf, CONF_logflush); term->logtype = conf_get_int(term->conf, CONF_logtype); - term->mouse_override = conf_get_int(term->conf, CONF_mouse_override); - term->nethack_keypad = conf_get_int(term->conf, CONF_nethack_keypad); - term->no_alt_screen = conf_get_int(term->conf, CONF_no_alt_screen); - term->no_applic_c = conf_get_int(term->conf, CONF_no_applic_c); - term->no_applic_k = conf_get_int(term->conf, CONF_no_applic_k); - term->no_dbackspace = conf_get_int(term->conf, CONF_no_dbackspace); - term->no_mouse_rep = conf_get_int(term->conf, CONF_no_mouse_rep); - term->no_remote_charset = conf_get_int(term->conf, CONF_no_remote_charset); - term->no_remote_resize = conf_get_int(term->conf, CONF_no_remote_resize); - term->no_remote_wintitle = conf_get_int(term->conf, CONF_no_remote_wintitle); - term->no_remote_clearscroll = conf_get_int(term->conf, CONF_no_remote_clearscroll); - term->rawcnp = conf_get_int(term->conf, CONF_rawcnp); - term->utf8linedraw = conf_get_int(term->conf, CONF_utf8linedraw); - term->rect_select = conf_get_int(term->conf, CONF_rect_select); + term->mouse_override = conf_get_bool(term->conf, CONF_mouse_override); + term->nethack_keypad = conf_get_bool(term->conf, CONF_nethack_keypad); + term->no_alt_screen = conf_get_bool(term->conf, CONF_no_alt_screen); + term->no_applic_c = conf_get_bool(term->conf, CONF_no_applic_c); + term->no_applic_k = conf_get_bool(term->conf, CONF_no_applic_k); + term->no_dbackspace = conf_get_bool(term->conf, CONF_no_dbackspace); + term->no_mouse_rep = conf_get_bool(term->conf, CONF_no_mouse_rep); + term->no_remote_charset = conf_get_bool(term->conf, CONF_no_remote_charset); + term->no_remote_resize = conf_get_bool(term->conf, CONF_no_remote_resize); + term->no_remote_wintitle = conf_get_bool(term->conf, CONF_no_remote_wintitle); + term->no_remote_clearscroll = conf_get_bool(term->conf, CONF_no_remote_clearscroll); + term->rawcnp = conf_get_bool(term->conf, CONF_rawcnp); + term->utf8linedraw = conf_get_bool(term->conf, CONF_utf8linedraw); + term->rect_select = conf_get_bool(term->conf, CONF_rect_select); term->remote_qtitle_action = conf_get_int(term->conf, CONF_remote_qtitle_action); - term->rxvt_homeend = conf_get_int(term->conf, CONF_rxvt_homeend); - term->scroll_on_disp = conf_get_int(term->conf, CONF_scroll_on_disp); - term->scroll_on_key = conf_get_int(term->conf, CONF_scroll_on_key); - term->xterm_256_colour = conf_get_int(term->conf, CONF_xterm_256_colour); - term->true_colour = conf_get_int(term->conf, CONF_true_colour); + term->rxvt_homeend = conf_get_bool(term->conf, CONF_rxvt_homeend); + term->scroll_on_disp = conf_get_bool(term->conf, CONF_scroll_on_disp); + term->scroll_on_key = conf_get_bool(term->conf, CONF_scroll_on_key); + term->xterm_256_colour = conf_get_bool(term->conf, CONF_xterm_256_colour); + term->true_colour = conf_get_bool(term->conf, CONF_true_colour); /* * Parse the control-character escapes in the configured @@ -1512,14 +1512,14 @@ void term_reconfig(Terminal *term, Conf *conf) int reset_wrap, reset_decom, reset_bce, reset_tblink, reset_charclass; int i; - reset_wrap = (conf_get_int(term->conf, CONF_wrap_mode) != - conf_get_int(conf, CONF_wrap_mode)); - reset_decom = (conf_get_int(term->conf, CONF_dec_om) != - conf_get_int(conf, CONF_dec_om)); - reset_bce = (conf_get_int(term->conf, CONF_bce) != - conf_get_int(conf, CONF_bce)); - reset_tblink = (conf_get_int(term->conf, CONF_blinktext) != - conf_get_int(conf, CONF_blinktext)); + reset_wrap = (conf_get_bool(term->conf, CONF_wrap_mode) != + conf_get_bool(conf, CONF_wrap_mode)); + reset_decom = (conf_get_bool(term->conf, CONF_dec_om) != + conf_get_bool(conf, CONF_dec_om)); + reset_bce = (conf_get_bool(term->conf, CONF_bce) != + conf_get_bool(conf, CONF_bce)); + reset_tblink = (conf_get_bool(term->conf, CONF_blinktext) != + conf_get_bool(conf, CONF_blinktext)); reset_charclass = 0; for (i = 0; i < 256; i++) if (conf_get_int_int(term->conf, CONF_wordness, i) != @@ -1530,10 +1530,10 @@ void term_reconfig(Terminal *term, Conf *conf) * If the bidi or shaping settings have changed, flush the bidi * cache completely. */ - if (conf_get_int(term->conf, CONF_arabicshaping) != - conf_get_int(conf, CONF_arabicshaping) || - conf_get_int(term->conf, CONF_bidi) != - conf_get_int(conf, CONF_bidi)) { + if (conf_get_bool(term->conf, CONF_arabicshaping) != + conf_get_bool(conf, CONF_arabicshaping) || + conf_get_bool(term->conf, CONF_bidi) != + conf_get_bool(conf, CONF_bidi)) { for (i = 0; i < term->bidi_cache_size; i++) { sfree(term->pre_bidi_cache[i].chars); sfree(term->post_bidi_cache[i].chars); @@ -1548,27 +1548,27 @@ void term_reconfig(Terminal *term, Conf *conf) term->conf = conf_copy(conf); if (reset_wrap) - term->alt_wrap = term->wrap = conf_get_int(term->conf, CONF_wrap_mode); + term->alt_wrap = term->wrap = conf_get_bool(term->conf, CONF_wrap_mode); if (reset_decom) - term->alt_om = term->dec_om = conf_get_int(term->conf, CONF_dec_om); + term->alt_om = term->dec_om = conf_get_bool(term->conf, CONF_dec_om); if (reset_bce) { - term->use_bce = conf_get_int(term->conf, CONF_bce); + term->use_bce = conf_get_bool(term->conf, CONF_bce); set_erase_char(term); } if (reset_tblink) { - term->blink_is_real = conf_get_int(term->conf, CONF_blinktext); + term->blink_is_real = conf_get_bool(term->conf, CONF_blinktext); } if (reset_charclass) for (i = 0; i < 256; i++) term->wordness[i] = conf_get_int_int(term->conf, CONF_wordness, i); - if (conf_get_int(term->conf, CONF_no_alt_screen)) + if (conf_get_bool(term->conf, CONF_no_alt_screen)) swap_screen(term, 0, false, false); - if (conf_get_int(term->conf, CONF_no_mouse_rep)) { + if (conf_get_bool(term->conf, CONF_no_mouse_rep)) { term->xterm_mouse = 0; win_set_raw_mouse_mode(term->win, 0); } - if (conf_get_int(term->conf, CONF_no_remote_charset)) { + if (conf_get_bool(term->conf, CONF_no_remote_charset)) { term->cset_attr[0] = term->cset_attr[1] = CSET_ASCII; term->sco_acs = term->alt_sco_acs = 0; term->utf = 0; @@ -6065,7 +6065,7 @@ static int wstartswith(const wchar_t *a, size_t alen, void term_do_paste(Terminal *term, const wchar_t *data, int len) { const wchar_t *p; - int paste_controls = conf_get_int(term->conf, CONF_paste_controls); + int paste_controls = conf_get_bool(term->conf, CONF_paste_controls); /* * Pasting data into the terminal counts as a keyboard event (for diff --git a/unix/gtkmain.c b/unix/gtkmain.c index 8e357525..cacf56b8 100644 --- a/unix/gtkmain.c +++ b/unix/gtkmain.c @@ -486,31 +486,31 @@ int do_cmdline(int argc, char **argv, int do_everything, Conf *conf) } else if (!strcmp(p, "-ut-") || !strcmp(p, "+ut")) { SECOND_PASS_ONLY; - conf_set_int(conf, CONF_stamp_utmp, 0); + conf_set_bool(conf, CONF_stamp_utmp, false); } else if (!strcmp(p, "-ut")) { SECOND_PASS_ONLY; - conf_set_int(conf, CONF_stamp_utmp, 1); + conf_set_bool(conf, CONF_stamp_utmp, true); } else if (!strcmp(p, "-ls-") || !strcmp(p, "+ls")) { SECOND_PASS_ONLY; - conf_set_int(conf, CONF_login_shell, 0); + conf_set_bool(conf, CONF_login_shell, false); } else if (!strcmp(p, "-ls")) { SECOND_PASS_ONLY; - conf_set_int(conf, CONF_login_shell, 1); + conf_set_bool(conf, CONF_login_shell, true); } else if (!strcmp(p, "-nethack")) { SECOND_PASS_ONLY; - conf_set_int(conf, CONF_nethack_keypad, 1); + conf_set_bool(conf, CONF_nethack_keypad, true); } else if (!strcmp(p, "-sb-") || !strcmp(p, "+sb")) { SECOND_PASS_ONLY; - conf_set_int(conf, CONF_scrollbar, 0); + conf_set_bool(conf, CONF_scrollbar, false); } else if (!strcmp(p, "-sb")) { SECOND_PASS_ONLY; - conf_set_int(conf, CONF_scrollbar, 1); + conf_set_bool(conf, CONF_scrollbar, true); } else if (!strcmp(p, "-name")) { EXPECTS_ARG; diff --git a/unix/gtkwin.c b/unix/gtkwin.c index 2887d071..f88cba75 100644 --- a/unix/gtkwin.c +++ b/unix/gtkwin.c @@ -194,9 +194,9 @@ static void cache_conf_values(GtkFrontend *inst) inst->cursor_type = conf_get_int(inst->conf, CONF_cursor_type); #ifdef OSX_META_KEY_CONFIG inst->meta_mod_mask = 0; - if (conf_get_int(inst->conf, CONF_osx_option_meta)) + if (conf_get_bool(inst->conf, CONF_osx_option_meta)) inst->meta_mod_mask |= GDK_MOD1_MASK; - if (conf_get_int(inst->conf, CONF_osx_command_meta)) + if (conf_get_bool(inst->conf, CONF_osx_command_meta)) inst->meta_mod_mask |= GDK_MOD2_MASK; inst->system_mod_mask = GDK_MOD2_MASK & ~inst->meta_mod_mask; #else @@ -292,12 +292,19 @@ char *platform_default_s(const char *name) return NULL; } +bool platform_default_b(const char *name, bool def) +{ + if (!strcmp(name, "WinNameAlways")) { + /* X natively supports icon titles, so use 'em by default */ + return false; + } + return def; +} + int platform_default_i(const char *name, int def) { if (!strcmp(name, "CloseOnExit")) return 2; /* maps to FORCE_ON after painful rearrangement :-( */ - if (!strcmp(name, "WinNameAlways")) - return 0; /* X natively supports icon titles, so use 'em by default */ return def; } @@ -629,7 +636,7 @@ static void warn_on_close_callback(void *vctx, int result) */ gint delete_window(GtkWidget *widget, GdkEvent *event, GtkFrontend *inst) { - if (!inst->exited && conf_get_int(inst->conf, CONF_warn_on_close)) { + if (!inst->exited && conf_get_bool(inst->conf, CONF_warn_on_close)) { /* * We're not going to exit right now. We must put up a * warn-on-close dialog, unless one already exists, in which @@ -678,7 +685,7 @@ static void update_mouseptr(GtkFrontend *inst) static void show_mouseptr(GtkFrontend *inst, int show) { - if (!conf_get_int(inst->conf, CONF_hide_mouseptr)) + if (!conf_get_bool(inst->conf, CONF_hide_mouseptr)) show = 1; inst->mouseptr_visible = show; update_mouseptr(inst); @@ -973,8 +980,8 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) char output[256]; wchar_t ucsoutput[2]; int ucsval, start, end, special, output_charset, use_ucsoutput; - int nethack_mode, app_keypad_mode; - int generated_something = false; + bool nethack_mode, app_keypad_mode; + bool generated_something = false; #ifdef OSX_META_KEY_CONFIG if (event->state & inst->system_mod_mask) @@ -1371,9 +1378,9 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) special = false; use_ucsoutput = false; - nethack_mode = conf_get_int(inst->conf, CONF_nethack_keypad); + nethack_mode = conf_get_bool(inst->conf, CONF_nethack_keypad); app_keypad_mode = (inst->term->app_keypad_keys && - !conf_get_int(inst->conf, CONF_no_applic_k)); + !conf_get_bool(inst->conf, CONF_no_applic_k)); /* ALT+things gives leading Escape. */ output[0] = '\033'; @@ -1709,7 +1716,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) /* We don't let GTK tell us what Backspace is! We know better. */ if (event->keyval == GDK_KEY_BackSpace && !(event->state & GDK_SHIFT_MASK)) { - output[1] = conf_get_int(inst->conf, CONF_bksp_is_delete) ? + output[1] = conf_get_bool(inst->conf, CONF_bksp_is_delete) ? '\x7F' : '\x08'; #ifdef KEY_EVENT_DIAGNOSTICS debug((" - Backspace, translating as %02x\n", @@ -1722,7 +1729,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) /* For Shift Backspace, do opposite of what is configured. */ if (event->keyval == GDK_KEY_BackSpace && (event->state & GDK_SHIFT_MASK)) { - output[1] = conf_get_int(inst->conf, CONF_bksp_is_delete) ? + output[1] = conf_get_bool(inst->conf, CONF_bksp_is_delete) ? '\x08' : '\x7F'; #ifdef KEY_EVENT_DIAGNOSTICS debug((" - Shift-Backspace, translating as %02x\n", @@ -2049,7 +2056,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) goto done; } if ((code == 1 || code == 4) && - conf_get_int(inst->conf, CONF_rxvt_homeend)) { + conf_get_bool(inst->conf, CONF_rxvt_homeend)) { #ifdef KEY_EVENT_DIAGNOSTICS debug((" - rxvt style Home/End")); #endif @@ -2249,8 +2256,8 @@ gboolean scroll_internal(GtkFrontend *inst, gdouble delta, guint state, y = (ey - inst->window_border) / inst->font_height; raw_mouse_mode = - send_raw_mouse && !(shift && conf_get_int(inst->conf, - CONF_mouse_override)); + send_raw_mouse && !(shift && conf_get_bool(inst->conf, + CONF_mouse_override)); inst->cumulative_scroll += delta * SCROLL_INCREMENT_LINES; @@ -2300,8 +2307,8 @@ static gboolean button_internal(GtkFrontend *inst, GdkEventButton *event) alt = event->state & inst->meta_mod_mask; raw_mouse_mode = - send_raw_mouse && !(shift && conf_get_int(inst->conf, - CONF_mouse_override)); + send_raw_mouse && !(shift && conf_get_bool(inst->conf, + CONF_mouse_override)); if (!raw_mouse_mode) { if (event->button == 4 && event->type == GDK_BUTTON_PRESS) { @@ -2593,7 +2600,7 @@ static void gtk_seat_set_busy_status(Seat *seat, BusyStatus status) static void gtkwin_set_raw_mouse_mode(TermWin *tw, int activate) { GtkFrontend *inst = container_of(tw, GtkFrontend, termwin); - activate = activate && !conf_get_int(inst->conf, CONF_no_mouse_rep); + activate = activate && !conf_get_bool(inst->conf, CONF_no_mouse_rep); send_raw_mouse = activate; update_mouseptr(inst); } @@ -3471,7 +3478,7 @@ static void set_window_titles(GtkFrontend *inst) * is life. */ gtk_window_set_title(GTK_WINDOW(inst->window), inst->wintitle); - if (!conf_get_int(inst->conf, CONF_win_name_always)) + if (!conf_get_bool(inst->conf, CONF_win_name_always)) gdk_window_set_icon_name(gtk_widget_get_window(inst->window), inst->icontitle); } @@ -3504,7 +3511,7 @@ void set_title_and_icon(GtkFrontend *inst, char *title, char *icon) static void gtkwin_set_scrollbar(TermWin *tw, int total, int start, int page) { GtkFrontend *inst = container_of(tw, GtkFrontend, termwin); - if (!conf_get_int(inst->conf, CONF_scrollbar)) + if (!conf_get_bool(inst->conf, CONF_scrollbar)) return; inst->ignore_sbar = true; gtk_adjustment_set_lower(inst->sbar_adjust, 0); @@ -3521,7 +3528,7 @@ static void gtkwin_set_scrollbar(TermWin *tw, int total, int start, int page) void scrollbar_moved(GtkAdjustment *adj, GtkFrontend *inst) { - if (!conf_get_int(inst->conf, CONF_scrollbar)) + if (!conf_get_bool(inst->conf, CONF_scrollbar)) return; if (!inst->ignore_sbar) term_scroll(inst->term, 1, (int)gtk_adjustment_get_value(adj)); @@ -4269,7 +4276,7 @@ static int gtkwin_is_utf8(TermWin *tw) char *setup_fonts_ucs(GtkFrontend *inst) { - int shadowbold = conf_get_int(inst->conf, CONF_shadowbold); + int shadowbold = conf_get_bool(inst->conf, CONF_shadowbold); int shadowboldoffset = conf_get_int(inst->conf, CONF_shadowboldoffset); FontSpec *fs; unifont *fonts[4]; @@ -4349,7 +4356,7 @@ char *setup_fonts_ucs(GtkFrontend *inst) inst->direct_to_font = init_ucs(&inst->ucsdata, conf_get_str(inst->conf, CONF_line_codepage), - conf_get_int(inst->conf, CONF_utf8_override), + conf_get_bool(inst->conf, CONF_utf8_override), inst->fonts[0]->public_charset, conf_get_int(inst->conf, CONF_vtmode)); @@ -4559,7 +4566,7 @@ void setup_clipboards(GtkFrontend *inst, Terminal *term, Conf *conf) term->mouse_select_clipboards[ term->n_mouse_select_clipboards++] = MOUSE_SELECT_CLIPBOARD; - if (conf_get_int(conf, CONF_mouseautocopy)) { + if (conf_get_bool(conf, CONF_mouseautocopy)) { term->mouse_select_clipboards[ term->n_mouse_select_clipboards++] = CLIP_CLIPBOARD; } @@ -4730,15 +4737,15 @@ static void after_change_settings_dialog(void *vctx, int retval) * If the scrollbar needs to be shown, hidden, or moved * from one end to the other of the window, do so now. */ - if (conf_get_int(oldconf, CONF_scrollbar) != - conf_get_int(newconf, CONF_scrollbar)) { - show_scrollbar(inst, conf_get_int(newconf, CONF_scrollbar)); + if (conf_get_bool(oldconf, CONF_scrollbar) != + conf_get_bool(newconf, CONF_scrollbar)) { + show_scrollbar(inst, conf_get_bool(newconf, CONF_scrollbar)); need_size = true; } - if (conf_get_int(oldconf, CONF_scrollbar_on_left) != - conf_get_int(newconf, CONF_scrollbar_on_left)) { + if (conf_get_bool(oldconf, CONF_scrollbar_on_left) != + conf_get_bool(newconf, CONF_scrollbar_on_left)) { gtk_box_reorder_child(inst->hbox, inst->sbar, - conf_get_int(newconf, CONF_scrollbar_on_left) + conf_get_bool(newconf, CONF_scrollbar_on_left) ? 0 : 1); } @@ -4765,12 +4772,12 @@ static void after_change_settings_dialog(void *vctx, int retval) conf_get_fontspec(newconf, CONF_wideboldfont)->name) || strcmp(conf_get_str(oldconf, CONF_line_codepage), conf_get_str(newconf, CONF_line_codepage)) || - conf_get_int(oldconf, CONF_utf8_override) != - conf_get_int(newconf, CONF_utf8_override) || + conf_get_bool(oldconf, CONF_utf8_override) != + conf_get_bool(newconf, CONF_utf8_override) || conf_get_int(oldconf, CONF_vtmode) != conf_get_int(newconf, CONF_vtmode) || - conf_get_int(oldconf, CONF_shadowbold) != - conf_get_int(newconf, CONF_shadowbold) || + conf_get_bool(oldconf, CONF_shadowbold) != + conf_get_bool(newconf, CONF_shadowbold) || conf_get_int(oldconf, CONF_shadowboldoffset) != conf_get_int(newconf, CONF_shadowboldoffset)) { char *errmsg = setup_fonts_ucs(inst); @@ -5119,8 +5126,8 @@ static void start_backend(GtkFrontend *inst) conf_get_str(inst->conf, CONF_host), conf_get_int(inst->conf, CONF_port), &realhost, - conf_get_int(inst->conf, CONF_tcp_nodelay), - conf_get_int(inst->conf, CONF_tcp_keepalives)); + conf_get_bool(inst->conf, CONF_tcp_nodelay), + conf_get_bool(inst->conf, CONF_tcp_keepalives)); if (error) { char *msg = dupprintf("Unable to open connection to %s:\n%s", @@ -5330,16 +5337,16 @@ void new_session_window(Conf *conf, const char *geometry_string) * unwanted, so we can pop it up quickly if it suddenly becomes * desirable. */ - if (conf_get_int(inst->conf, CONF_scrollbar_on_left)) + if (conf_get_bool(inst->conf, CONF_scrollbar_on_left)) gtk_box_pack_start(inst->hbox, inst->sbar, false, false, 0); gtk_box_pack_start(inst->hbox, inst->area, true, true, 0); - if (!conf_get_int(inst->conf, CONF_scrollbar_on_left)) + if (!conf_get_bool(inst->conf, CONF_scrollbar_on_left)) gtk_box_pack_start(inst->hbox, inst->sbar, false, false, 0); gtk_container_add(GTK_CONTAINER(inst->window), GTK_WIDGET(inst->hbox)); gtk_widget_show(inst->area); - show_scrollbar(inst, conf_get_int(inst->conf, CONF_scrollbar)); + show_scrollbar(inst, conf_get_bool(inst->conf, CONF_scrollbar)); gtk_widget_show(GTK_WIDGET(inst->hbox)); /* @@ -5441,7 +5448,7 @@ void new_session_window(Conf *conf, const char *geometry_string) g_signal_connect(G_OBJECT(inst->imc), "commit", G_CALLBACK(input_method_commit_event), inst); #endif - if (conf_get_int(inst->conf, CONF_scrollbar)) + if (conf_get_bool(inst->conf, CONF_scrollbar)) g_signal_connect(G_OBJECT(inst->sbar_adjust), "value_changed", G_CALLBACK(scrollbar_moved), inst); gtk_widget_add_events(GTK_WIDGET(inst->area), diff --git a/unix/uxpgnt.c b/unix/uxpgnt.c index ac536843..4cf9b0ff 100644 --- a/unix/uxpgnt.c +++ b/unix/uxpgnt.c @@ -54,6 +54,7 @@ void random_save_seed(void) {} void random_destroy_seed(void) {} void noise_ultralight(unsigned long data) {} char *platform_default_s(const char *name) { return NULL; } +bool platform_default_b(const char *name, bool def) { return def; } int platform_default_i(const char *name, int def) { return def; } FontSpec *platform_default_fontspec(const char *name) { return fontspec_new(""); } Filename *platform_default_filename(const char *name) { return filename_from_str(""); } diff --git a/unix/uxplink.c b/unix/uxplink.c index dad746d9..6794eff6 100644 --- a/unix/uxplink.c +++ b/unix/uxplink.c @@ -55,6 +55,11 @@ char *platform_default_s(const char *name) return NULL; } +bool platform_default_b(const char *name, bool def) +{ + return def; +} + int platform_default_i(const char *name, int def) { return def; @@ -674,7 +679,7 @@ int main(int argc, char **argv) /* change trailing blank to NUL */ conf_set_str(conf, CONF_remote_cmd, command); conf_set_str(conf, CONF_remote_cmd2, ""); - conf_set_int(conf, CONF_nopty, true); /* command => no tty */ + conf_set_bool(conf, CONF_nopty, true); /* command => no tty */ break; /* done with cmdline */ } else { @@ -713,7 +718,7 @@ int main(int argc, char **argv) * Apply subsystem status. */ if (use_subsystem) - conf_set_int(conf, CONF_ssh_subsys, true); + conf_set_bool(conf, CONF_ssh_subsys, true); if (!*conf_get_str(conf, CONF_remote_cmd) && !*conf_get_str(conf, CONF_remote_cmd2) && @@ -769,10 +774,10 @@ int main(int argc, char **argv) * the "simple" flag. */ if (conf_get_int(conf, CONF_protocol) == PROT_SSH && - !conf_get_int(conf, CONF_x11_forward) && - !conf_get_int(conf, CONF_agentfwd) && + !conf_get_bool(conf, CONF_x11_forward) && + !conf_get_bool(conf, CONF_agentfwd) && !conf_get_str_nthstrkey(conf, CONF_portfwd, 0)) - conf_set_int(conf, CONF_ssh_simple, true); + conf_set_bool(conf, CONF_ssh_simple, true); if (just_test_share_exists) { if (!backvt->test_for_upstream) { @@ -795,7 +800,7 @@ int main(int argc, char **argv) const char *error; char *realhost; /* nodelay is only useful if stdin is a terminal device */ - int nodelay = conf_get_int(conf, CONF_tcp_nodelay) && isatty(0); + int nodelay = conf_get_bool(conf, CONF_tcp_nodelay) && isatty(0); /* This is a good place for a fuzzer to fork us. */ #ifdef __AFL_HAVE_MANUAL_CONTROL @@ -806,7 +811,7 @@ int main(int argc, char **argv) conf_get_str(conf, CONF_host), conf_get_int(conf, CONF_port), &realhost, nodelay, - conf_get_int(conf, CONF_tcp_keepalives)); + conf_get_bool(conf, CONF_tcp_keepalives)); if (error) { fprintf(stderr, "Unable to open connection:\n%s\n", error); return 1; diff --git a/unix/uxpty.c b/unix/uxpty.c index 6b9f3555..e767aeb6 100644 --- a/unix/uxpty.c +++ b/unix/uxpty.c @@ -920,7 +920,7 @@ Backend *pty_backend_create( * or not. */ if (pty_utmp_helper_pipe >= 0) { /* if it's < 0, we can't anyway */ - if (!conf_get_int(conf, CONF_stamp_utmp)) { + if (!conf_get_bool(conf, CONF_stamp_utmp)) { /* We're not stamping utmp, so just let the child * process die that was waiting to unstamp it later. */ close(pty_utmp_helper_pipe); @@ -1046,7 +1046,7 @@ Backend *pty_backend_create( * Set the backspace character to be whichever of ^H and * ^? is specified by bksp_is_delete. */ - attrs.c_cc[VERASE] = conf_get_int(conf, CONF_bksp_is_delete) + attrs.c_cc[VERASE] = conf_get_bool(conf, CONF_bksp_is_delete) ? '\177' : '\010'; /* @@ -1176,7 +1176,7 @@ Backend *pty_backend_create( } else { char *shell = getenv("SHELL"); char *shellname; - if (conf_get_int(conf, CONF_login_shell)) { + if (conf_get_bool(conf, CONF_login_shell)) { char *p = strrchr(shell, '/'); shellname = snewn(2+strlen(shell), char); p = p ? p+1 : shell; diff --git a/unix/uxserver.c b/unix/uxserver.c index c42afc1e..4c532212 100644 --- a/unix/uxserver.c +++ b/unix/uxserver.c @@ -73,6 +73,11 @@ char *platform_default_s(const char *name) return NULL; } +bool platform_default_b(const char *name, bool def) +{ + return def; +} + int platform_default_i(const char *name, int def) { return def; diff --git a/unix/uxsftp.c b/unix/uxsftp.c index 328b335a..62c9bce6 100644 --- a/unix/uxsftp.c +++ b/unix/uxsftp.c @@ -47,6 +47,11 @@ char *platform_default_s(const char *name) return NULL; } +bool platform_default_b(const char *name, bool def) +{ + return def; +} + int platform_default_i(const char *name, int def) { return def; diff --git a/windows/windefs.c b/windows/windefs.c index 24a2ea41..b210cde0 100644 --- a/windows/windefs.c +++ b/windows/windefs.c @@ -29,6 +29,11 @@ char *platform_default_s(const char *name) return NULL; } +bool platform_default_b(const char *name, bool def) +{ + return def; +} + int platform_default_i(const char *name, int def) { return def; diff --git a/windows/window.c b/windows/window.c index 50bca70e..e4bcbf43 100644 --- a/windows/window.c +++ b/windows/window.c @@ -375,8 +375,8 @@ static void start_backend(void) conf_get_str(conf, CONF_host), conf_get_int(conf, CONF_port), &realhost, - conf_get_int(conf, CONF_tcp_nodelay), - conf_get_int(conf, CONF_tcp_keepalives)); + conf_get_bool(conf, CONF_tcp_nodelay), + conf_get_bool(conf, CONF_tcp_keepalives)); if (error) { char *str = dupprintf("%s Error", appname); sprintf(msg, "Unable to open connection to\n" @@ -710,13 +710,13 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) int winmode = WS_OVERLAPPEDWINDOW | WS_VSCROLL; int exwinmode = 0; wchar_t *uappname = dup_mb_to_wc(DEFAULT_CODEPAGE, 0, appname); - if (!conf_get_int(conf, CONF_scrollbar)) + if (!conf_get_bool(conf, CONF_scrollbar)) winmode &= ~(WS_VSCROLL); if (conf_get_int(conf, CONF_resize_action) == RESIZE_DISABLED) winmode &= ~(WS_THICKFRAME | WS_MAXIMIZEBOX); - if (conf_get_int(conf, CONF_alwaysontop)) + if (conf_get_bool(conf, CONF_alwaysontop)) exwinmode |= WS_EX_TOPMOST; - if (conf_get_int(conf, CONF_sunken_edge)) + if (conf_get_bool(conf, CONF_sunken_edge)) exwinmode |= WS_EX_CLIENTEDGE; hwnd = CreateWindowExW(exwinmode, uappname, uappname, winmode, CW_USEDEFAULT, CW_USEDEFAULT, @@ -960,7 +960,7 @@ static void setup_clipboards(Terminal *term, Conf *conf) term->n_mouse_select_clipboards = 1; - if (conf_get_int(conf, CONF_mouseautocopy)) { + if (conf_get_bool(conf, CONF_mouseautocopy)) { term->mouse_select_clipboards[ term->n_mouse_select_clipboards++] = CLIP_SYSTEM; } @@ -1168,7 +1168,7 @@ static void win_seat_set_busy_status(Seat *seat, BusyStatus status) */ static void wintw_set_raw_mouse_mode(TermWin *tw, int activate) { - activate = activate && !conf_get_int(conf, CONF_no_mouse_rep); + activate = activate && !conf_get_bool(conf, CONF_no_mouse_rep); send_raw_mouse = activate; update_mouse_pointer(); } @@ -1251,7 +1251,7 @@ static void conftopalette(void) } /* Override with system colours if appropriate */ - if (conf_get_int(conf, CONF_system_colour)) + if (conf_get_bool(conf, CONF_system_colour)) systopalette(); } @@ -1304,7 +1304,7 @@ static void init_palette(void) int i; HDC hdc = GetDC(hwnd); if (hdc) { - if (conf_get_int(conf, CONF_try_palette) && + if (conf_get_bool(conf, CONF_try_palette) && GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE) { /* * This is a genuine case where we must use smalloc @@ -2003,7 +2003,7 @@ static void click(Mouse_Button b, int x, int y, int shift, int ctrl, int alt) int thistime = GetMessageTime(); if (send_raw_mouse && - !(shift && conf_get_int(conf, CONF_mouse_override))) { + !(shift && conf_get_bool(conf, CONF_mouse_override))) { lastbtn = MBT_NOTHING; term_mouse(term, b, translate_button(b), MA_CLICK, x, y, shift, ctrl, alt); @@ -2046,7 +2046,7 @@ static void show_mouseptr(int show) /* NB that the counter in ShowCursor() is also frobbed by * update_mouse_pointer() */ static int cursor_visible = 1; - if (!conf_get_int(conf, CONF_hide_mouseptr)) + if (!conf_get_bool(conf, CONF_hide_mouseptr)) show = 1; /* override if this feature disabled */ if (cursor_visible && !show) ShowCursor(false); @@ -2169,7 +2169,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, char *str; show_mouseptr(1); str = dupprintf("%s Exit Confirmation", appname); - if (session_closed || !conf_get_int(conf, CONF_warn_on_close) || + if (session_closed || !conf_get_bool(conf, CONF_warn_on_close) || MessageBox(hwnd, "Are you sure you want to close this session?", str, MB_ICONWARNING | MB_OKCANCEL | MB_DEFBUTTON1) @@ -2384,9 +2384,9 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, GetWindowLongPtr(hwnd, GWL_EXSTYLE); nexflag = exflag; - if (conf_get_int(conf, CONF_alwaysontop) != - conf_get_int(prev_conf, CONF_alwaysontop)) { - if (conf_get_int(conf, CONF_alwaysontop)) { + if (conf_get_bool(conf, CONF_alwaysontop) != + conf_get_bool(prev_conf, CONF_alwaysontop)) { + if (conf_get_bool(conf, CONF_alwaysontop)) { nexflag |= WS_EX_TOPMOST; SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); @@ -2396,15 +2396,15 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, SWP_NOMOVE | SWP_NOSIZE); } } - if (conf_get_int(conf, CONF_sunken_edge)) + if (conf_get_bool(conf, CONF_sunken_edge)) nexflag |= WS_EX_CLIENTEDGE; else nexflag &= ~(WS_EX_CLIENTEDGE); nflg = flag; - if (conf_get_int(conf, is_full_screen() ? - CONF_scrollbar_in_fullscreen : - CONF_scrollbar)) + if (conf_get_bool(conf, is_full_screen() ? + CONF_scrollbar_in_fullscreen : + CONF_scrollbar)) nflg |= WS_VSCROLL; else nflg &= ~WS_VSCROLL; @@ -2444,7 +2444,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, win_set_title(wintw, conf_get_str(conf, CONF_wintitle)); if (IsIconic(hwnd)) { SetWindowText(hwnd, - conf_get_int(conf, CONF_win_name_always) ? + conf_get_bool(conf, CONF_win_name_always) ? window_name : icon_name); } @@ -2985,7 +2985,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, #endif if (wParam == SIZE_MINIMIZED) SetWindowText(hwnd, - conf_get_int(conf, CONF_win_name_always) ? + conf_get_bool(conf, CONF_win_name_always) ? window_name : icon_name); if (wParam == SIZE_RESTORED || wParam == SIZE_MAXIMIZED) SetWindowText(hwnd, window_name); @@ -3315,7 +3315,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, } return 0; case WM_SYSCOLORCHANGE: - if (conf_get_int(conf, CONF_system_colour)) { + if (conf_get_bool(conf, CONF_system_colour)) { /* Refresh palette from system colours. */ /* XXX actually this zaps the entire palette. */ systopalette(); @@ -3366,7 +3366,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, break; if (send_raw_mouse && - !(conf_get_int(conf, CONF_mouse_override) && + !(conf_get_bool(conf, CONF_mouse_override) && shift_pressed)) { /* Mouse wheel position is in screen coordinates for * some reason */ @@ -4061,9 +4061,9 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, unsigned char *p = output; static int alt_sum = 0; int funky_type = conf_get_int(conf, CONF_funky_type); - int no_applic_k = conf_get_int(conf, CONF_no_applic_k); - int ctrlaltkeys = conf_get_int(conf, CONF_ctrlaltkeys); - int nethack_keypad = conf_get_int(conf, CONF_nethack_keypad); + bool no_applic_k = conf_get_bool(conf, CONF_no_applic_k); + bool ctrlaltkeys = conf_get_bool(conf, CONF_ctrlaltkeys); + bool nethack_keypad = conf_get_bool(conf, CONF_nethack_keypad); HKL kbd_layout = GetKeyboardLayout(0); @@ -4199,7 +4199,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, /* Note if AltGr was pressed and if it was used as a compose key */ if (!compose_state) { compose_keycode = 0x100; - if (conf_get_int(conf, CONF_compose_key)) { + if (conf_get_bool(conf, CONF_compose_key)) { if (wParam == VK_MENU && (HIWORD(lParam) & KF_EXTENDED)) compose_keycode = wParam; } @@ -4356,16 +4356,16 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, } return 0; } - if (left_alt && wParam == VK_F4 && conf_get_int(conf, CONF_alt_f4)) { + if (left_alt && wParam == VK_F4 && conf_get_bool(conf, CONF_alt_f4)) { return -1; } - if (left_alt && wParam == VK_SPACE && conf_get_int(conf, - CONF_alt_space)) { + if (left_alt && wParam == VK_SPACE && conf_get_bool(conf, + CONF_alt_space)) { SendMessage(hwnd, WM_SYSCOMMAND, SC_KEYMENU, 0); return -1; } if (left_alt && wParam == VK_RETURN && - conf_get_int(conf, CONF_fullscreenonaltenter) && + conf_get_bool(conf, CONF_fullscreenonaltenter) && (conf_get_int(conf, CONF_resize_action) != RESIZE_DISABLED)) { if ((HIWORD(lParam) & (KF_UP | KF_REPEAT)) != KF_REPEAT) flip_full_screen(); @@ -4509,13 +4509,13 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, } if (wParam == VK_BACK && shift_state == 0) { /* Backspace */ - *p++ = (conf_get_int(conf, CONF_bksp_is_delete) ? 0x7F : 0x08); + *p++ = (conf_get_bool(conf, CONF_bksp_is_delete) ? 0x7F : 0x08); *p++ = 0; return -2; } if (wParam == VK_BACK && shift_state == 1) { /* Shift Backspace */ /* We do the opposite of what is configured */ - *p++ = (conf_get_int(conf, CONF_bksp_is_delete) ? 0x08 : 0x7F); + *p++ = (conf_get_bool(conf, CONF_bksp_is_delete) ? 0x08 : 0x7F); *p++ = 0; return -2; } @@ -4725,7 +4725,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, return p - output; } if ((code == 1 || code == 4) && - conf_get_int(conf, CONF_rxvt_homeend)) { + conf_get_bool(conf, CONF_rxvt_homeend)) { p += sprintf((char *) p, code == 1 ? "\x1B[H" : "\x1BOw"); return p - output; } @@ -4786,7 +4786,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, /* helg: clear CAPS LOCK state if caps lock switches to cyrillic */ if(keystate[VK_CAPITAL] != 0 && - conf_get_int(conf, CONF_xlat_capslockcyr)) { + conf_get_bool(conf, CONF_xlat_capslockcyr)) { capsOn= !left_alt; keystate[VK_CAPITAL] = 0; } @@ -4936,7 +4936,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, * we return -1, which means Windows will give the keystroke * its default handling (i.e. bring up the System menu). */ - if (wParam == VK_MENU && !conf_get_int(conf, CONF_alt_only)) + if (wParam == VK_MENU && !conf_get_bool(conf, CONF_alt_only)) return 0; return -1; @@ -4947,7 +4947,7 @@ static void wintw_set_title(TermWin *tw, const char *title) sfree(window_name); window_name = snewn(1 + strlen(title), char); strcpy(window_name, title); - if (conf_get_int(conf, CONF_win_name_always) || !IsIconic(hwnd)) + if (conf_get_bool(conf, CONF_win_name_always) || !IsIconic(hwnd)) SetWindowText(hwnd, title); } @@ -4956,7 +4956,7 @@ static void wintw_set_icon_title(TermWin *tw, const char *title) sfree(icon_name); icon_name = snewn(1 + strlen(title), char); strcpy(icon_name, title); - if (!conf_get_int(conf, CONF_win_name_always) && IsIconic(hwnd)) + if (!conf_get_bool(conf, CONF_win_name_always) && IsIconic(hwnd)) SetWindowText(hwnd, title); } @@ -4964,8 +4964,8 @@ static void wintw_set_scrollbar(TermWin *tw, int total, int start, int page) { SCROLLINFO si; - if (!conf_get_int(conf, is_full_screen() ? - CONF_scrollbar_in_fullscreen : CONF_scrollbar)) + if (!conf_get_bool(conf, is_full_screen() ? + CONF_scrollbar_in_fullscreen : CONF_scrollbar)) return; si.cbSize = sizeof(si); @@ -5150,7 +5150,7 @@ static void wintw_clip_write( memcpy(lock, data, len * sizeof(wchar_t)); WideCharToMultiByte(CP_ACP, 0, data, len, lock2, len2, NULL, NULL); - if (conf_get_int(conf, CONF_rtf_paste)) { + if (conf_get_bool(conf, CONF_rtf_paste)) { wchar_t unitab[256]; char *rtf = NULL; unsigned char *tdata = (unsigned char *)lock2; @@ -5814,7 +5814,7 @@ static void wintw_move(TermWin *tw, int x, int y) */ static void wintw_set_zorder(TermWin *tw, int top) { - if (conf_get_int(conf, CONF_alwaysontop)) + if (conf_get_bool(conf, CONF_alwaysontop)) return; /* ignore */ SetWindowPos(hwnd, top ? HWND_TOP : HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); @@ -5936,7 +5936,7 @@ static void make_full_screen() /* Remove the window furniture. */ style = GetWindowLongPtr(hwnd, GWL_STYLE); style &= ~(WS_CAPTION | WS_BORDER | WS_THICKFRAME); - if (conf_get_int(conf, CONF_scrollbar_in_fullscreen)) + if (conf_get_bool(conf, CONF_scrollbar_in_fullscreen)) style |= WS_VSCROLL; else style &= ~WS_VSCROLL; @@ -5975,7 +5975,7 @@ static void clear_full_screen() style &= ~WS_THICKFRAME; else style |= WS_THICKFRAME; - if (conf_get_int(conf, CONF_scrollbar)) + if (conf_get_bool(conf, CONF_scrollbar)) style |= WS_VSCROLL; else style &= ~WS_VSCROLL; diff --git a/windows/winplink.c b/windows/winplink.c index b777443a..14bb7498 100644 --- a/windows/winplink.c +++ b/windows/winplink.c @@ -362,7 +362,7 @@ int main(int argc, char **argv) /* change trailing blank to NUL */ conf_set_str(conf, CONF_remote_cmd, command); conf_set_str(conf, CONF_remote_cmd2, ""); - conf_set_int(conf, CONF_nopty, true); /* command => no tty */ + conf_set_bool(conf, CONF_nopty, true); /* command => no tty */ break; /* done with cmdline */ } else { @@ -389,7 +389,7 @@ int main(int argc, char **argv) * Apply subsystem status. */ if (use_subsystem) - conf_set_int(conf, CONF_ssh_subsys, true); + conf_set_bool(conf, CONF_ssh_subsys, true); if (!*conf_get_str(conf, CONF_remote_cmd) && !*conf_get_str(conf, CONF_remote_cmd2) && @@ -419,10 +419,10 @@ int main(int argc, char **argv) * the "simple" flag. */ if (conf_get_int(conf, CONF_protocol) == PROT_SSH && - !conf_get_int(conf, CONF_x11_forward) && - !conf_get_int(conf, CONF_agentfwd) && + !conf_get_bool(conf, CONF_x11_forward) && + !conf_get_bool(conf, CONF_agentfwd) && !conf_get_str_nthstrkey(conf, CONF_portfwd, 0)) - conf_set_int(conf, CONF_ssh_simple, true); + conf_set_bool(conf, CONF_ssh_simple, true); logctx = log_init(default_logpolicy, conf); @@ -451,14 +451,14 @@ int main(int argc, char **argv) const char *error; char *realhost; /* nodelay is only useful if stdin is a character device (console) */ - int nodelay = conf_get_int(conf, CONF_tcp_nodelay) && + int nodelay = conf_get_bool(conf, CONF_tcp_nodelay) && (GetFileType(GetStdHandle(STD_INPUT_HANDLE)) == FILE_TYPE_CHAR); error = backend_init(vt, plink_seat, &backend, logctx, conf, conf_get_str(conf, CONF_host), conf_get_int(conf, CONF_port), &realhost, nodelay, - conf_get_int(conf, CONF_tcp_keepalives)); + conf_get_bool(conf, CONF_tcp_keepalives)); if (error) { fprintf(stderr, "Unable to open connection:\n%s", error); return 1; From 3214563d8ed7469e20d4ffdddd55c430334ce803 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Fri, 2 Nov 2018 19:23:19 +0000 Subject: [PATCH 589/607] Convert a lot of 'int' variables to 'bool'. My normal habit these days, in new code, is to treat int and bool as _almost_ completely separate types. I'm still willing to use C's implicit test for zero on an integer (e.g. 'if (!blob.len)' is fine, no need to spell it out as blob.len != 0), but generally, if a variable is going to be conceptually a boolean, I like to declare it bool and assign to it using 'true' or 'false' rather than 0 or 1. PuTTY is an exception, because it predates the C99 bool, and I've stuck to its existing coding style even when adding new code to it. But it's been annoying me more and more, so now that I've decided C99 bool is an acceptable thing to require from our toolchain in the first place, here's a quite thorough trawl through the source doing 'boolification'. Many variables and function parameters are now typed as bool rather than int; many assignments of 0 or 1 to those variables are now spelled 'true' or 'false'. I managed this thorough conversion with the help of a custom clang plugin that I wrote to trawl the AST and apply heuristics to point out where things might want changing. So I've even managed to do a decent job on parts of the code I haven't looked at in years! To make the plugin's work easier, I pushed platform front ends generally in the direction of using standard 'bool' in preference to platform-specific boolean types like Windows BOOL or GTK's gboolean; I've left the platform booleans in places they _have_ to be for the platform APIs to work right, but variables only used by my own code have been converted wherever I found them. In a few places there are int values that look very like booleans in _most_ of the places they're used, but have a rarely-used third value, or a distinction between different nonzero values that most users don't care about. In these cases, I've _removed_ uses of 'true' and 'false' for the return values, to emphasise that there's something more subtle going on than a simple boolean answer: - the 'multisel' field in dialog.h's list box structure, for which the GTK front end in particular recognises a difference between 1 and 2 but nearly everything else treats as boolean - the 'urgent' parameter to plug_receive, where 1 vs 2 tells you something about the specific location of the urgent pointer, but most clients only care about 0 vs 'something nonzero' - the return value of wc_match, where -1 indicates a syntax error in the wildcard. - the return values from SSH-1 RSA-key loading functions, which use -1 for 'wrong passphrase' and 0 for all other failures (so any caller which already knows it's not loading an _encrypted private_ key can treat them as boolean) - term->esc_query, and the 'query' parameter in toggle_mode in terminal.c, which _usually_ hold 0 for ESC[123h or 1 for ESC[?123h, but can also hold -1 for some other intervening character that we don't support. In a few places there's an integer that I haven't turned into a bool even though it really _can_ only take values 0 or 1 (and, as above, tried to make the call sites consistent in not calling those values true and false), on the grounds that I thought it would make it more confusing to imply that the 0 value was in some sense 'negative' or bad and the 1 positive or good: - the return value of plug_accepting uses the POSIXish convention of 0=success and nonzero=error; I think if I made it bool then I'd also want to reverse its sense, and that's a job for a separate piece of work. - the 'screen' parameter to lineptr() in terminal.c, where 0 and 1 represent the default and alternate screens. There's no obvious reason why one of those should be considered 'true' or 'positive' or 'success' - they're just indices - so I've left it as int. ssh_scp_recv had particularly confusing semantics for its previous int return value: its call sites used '<= 0' to check for error, but it never actually returned a negative number, just 0 or 1. Now the function and its call sites agree that it's a bool. In a couple of places I've renamed variables called 'ret', because I don't like that name any more - it's unclear whether it means the return value (in preparation) for the _containing_ function or the return value received from a subroutine call, and occasionally I've accidentally used the same variable for both and introduced a bug. So where one of those got in my way, I've renamed it to 'toret' or 'retd' (the latter short for 'returned') in line with my usual modern practice, but I haven't done a thorough job of finding all of them. Finally, one amusing side effect of doing this is that I've had to separate quite a few chained assignments. It used to be perfectly fine to write 'a = b = c = TRUE' when a,b,c were int and TRUE was just a the 'true' defined by stdbool.h, that idiom provokes a warning from gcc: 'suggest parentheses around assignment used as truth value'! --- agentf.c | 12 +- be_misc.c | 2 +- callback.c | 6 +- cmdgen.c | 17 +-- cmdline.c | 16 +-- conf.c | 9 +- config.c | 44 +++--- dialog.c | 30 ++--- dialog.h | 30 ++--- fuzzterm.c | 30 ++--- import.c | 117 ++++++++-------- ldisc.c | 8 +- ldisc.h | 6 +- ldiscucs.c | 4 +- logging.c | 6 +- mainchan.c | 44 +++--- marshal.c | 10 +- marshal.h | 6 +- minibidi.c | 30 +++-- misc.c | 36 ++--- misc.h | 26 ++-- network.h | 34 ++--- nullplug.c | 2 +- pageant.c | 23 ++-- pageant.h | 8 +- pinger.c | 2 +- portfwd.c | 36 ++--- proxy.c | 52 +++---- proxy.h | 16 +-- pscp.c | 191 +++++++++++++------------- psftp.c | 270 +++++++++++++++++++------------------ psftp.h | 12 +- putty.h | 135 +++++++++---------- raw.c | 24 ++-- rlogin.c | 30 ++--- scpserver.c | 31 ++--- sercfg.c | 2 +- sesschan.c | 96 ++++++------- settings.c | 203 ++++++++++++++-------------- sftp.c | 114 +++++++--------- sftp.h | 59 ++++---- sftpcommon.c | 6 +- ssh.c | 51 +++---- ssh.h | 126 ++++++++--------- ssh1bpp.c | 2 +- ssh1censor.c | 2 +- ssh1connection-client.c | 51 ++++--- ssh1connection-server.c | 14 +- ssh1connection.c | 38 +++--- ssh1connection.h | 32 ++--- ssh1login-server.c | 10 +- ssh1login.c | 36 ++--- ssh2bpp.c | 22 +-- ssh2censor.c | 2 +- ssh2connection-client.c | 36 ++--- ssh2connection-server.c | 36 ++--- ssh2connection.c | 48 +++---- ssh2connection.h | 64 ++++----- ssh2kex-client.c | 8 +- ssh2transhk.c | 8 +- ssh2transport.c | 75 ++++++----- ssh2transport.h | 46 ++++--- ssh2userauth-server.c | 6 +- ssh2userauth.c | 47 ++++--- sshaes.c | 12 +- sshbn.c | 7 +- sshbpp.h | 24 ++-- sshchan.h | 110 +++++++-------- sshcommon.c | 74 +++++----- sshcrcda.c | 16 +-- sshdh.c | 2 +- sshdss.c | 18 +-- sshecc.c | 221 +++++++++++++++--------------- sshmac.c | 7 +- sshppl.h | 22 +-- sshpubk.c | 107 +++++++-------- sshrand.c | 2 +- sshrsa.c | 45 ++++--- sshserver.c | 8 +- sshserver.h | 12 +- sshsha.c | 12 +- sshshare.c | 35 ++--- sshverstring.c | 16 +-- sshzlib.c | 20 +-- telnet.c | 39 +++--- terminal.c | 290 ++++++++++++++++++++++------------------ terminal.h | 136 ++++++++++--------- testbn.c | 4 +- timing.c | 2 +- tree234.c | 3 +- unix/gtkapp.c | 8 +- unix/gtkask.c | 14 +- unix/gtkcfg.c | 2 +- unix/gtkcols.c | 2 +- unix/gtkcols.h | 2 +- unix/gtkcomm.c | 2 +- unix/gtkdlg.c | 53 ++++---- unix/gtkfont.c | 164 ++++++++++++----------- unix/gtkfont.h | 14 +- unix/gtkmain.c | 34 ++--- unix/gtkmisc.c | 3 +- unix/gtkmisc.h | 3 +- unix/gtkwin.c | 155 +++++++++++---------- unix/unix.h | 26 ++-- unix/ux_x11.c | 4 +- unix/uxagentc.c | 20 +-- unix/uxcfg.c | 4 +- unix/uxcons.c | 8 +- unix/uxfdsock.c | 2 +- unix/uxmisc.c | 12 +- unix/uxnet.c | 113 ++++++++-------- unix/uxnoise.c | 12 +- unix/uxpeer.c | 2 +- unix/uxpgnt.c | 85 ++++++------ unix/uxplink.c | 44 +++--- unix/uxproxy.c | 4 +- unix/uxpterm.c | 11 +- unix/uxpty.c | 36 ++--- unix/uxputty.c | 12 +- unix/uxser.c | 18 +-- unix/uxserver.c | 18 +-- unix/uxsftp.c | 18 +-- unix/uxsftpserver.c | 16 +-- unix/uxshare.c | 5 +- unix/uxsignal.c | 4 +- unix/uxstore.c | 4 +- unix/uxucs.c | 13 +- wcwidth.c | 8 +- wildcard.c | 16 +-- windows/sizetip.c | 4 +- windows/wincapi.c | 6 +- windows/wincapi.h | 2 +- windows/wincfg.c | 4 +- windows/wincons.c | 9 +- windows/winctrls.c | 67 +++++----- windows/windefs.c | 4 +- windows/windlg.c | 15 ++- windows/window.c | 266 +++++++++++++++++++----------------- windows/winhandl.c | 37 ++--- windows/winhelp.c | 6 +- windows/winhsock.c | 6 +- windows/winjump.c | 6 +- windows/winmisc.c | 15 +-- windows/winnet.c | 131 +++++++++--------- windows/winnoise.c | 4 +- windows/winnpc.c | 2 +- windows/winnps.c | 6 +- windows/winpgen.c | 34 ++--- windows/winpgnt.c | 16 +-- windows/winpgntc.c | 2 +- windows/winplink.c | 34 ++--- windows/winprint.c | 12 +- windows/winproxy.c | 6 +- windows/winsecur.c | 26 ++-- windows/winsecur.h | 8 +- windows/winser.c | 16 +-- windows/winsftp.c | 30 ++--- windows/winshare.c | 2 +- windows/winstore.c | 10 +- windows/winstuff.h | 60 +++++---- windows/winucs.c | 10 +- windows/winutils.c | 10 +- windows/winx11.c | 2 +- x11fwd.c | 41 +++--- 164 files changed, 2914 insertions(+), 2805 deletions(-) diff --git a/agentf.c b/agentf.c index db4f702a..4b859f44 100644 --- a/agentf.c +++ b/agentf.c @@ -15,8 +15,8 @@ typedef struct agentf { SshChannel *c; bufchain inbuffer; agent_pending_query *pending; - int input_wanted; - int rcvd_eof; + bool input_wanted; + bool rcvd_eof; Channel chan; } agentf; @@ -142,10 +142,10 @@ static void agentf_callback(void *vctx, void *reply, int replylen) } static void agentf_free(Channel *chan); -static int agentf_send(Channel *chan, int is_stderr, const void *, int); +static int agentf_send(Channel *chan, bool is_stderr, const void *, int); static void agentf_send_eof(Channel *chan); static char *agentf_log_close_msg(Channel *chan); -static void agentf_set_input_wanted(Channel *chan, int wanted); +static void agentf_set_input_wanted(Channel *chan, bool wanted); static const struct ChannelVtable agentf_channelvt = { agentf_free, @@ -196,7 +196,7 @@ static void agentf_free(Channel *chan) sfree(af); } -static int agentf_send(Channel *chan, int is_stderr, +static int agentf_send(Channel *chan, bool is_stderr, const void *data, int length) { assert(chan->vt == &agentf_channelvt); @@ -233,7 +233,7 @@ static char *agentf_log_close_msg(Channel *chan) return dupstr("Agent-forwarding connection closed"); } -static void agentf_set_input_wanted(Channel *chan, int wanted) +static void agentf_set_input_wanted(Channel *chan, bool wanted) { assert(chan->vt == &agentf_channelvt); agentf *af = container_of(chan, agentf, chan); diff --git a/be_misc.c b/be_misc.c index 8c1ff481..79a6d33c 100644 --- a/be_misc.c +++ b/be_misc.c @@ -11,7 +11,7 @@ void backend_socket_log(Seat *seat, LogContext *logctx, int type, SockAddr *addr, int port, const char *error_msg, int error_code, Conf *conf, - int session_started) + bool session_started) { char addrbuf[256], *msg; diff --git a/callback.c b/callback.c index b0ecbca2..076d7b4d 100644 --- a/callback.c +++ b/callback.c @@ -99,9 +99,9 @@ void queue_toplevel_callback(toplevel_callback_fn_t fn, void *ctx) cb->next = NULL; } -int run_toplevel_callbacks(void) +bool run_toplevel_callbacks(void) { - int done_something = false; + bool done_something = false; if (cbhead) { /* @@ -127,7 +127,7 @@ int run_toplevel_callbacks(void) return done_something; } -int toplevel_callback_pending(void) +bool toplevel_callback_pending(void) { return cbcurr != NULL || cbhead != NULL; } diff --git a/cmdgen.c b/cmdgen.c index 16c63a5d..4ef972f3 100644 --- a/cmdgen.c +++ b/cmdgen.c @@ -114,7 +114,7 @@ void showversion(void) sfree(buildinfo_text); } -void usage(int standalone) +void usage(bool standalone) { fprintf(standalone ? stderr : stdout, "Usage: puttygen ( keyfile | -t type [ -b bits ] )\n" @@ -163,7 +163,7 @@ void help(void) ); } -static int move(char *from, char *to) +static bool move(char *from, char *to) { int ret; @@ -208,7 +208,7 @@ static char *readpassphrase(const char *filename) #define DEFAULT_RSADSA_BITS 2048 /* For Unix in particular, but harmless if this main() is reused elsewhere */ -const int buildinfo_gtk_relevant = false; +const bool buildinfo_gtk_relevant = false; int main(int argc, char **argv) { @@ -220,8 +220,8 @@ int main(int argc, char **argv) OPENSSH_NEW, SSHCOM } outtype = PRIVATE; int bits = -1; char *comment = NULL, *origcomment = NULL; - int change_passphrase = false; - int errs = false, nogo = false; + bool change_passphrase = false; + bool errs = false, nogo = false; int intype = SSH_KEYTYPE_UNOPENABLE; int sshver = 0; struct ssh2_userkey *ssh2key = NULL; @@ -229,7 +229,7 @@ int main(int argc, char **argv) strbuf *ssh2blob = NULL; char *ssh2alg = NULL; char *old_passphrase = NULL, *new_passphrase = NULL; - int load_encrypted; + bool load_encrypted; progfn_t progressfn = is_interactive() ? progress_update : no_progress; const char *random_device = NULL; @@ -735,7 +735,7 @@ int main(int argc, char **argv) } else { const char *error = NULL; - int encrypted; + bool encrypted; assert(infile != NULL); @@ -930,7 +930,8 @@ int main(int argc, char **argv) outfilename = filename_from_str(outfile ? outfile : ""); switch (outtype) { - int ret, real_outtype; + bool ret; + int real_outtype; case PRIVATE: if (sshver == 1) { diff --git a/cmdline.c b/cmdline.c index ea084e45..f71a7763 100644 --- a/cmdline.c +++ b/cmdline.c @@ -87,7 +87,7 @@ void cmdline_cleanup(void) */ int cmdline_get_passwd_input(prompts_t *p) { - static int tried_once = 0; + static bool tried_once = false; /* * We only handle prompts which don't echo (which we assume to be @@ -109,7 +109,7 @@ int cmdline_get_passwd_input(prompts_t *p) smemclr(cmdline_password, strlen(cmdline_password)); sfree(cmdline_password); cmdline_password = NULL; - tried_once = 1; + tried_once = true; return 1; } @@ -125,13 +125,13 @@ int cmdline_get_passwd_input(prompts_t *p) */ int cmdline_tooltype = 0; -static int cmdline_check_unavailable(int flag, const char *p) +static bool cmdline_check_unavailable(int flag, const char *p) { if (cmdline_tooltype & flag) { cmdline_error("option \"%s\" not available in this tool", p); - return 1; + return true; } - return 0; + return false; } #define UNAVAILABLE_IN(flag) do { \ @@ -159,8 +159,8 @@ static int cmdline_check_unavailable(int flag, const char *p) if (need_save < 0) return x; \ } while (0) -static int seen_hostname_argument = false; -static int seen_port_argument = false; +static bool seen_hostname_argument = false; +static bool seen_port_argument = false; int cmdline_process_param(const char *p, char *value, int need_save, Conf *conf) @@ -881,7 +881,7 @@ void cmdline_run_saved(Conf *conf) } } -int cmdline_host_ok(Conf *conf) +bool cmdline_host_ok(Conf *conf) { /* * Return true if the command-line arguments we've processed in diff --git a/conf.c b/conf.c index 8eee8447..f97b47df 100644 --- a/conf.c +++ b/conf.c @@ -410,7 +410,7 @@ void conf_set_bool(Conf *conf, int primary, bool value) assert(subkeytypes[primary] == TYPE_NONE); assert(valuetypes[primary] == TYPE_BOOL); entry->key.primary = primary; - entry->value.u.boolval = value; + entry->value.u.boolval = value; conf_insert(conf, entry); } @@ -421,11 +421,12 @@ void conf_set_int(Conf *conf, int primary, int value) assert(subkeytypes[primary] == TYPE_NONE); assert(valuetypes[primary] == TYPE_INT); entry->key.primary = primary; - entry->value.u.intval = value; + entry->value.u.intval = value; conf_insert(conf, entry); } -void conf_set_int_int(Conf *conf, int primary, int secondary, int value) +void conf_set_int_int(Conf *conf, int primary, + int secondary, int value) { struct conf_entry *entry = snew(struct conf_entry); @@ -537,7 +538,7 @@ void conf_serialise(BinarySink *bs, Conf *conf) put_uint32(bs, 0xFFFFFFFFU); } -int conf_deserialise(Conf *conf, BinarySource *src) +bool conf_deserialise(Conf *conf, BinarySource *src) { struct conf_entry *entry; unsigned primary; diff --git a/config.c b/config.c index a4e3f778..f30a581f 100644 --- a/config.c +++ b/config.c @@ -85,9 +85,9 @@ void conf_checkbox_handler(union control *ctrl, dlgparam *dlg, key = ctrl->checkbox.context.i; if (key & CHECKBOX_INVERT) { key &= ~CHECKBOX_INVERT; - invert = 1; + invert = true; } else - invert = 0; + invert = false; /* * C lacks a logical XOR, so the following code uses the idiom @@ -159,7 +159,8 @@ void conf_filesel_handler(union control *ctrl, dlgparam *dlg, Conf *conf = (Conf *)data; if (event == EVENT_REFRESH) { - dlg_filesel_set(ctrl, dlg, conf_get_filename(conf, key)); + dlg_filesel_set( + ctrl, dlg, conf_get_filename(conf, key)); } else if (event == EVENT_VALCHANGE) { Filename *filename = dlg_filesel_get(ctrl, dlg); conf_set_filename(conf, key, filename); @@ -174,7 +175,8 @@ void conf_fontsel_handler(union control *ctrl, dlgparam *dlg, Conf *conf = (Conf *)data; if (event == EVENT_REFRESH) { - dlg_fontsel_set(ctrl, dlg, conf_get_fontspec(conf, key)); + dlg_fontsel_set( + ctrl, dlg, conf_get_fontspec(conf, key)); } else if (event == EVENT_VALCHANGE) { FontSpec *fontspec = dlg_fontsel_get(ctrl, dlg); conf_set_fontspec(conf, key, fontspec); @@ -634,7 +636,7 @@ struct sessionsaver_data { union control *editbox, *listbox, *loadbutton, *savebutton, *delbutton; union control *okbutton, *cancelbutton; struct sesslist sesslist; - int midsession; + bool midsession; char *savedsession; /* the current contents of ssd->editbox */ }; @@ -651,14 +653,15 @@ static void sessionsaver_data_free(void *ssdv) * any, as this is done in more than one place below. Returns 0 for * failure. */ -static int load_selected_session(struct sessionsaver_data *ssd, - dlgparam *dlg, Conf *conf, int *maybe_launch) +static bool load_selected_session( + struct sessionsaver_data *ssd, + dlgparam *dlg, Conf *conf, bool *maybe_launch) { int i = dlg_listbox_index(ssd->listbox, dlg); - int isdef; + bool isdef; if (i < 0) { dlg_beep(dlg); - return 0; + return false; } isdef = !strcmp(ssd->sesslist.sessions[i], "Default Settings"); load_settings(ssd->sesslist.sessions[i], conf); @@ -670,7 +673,7 @@ static int load_selected_session(struct sessionsaver_data *ssd, /* Restore the selection, which might have been clobbered by * changing the value of the edit box. */ dlg_listbox_select(ssd->listbox, dlg, i); - return 1; + return true; } static void sessionsaver_handler(union control *ctrl, dlgparam *dlg, @@ -713,7 +716,7 @@ static void sessionsaver_handler(union control *ctrl, dlgparam *dlg, dlg_listbox_select(ssd->listbox, dlg, top); } } else if (event == EVENT_ACTION) { - int mbl = false; + bool mbl = false; if (!ssd->midsession && (ctrl == ssd->listbox || (ssd->loadbutton && ctrl == ssd->loadbutton))) { @@ -729,7 +732,7 @@ static void sessionsaver_handler(union control *ctrl, dlgparam *dlg, dlg_end(dlg, 1); /* it's all over, and succeeded */ } } else if (ctrl == ssd->savebutton) { - int isdef = !strcmp(ssd->savedsession, "Default Settings"); + bool isdef = !strcmp(ssd->savedsession, "Default Settings"); if (!ssd->savedsession[0]) { int i = dlg_listbox_index(ssd->listbox, dlg); if (i < 0) { @@ -779,7 +782,7 @@ static void sessionsaver_handler(union control *ctrl, dlgparam *dlg, if (dlg_last_focused(ctrl, dlg) == ssd->listbox && !conf_launchable(conf)) { Conf *conf2 = conf_new(); - int mbl = false; + bool mbl = false; if (!load_selected_session(ssd, dlg, conf2, &mbl)) { dlg_beep(dlg); conf_free(conf2); @@ -875,7 +878,8 @@ static void colour_handler(union control *ctrl, dlgparam *dlg, Conf *conf = (Conf *)data; struct colour_data *cd = (struct colour_data *)ctrl->generic.context.p; - int update = false, clear = false, r, g, b; + bool update = false, clear = false; + int r, g, b; if (event == EVENT_REFRESH) { if (ctrl == cd->listbox) { @@ -1464,7 +1468,7 @@ static void clipboard_control(struct controlset *s, const char *label, #endif } -void setup_config_box(struct controlbox *b, int midsession, +void setup_config_box(struct controlbox *b, bool midsession, int protocol, int protcfginfo) { struct controlset *s; @@ -2275,7 +2279,7 @@ void setup_config_box(struct controlbox *b, int midsession, HELPCTX(proxy_auth), conf_editbox_handler, I(CONF_proxy_password), I(1)); - c->editbox.password = 1; + c->editbox.password = true; ctrl_editbox(s, "Telnet command", 'm', 100, HELPCTX(proxy_command), conf_editbox_handler, @@ -2501,7 +2505,7 @@ void setup_config_box(struct controlbox *b, int midsession, HELPCTX(ssh_kex_manual_hostkeys), manual_hostkey_handler, P(mh)); mh->rembutton->generic.column = 1; - mh->rembutton->generic.tabdelay = 1; + mh->rembutton->generic.tabdelay = true; mh->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT, HELPCTX(ssh_kex_manual_hostkeys), manual_hostkey_handler, P(mh)); @@ -2683,7 +2687,7 @@ void setup_config_box(struct controlbox *b, int midsession, HELPCTX(ssh_ttymodes), ttymodes_handler, P(td)); td->setbutton->generic.column = 1; - td->setbutton->generic.tabdelay = 1; + td->setbutton->generic.tabdelay = true; ctrl_columns(s, 1, 100); /* column break */ /* Bit of a hack to get the value radio buttons and * edit-box on the same row. */ @@ -2752,7 +2756,7 @@ void setup_config_box(struct controlbox *b, int midsession, HELPCTX(ssh_tunnels_portfwd), portfwd_handler, P(pfd)); pfd->rembutton->generic.column = 2; - pfd->rembutton->generic.tabdelay = 1; + pfd->rembutton->generic.tabdelay = true; pfd->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT, HELPCTX(ssh_tunnels_portfwd), portfwd_handler, P(pfd)); @@ -2769,7 +2773,7 @@ void setup_config_box(struct controlbox *b, int midsession, HELPCTX(ssh_tunnels_portfwd), portfwd_handler, P(pfd)); pfd->addbutton->generic.column = 2; - pfd->addbutton->generic.tabdelay = 1; + pfd->addbutton->generic.tabdelay = true; pfd->sourcebox = ctrl_editbox(s, "Source port", 's', 40, HELPCTX(ssh_tunnels_portfwd), portfwd_handler, P(pfd), P(NULL)); diff --git a/dialog.c b/dialog.c index e712c452..d00e2529 100644 --- a/dialog.c +++ b/dialog.c @@ -86,7 +86,7 @@ void ctrl_free_set(struct controlset *s) * path. If that path doesn't exist, return the index where it * should be inserted. */ -static int ctrl_find_set(struct controlbox *b, const char *path, int start) +static int ctrl_find_set(struct controlbox *b, const char *path, bool start) { int i, last, thisone; @@ -115,7 +115,7 @@ static int ctrl_find_set(struct controlbox *b, const char *path, int start) int ctrl_find_path(struct controlbox *b, const char *path, int index) { if (index < 0) - index = ctrl_find_set(b, path, 1); + index = ctrl_find_set(b, path, true); else index++; @@ -131,7 +131,7 @@ struct controlset *ctrl_settitle(struct controlbox *b, { struct controlset *s = snew(struct controlset); - int index = ctrl_find_set(b, path, 1); + int index = ctrl_find_set(b, path, true); s->pathname = dupstr(path); s->boxname = NULL; s->boxtitle = dupstr(title); @@ -155,7 +155,7 @@ struct controlset *ctrl_getset(struct controlbox *b, const char *path, const char *name, const char *boxtitle) { struct controlset *s; - int index = ctrl_find_set(b, path, 1); + int index = ctrl_find_set(b, path, true); while (index < b->nctrlsets && !strcmp(b->ctrlsets[index]->pathname, path)) { if (b->ctrlsets[index]->boxname && @@ -227,7 +227,7 @@ static union control *ctrl_new(struct controlset *s, int type, * Fill in the standard fields. */ c->generic.type = type; - c->generic.tabdelay = 0; + c->generic.tabdelay = false; c->generic.column = COLUMN_FIELD(0, s->ncolumns); c->generic.helpctx = helpctx; c->generic.handler = handler; @@ -266,8 +266,8 @@ union control *ctrl_editbox(struct controlset *s, const char *label, c->editbox.label = label ? dupstr(label) : NULL; c->editbox.shortcut = shortcut; c->editbox.percentwidth = percentage; - c->editbox.password = 0; - c->editbox.has_list = 0; + c->editbox.password = false; + c->editbox.has_list = false; c->editbox.context2 = context2; return c; } @@ -281,8 +281,8 @@ union control *ctrl_combobox(struct controlset *s, const char *label, c->editbox.label = label ? dupstr(label) : NULL; c->editbox.shortcut = shortcut; c->editbox.percentwidth = percentage; - c->editbox.password = 0; - c->editbox.has_list = 1; + c->editbox.password = false; + c->editbox.has_list = true; c->editbox.context2 = context2; return c; } @@ -346,8 +346,8 @@ union control *ctrl_pushbutton(struct controlset *s, const char *label, union control *c = ctrl_new(s, CTRL_BUTTON, helpctx, handler, context); c->button.label = label ? dupstr(label) : NULL; c->button.shortcut = shortcut; - c->button.isdefault = 0; - c->button.iscancel = 0; + c->button.isdefault = false; + c->button.iscancel = false; return c; } @@ -359,7 +359,7 @@ union control *ctrl_listbox(struct controlset *s, const char *label, c->listbox.label = label ? dupstr(label) : NULL; c->listbox.shortcut = shortcut; c->listbox.height = 5; /* *shrug* a plausible default */ - c->listbox.draglist = 0; + c->listbox.draglist = false; c->listbox.multisel = 0; c->listbox.percentwidth = 100; c->listbox.ncols = 0; @@ -376,7 +376,7 @@ union control *ctrl_droplist(struct controlset *s, const char *label, c->listbox.label = label ? dupstr(label) : NULL; c->listbox.shortcut = shortcut; c->listbox.height = 0; /* means it's a drop-down list */ - c->listbox.draglist = 0; + c->listbox.draglist = false; c->listbox.multisel = 0; c->listbox.percentwidth = percentage; c->listbox.ncols = 0; @@ -393,7 +393,7 @@ union control *ctrl_draglist(struct controlset *s, const char *label, c->listbox.label = label ? dupstr(label) : NULL; c->listbox.shortcut = shortcut; c->listbox.height = 5; /* *shrug* a plausible default */ - c->listbox.draglist = 1; + c->listbox.draglist = true; c->listbox.multisel = 0; c->listbox.percentwidth = 100; c->listbox.ncols = 0; @@ -403,7 +403,7 @@ union control *ctrl_draglist(struct controlset *s, const char *label, } union control *ctrl_filesel(struct controlset *s, const char *label, - char shortcut, const char *filter, int write, + char shortcut, const char *filter, bool write, const char *title, intorptr helpctx, handler_fn handler, intorptr context) { diff --git a/dialog.h b/dialog.h index fe32da72..864471bb 100644 --- a/dialog.h +++ b/dialog.h @@ -109,7 +109,7 @@ typedef void (*handler_fn)(union control *ctrl, dlgparam *dp, #define STANDARD_PREFIX \ int type; \ char *label; \ - int tabdelay; \ + bool tabdelay; \ int column; \ handler_fn handler; \ intorptr context; \ @@ -142,7 +142,7 @@ union control { * particular control should not yet appear in the tab * order. A subsequent CTRL_TABDELAY entry will place it. */ - int tabdelay; + bool tabdelay; /* * Indicate which column(s) this control occupies. This can * be unpacked into starting column and column span by the @@ -197,7 +197,7 @@ union control { * itself. */ int percentwidth; - int password; /* details of input are hidden */ + bool password; /* details of input are hidden */ /* * A special case of the edit box is the combo box, which * has a drop-down list built in. (Note that a _non_- @@ -208,7 +208,7 @@ union control { * control; front ends are not required to support that * combination. */ - int has_list; + bool has_list; /* * Edit boxes tend to need two items of context, so here's * a spare. @@ -279,12 +279,12 @@ union control { * button', which gets implicitly pressed when you hit * Return even if it doesn't have the input focus. */ - int isdefault; + bool isdefault; /* * Also, the reverse of this: a default cancel-type button, * which is implicitly pressed when you hit Escape. */ - int iscancel; + bool iscancel; } button; struct { STANDARD_PREFIX; @@ -301,7 +301,7 @@ union control { * comfortable with). This is not guaranteed to work on a * drop-down list, so don't try it! */ - int draglist; + bool draglist; /* * If this is non-zero, the list can have more than one * element selected at a time. This is not guaranteed to @@ -344,7 +344,7 @@ union control { * scroll bar if a list box entry goes off the right-hand * side. */ - int hscroll; + bool hscroll; } listbox; struct { STANDARD_PREFIX; @@ -374,7 +374,7 @@ union control { * choosing a file to read or one to write (and possibly * create). */ - int for_writing; + bool for_writing; /* * On at least some platforms, the file selector is a * separate dialog box, and contains a user-settable title. @@ -517,7 +517,7 @@ union control *ctrl_draglist(struct controlset *, const char *label, char shortcut, intorptr helpctx, handler_fn handler, intorptr context); union control *ctrl_filesel(struct controlset *, const char *label, - char shortcut, const char *filter, int write, + char shortcut, const char *filter, bool write, const char *title, intorptr helpctx, handler_fn handler, intorptr context); union control *ctrl_fontsel(struct controlset *, const char *label, @@ -536,8 +536,8 @@ union control *ctrl_tabdelay(struct controlset *, union control *); */ void dlg_radiobutton_set(union control *ctrl, dlgparam *dp, int whichbutton); int dlg_radiobutton_get(union control *ctrl, dlgparam *dp); -void dlg_checkbox_set(union control *ctrl, dlgparam *dp, int checked); -int dlg_checkbox_get(union control *ctrl, dlgparam *dp); +void dlg_checkbox_set(union control *ctrl, dlgparam *dp, bool checked); +bool dlg_checkbox_get(union control *ctrl, dlgparam *dp); void dlg_editbox_set(union control *ctrl, dlgparam *dp, char const *text); char *dlg_editbox_get(union control *ctrl, dlgparam *dp); /* result must be freed by caller */ /* The `listbox' functions can also apply to combo boxes. */ @@ -556,7 +556,7 @@ void dlg_listbox_addwithid(union control *ctrl, dlgparam *dp, int dlg_listbox_getid(union control *ctrl, dlgparam *dp, int index); /* dlg_listbox_index returns <0 if no single element is selected. */ int dlg_listbox_index(union control *ctrl, dlgparam *dp); -int dlg_listbox_issel(union control *ctrl, dlgparam *dp, int index); +bool dlg_listbox_issel(union control *ctrl, dlgparam *dp, int index); void dlg_listbox_select(union control *ctrl, dlgparam *dp, int index); void dlg_text_set(union control *ctrl, dlgparam *dp, char const *text); void dlg_filesel_set(union control *ctrl, dlgparam *dp, Filename *fn); @@ -614,8 +614,8 @@ void dlg_end(dlgparam *dp, int value); */ void dlg_coloursel_start(union control *ctrl, dlgparam *dp, int r, int g, int b); -int dlg_coloursel_results(union control *ctrl, dlgparam *dp, - int *r, int *g, int *b); +bool dlg_coloursel_results(union control *ctrl, dlgparam *dp, + int *r, int *g, int *b); /* * This routine is used by the platform-independent code to diff --git a/fuzzterm.c b/fuzzterm.c index 477dda58..83a176e6 100644 --- a/fuzzterm.c +++ b/fuzzterm.c @@ -7,7 +7,7 @@ #include "terminal.h" /* For Unix in particular, but harmless if this main() is reused elsewhere */ -const int buildinfo_gtk_relevant = false; +const bool buildinfo_gtk_relevant = false; static const TermWinVtable fuzz_termwin_vt; @@ -37,14 +37,14 @@ int main(int argc, char **argv) #endif while (!feof(stdin)) { len = fread(blk, 1, sizeof(blk), stdin); - term_data(term, 0, blk, len); + term_data(term, false, blk, len); } term_update(term); return 0; } /* functions required by terminal.c */ -static int fuzz_setup_draw_ctx(TermWin *tw) { return true; } +static bool fuzz_setup_draw_ctx(TermWin *tw) { return true; } static void fuzz_draw_text( TermWin *tw, int x, int y, wchar_t *text, int len, unsigned long attr, int lattr, truecolour tc) @@ -72,30 +72,30 @@ static void fuzz_draw_cursor( static int fuzz_char_width(TermWin *tw, int uc) { return 1; } static void fuzz_free_draw_ctx(TermWin *tw) {} static void fuzz_set_cursor_pos(TermWin *tw, int x, int y) {} -static void fuzz_set_raw_mouse_mode(TermWin *tw, int enable) {} +static void fuzz_set_raw_mouse_mode(TermWin *tw, bool enable) {} static void fuzz_set_scrollbar(TermWin *tw, int total, int start, int page) {} static void fuzz_bell(TermWin *tw, int mode) {} static void fuzz_clip_write( TermWin *tw, int clipboard, wchar_t *text, int *attrs, - truecolour *colours, int len, int must_deselect) {} + truecolour *colours, int len, bool must_deselect) {} static void fuzz_clip_request_paste(TermWin *tw, int clipboard) {} static void fuzz_refresh(TermWin *tw) {} static void fuzz_request_resize(TermWin *tw, int w, int h) {} static void fuzz_set_title(TermWin *tw, const char *title) {} static void fuzz_set_icon_title(TermWin *tw, const char *icontitle) {} -static void fuzz_set_minimised(TermWin *tw, int minimised) {} -static int fuzz_is_minimised(TermWin *tw) { return false; } -static void fuzz_set_maximised(TermWin *tw, int maximised) {} +static void fuzz_set_minimised(TermWin *tw, bool minimised) {} +static bool fuzz_is_minimised(TermWin *tw) { return false; } +static void fuzz_set_maximised(TermWin *tw, bool maximised) {} static void fuzz_move(TermWin *tw, int x, int y) {} -static void fuzz_set_zorder(TermWin *tw, int top) {} -static int fuzz_palette_get(TermWin *tw, int n, int *r, int *g, int *b) +static void fuzz_set_zorder(TermWin *tw, bool top) {} +static bool fuzz_palette_get(TermWin *tw, int n, int *r, int *g, int *b) { return false; } static void fuzz_palette_set(TermWin *tw, int n, int r, int g, int b) {} static void fuzz_palette_reset(TermWin *tw) {} static void fuzz_get_pos(TermWin *tw, int *x, int *y) { *x = *y = 0; } static void fuzz_get_pixels(TermWin *tw, int *x, int *y) { *x = *y = 0; } -static const char *fuzz_get_title(TermWin *tw, int icon) { return "moo"; } -static int fuzz_is_utf8(TermWin *tw) { return true; } +static const char *fuzz_get_title(TermWin *tw, bool icon) { return "moo"; } +static bool fuzz_is_utf8(TermWin *tw) { return true; } static const TermWinVtable fuzz_termwin_vt = { fuzz_setup_draw_ctx, @@ -127,7 +127,7 @@ static const TermWinVtable fuzz_termwin_vt = { fuzz_is_utf8, }; -void ldisc_send(Ldisc *ldisc, const void *buf, int len, int interactive) {} +void ldisc_send(Ldisc *ldisc, const void *buf, int len, bool interactive) {} void ldisc_echoedit_update(Ldisc *ldisc) {} void modalfatalbox(const char *fmt, ...) { exit(0); } void nonfatal(const char *fmt, ...) { } @@ -167,8 +167,8 @@ void dlg_error_msg(void *dlg, const char *msg) { } void dlg_end(void *dlg, int value) { } void dlg_coloursel_start(union control *ctrl, void *dlg, int r, int g, int b) { } -int dlg_coloursel_results(union control *ctrl, void *dlg, - int *r, int *g, int *b) { return 0; } +bool dlg_coloursel_results(union control *ctrl, void *dlg, + int *r, int *g, int *b) { return false; } void dlg_refresh(union control *ctrl, void *dlg) { } const char *const appname = "FuZZterm"; diff --git a/import.c b/import.c index d3b1d331..d88ad2bb 100644 --- a/import.c +++ b/import.c @@ -12,39 +12,39 @@ #include "ssh.h" #include "misc.h" -int openssh_pem_encrypted(const Filename *filename); -int openssh_new_encrypted(const Filename *filename); +bool openssh_pem_encrypted(const Filename *filename); +bool openssh_new_encrypted(const Filename *filename); struct ssh2_userkey *openssh_pem_read(const Filename *filename, char *passphrase, const char **errmsg_p); struct ssh2_userkey *openssh_new_read(const Filename *filename, char *passphrase, const char **errmsg_p); -int openssh_auto_write(const Filename *filename, struct ssh2_userkey *key, +bool openssh_auto_write(const Filename *filename, struct ssh2_userkey *key, + char *passphrase); +bool openssh_pem_write(const Filename *filename, struct ssh2_userkey *key, + char *passphrase); +bool openssh_new_write(const Filename *filename, struct ssh2_userkey *key, char *passphrase); -int openssh_pem_write(const Filename *filename, struct ssh2_userkey *key, - char *passphrase); -int openssh_new_write(const Filename *filename, struct ssh2_userkey *key, - char *passphrase); -int sshcom_encrypted(const Filename *filename, char **comment); +bool sshcom_encrypted(const Filename *filename, char **comment); struct ssh2_userkey *sshcom_read(const Filename *filename, char *passphrase, const char **errmsg_p); -int sshcom_write(const Filename *filename, struct ssh2_userkey *key, - char *passphrase); +bool sshcom_write(const Filename *filename, struct ssh2_userkey *key, + char *passphrase); /* * Given a key type, determine whether we know how to import it. */ -int import_possible(int type) +bool import_possible(int type) { if (type == SSH_KEYTYPE_OPENSSH_PEM) - return 1; + return true; if (type == SSH_KEYTYPE_OPENSSH_NEW) - return 1; + return true; if (type == SSH_KEYTYPE_SSHCOM) - return 1; - return 0; + return true; + return false; } /* @@ -63,7 +63,7 @@ int import_target_type(int type) /* * Determine whether a foreign key is encrypted. */ -int import_encrypted(const Filename *filename, int type, char **comment) +bool import_encrypted(const Filename *filename, int type, char **comment) { if (type == SSH_KEYTYPE_OPENSSH_PEM) { /* OpenSSH PEM format doesn't contain a key comment at all */ @@ -77,7 +77,7 @@ int import_encrypted(const Filename *filename, int type, char **comment) } else if (type == SSH_KEYTYPE_SSHCOM) { return sshcom_encrypted(filename, comment); } - return 0; + return false; } /* @@ -107,17 +107,17 @@ struct ssh2_userkey *import_ssh2(const Filename *filename, int type, /* * Export an SSH-1 key. */ -int export_ssh1(const Filename *filename, int type, struct RSAKey *key, - char *passphrase) +bool export_ssh1(const Filename *filename, int type, struct RSAKey *key, + char *passphrase) { - return 0; + return false; } /* * Export an SSH-2 key. */ -int export_ssh2(const Filename *filename, int type, - struct ssh2_userkey *key, char *passphrase) +bool export_ssh2(const Filename *filename, int type, + struct ssh2_userkey *key, char *passphrase) { if (type == SSH_KEYTYPE_OPENSSH_AUTO) return openssh_auto_write(filename, key, passphrase); @@ -125,7 +125,7 @@ int export_ssh2(const Filename *filename, int type, return openssh_new_write(filename, key, passphrase); if (type == SSH_KEYTYPE_SSHCOM) return sshcom_write(filename, key, passphrase); - return 0; + return false; } /* @@ -276,7 +276,7 @@ typedef enum { struct openssh_pem_key { openssh_pem_keytype keytype; - int encrypted; + bool encrypted; openssh_pem_enc encryption; char iv[32]; strbuf *keyblob; @@ -309,7 +309,7 @@ static struct openssh_pem_key *load_openssh_pem_key(const Filename *filename, char *line = NULL; const char *errmsg; char *p; - int headers_done; + bool headers_done; char base64_bit[4]; int base64_chars = 0; @@ -358,7 +358,7 @@ static struct openssh_pem_key *load_openssh_pem_key(const Filename *filename, ret->encrypted = false; memset(ret->iv, 0, sizeof(ret->iv)); - headers_done = 0; + headers_done = false; while (1) { if (!(line = fgetline(fp))) { errmsg = "unexpected end of file"; @@ -415,7 +415,7 @@ static struct openssh_pem_key *load_openssh_pem_key(const Filename *filename, } } } else { - headers_done = 1; + headers_done = true; p = line; while (isbase64(*p)) { @@ -482,13 +482,13 @@ static struct openssh_pem_key *load_openssh_pem_key(const Filename *filename, return NULL; } -int openssh_pem_encrypted(const Filename *filename) +bool openssh_pem_encrypted(const Filename *filename) { struct openssh_pem_key *key = load_openssh_pem_key(filename, NULL); - int ret; + bool ret; if (!key) - return 0; + return false; ret = key->encrypted; strbuf_free(key->keyblob); smemclr(key, sizeof(*key)); @@ -775,8 +775,8 @@ struct ssh2_userkey *openssh_pem_read(const Filename *filename, return retval; } -int openssh_pem_write(const Filename *filename, struct ssh2_userkey *key, - char *passphrase) +bool openssh_pem_write(const Filename *filename, struct ssh2_userkey *key, + char *passphrase) { strbuf *pubblob, *privblob, *outblob; unsigned char *spareblob; @@ -786,7 +786,7 @@ int openssh_pem_write(const Filename *filename, struct ssh2_userkey *key, const char *header, *footer; char zero[1]; unsigned char iv[8]; - int ret = 0; + bool ret = false; FILE *fp; BinarySource src[1]; @@ -1061,7 +1061,7 @@ int openssh_pem_write(const Filename *filename, struct ssh2_userkey *key, base64_encode(fp, outblob->u, outblob->len, 64); fputs(footer, fp); fclose(fp); - ret = 1; + ret = true; error: if (outblob) @@ -1319,13 +1319,13 @@ static struct openssh_new_key *load_openssh_new_key(const Filename *filename, return NULL; } -int openssh_new_encrypted(const Filename *filename) +bool openssh_new_encrypted(const Filename *filename) { struct openssh_new_key *key = load_openssh_new_key(filename, NULL); - int ret; + bool ret; if (!key) - return 0; + return false; ret = (key->cipher != ON_E_NONE); smemclr(key->keyblob, key->keyblob_size); sfree(key->keyblob); @@ -1515,13 +1515,13 @@ struct ssh2_userkey *openssh_new_read(const Filename *filename, return retval; } -int openssh_new_write(const Filename *filename, struct ssh2_userkey *key, - char *passphrase) +bool openssh_new_write(const Filename *filename, struct ssh2_userkey *key, + char *passphrase) { strbuf *pubblob, *privblob, *cblob; int padvalue, i; unsigned checkint; - int ret = 0; + bool ret = false; unsigned char bcrypt_salt[16]; const int bcrypt_rounds = 16; FILE *fp; @@ -1628,7 +1628,7 @@ int openssh_new_write(const Filename *filename, struct ssh2_userkey *key, base64_encode(fp, cblob->u, cblob->len, 64); fputs("-----END OPENSSH PRIVATE KEY-----\n", fp); fclose(fp); - ret = 1; + ret = true; error: if (cblob) @@ -1644,8 +1644,8 @@ int openssh_new_write(const Filename *filename, struct ssh2_userkey *key, * The switch function openssh_auto_write(), which chooses one of the * concrete OpenSSH output formats based on the key type. */ -int openssh_auto_write(const Filename *filename, struct ssh2_userkey *key, - char *passphrase) +bool openssh_auto_write(const Filename *filename, struct ssh2_userkey *key, + char *passphrase) { /* * The old OpenSSH format supports a fixed list of key types. We @@ -1753,7 +1753,7 @@ static struct sshcom_key *load_sshcom_key(const Filename *filename, int hdrstart, len; const char *errmsg; char *p; - int headers_done; + bool headers_done; char base64_bit[4]; int base64_chars = 0; @@ -1780,7 +1780,7 @@ static struct sshcom_key *load_sshcom_key(const Filename *filename, sfree(line); line = NULL; - headers_done = 0; + headers_done = false; while (1) { if (!(line = fgetline(fp))) { errmsg = "unexpected end of file"; @@ -1840,7 +1840,7 @@ static struct sshcom_key *load_sshcom_key(const Filename *filename, ret->comment[sizeof(ret->comment)-1] = '\0'; } } else { - headers_done = 1; + headers_done = true; p = line; while (isbase64(*p)) { @@ -1905,12 +1905,12 @@ static struct sshcom_key *load_sshcom_key(const Filename *filename, return NULL; } -int sshcom_encrypted(const Filename *filename, char **comment) +bool sshcom_encrypted(const Filename *filename, char **comment) { struct sshcom_key *key = load_sshcom_key(filename, NULL); BinarySource src[1]; ptrlen str; - int answer = false; + bool answer = false; *comment = NULL; if (!key) @@ -1981,7 +1981,7 @@ struct ssh2_userkey *sshcom_read(const Filename *filename, char *passphrase, const char prefix_rsa[] = "if-modn{sign{rsa"; const char prefix_dsa[] = "dl-modp{sign{dsa"; enum { RSA, DSA } type; - int encrypted; + bool encrypted; struct ssh2_userkey *ret = NULL, *retkey; const ssh_keyalg *alg; strbuf *blob = NULL; @@ -2017,9 +2017,9 @@ struct ssh2_userkey *sshcom_read(const Filename *filename, char *passphrase, */ str = get_string(src); if (ptrlen_eq_string(str, "none")) - encrypted = 0; + encrypted = false; else if (ptrlen_eq_string(str, "3des-cbc")) - encrypted = 1; + encrypted = true; else { errmsg = "key encryption is of unknown type"; goto error; @@ -2181,17 +2181,18 @@ struct ssh2_userkey *sshcom_read(const Filename *filename, char *passphrase, return ret; } -int sshcom_write(const Filename *filename, struct ssh2_userkey *key, - char *passphrase) +bool sshcom_write(const Filename *filename, struct ssh2_userkey *key, + char *passphrase) { strbuf *pubblob, *privblob, *outblob; ptrlen numbers[6]; - int nnumbers, initial_zero, lenpos, i; + int nnumbers, lenpos, i; + bool initial_zero; BinarySource src[1]; const char *type; char *ciphertext; int cipherlen; - int ret = 0; + bool ret = false; FILE *fp; /* @@ -2234,7 +2235,7 @@ int sshcom_write(const Filename *filename, struct ssh2_userkey *key, numbers[5] = p; nnumbers = 6; - initial_zero = 0; + initial_zero = false; type = "if-modn{sign{rsa-pkcs1-sha1},encrypt{rsa-pkcs1v2-oaep}}"; } else if (ssh_key_alg(key->key) == &ssh_dss) { ptrlen p, q, g, y, x; @@ -2261,7 +2262,7 @@ int sshcom_write(const Filename *filename, struct ssh2_userkey *key, numbers[4] = x; nnumbers = 5; - initial_zero = 1; + initial_zero = true; type = "dl-modp{sign{dsa-nist-sha1},dh{plain}}"; } else { goto error; /* unsupported key type */ @@ -2362,7 +2363,7 @@ int sshcom_write(const Filename *filename, struct ssh2_userkey *key, base64_encode(fp, outblob->u, outblob->len, 70); fputs("---- END SSH2 ENCRYPTED PRIVATE KEY ----\n", fp); fclose(fp); - ret = 1; + ret = true; error: if (outblob) diff --git a/ldisc.c b/ldisc.c index 1273d05d..0779d142 100644 --- a/ldisc.c +++ b/ldisc.c @@ -60,12 +60,12 @@ static void pwrite(Ldisc *ldisc, unsigned char c) } } -static int char_start(Ldisc *ldisc, unsigned char c) +static bool char_start(Ldisc *ldisc, unsigned char c) { if (in_utf(ldisc->term)) return (c < 0x80 || c >= 0xC0); else - return 1; + return true; } static void bsb(Ldisc *ldisc, int n) @@ -84,7 +84,7 @@ Ldisc *ldisc_create(Conf *conf, Terminal *term, Backend *backend, Seat *seat) ldisc->buf = NULL; ldisc->buflen = 0; ldisc->bufsiz = 0; - ldisc->quotenext = 0; + ldisc->quotenext = false; ldisc->backend = backend; ldisc->term = term; @@ -126,7 +126,7 @@ void ldisc_echoedit_update(Ldisc *ldisc) seat_echoedit_update(ldisc->seat, ECHOING, EDITING); } -void ldisc_send(Ldisc *ldisc, const void *vbuf, int len, int interactive) +void ldisc_send(Ldisc *ldisc, const void *vbuf, int len, bool interactive) { const char *buf = (const char *)vbuf; int keyflag = 0; diff --git a/ldisc.h b/ldisc.h index 3b5e8249..65a544ad 100644 --- a/ldisc.h +++ b/ldisc.h @@ -16,10 +16,12 @@ struct Ldisc_tag { /* * Values cached out of conf. */ - int telnet_keyboard, telnet_newline, protocol, localecho, localedit; + bool telnet_keyboard, telnet_newline; + int protocol, localecho, localedit; char *buf; - int buflen, bufsiz, quotenext; + int buflen, bufsiz; + bool quotenext; }; #endif /* PUTTY_LDISC_H */ diff --git a/ldiscucs.c b/ldiscucs.c index 50ce2094..774368f3 100644 --- a/ldiscucs.c +++ b/ldiscucs.c @@ -13,7 +13,7 @@ #include "ldisc.h" void lpage_send(Ldisc *ldisc, - int codepage, const char *buf, int len, int interactive) + int codepage, const char *buf, int len, bool interactive) { wchar_t *widebuffer = 0; int widesize = 0; @@ -33,7 +33,7 @@ void lpage_send(Ldisc *ldisc, sfree(widebuffer); } -void luni_send(Ldisc *ldisc, const wchar_t *widebuf, int len, int interactive) +void luni_send(Ldisc *ldisc, const wchar_t *widebuf, int len, bool interactive) { int ratio = (in_utf(ldisc->term))?3:1; char *linebuffer; diff --git a/logging.c b/logging.c index 68bb8acf..a43ebcd1 100644 --- a/logging.c +++ b/logging.c @@ -87,7 +87,7 @@ static void logfopen_callback(void *vctx, int mode) char buf[256], *event; struct tm tm; const char *fmode; - int shout = false; + bool shout = false; if (mode == 0) { ctx->state = L_ERROR; /* disable logging */ @@ -419,7 +419,7 @@ void log_free(LogContext *ctx) void log_reconfig(LogContext *ctx, Conf *conf) { - int reset_logging; + bool reset_logging; if (!filename_equal(conf_get_filename(ctx->conf, CONF_logfilename), conf_get_filename(conf, CONF_logfilename)) || @@ -463,7 +463,7 @@ static Filename *xlatlognam(Filename *src, char *hostname, int port, s = filename_to_str(src); while (*s) { - int sanitise = false; + bool sanitise = false; /* Let (bufp, len) be the string to append. */ bufp = buf; /* don't usually override this */ if (*s == '&') { diff --git a/mainchan.c b/mainchan.c index ffbbb761..ce991933 100644 --- a/mainchan.c +++ b/mainchan.c @@ -14,16 +14,16 @@ static void mainchan_free(Channel *chan); static void mainchan_open_confirmation(Channel *chan); static void mainchan_open_failure(Channel *chan, const char *errtext); -static int mainchan_send(Channel *chan, int is_stderr, const void *, int); +static int mainchan_send(Channel *chan, bool is_stderr, const void *, int); static void mainchan_send_eof(Channel *chan); -static void mainchan_set_input_wanted(Channel *chan, int wanted); +static void mainchan_set_input_wanted(Channel *chan, bool wanted); static char *mainchan_log_close_msg(Channel *chan); -static int mainchan_rcvd_exit_status(Channel *chan, int status); -static int mainchan_rcvd_exit_signal( - Channel *chan, ptrlen signame, int core_dumped, ptrlen msg); -static int mainchan_rcvd_exit_signal_numeric( - Channel *chan, int signum, int core_dumped, ptrlen msg); -static void mainchan_request_response(Channel *chan, int success); +static bool mainchan_rcvd_exit_status(Channel *chan, int status); +static bool mainchan_rcvd_exit_signal( + Channel *chan, ptrlen signame, bool core_dumped, ptrlen msg); +static bool mainchan_rcvd_exit_signal_numeric( + Channel *chan, int signum, bool core_dumped, ptrlen msg); +static void mainchan_request_response(Channel *chan, bool success); static const struct ChannelVtable mainchan_channelvt = { mainchan_free, @@ -61,11 +61,11 @@ struct mainchan { ConnectionLayer *cl; MainChanType type; - int is_simple; + bool is_simple; - int req_x11, req_agent, req_pty, req_cmd_primary, req_cmd_fallback; + bool req_x11, req_agent, req_pty, req_cmd_primary, req_cmd_fallback; int n_req_env, n_env_replies, n_env_fails; - int eof_pending, eof_sent, got_pty, ready; + bool eof_pending, eof_sent, got_pty, ready; int term_width, term_height; @@ -74,7 +74,7 @@ struct mainchan { mainchan *mainchan_new( PacketProtocolLayer *ppl, ConnectionLayer *cl, Conf *conf, - int term_width, int term_height, int is_simple, SshChannel **sc_out) + int term_width, int term_height, bool is_simple, SshChannel **sc_out) { mainchan *mc; @@ -139,7 +139,7 @@ static void mainchan_open_confirmation(Channel *chan) char *key, *val, *cmd; struct X11Display *x11disp; struct X11FakeAuth *x11auth; - int retry_cmd_now = false; + bool retry_cmd_now = false; if (conf_get_bool(mc->conf, CONF_x11_forward)) {; char *x11_setup_err; @@ -212,7 +212,7 @@ static void mainchan_try_fallback_command(mainchan *mc) mc->req_cmd_fallback = true; } -static void mainchan_request_response(Channel *chan, int success) +static void mainchan_request_response(Channel *chan, bool success) { assert(chan->vt == &mainchan_channelvt); mainchan *mc = container_of(chan, mainchan, chan); @@ -362,7 +362,7 @@ static void mainchan_open_failure(Channel *chan, const char *errtext) queue_toplevel_callback(mainchan_open_failure_abort, ctx); } -static int mainchan_send(Channel *chan, int is_stderr, +static int mainchan_send(Channel *chan, bool is_stderr, const void *data, int length) { assert(chan->vt == &mainchan_channelvt); @@ -391,7 +391,7 @@ static void mainchan_send_eof(Channel *chan) ssh_set_wants_user_input(mc->cl, false); /* now stop reading from stdin */ } -static void mainchan_set_input_wanted(Channel *chan, int wanted) +static void mainchan_set_input_wanted(Channel *chan, bool wanted) { assert(chan->vt == &mainchan_channelvt); mainchan *mc = container_of(chan, mainchan, chan); @@ -410,7 +410,7 @@ static char *mainchan_log_close_msg(Channel *chan) return dupstr("Main session channel closed"); } -static int mainchan_rcvd_exit_status(Channel *chan, int status) +static bool mainchan_rcvd_exit_status(Channel *chan, int status) { assert(chan->vt == &mainchan_channelvt); mainchan *mc = container_of(chan, mainchan, chan); @@ -423,7 +423,7 @@ static int mainchan_rcvd_exit_status(Channel *chan, int status) static void mainchan_log_exit_signal_common( mainchan *mc, const char *sigdesc, - int core_dumped, ptrlen msg) + bool core_dumped, ptrlen msg) { PacketProtocolLayer *ppl = mc->ppl; /* for ppl_logevent */ @@ -434,8 +434,8 @@ static void mainchan_log_exit_signal_common( sigdesc, core_msg, msg_pre, PTRLEN_PRINTF(msg), msg_post)); } -static int mainchan_rcvd_exit_signal( - Channel *chan, ptrlen signame, int core_dumped, ptrlen msg) +static bool mainchan_rcvd_exit_signal( + Channel *chan, ptrlen signame, bool core_dumped, ptrlen msg) { assert(chan->vt == &mainchan_channelvt); mainchan *mc = container_of(chan, mainchan, chan); @@ -469,8 +469,8 @@ static int mainchan_rcvd_exit_signal( return true; } -static int mainchan_rcvd_exit_signal_numeric( - Channel *chan, int signum, int core_dumped, ptrlen msg) +static bool mainchan_rcvd_exit_signal_numeric( + Channel *chan, int signum, bool core_dumped, ptrlen msg) { assert(chan->vt == &mainchan_channelvt); mainchan *mc = container_of(chan, mainchan, chan); diff --git a/marshal.c b/marshal.c index 349367aa..06f6d631 100644 --- a/marshal.c +++ b/marshal.c @@ -26,7 +26,7 @@ void BinarySink_put_byte(BinarySink *bs, unsigned char val) bs->write(bs, &val, 1); } -void BinarySink_put_bool(BinarySink *bs, int val) +void BinarySink_put_bool(BinarySink *bs, bool val) { unsigned char cval = val ? 1 : 0; bs->write(bs, &cval, 1); @@ -84,7 +84,7 @@ void BinarySink_put_asciz(BinarySink *bs, const char *str) bs->write(bs, str, strlen(str) + 1); } -int BinarySink_put_pstring(BinarySink *bs, const char *str) +bool BinarySink_put_pstring(BinarySink *bs, const char *str) { size_t len = strlen(str); if (len > 255) @@ -96,7 +96,7 @@ int BinarySink_put_pstring(BinarySink *bs, const char *str) /* ---------------------------------------------------------------------- */ -static int BinarySource_data_avail(BinarySource *src, size_t wanted) +static bool BinarySource_data_avail(BinarySource *src, size_t wanted) { if (src->err) return false; @@ -134,12 +134,12 @@ unsigned char BinarySource_get_byte(BinarySource *src) return *ucp; } -int BinarySource_get_bool(BinarySource *src) +bool BinarySource_get_bool(BinarySource *src) { const unsigned char *ucp; if (!avail(1)) - return 0; + return false; ucp = consume(1); return *ucp != 0; diff --git a/marshal.h b/marshal.h index af35ff7e..e19cd0b9 100644 --- a/marshal.h +++ b/marshal.h @@ -142,7 +142,7 @@ struct BinarySink { void BinarySink_put_data(BinarySink *, const void *data, size_t len); void BinarySink_put_padding(BinarySink *, size_t len, unsigned char padbyte); void BinarySink_put_byte(BinarySink *, unsigned char); -void BinarySink_put_bool(BinarySink *, int); +void BinarySink_put_bool(BinarySink *, bool); void BinarySink_put_uint16(BinarySink *, unsigned long); void BinarySink_put_uint32(BinarySink *, unsigned long); void BinarySink_put_uint64(BinarySink *, uint64_t); @@ -152,7 +152,7 @@ void BinarySink_put_stringz(BinarySink *, const char *str); struct strbuf; void BinarySink_put_stringsb(BinarySink *, struct strbuf *); void BinarySink_put_asciz(BinarySink *, const char *str); -int BinarySink_put_pstring(BinarySink *, const char *str); +bool BinarySink_put_pstring(BinarySink *, const char *str); /* ---------------------------------------------------------------------- */ @@ -274,7 +274,7 @@ struct BinarySource { ptrlen BinarySource_get_data(BinarySource *, size_t); unsigned char BinarySource_get_byte(BinarySource *); -int BinarySource_get_bool(BinarySource *); +bool BinarySource_get_bool(BinarySource *); unsigned BinarySource_get_uint16(BinarySource *); unsigned long BinarySource_get_uint32(BinarySource *); uint64_t BinarySource_get_uint64(BinarySource *); diff --git a/minibidi.c b/minibidi.c index 2bdf4deb..64f27a96 100644 --- a/minibidi.c +++ b/minibidi.c @@ -1086,9 +1086,10 @@ int getPreviousLevel(unsigned char* level, int from) */ int do_shape(bidi_char *line, bidi_char *to, int count) { - int i, tempShape, ligFlag; + int i, tempShape; + bool ligFlag = false; - for (ligFlag=i=0; i 0) switch (line[i-1].wc) { case 0x622: - ligFlag = 1; + ligFlag = true; if ((tempShape == SL) || (tempShape == SD) || (tempShape == SC)) to[i].wc = 0xFEF6; else to[i].wc = 0xFEF5; break; case 0x623: - ligFlag = 1; + ligFlag = true; if ((tempShape == SL) || (tempShape == SD) || (tempShape == SC)) to[i].wc = 0xFEF8; else to[i].wc = 0xFEF7; break; case 0x625: - ligFlag = 1; + ligFlag = true; if ((tempShape == SL) || (tempShape == SD) || (tempShape == SC)) to[i].wc = 0xFEFA; else to[i].wc = 0xFEF9; break; case 0x627: - ligFlag = 1; + ligFlag = true; if ((tempShape == SL) || (tempShape == SD) || (tempShape == SC)) to[i].wc = 0xFEFC; else @@ -1143,7 +1144,7 @@ int do_shape(bidi_char *line, bidi_char *to, int count) } if (ligFlag) { to[i-1].wc = 0x20; - ligFlag = 0; + ligFlag = false; break; } } @@ -1186,18 +1187,19 @@ int do_bidi(bidi_char *line, int count) unsigned char currentEmbedding; unsigned char currentOverride; unsigned char tempType; - int i, j, yes, bover; + int i, j; + bool yes, bover; /* Check the presence of R or AL types as optimization */ - yes = 0; + yes = false; for (i=0; iname_reqd = p->instr_reqd = false; return p; } -void add_prompt(prompts_t *p, char *promptstr, int echo) +void add_prompt(prompts_t *p, char *promptstr, bool echo) { prompt_t *pr = snew(prompt_t); pr->prompt = promptstr; @@ -826,7 +826,7 @@ void bufchain_fetch_consume(bufchain *ch, void *data, int len) bufchain_consume(ch, len); } -int bufchain_try_fetch_consume(bufchain *ch, void *data, int len) +bool bufchain_try_fetch_consume(bufchain *ch, void *data, int len) { if (ch->buffersize >= len) { bufchain_fetch_consume(ch, data, len); @@ -1055,7 +1055,7 @@ void debug_memdump(const void *buf, int len, int L) * Determine whether or not a Conf represents a session which can * sensibly be launched right now. */ -int conf_launchable(Conf *conf) +bool conf_launchable(Conf *conf) { if (conf_get_int(conf, CONF_protocol) == PROT_SERIAL) return conf_get_str(conf, CONF_serline)[0] != 0; @@ -1119,7 +1119,7 @@ void smemclr(void *b, size_t n) { * original version), suitable for putting into the Conf. If not * valid, we return false. */ -int validate_manual_hostkey(char *key) +bool validate_manual_hostkey(char *key) { char *p, *q, *r, *s; @@ -1208,7 +1208,7 @@ int validate_manual_hostkey(char *key) return false; } -int smemeq(const void *av, const void *bv, size_t len) +bool smemeq(const void *av, const void *bv, size_t len) { const unsigned char *a = (const unsigned char *)av; const unsigned char *b = (const unsigned char *)bv; @@ -1253,18 +1253,18 @@ ptrlen ptrlen_from_strbuf(strbuf *sb) return make_ptrlen(sb->u, sb->len); } -int ptrlen_eq_string(ptrlen pl, const char *str) +bool ptrlen_eq_string(ptrlen pl, const char *str) { size_t len = strlen(str); return (pl.len == len && !memcmp(pl.ptr, str, len)); } -int ptrlen_eq_ptrlen(ptrlen pl1, ptrlen pl2) +bool ptrlen_eq_ptrlen(ptrlen pl1, ptrlen pl2) { return (pl1.len == pl2.len && !memcmp(pl1.ptr, pl2.ptr, pl1.len)); } -int ptrlen_startswith(ptrlen whole, ptrlen prefix, ptrlen *tail) +bool ptrlen_startswith(ptrlen whole, ptrlen prefix, ptrlen *tail) { if (whole.len >= prefix.len && !memcmp(whole.ptr, prefix.ptr, prefix.len)) { @@ -1285,12 +1285,12 @@ char *mkstr(ptrlen pl) return p; } -int strstartswith(const char *s, const char *t) +bool strstartswith(const char *s, const char *t) { return !memcmp(s, t, strlen(t)); } -int strendswith(const char *s, const char *t) +bool strendswith(const char *s, const char *t) { size_t slen = strlen(s), tlen = strlen(t); return slen >= tlen && !strcmp(s + (slen - tlen), t); @@ -1390,8 +1390,8 @@ char *buildinfo(const char *newline) } int nullseat_output( - Seat *seat, int is_stderr, const void *data, int len) { return 0; } -int nullseat_eof(Seat *seat) { return true; } + Seat *seat, bool is_stderr, const void *data, int len) { return 0; } +bool nullseat_eof(Seat *seat) { return true; } int nullseat_get_userpass_input( Seat *seat, prompts_t *p, bufchain *input) { return 0; } void nullseat_notify_remote_exit(Seat *seat) {} @@ -1409,12 +1409,12 @@ int nullseat_confirm_weak_crypto_primitive( int nullseat_confirm_weak_cached_hostkey( Seat *seat, const char *algname, const char *betteralgs, void (*callback)(void *ctx, int result), void *ctx) { return 0; } -int nullseat_is_never_utf8(Seat *seat) { return false; } -int nullseat_is_always_utf8(Seat *seat) { return true; } -void nullseat_echoedit_update(Seat *seat, int echoing, int editing) {} +bool nullseat_is_never_utf8(Seat *seat) { return false; } +bool nullseat_is_always_utf8(Seat *seat) { return true; } +void nullseat_echoedit_update(Seat *seat, bool echoing, bool editing) {} const char *nullseat_get_x_display(Seat *seat) { return NULL; } -int nullseat_get_windowid(Seat *seat, long *id_out) { return false; } -int nullseat_get_window_pixel_size( +bool nullseat_get_windowid(Seat *seat, long *id_out) { return false; } +bool nullseat_get_window_pixel_size( Seat *seat, int *width, int *height) { return false; } void sk_free_peer_info(SocketPeerInfo *pi) diff --git a/misc.h b/misc.h index 587e97e3..5d493c48 100644 --- a/misc.h +++ b/misc.h @@ -61,8 +61,8 @@ int toint(unsigned); char *fgetline(FILE *fp); char *chomp(char *str); -int strstartswith(const char *s, const char *t); -int strendswith(const char *s, const char *t); +bool strstartswith(const char *s, const char *t); +bool strendswith(const char *s, const char *t); void base64_encode_atom(const unsigned char *data, int n, char *out); int base64_decode_atom(const char *atom, unsigned char *out); @@ -82,11 +82,11 @@ void bufchain_prefix(bufchain *ch, void **data, int *len); void bufchain_consume(bufchain *ch, int len); void bufchain_fetch(bufchain *ch, void *data, int len); void bufchain_fetch_consume(bufchain *ch, void *data, int len); -int bufchain_try_fetch_consume(bufchain *ch, void *data, int len); +bool bufchain_try_fetch_consume(bufchain *ch, void *data, int len); void sanitise_term_data(bufchain *out, const void *vdata, int len); -int validate_manual_hostkey(char *key); +bool validate_manual_hostkey(char *key); struct tm ltime(void); @@ -99,9 +99,9 @@ int nullstrcmp(const char *a, const char *b); ptrlen make_ptrlen(const void *ptr, size_t len); ptrlen ptrlen_from_asciz(const char *str); ptrlen ptrlen_from_strbuf(strbuf *sb); -int ptrlen_eq_string(ptrlen pl, const char *str); -int ptrlen_eq_ptrlen(ptrlen pl1, ptrlen pl2); -int ptrlen_startswith(ptrlen whole, ptrlen prefix, ptrlen *tail); +bool ptrlen_eq_string(ptrlen pl, const char *str); +bool ptrlen_eq_ptrlen(ptrlen pl1, ptrlen pl2); +bool ptrlen_startswith(ptrlen whole, ptrlen prefix, ptrlen *tail); char *mkstr(ptrlen pl); int string_length_for_printf(size_t); /* Derive two printf arguments from a ptrlen, suitable for "%.*s" */ @@ -124,9 +124,9 @@ void smemclr(void *b, size_t len); /* Compare two fixed-length chunks of memory for equality, without * data-dependent control flow (so an attacker with a very accurate * stopwatch can't try to guess where the first mismatching byte was). - * Returns 0 for mismatch or 1 for equality (unlike memcmp), hinted at - * by the 'eq' in the name. */ -int smemeq(const void *av, const void *bv, size_t len); + * Returns false for mismatch or true for equality (unlike memcmp), + * hinted at by the 'eq' in the name. */ +bool smemeq(const void *av, const void *bv, size_t len); char *buildinfo(const char *newline); @@ -145,10 +145,10 @@ char *buildinfo(const char *newline); #ifdef DEBUG void debug_printf(const char *fmt, ...); -void debug_memdump(const void *buf, int len, int L); +void debug_memdump(const void *buf, int len, bool L); #define debug(x) (debug_printf x) -#define dmemdump(buf,len) debug_memdump (buf, len, 0); -#define dmemdumpl(buf,len) debug_memdump (buf, len, 1); +#define dmemdump(buf,len) debug_memdump (buf, len, false); +#define dmemdumpl(buf,len) debug_memdump (buf, len, true); #else #define debug(x) #define dmemdump(buf,len) diff --git a/network.h b/network.h index 62f3afe3..a394a356 100644 --- a/network.h +++ b/network.h @@ -32,7 +32,7 @@ struct SocketVtable { int (*write_oob) (Socket *s, const void *data, int len); void (*write_eof) (Socket *s); void (*flush) (Socket *s); - void (*set_frozen) (Socket *s, int is_frozen); + void (*set_frozen) (Socket *s, bool is_frozen); /* ignored by tcp, but vital for ssl */ const char *(*socket_error) (Socket *s); SocketPeerInfo *(*peer_info) (Socket *s); @@ -66,7 +66,7 @@ struct PlugVtable { * indicate this. */ void (*closing) - (Plug *p, const char *error_msg, int error_code, int calling_back); + (Plug *p, const char *error_msg, int error_code, bool calling_back); /* error_msg is NULL iff it is not an error (ie it closed normally) */ /* calling_back != 0 iff there is a Plug function */ /* currently running (would cure the fixme in try_send()) */ @@ -100,22 +100,22 @@ struct PlugVtable { /* NB, control of 'addr' is passed via new_connection, which takes * responsibility for freeing it */ Socket *new_connection(SockAddr *addr, const char *hostname, - int port, int privport, - int oobinline, int nodelay, int keepalive, + int port, bool privport, + bool oobinline, bool nodelay, bool keepalive, Plug *plug, Conf *conf); Socket *new_listener(const char *srcaddr, int port, Plug *plug, - int local_host_only, Conf *conf, int addressfamily); + bool local_host_only, Conf *conf, int addressfamily); SockAddr *name_lookup(const char *host, int port, char **canonicalname, Conf *conf, int addressfamily, LogContext *logctx, const char *lookup_reason_for_logging); -int proxy_for_destination (SockAddr *addr, const char *hostname, int port, - Conf *conf); +bool proxy_for_destination (SockAddr *addr, const char *hostname, int port, + Conf *conf); /* platform-dependent callback from new_connection() */ /* (same caveat about addr as new_connection()) */ Socket *platform_new_connection(SockAddr *addr, const char *hostname, - int port, int privport, - int oobinline, int nodelay, int keepalive, + int port, bool privport, + bool oobinline, bool nodelay, bool keepalive, Plug *plug, Conf *conf); /* socket functions */ @@ -126,10 +126,10 @@ void sk_cleanup(void); /* called just before program exit */ SockAddr *sk_namelookup(const char *host, char **canonicalname, int address_family); SockAddr *sk_nonamelookup(const char *host); void sk_getaddr(SockAddr *addr, char *buf, int buflen); -int sk_addr_needs_port(SockAddr *addr); -int sk_hostname_is_local(const char *name); -int sk_address_is_local(SockAddr *addr); -int sk_address_is_special_local(SockAddr *addr); +bool sk_addr_needs_port(SockAddr *addr); +bool sk_hostname_is_local(const char *name); +bool sk_address_is_local(SockAddr *addr); +bool sk_address_is_special_local(SockAddr *addr); int sk_addrtype(SockAddr *addr); void sk_addrcopy(SockAddr *addr, char *buf); void sk_addr_free(SockAddr *addr); @@ -142,11 +142,11 @@ SockAddr *sk_addr_dup(SockAddr *addr); /* NB, control of 'addr' is passed via sk_new, which takes responsibility * for freeing it, as for new_connection() */ -Socket *sk_new(SockAddr *addr, int port, int privport, int oobinline, - int nodelay, int keepalive, Plug *p); +Socket *sk_new(SockAddr *addr, int port, bool privport, bool oobinline, + bool nodelay, bool keepalive, Plug *p); Socket *sk_newlistener(const char *srcaddr, int port, Plug *plug, - int local_host_only, int address_family); + bool local_host_only, int address_family); #define sk_plug(s,p) (((s)->vt->plug) (s, p)) #define sk_close(s) (((s)->vt->close) (s)) @@ -278,7 +278,7 @@ extern Plug *const nullplug; void backend_socket_log(Seat *seat, LogContext *logctx, int type, SockAddr *addr, int port, const char *error_msg, int error_code, Conf *conf, - int session_started); + bool session_started); void log_proxy_stderr(Plug *plug, bufchain *buf, const void *vdata, int len); #endif diff --git a/nullplug.c b/nullplug.c index 4fc16841..ca6c7c2c 100644 --- a/nullplug.c +++ b/nullplug.c @@ -13,7 +13,7 @@ static void nullplug_socket_log(Plug *plug, int type, SockAddr *addr, int port, } static void nullplug_closing(Plug *plug, const char *error_msg, int error_code, - int calling_back) + bool calling_back) { } diff --git a/pageant.c b/pageant.c index a50a4397..8bdbe1f6 100644 --- a/pageant.c +++ b/pageant.c @@ -27,7 +27,7 @@ int random_byte(void) return 0; /* unreachable, but placate optimiser */ } -static int pageant_local = false; +static bool pageant_local = false; /* * rsakeys stores SSH-1 RSA keys. ssh2keys stores all SSH-2 keys. @@ -652,17 +652,17 @@ int pageant_count_ssh2_keys(void) return count234(ssh2keys); } -int pageant_add_ssh1_key(struct RSAKey *rkey) +bool pageant_add_ssh1_key(struct RSAKey *rkey) { return add234(rsakeys, rkey) == rkey; } -int pageant_add_ssh2_key(struct ssh2_userkey *skey) +bool pageant_add_ssh2_key(struct ssh2_userkey *skey) { return add234(ssh2keys, skey) == skey; } -int pageant_delete_ssh1_key(struct RSAKey *rkey) +bool pageant_delete_ssh1_key(struct RSAKey *rkey) { struct RSAKey *deleted = del234(rsakeys, rkey); if (!deleted) @@ -671,7 +671,7 @@ int pageant_delete_ssh1_key(struct RSAKey *rkey) return true; } -int pageant_delete_ssh2_key(struct ssh2_userkey *skey) +bool pageant_delete_ssh2_key(struct ssh2_userkey *skey) { struct ssh2_userkey *deleted = del234(ssh2keys, skey); if (!deleted) @@ -704,14 +704,14 @@ struct pageant_conn_state { pageant_logfn_t logfn; unsigned char lenbuf[4], pktbuf[AGENT_MAX_MSGLEN]; unsigned len, got; - int real_packet; + bool real_packet; int crLine; /* for coroutine in pageant_conn_receive */ Plug plug; }; static void pageant_conn_closing(Plug *plug, const char *error_msg, - int error_code, int calling_back) + int error_code, bool calling_back) { struct pageant_conn_state *pc = container_of( plug, struct pageant_conn_state, plug); @@ -805,7 +805,7 @@ struct pageant_listen_state { }; static void pageant_listen_closing(Plug *plug, const char *error_msg, - int error_code, int calling_back) + int error_code, bool calling_back) { struct pageant_listen_state *pl = container_of( plug, struct pageant_listen_state, plug); @@ -842,7 +842,7 @@ static int pageant_listen_accepting(Plug *plug, if ((err = sk_socket_error(pc->connsock)) != NULL) { sk_close(pc->connsock); sfree(pc); - return true; + return 1; } sk_set_frozen(pc->connsock, 0); @@ -998,7 +998,7 @@ int pageant_add_keyfile(Filename *filename, const char *passphrase, { struct RSAKey *rkey = NULL; struct ssh2_userkey *skey = NULL; - int needs_pass; + bool needs_pass; int ret; int attempts; char *comment; @@ -1432,7 +1432,8 @@ int pageant_delete_all_keys(char **retstr) { strbuf *request; unsigned char *response; - int resplen, success; + int resplen; + bool success; void *vresponse; request = strbuf_new_for_agent_query(); diff --git a/pageant.h b/pageant.h index e491d4f8..e033546a 100644 --- a/pageant.h +++ b/pageant.h @@ -60,10 +60,10 @@ struct RSAKey *pageant_nth_ssh1_key(int i); struct ssh2_userkey *pageant_nth_ssh2_key(int i); int pageant_count_ssh1_keys(void); int pageant_count_ssh2_keys(void); -int pageant_add_ssh1_key(struct RSAKey *rkey); -int pageant_add_ssh2_key(struct ssh2_userkey *skey); -int pageant_delete_ssh1_key(struct RSAKey *rkey); -int pageant_delete_ssh2_key(struct ssh2_userkey *skey); +bool pageant_add_ssh1_key(struct RSAKey *rkey); +bool pageant_add_ssh2_key(struct ssh2_userkey *skey); +bool pageant_delete_ssh1_key(struct RSAKey *rkey); +bool pageant_delete_ssh2_key(struct ssh2_userkey *skey); /* * This callback must be provided by the Pageant front end code. diff --git a/pinger.c b/pinger.c index d03210e2..ddebc727 100644 --- a/pinger.c +++ b/pinger.c @@ -7,7 +7,7 @@ struct Pinger { int interval; - int pending; + bool pending; unsigned long when_set, next; Backend *backend; }; diff --git a/portfwd.c b/portfwd.c index 1515135d..eaba9820 100644 --- a/portfwd.c +++ b/portfwd.c @@ -27,8 +27,8 @@ typedef struct PortForwarding { ConnectionLayer *cl; /* the connection layer itself */ /* Note that ssh need not be filled in if c is non-NULL */ Socket *s; - int input_wanted; - int ready; + bool input_wanted; + bool ready; SocksState socks_state; /* * `hostname' and `port' are the real hostname and port, once @@ -51,7 +51,7 @@ typedef struct PortForwarding { struct PortListener { ConnectionLayer *cl; Socket *s; - int is_dynamic; + bool is_dynamic; /* * `hostname' and `port' are the real hostname and port, for * ordinary forwardings. @@ -110,7 +110,7 @@ static void pfl_log(Plug *plug, int type, SockAddr *addr, int port, static void pfd_close(struct PortForwarding *pf); static void pfd_closing(Plug *plug, const char *error_msg, int error_code, - int calling_back) + bool calling_back) { struct PortForwarding *pf = container_of(plug, struct PortForwarding, plug); @@ -143,7 +143,7 @@ static void pfd_closing(Plug *plug, const char *error_msg, int error_code, static void pfl_terminate(struct PortListener *pl); static void pfl_closing(Plug *plug, const char *error_msg, int error_code, - int calling_back) + bool calling_back) { struct PortListener *pl = (struct PortListener *) plug; pfl_terminate(pl); @@ -254,7 +254,7 @@ static void pfd_receive(Plug *plug, int urgent, char *data, int len) return; if (socks_version == 4 && message_type == 1) { /* CONNECT message */ - int name_based = false; + bool name_based = false; port = get_uint16(src); ipv4 = get_uint32(src); @@ -437,9 +437,9 @@ static const PlugVtable PortForwarding_plugvt = { static void pfd_chan_free(Channel *chan); static void pfd_open_confirmation(Channel *chan); static void pfd_open_failure(Channel *chan, const char *errtext); -static int pfd_send(Channel *chan, int is_stderr, const void *data, int len); +static int pfd_send(Channel *chan, bool is_stderr, const void *data, int len); static void pfd_send_eof(Channel *chan); -static void pfd_set_input_wanted(Channel *chan, int wanted); +static void pfd_set_input_wanted(Channel *chan, bool wanted); static char *pfd_log_close_msg(Channel *chan); static const struct ChannelVtable PortForwarding_channelvt = { @@ -481,7 +481,7 @@ Channel *portfwd_raw_new(ConnectionLayer *cl, Plug **plug) pf->cl = cl; pf->input_wanted = true; - pf->ready = 0; + pf->ready = false; pf->socks_state = SOCKS_NONE; pf->hostname = NULL; @@ -526,7 +526,7 @@ static int pfl_accepting(Plug *p, accept_fn_t constructor, accept_ctx_t ctx) s = constructor(ctx, plug); if ((err = sk_socket_error(s)) != NULL) { portfwd_raw_free(chan); - return true; + return 1; } pf = container_of(chan, struct PortForwarding, chan); @@ -626,7 +626,7 @@ static void pfl_terminate(struct PortListener *pl) free_portlistener_state(pl); } -static void pfd_set_input_wanted(Channel *chan, int wanted) +static void pfd_set_input_wanted(Channel *chan, bool wanted) { assert(chan->vt == &PortForwarding_channelvt); PortForwarding *pf = container_of(chan, PortForwarding, chan); @@ -644,7 +644,7 @@ static void pfd_chan_free(Channel *chan) /* * Called to send data down the raw connection. */ -static int pfd_send(Channel *chan, int is_stderr, const void *data, int len) +static int pfd_send(Channel *chan, bool is_stderr, const void *data, int len) { assert(chan->vt == &PortForwarding_channelvt); PortForwarding *pf = container_of(chan, PortForwarding, chan); @@ -663,7 +663,7 @@ static void pfd_open_confirmation(Channel *chan) assert(chan->vt == &PortForwarding_channelvt); PortForwarding *pf = container_of(chan, PortForwarding, chan); - pf->ready = 1; + pf->ready = true; sk_set_frozen(pf->s, 0); sk_write(pf->s, NULL, 0); if (pf->socksbuf) { @@ -1050,8 +1050,8 @@ void portfwdmgr_config(PortFwdManager *mgr, Conf *conf) } } -int portfwdmgr_listen(PortFwdManager *mgr, const char *host, int port, - const char *keyhost, int keyport, Conf *conf) +bool portfwdmgr_listen(PortFwdManager *mgr, const char *host, int port, + const char *keyhost, int keyport, Conf *conf) { PortFwdRecord *pfr; @@ -1091,7 +1091,7 @@ int portfwdmgr_listen(PortFwdManager *mgr, const char *host, int port, return true; } -int portfwdmgr_unlisten(PortFwdManager *mgr, const char *host, int port) +bool portfwdmgr_unlisten(PortFwdManager *mgr, const char *host, int port) { PortFwdRecord pfr_key; @@ -1153,13 +1153,13 @@ char *portfwdmgr_connect(PortFwdManager *mgr, Channel **chan_ret, pf->chan.initial_fixed_window_size = 0; pf->chan.vt = &PortForwarding_channelvt; pf->input_wanted = true; - pf->ready = 1; + pf->ready = true; pf->c = c; pf->cl = mgr->cl; pf->socks_state = SOCKS_NONE; pf->s = new_connection(addr, dummy_realhost, port, - 0, 1, 0, 0, &pf->plug, mgr->conf); + false, true, false, false, &pf->plug, mgr->conf); sfree(dummy_realhost); if ((err = sk_socket_error(pf->s)) != NULL) { char *err_ret = dupstr(err); diff --git a/proxy.c b/proxy.c index 89d34952..0aa9cf35 100644 --- a/proxy.c +++ b/proxy.c @@ -33,7 +33,7 @@ void proxy_activate (ProxySocket *p) /* we want to ignore new receive events until we have sent * all of our buffered receive data. */ - sk_set_frozen(p->sub_socket, 1); + sk_set_frozen(p->sub_socket, true); /* how many bytes of output have we buffered? */ output_before = bufchain_size(&p->pending_oob_output_data) + @@ -124,7 +124,7 @@ static void sk_proxy_write_eof (Socket *s) ProxySocket *ps = container_of(s, ProxySocket, sock); if (ps->state != PROXY_STATE_ACTIVE) { - ps->pending_eof = 1; + ps->pending_eof = true; return; } sk_write_eof(ps->sub_socket); @@ -135,13 +135,13 @@ static void sk_proxy_flush (Socket *s) ProxySocket *ps = container_of(s, ProxySocket, sock); if (ps->state != PROXY_STATE_ACTIVE) { - ps->pending_flush = 1; + ps->pending_flush = true; return; } sk_flush(ps->sub_socket); } -static void sk_proxy_set_frozen (Socket *s, int is_frozen) +static void sk_proxy_set_frozen (Socket *s, bool is_frozen) { ProxySocket *ps = container_of(s, ProxySocket, sock); @@ -200,7 +200,7 @@ static void plug_proxy_log(Plug *plug, int type, SockAddr *addr, int port, } static void plug_proxy_closing (Plug *p, const char *error_msg, - int error_code, int calling_back) + int error_code, bool calling_back) { ProxySocket *ps = container_of(p, ProxySocket, plugimpl); @@ -224,7 +224,7 @@ static void plug_proxy_receive (Plug *p, int urgent, char *data, int len) * process, hopefully it won't affect the protocol above us */ bufchain_add(&ps->pending_input_data, data, len); - ps->receive_urgent = urgent; + ps->receive_urgent = (urgent != 0); ps->receive_data = data; ps->receive_len = len; ps->negotiate(ps, PROXY_CHANGE_RECEIVE); @@ -262,7 +262,7 @@ static int plug_proxy_accepting(Plug *p, * This function can accept a NULL pointer as `addr', in which case * it will only check the host name. */ -int proxy_for_destination (SockAddr *addr, const char *hostname, +bool proxy_for_destination (SockAddr *addr, const char *hostname, int port, Conf *conf) { int s = 0, e = 0; @@ -277,7 +277,7 @@ int proxy_for_destination (SockAddr *addr, const char *hostname, * them. */ if (addr && sk_address_is_special_local(addr)) - return 0; /* do not proxy */ + return false; /* do not proxy */ /* * Check the host name and IP against the hard-coded @@ -286,7 +286,7 @@ int proxy_for_destination (SockAddr *addr, const char *hostname, if (!conf_get_bool(conf, CONF_even_proxy_localhost) && (sk_hostname_is_local(hostname) || (addr && sk_address_is_local(addr)))) - return 0; /* do not proxy */ + return false; /* do not proxy */ /* we want a string representation of the IP address for comparisons */ if (addr) { @@ -324,25 +324,27 @@ int proxy_for_destination (SockAddr *addr, const char *hostname, if ((addr && strnicmp(hostip + hostip_len - (e - s - 1), exclude_list + s + 1, e - s - 1) == 0) || strnicmp(hostname + hostname_len - (e - s - 1), - exclude_list + s + 1, e - s - 1) == 0) - return 0; /* IP/hostname range excluded. do not use proxy. */ - + exclude_list + s + 1, e - s - 1) == 0) { + /* IP/hostname range excluded. do not use proxy. */ + return false; + } } else if (exclude_list[e-1] == '*') { /* wildcard at end of entry */ if ((addr && strnicmp(hostip, exclude_list + s, e - s - 1) == 0) || - strnicmp(hostname, exclude_list + s, e - s - 1) == 0) - return 0; /* IP/hostname range excluded. do not use proxy. */ - + strnicmp(hostname, exclude_list + s, e - s - 1) == 0) { + /* IP/hostname range excluded. do not use proxy. */ + return false; + } } else { /* no wildcard at either end, so let's try an absolute * match (ie. a specific IP) */ if (addr && strnicmp(hostip, exclude_list + s, e - s) == 0) - return 0; /* IP/hostname excluded. do not use proxy. */ + return false; /* IP/hostname excluded. do not use proxy. */ if (strnicmp(hostname, exclude_list + s, e - s) == 0) - return 0; /* IP/hostname excluded. do not use proxy. */ + return false; /* IP/hostname excluded. do not use proxy. */ } s = e; @@ -354,7 +356,7 @@ int proxy_for_destination (SockAddr *addr, const char *hostname, } /* no matches in the exclude list, so use the proxy */ - return 1; + return true; } static char *dns_log_msg(const char *host, int addressfamily, @@ -410,8 +412,8 @@ static const struct PlugVtable ProxySocket_plugvt = { }; Socket *new_connection(SockAddr *addr, const char *hostname, - int port, int privport, - int oobinline, int nodelay, int keepalive, + int port, bool privport, + bool oobinline, bool nodelay, bool keepalive, Plug *plug, Conf *conf) { if (conf_get_int(conf, CONF_proxy_type) != PROXY_NONE && @@ -439,9 +441,9 @@ Socket *new_connection(SockAddr *addr, const char *hostname, ret->remote_port = port; ret->error = NULL; - ret->pending_flush = 0; - ret->pending_eof = 0; - ret->freeze = 0; + ret->pending_flush = false; + ret->pending_eof = false; + ret->freeze = false; bufchain_init(&ret->pending_input_data); bufchain_init(&ret->pending_output_data); @@ -530,7 +532,7 @@ Socket *new_connection(SockAddr *addr, const char *hostname, } Socket *new_listener(const char *srcaddr, int port, Plug *plug, - int local_host_only, Conf *conf, int addressfamily) + bool local_host_only, Conf *conf, int addressfamily) { /* TODO: SOCKS (and potentially others) support inbound * TODO: connections via the proxy. support them. @@ -778,7 +780,7 @@ int proxy_socks4_negotiate (ProxySocket *p, int change) strbuf *command = strbuf_new(); char hostname[512]; - int write_hostname = false; + bool write_hostname = false; put_byte(command, 4); /* SOCKS version 4 */ put_byte(command, 1); /* CONNECT command */ diff --git a/proxy.h b/proxy.h index e37b820c..2ecde43a 100644 --- a/proxy.h +++ b/proxy.h @@ -25,9 +25,9 @@ struct ProxySocket { bufchain pending_output_data; bufchain pending_oob_output_data; - int pending_flush; + bool pending_flush; bufchain pending_input_data; - int pending_eof; + bool pending_eof; #define PROXY_STATE_NEW -1 #define PROXY_STATE_ACTIVE 0 @@ -37,10 +37,10 @@ struct ProxySocket { * of the initialization/setup/negotiation with the * proxy server. */ - int freeze; /* should we freeze the underlying socket when - * we are done with the proxy negotiation? this - * simply caches the value of sk_set_frozen calls. - */ + bool freeze; /* should we freeze the underlying socket when + * we are done with the proxy negotiation? this + * simply caches the value of sk_set_frozen calls. + */ #define PROXY_CHANGE_NEW -1 #define PROXY_CHANGE_CLOSING 0 @@ -64,10 +64,10 @@ struct ProxySocket { /* closing */ const char *closing_error_msg; int closing_error_code; - int closing_calling_back; + bool closing_calling_back; /* receive */ - int receive_urgent; + bool receive_urgent; char *receive_data; int receive_len; diff --git a/pscp.c b/pscp.c index ebda4e01..a16825b9 100644 --- a/pscp.c +++ b/pscp.c @@ -26,25 +26,25 @@ #include "sftp.h" #include "storage.h" -static int list = 0; -static int verbose = 0; -static int recursive = 0; -static int preserve = 0; -static int targetshouldbedirectory = 0; -static int statistics = 1; +static bool list = false; +static bool verbose = false; +static bool recursive = false; +static bool preserve = false; +static bool targetshouldbedirectory = false; +static bool statistics = true; static int prev_stats_len = 0; -static int scp_unsafe_mode = 0; +static bool scp_unsafe_mode = false; static int errs = 0; -static int try_scp = 1; -static int try_sftp = 1; -static int main_cmd_is_sftp = 0; -static int fallback_cmd_is_sftp = 0; -static int using_sftp = 0; -static int uploading = 0; +static bool try_scp = true; +static bool try_sftp = true; +static bool main_cmd_is_sftp = false; +static bool fallback_cmd_is_sftp = false; +static bool using_sftp = false; +static bool uploading = false; static Backend *backend; static Conf *conf; -int sent_eof = false; +bool sent_eof = false; static void source(const char *src); static void rsource(const char *src); @@ -60,8 +60,8 @@ const char *const appname = "PSCP"; void ldisc_echoedit_update(Ldisc *ldisc) { } -static int pscp_output(Seat *, int is_stderr, const void *, int); -static int pscp_eof(Seat *); +static int pscp_output(Seat *, bool is_stderr, const void *, int); +static bool pscp_eof(Seat *); static const SeatVtable pscp_seat_vt = { pscp_output, @@ -148,7 +148,7 @@ static unsigned char *outptr; /* where to put the data */ static unsigned outlen; /* how much data required */ static unsigned char *pending = NULL; /* any spare data */ static unsigned pendlen = 0, pendsize = 0; /* length and phys. size of buffer */ -static int pscp_output(Seat *seat, int is_stderr, +static int pscp_output(Seat *seat, bool is_stderr, const void *data, int datalen) { unsigned char *p = (unsigned char *) data; @@ -187,7 +187,7 @@ static int pscp_output(Seat *seat, int is_stderr, return 0; } -static int pscp_eof(Seat *seat) +static bool pscp_eof(Seat *seat) { /* * We usually expect to be the party deciding when to close the @@ -201,7 +201,7 @@ static int pscp_eof(Seat *seat) } return false; } -static int ssh_scp_recv(void *buf, int len) +static bool ssh_scp_recv(void *buf, int len) { outptr = buf; outlen = len; @@ -225,15 +225,15 @@ static int ssh_scp_recv(void *buf, int len) pending = NULL; } if (outlen == 0) - return len; + return true; } while (outlen > 0) { if (backend_exitcode(backend) >= 0 || ssh_sftp_loop_iteration() < 0) - return 0; /* doom */ + return false; /* doom */ } - return len; + return true; } /* @@ -455,19 +455,19 @@ static void do_cmd(char *host, char *user, char *cmd) conf_set_str(conf, CONF_remote_cmd2, ""); if (try_sftp) { /* First choice is SFTP subsystem. */ - main_cmd_is_sftp = 1; + main_cmd_is_sftp = true; conf_set_str(conf, CONF_remote_cmd, "sftp"); conf_set_bool(conf, CONF_ssh_subsys, true); if (try_scp) { /* Fallback is to use the provided scp command. */ - fallback_cmd_is_sftp = 0; + fallback_cmd_is_sftp = false; conf_set_str(conf, CONF_remote_cmd2, cmd); conf_set_bool(conf, CONF_ssh_subsys2, false); } else { /* Since we're not going to try SCP, we may as well try * harder to find an SFTP server, since in the current * implementation we have a spare slot. */ - fallback_cmd_is_sftp = 1; + fallback_cmd_is_sftp = true; /* see psftp.c for full explanation of this kludge */ conf_set_str(conf, CONF_remote_cmd2, "test -x /usr/lib/sftp-server &&" @@ -479,7 +479,7 @@ static void do_cmd(char *host, char *user, char *cmd) } } else { /* Don't try SFTP at all; just try the scp command. */ - main_cmd_is_sftp = 0; + main_cmd_is_sftp = false; conf_set_str(conf, CONF_remote_cmd, cmd); conf_set_bool(conf, CONF_ssh_subsys, false); } @@ -572,7 +572,7 @@ static char *colon(char *str) /* * Determine whether a string is entirely composed of dots. */ -static int is_dots(char *str) +static bool is_dots(char *str) { return str[strspn(str, ".")] == '\0'; } @@ -586,7 +586,7 @@ static int response(void) char ch, resp, rbuf[2048]; int p; - if (ssh_scp_recv(&resp, 1) <= 0) + if (!ssh_scp_recv(&resp, 1)) bump("Lost connection"); p = 0; @@ -599,7 +599,7 @@ static int response(void) case 1: /* error */ case 2: /* fatal error */ do { - if (ssh_scp_recv(&ch, 1) <= 0) + if (!ssh_scp_recv(&ch, 1)) bump("Protocol error: Lost connection"); rbuf[p++] = ch; } while (p < sizeof(rbuf) && ch != '\n'); @@ -613,14 +613,14 @@ static int response(void) } } -int sftp_recvdata(char *buf, int len) +bool sftp_recvdata(char *buf, int len) { return ssh_scp_recv(buf, len); } -int sftp_senddata(char *buf, int len) +bool sftp_senddata(char *buf, int len) { backend_send(backend, buf, len); - return 1; + return true; } int sftp_sendbuffer(void) { @@ -724,19 +724,19 @@ static struct scp_sftp_dirstack { int namepos, namelen; char *dirpath; char *wildcard; - int matched_something; /* wildcard match set was non-empty */ + bool matched_something; /* wildcard match set was non-empty */ } *scp_sftp_dirstack_head; static char *scp_sftp_remotepath, *scp_sftp_currentname; static char *scp_sftp_wildcard; -static int scp_sftp_targetisdir, scp_sftp_donethistarget; -static int scp_sftp_preserve, scp_sftp_recursive; +static bool scp_sftp_targetisdir, scp_sftp_donethistarget; +static bool scp_sftp_preserve, scp_sftp_recursive; static unsigned long scp_sftp_mtime, scp_sftp_atime; -static int scp_has_times; +static bool scp_has_times; static struct fxp_handle *scp_sftp_filehandle; static struct fxp_xfer *scp_sftp_xfer; static uint64_t scp_sftp_fileoffset; -int scp_source_setup(const char *target, int shouldbedir) +int scp_source_setup(const char *target, bool shouldbedir) { if (using_sftp) { /* @@ -746,7 +746,7 @@ int scp_source_setup(const char *target, int shouldbedir) struct sftp_packet *pktin; struct sftp_request *req; struct fxp_attrs attrs; - int ret; + bool ret; if (!fxp_init()) { tell_user(stderr, "unable to initialise SFTP: %s", fxp_error()); @@ -759,7 +759,7 @@ int scp_source_setup(const char *target, int shouldbedir) ret = fxp_stat_recv(pktin, req, &attrs); if (!ret || !(attrs.flags & SSH_FILEXFER_ATTR_PERMISSIONS)) - scp_sftp_targetisdir = 0; + scp_sftp_targetisdir = false; else scp_sftp_targetisdir = (attrs.permissions & 0040000) != 0; @@ -769,7 +769,7 @@ int scp_source_setup(const char *target, int shouldbedir) scp_sftp_remotepath = dupstr(target); - scp_has_times = 0; + scp_has_times = false; } else { (void) response(); } @@ -792,7 +792,7 @@ int scp_send_filetimes(unsigned long mtime, unsigned long atime) if (using_sftp) { scp_sftp_mtime = mtime; scp_sftp_atime = atime; - scp_has_times = 1; + scp_has_times = true; return 0; } else { char buf[80]; @@ -901,11 +901,10 @@ int scp_send_finish(void) struct fxp_attrs attrs; struct sftp_packet *pktin; struct sftp_request *req; - int ret; while (!xfer_done(scp_sftp_xfer)) { pktin = sftp_recv(); - ret = xfer_upload_gotpkt(scp_sftp_xfer, pktin); + int ret = xfer_upload_gotpkt(scp_sftp_xfer, pktin); if (ret <= 0) { tell_user(stderr, "error while writing: %s", fxp_error()); if (ret == INT_MIN) /* pktin not even freed */ @@ -925,7 +924,7 @@ int scp_send_finish(void) attrs.mtime = scp_sftp_mtime; req = fxp_fsetstat_send(scp_sftp_filehandle, attrs); pktin = sftp_wait_for_reply(req); - ret = fxp_fsetstat_recv(pktin, req); + bool ret = fxp_fsetstat_recv(pktin, req); if (!ret) { tell_user(stderr, "unable to set file times: %s", fxp_error()); errs++; @@ -934,7 +933,7 @@ int scp_send_finish(void) req = fxp_close_send(scp_sftp_filehandle); pktin = sftp_wait_for_reply(req); fxp_close_recv(pktin, req); - scp_has_times = 0; + scp_has_times = false; return 0; } else { backend_send(backend, "", 1); @@ -964,7 +963,7 @@ int scp_send_dirname(const char *name, int modes) struct fxp_attrs attrs; struct sftp_packet *pktin; struct sftp_request *req; - int ret; + bool ret; if (scp_sftp_targetisdir) { fullname = dupcat(scp_sftp_remotepath, "/", name, NULL); @@ -1031,7 +1030,7 @@ int scp_send_enddir(void) * right at the start, whereas scp_sink_init is called to * initialise every level of recursion in the protocol. */ -int scp_sink_setup(const char *source, int preserve, int recursive) +int scp_sink_setup(const char *source, bool preserve, bool recursive) { if (using_sftp) { char *newsource; @@ -1056,7 +1055,7 @@ int scp_sink_setup(const char *source, int preserve, int recursive) sfree(newsource); dupsource = dupstr(source); - lastpart = stripslashes(dupsource, 0); + lastpart = stripslashes(dupsource, false); wildcard = dupstr(lastpart); *lastpart = '\0'; if (*dupsource && dupsource[1]) { @@ -1109,7 +1108,7 @@ int scp_sink_setup(const char *source, int preserve, int recursive) } scp_sftp_preserve = preserve; scp_sftp_recursive = recursive; - scp_sftp_donethistarget = 0; + scp_sftp_donethistarget = false; scp_sftp_dirstack_head = NULL; } return 0; @@ -1133,7 +1132,7 @@ struct scp_sink_action { char *name; /* filename or dirname (not ENDDIR) */ long permissions; /* access permissions (not ENDDIR) */ uint64_t size; /* file size (not ENDDIR) */ - int settime; /* 1 if atime and mtime are filled */ + bool settime; /* true if atime and mtime are filled */ unsigned long atime, mtime; /* access times for the file */ }; @@ -1141,11 +1140,11 @@ int scp_get_sink_action(struct scp_sink_action *act) { if (using_sftp) { char *fname; - int must_free_fname; + bool must_free_fname; struct fxp_attrs attrs; struct sftp_packet *pktin; struct sftp_request *req; - int ret; + bool ret; if (!scp_sftp_dirstack_head) { if (!scp_sftp_donethistarget) { @@ -1153,8 +1152,8 @@ int scp_get_sink_action(struct scp_sink_action *act) * Simple case: we are only dealing with one file. */ fname = scp_sftp_remotepath; - must_free_fname = 0; - scp_sftp_donethistarget = 1; + must_free_fname = false; + scp_sftp_donethistarget = true; } else { /* * Even simpler case: one file _which we've done_. @@ -1176,11 +1175,11 @@ int scp_get_sink_action(struct scp_sink_action *act) head->names[head->namepos].filename)))) head->namepos++; /* skip . and .. */ if (head->namepos < head->namelen) { - head->matched_something = 1; + head->matched_something = true; fname = dupcat(head->dirpath, "/", head->names[head->namepos++].filename, NULL); - must_free_fname = 1; + must_free_fname = true; } else { /* * We've come to the end of the list; pop it off @@ -1345,7 +1344,7 @@ int scp_get_sink_action(struct scp_sink_action *act) newitem->dirpath = dupstr(fname); if (scp_sftp_wildcard) { newitem->wildcard = scp_sftp_wildcard; - newitem->matched_something = 0; + newitem->matched_something = false; scp_sftp_wildcard = NULL; } else { newitem->wildcard = NULL; @@ -1356,7 +1355,7 @@ int scp_get_sink_action(struct scp_sink_action *act) act->action = SCP_SINK_RETRY; } else { act->action = SCP_SINK_DIR; - act->buf = dupstr(stripslashes(fname, 0)); + act->buf = dupstr(stripslashes(fname, false)); act->name = act->buf; act->size = 0; /* duhh, it's a directory */ act->permissions = 07777 & attrs.permissions; @@ -1364,9 +1363,9 @@ int scp_get_sink_action(struct scp_sink_action *act) (attrs.flags & SSH_FILEXFER_ATTR_ACMODTIME)) { act->atime = attrs.atime; act->mtime = attrs.mtime; - act->settime = 1; + act->settime = true; } else - act->settime = 0; + act->settime = false; } return 0; @@ -1375,7 +1374,7 @@ int scp_get_sink_action(struct scp_sink_action *act) * It's a file. Return SCP_SINK_FILE. */ act->action = SCP_SINK_FILE; - act->buf = dupstr(stripslashes(fname, 0)); + act->buf = dupstr(stripslashes(fname, false)); act->name = act->buf; if (attrs.flags & SSH_FILEXFER_ATTR_SIZE) { act->size = attrs.size; @@ -1386,9 +1385,9 @@ int scp_get_sink_action(struct scp_sink_action *act) (attrs.flags & SSH_FILEXFER_ATTR_ACMODTIME)) { act->atime = attrs.atime; act->mtime = attrs.mtime; - act->settime = 1; + act->settime = true; } else - act->settime = 0; + act->settime = false; if (must_free_fname) scp_sftp_currentname = fname; else @@ -1397,24 +1396,24 @@ int scp_get_sink_action(struct scp_sink_action *act) } } else { - int done = 0; + bool done = false; int i, bufsize; int action; char ch; - act->settime = 0; + act->settime = false; act->buf = NULL; bufsize = 0; while (!done) { - if (ssh_scp_recv(&ch, 1) <= 0) + if (!ssh_scp_recv(&ch, 1)) return 1; if (ch == '\n') bump("Protocol error: Unexpected newline"); i = 0; action = ch; do { - if (ssh_scp_recv(&ch, 1) <= 0) + if (!ssh_scp_recv(&ch, 1)) bump("Lost connection"); if (i >= bufsize) { bufsize = i + 128; @@ -1437,7 +1436,7 @@ int scp_get_sink_action(struct scp_sink_action *act) case 'T': if (sscanf(act->buf, "%lu %*d %lu %*d", &act->mtime, &act->atime) == 2) { - act->settime = 1; + act->settime = true; backend_send(backend, "", 1); continue; /* go round again */ } @@ -1457,7 +1456,7 @@ int scp_get_sink_action(struct scp_sink_action *act) * We will go round this loop only once, unless we hit * `continue' above. */ - done = 1; + done = true; } /* @@ -1542,7 +1541,7 @@ int scp_recv_filedata(char *data, int len) return actuallen; } else { - return ssh_scp_recv(data, len); + return ssh_scp_recv(data, len) ? len : 0; } } @@ -1763,19 +1762,19 @@ static void rsource(const char *src) static void sink(const char *targ, const char *src) { char *destfname; - int targisdir = 0; - int exists; + bool targisdir = false; + bool exists; int attr; WFile *f; uint64_t received; - int wrerror = 0; + bool wrerror = false; uint64_t stat_bytes; time_t stat_starttime, stat_lasttime; char *stat_name; attr = file_type(targ); if (attr == FILE_TYPE_DIRECTORY) - targisdir = 1; + targisdir = true; if (targetshouldbedirectory && !targisdir) bump("%s: Not a directory", targ); @@ -1825,7 +1824,7 @@ static void sink(const char *targ, const char *src) */ char *striptarget, *stripsrc; - striptarget = stripslashes(act.name, 1); + striptarget = stripslashes(act.name, true); if (striptarget != act.name) { tell_user(stderr, "warning: remote host sent a compound" " pathname '%s'", act.name); @@ -1844,7 +1843,7 @@ static void sink(const char *targ, const char *src) } if (src) { - stripsrc = stripslashes(src, 1); + stripsrc = stripslashes(src, true); if (strcmp(striptarget, stripsrc) && !using_sftp && !scp_unsafe_mode) { tell_user(stderr, "warning: remote host tried to write " @@ -1910,7 +1909,7 @@ static void sink(const char *targ, const char *src) stat_bytes = 0; stat_starttime = time(NULL); stat_lasttime = 0; - stat_name = stripslashes(destfname, 1); + stat_name = stripslashes(destfname, true); received = 0; while (received < act.size) { @@ -1928,7 +1927,7 @@ static void sink(const char *targ, const char *src) continue; } if (write_to_file(f, transbuf, read) != (int)read) { - wrerror = 1; + wrerror = true; /* FIXME: in sftp we can actually abort the transfer */ if (statistics) printf("\r%-25.25s | %50s\n", @@ -1974,7 +1973,7 @@ static void toremote(int argc, char *argv[]) char *cmd; int i, wc_type; - uploading = 1; + uploading = true; wtarg = argv[argc - 1]; @@ -2006,11 +2005,11 @@ static void toremote(int argc, char *argv[]) if (colon(argv[0]) != NULL) bump("%s: Remote to remote not supported", argv[0]); - wc_type = test_wildcard(argv[0], 1); + wc_type = test_wildcard(argv[0], true); if (wc_type == WCTYPE_NONEXISTENT) bump("%s: No such file or directory\n", argv[0]); else if (wc_type == WCTYPE_WILDCARD) - targetshouldbedirectory = 1; + targetshouldbedirectory = true; } cmd = dupprintf("scp%s%s%s%s -t %s", @@ -2032,7 +2031,7 @@ static void toremote(int argc, char *argv[]) continue; } - wc_type = test_wildcard(src, 1); + wc_type = test_wildcard(src, true); if (wc_type == WCTYPE_NONEXISTENT) { run_err("%s: No such file or directory", src); continue; @@ -2068,7 +2067,7 @@ static void tolocal(int argc, char *argv[]) const char *src, *targ; char *cmd; - uploading = 0; + uploading = false; if (argc != 2) bump("More than one remote source not supported"); @@ -2173,7 +2172,7 @@ static void get_dir_list(int argc, char *argv[]) if (using_sftp) { scp_sftp_listdir(src); } else { - while (ssh_scp_recv(&c, 1) > 0) + while (ssh_scp_recv(&c, 1)) tell_char(stdout, c); } } @@ -2239,8 +2238,8 @@ void cmdline_error(const char *p, ...) exit(1); } -const int share_can_be_downstream = true; -const int share_can_be_upstream = false; +const bool share_can_be_downstream = true; +const bool share_can_be_upstream = false; /* * Main program. (Called `psftp_main' because it gets called from @@ -2277,16 +2276,16 @@ int psftp_main(int argc, char *argv[]) } else if (ret == 1) { /* We have our own verbosity in addition to `flags'. */ if (flags & FLAG_VERBOSE) - verbose = 1; + verbose = true; } else if (strcmp(argv[i], "-pgpfp") == 0) { pgp_fingerprints(); return 1; } else if (strcmp(argv[i], "-r") == 0) { - recursive = 1; + recursive = true; } else if (strcmp(argv[i], "-p") == 0) { - preserve = 1; + preserve = true; } else if (strcmp(argv[i], "-q") == 0) { - statistics = 0; + statistics = false; } else if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "-?") == 0 || strcmp(argv[i], "--help") == 0) { @@ -2295,15 +2294,15 @@ int psftp_main(int argc, char *argv[]) strcmp(argv[i], "--version") == 0) { version(); } else if (strcmp(argv[i], "-ls") == 0) { - list = 1; + list = true; } else if (strcmp(argv[i], "-batch") == 0) { - console_batch_mode = 1; + console_batch_mode = true; } else if (strcmp(argv[i], "-unsafe") == 0) { - scp_unsafe_mode = 1; + scp_unsafe_mode = true; } else if (strcmp(argv[i], "-sftp") == 0) { - try_scp = 0; try_sftp = 1; + try_scp = false; try_sftp = true; } else if (strcmp(argv[i], "-scp") == 0) { - try_scp = 1; try_sftp = 0; + try_scp = true; try_sftp = false; } else if (strcmp(argv[i], "--") == 0) { i++; break; @@ -2325,7 +2324,7 @@ int psftp_main(int argc, char *argv[]) if (argc < 2) usage(); if (argc > 2) - targetshouldbedirectory = 1; + targetshouldbedirectory = true; if (colon(argv[argc - 1]) != NULL) toremote(argc, argv); diff --git a/psftp.c b/psftp.c index 84c81454..3fb8ffbe 100644 --- a/psftp.c +++ b/psftp.c @@ -35,14 +35,14 @@ void do_sftp_cleanup(); char *pwd, *homedir; static Backend *backend; static Conf *conf; -int sent_eof = false; +bool sent_eof = false; /* ------------------------------------------------------------ * Seat vtable. */ -static int psftp_output(Seat *, int is_stderr, const void *, int); -static int psftp_eof(Seat *); +static int psftp_output(Seat *, bool is_stderr, const void *, int); +static bool psftp_eof(Seat *); static const SeatVtable psftp_seat_vt = { psftp_output, @@ -227,7 +227,7 @@ static void not_connected(void) /* ---------------------------------------------------------------------- * The meat of the `get' and `put' commands. */ -int sftp_get_file(char *fname, char *outfname, int recurse, int restart) +bool sftp_get_file(char *fname, char *outfname, bool recurse, bool restart) { struct fxp_handle *fh; struct sftp_packet *pktin; @@ -235,7 +235,7 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart) struct fxp_xfer *xfer; uint64_t offset; WFile *file; - int ret, shown_err = false; + bool toret, shown_err = false; struct fxp_attrs attrs; /* @@ -244,7 +244,7 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart) * subsequent FXP_OPEN will return a usable error message.) */ if (recurse) { - int result; + bool result; req = fxp_stat_send(fname); pktin = sftp_wait_for_reply(req); @@ -267,7 +267,7 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart) if (file_type(outfname) != FILE_TYPE_DIRECTORY && !create_directory(outfname)) { printf("%s: Cannot create directory\n", outfname); - return 0; + return false; } /* @@ -281,7 +281,7 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart) if (!dirhandle) { printf("%s: unable to open directory: %s\n", fname, fxp_error()); - return 0; + return false; } nnames = namesize = 0; ournames = NULL; @@ -302,7 +302,7 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart) fxp_close_recv(pktin, req); sfree(ournames); - return 0; + return false; } if (names->nnames == 0) { fxp_free_names(names); @@ -352,12 +352,13 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart) if (restart) { while (i < nnames) { char *nextoutfname; - int ret; + bool nonexistent; nextoutfname = dir_file_cat(outfname, ournames[i]->filename); - ret = (file_type(nextoutfname) == FILE_TYPE_NONEXISTENT); + nonexistent = (file_type(nextoutfname) == + FILE_TYPE_NONEXISTENT); sfree(nextoutfname); - if (ret) + if (nonexistent) break; i++; } @@ -373,20 +374,21 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart) */ for (; i < nnames; i++) { char *nextfname, *nextoutfname; - int ret; + bool retd; nextfname = dupcat(fname, "/", ournames[i]->filename, NULL); nextoutfname = dir_file_cat(outfname, ournames[i]->filename); - ret = sftp_get_file(nextfname, nextoutfname, recurse, restart); + retd = sftp_get_file( + nextfname, nextoutfname, recurse, restart); restart = false; /* after first partial file, do full */ sfree(nextoutfname); sfree(nextfname); - if (!ret) { + if (!retd) { for (i = 0; i < nnames; i++) { fxp_free_name(ournames[i]); } sfree(ournames); - return 0; + return false; } } @@ -398,7 +400,7 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart) } sfree(ournames); - return 1; + return true; } } @@ -413,7 +415,7 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart) if (!fh) { printf("%s: open for read: %s\n", fname, fxp_error()); - return 0; + return false; } if (restart) { @@ -429,7 +431,7 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart) pktin = sftp_wait_for_reply(req); fxp_close_recv(pktin, req); - return 0; + return false; } if (restart) { @@ -441,7 +443,7 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart) pktin = sftp_wait_for_reply(req); fxp_close_recv(pktin, req); - return 0; + return false; } offset = get_file_posn(file); @@ -456,24 +458,24 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart) * FIXME: we can use FXP_FSTAT here to get the file size, and * thus put up a progress bar. */ - ret = 1; + toret = true; xfer = xfer_download_init(fh, offset); while (!xfer_done(xfer)) { void *vbuf; - int len; + int retd, len; int wpos, wlen; xfer_download_queue(xfer); pktin = sftp_recv(); - ret = xfer_download_gotpkt(xfer, pktin); - if (ret <= 0) { + retd = xfer_download_gotpkt(xfer, pktin); + if (retd <= 0) { if (!shown_err) { printf("error while reading: %s\n", fxp_error()); shown_err = true; } - if (ret == INT_MIN) /* pktin not even freed */ + if (retd == INT_MIN) /* pktin not even freed */ sfree(pktin); - ret = 0; + toret = false; } while (xfer_download_data(xfer, &vbuf, &len)) { @@ -484,14 +486,14 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart) wlen = write_to_file(file, buf + wpos, len - wpos); if (wlen <= 0) { printf("error while writing local file\n"); - ret = 0; + toret = false; xfer_set_error(xfer); break; } wpos += wlen; } if (wpos < len) { /* we had an error */ - ret = 0; + toret = false; xfer_set_error(xfer); } @@ -507,10 +509,10 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart) pktin = sftp_wait_for_reply(req); fxp_close_recv(pktin, req); - return ret; + return toret; } -int sftp_put_file(char *fname, char *outfname, int recurse, int restart) +bool sftp_put_file(char *fname, char *outfname, bool recurse, bool restart) { struct fxp_handle *fh; struct fxp_xfer *xfer; @@ -518,7 +520,7 @@ int sftp_put_file(char *fname, char *outfname, int recurse, int restart) struct sftp_request *req; uint64_t offset; RFile *file; - int err = 0, eof; + bool err = false, eof; struct fxp_attrs attrs; long permissions; @@ -528,7 +530,7 @@ int sftp_put_file(char *fname, char *outfname, int recurse, int restart) * subsequent fopen will return an error message.) */ if (recurse && file_type(fname) == FILE_TYPE_DIRECTORY) { - int result; + bool result; int nnames, namesize; char *name, **ournames; DirHandle *dh; @@ -551,7 +553,7 @@ int sftp_put_file(char *fname, char *outfname, int recurse, int restart) if (!result) { printf("%s: create directory: %s\n", outfname, fxp_error()); - return 0; + return false; } } @@ -564,7 +566,7 @@ int sftp_put_file(char *fname, char *outfname, int recurse, int restart) dh = open_directory(fname); if (!dh) { printf("%s: unable to open directory\n", fname); - return 0; + return false; } while ((name = read_filename(dh)) != NULL) { if (nnames >= namesize) { @@ -617,20 +619,20 @@ int sftp_put_file(char *fname, char *outfname, int recurse, int restart) */ for (; i < nnames; i++) { char *nextfname, *nextoutfname; - int ret; + bool retd; nextfname = dir_file_cat(fname, ournames[i]); nextoutfname = dupcat(outfname, "/", ournames[i], NULL); - ret = sftp_put_file(nextfname, nextoutfname, recurse, restart); + retd = sftp_put_file(nextfname, nextoutfname, recurse, restart); restart = false; /* after first partial file, do full */ sfree(nextoutfname); sfree(nextfname); - if (!ret) { + if (!retd) { for (i = 0; i < nnames; i++) { sfree(ournames[i]); } sfree(ournames); - return 0; + return false; } } @@ -642,13 +644,13 @@ int sftp_put_file(char *fname, char *outfname, int recurse, int restart) } sfree(ournames); - return 1; + return true; } file = open_existing_file(fname, NULL, NULL, NULL, &permissions); if (!file) { printf("local: unable to open %s\n", fname); - return 0; + return false; } attrs.flags = 0; PUT_PERMISSIONS(attrs, permissions); @@ -665,25 +667,25 @@ int sftp_put_file(char *fname, char *outfname, int recurse, int restart) if (!fh) { close_rfile(file); printf("%s: open for write: %s\n", outfname, fxp_error()); - return 0; + return false; } if (restart) { struct fxp_attrs attrs; - int ret; + bool retd; req = fxp_fstat_send(fh); pktin = sftp_wait_for_reply(req); - ret = fxp_fstat_recv(pktin, req, &attrs); + retd = fxp_fstat_recv(pktin, req, &attrs); - if (!ret) { + if (!retd) { printf("read size of %s: %s\n", outfname, fxp_error()); - err = 1; + err = true; goto cleanup; } if (!(attrs.flags & SSH_FILEXFER_ATTR_SIZE)) { printf("read size of %s: size was not given\n", outfname); - err = 1; + err = true; goto cleanup; } offset = attrs.size; @@ -702,7 +704,7 @@ int sftp_put_file(char *fname, char *outfname, int recurse, int restart) * thus put up a progress bar. */ xfer = xfer_upload_init(fh, offset); - eof = 0; + eof = false; while ((!err && !eof) || !xfer_done(xfer)) { char buffer[4096]; int len, ret; @@ -711,9 +713,9 @@ int sftp_put_file(char *fname, char *outfname, int recurse, int restart) len = read_from_file(file, buffer, sizeof(buffer)); if (len == -1) { printf("error while reading local file\n"); - err = 1; + err = true; } else if (len == 0) { - eof = 1; + eof = true; } else { xfer_upload_data(xfer, buffer, len); } @@ -727,7 +729,7 @@ int sftp_put_file(char *fname, char *outfname, int recurse, int restart) sfree(pktin); if (!err) { printf("error while writing: %s\n", fxp_error()); - err = 1; + err = true; } } } @@ -741,13 +743,13 @@ int sftp_put_file(char *fname, char *outfname, int recurse, int restart) if (!fxp_close_recv(pktin, req)) { if (!err) { printf("error while closing: %s", fxp_error()); - err = 1; + err = true; } } close_rfile(file); - return (err == 0) ? 1 : 0; + return !err; } /* ---------------------------------------------------------------------- @@ -768,7 +770,8 @@ SftpWildcardMatcher *sftp_begin_wildcard_matching(char *name) struct sftp_request *req; char *wildcard; char *unwcdir, *tmpdir, *cdir; - int len, check; + int len; + bool check; SftpWildcardMatcher *swcm; struct fxp_handle *dirh; @@ -777,7 +780,7 @@ SftpWildcardMatcher *sftp_begin_wildcard_matching(char *name) * a fully specified directory part, followed by a wildcard * after that. */ - wildcard = stripslashes(name, 0); + wildcard = stripslashes(name, false); unwcdir = dupstr(name); len = wildcard - name; @@ -904,33 +907,34 @@ void sftp_finish_wildcard_matching(SftpWildcardMatcher *swcm) * argument and iterate over every matching file. Used in several * PSFTP commands (rmdir, rm, chmod, mv). */ -int wildcard_iterate(char *filename, int (*func)(void *, char *), void *ctx) +bool wildcard_iterate(char *filename, bool (*func)(void *, char *), void *ctx) { char *unwcfname, *newname, *cname; - int is_wc, ret; + bool is_wc, toret; unwcfname = snewn(strlen(filename)+1, char); is_wc = !wc_unescape(unwcfname, filename); if (is_wc) { SftpWildcardMatcher *swcm = sftp_begin_wildcard_matching(filename); - int matched = false; + bool matched = false; sfree(unwcfname); if (!swcm) - return 0; + return false; - ret = 1; + toret = true; while ( (newname = sftp_wildcard_get_filename(swcm)) != NULL ) { cname = canonify(newname); if (!cname) { printf("%s: canonify: %s\n", newname, fxp_error()); - ret = 0; + toret = false; } sfree(newname); matched = true; - ret &= func(ctx, cname); + if (!func(ctx, cname)) + toret = false; sfree(cname); } @@ -944,23 +948,23 @@ int wildcard_iterate(char *filename, int (*func)(void *, char *), void *ctx) cname = canonify(unwcfname); if (!cname) { printf("%s: canonify: %s\n", filename, fxp_error()); - ret = 0; + toret = false; } - ret = func(ctx, cname); + toret = func(ctx, cname); sfree(cname); sfree(unwcfname); } - return ret; + return toret; } /* * Handy helper function. */ -int is_wildcard(char *name) +bool is_wildcard(char *name) { char *unwcfname = snewn(strlen(name)+1, char); - int is_wc = !wc_unescape(unwcfname, name); + bool is_wc = !wc_unescape(unwcfname, name); sfree(unwcfname); return is_wc; } @@ -1040,10 +1044,11 @@ int sftp_cmd_ls(struct sftp_command *cmd) wildcard = NULL; } else { char *tmpdir; - int len, check; + int len; + bool check; sfree(unwcdir); - wildcard = stripslashes(dir, 0); + wildcard = stripslashes(dir, false); unwcdir = dupstr(dir); len = wildcard - dir; unwcdir[len] = '\0'; @@ -1207,11 +1212,11 @@ int sftp_cmd_pwd(struct sftp_command *cmd) * transfer (never as a different local name for a remote file) and * can handle wildcards. */ -int sftp_general_get(struct sftp_command *cmd, int restart, int multiple) +int sftp_general_get(struct sftp_command *cmd, bool restart, bool multiple) { char *fname, *unwcfname, *origfname, *origwfname, *outfname; - int i, ret; - int recurse = false; + int i, toret; + bool recurse = false; if (!backend) { not_connected(); @@ -1238,7 +1243,7 @@ int sftp_general_get(struct sftp_command *cmd, int restart, int multiple) return 0; } - ret = 1; + toret = 1; do { SftpWildcardMatcher *swcm; @@ -1278,9 +1283,9 @@ int sftp_general_get(struct sftp_command *cmd, int restart, int multiple) if (!multiple && i < cmd->nwords) outfname = cmd->words[i++]; else - outfname = stripslashes(origwfname, 0); + outfname = stripslashes(origwfname, false); - ret = sftp_get_file(fname, outfname, recurse, restart); + toret = sftp_get_file(fname, outfname, recurse, restart); sfree(fname); @@ -1294,24 +1299,24 @@ int sftp_general_get(struct sftp_command *cmd, int restart, int multiple) sfree(unwcfname); if (swcm) sftp_finish_wildcard_matching(swcm); - if (!ret) - return ret; + if (!toret) + return toret; } while (multiple && i < cmd->nwords); - return ret; + return toret; } int sftp_cmd_get(struct sftp_command *cmd) { - return sftp_general_get(cmd, 0, 0); + return sftp_general_get(cmd, false, false); } int sftp_cmd_mget(struct sftp_command *cmd) { - return sftp_general_get(cmd, 0, 1); + return sftp_general_get(cmd, false, true); } int sftp_cmd_reget(struct sftp_command *cmd) { - return sftp_general_get(cmd, 1, 0); + return sftp_general_get(cmd, true, false); } /* @@ -1323,11 +1328,12 @@ int sftp_cmd_reget(struct sftp_command *cmd) * transfer (never as a different remote name for a local file) and * can handle wildcards. */ -int sftp_general_put(struct sftp_command *cmd, int restart, int multiple) +int sftp_general_put(struct sftp_command *cmd, bool restart, bool multiple) { char *fname, *wfname, *origoutfname, *outfname; - int i, ret; - int recurse = false; + int i; + int toret; + bool recurse = false; if (!backend) { not_connected(); @@ -1354,7 +1360,7 @@ int sftp_general_put(struct sftp_command *cmd, int restart, int multiple) return 0; } - ret = 1; + toret = 1; do { WildcardMatcher *wcm; fname = cmd->words[i++]; @@ -1377,7 +1383,7 @@ int sftp_general_put(struct sftp_command *cmd, int restart, int multiple) if (!multiple && i < cmd->nwords) origoutfname = cmd->words[i++]; else - origoutfname = stripslashes(wfname, 1); + origoutfname = stripslashes(wfname, true); outfname = canonify(origoutfname); if (!outfname) { @@ -1388,7 +1394,7 @@ int sftp_general_put(struct sftp_command *cmd, int restart, int multiple) } return 0; } - ret = sftp_put_file(wfname, outfname, recurse, restart); + toret = sftp_put_file(wfname, outfname, recurse, restart); sfree(outfname); if (wcm) { @@ -1402,24 +1408,24 @@ int sftp_general_put(struct sftp_command *cmd, int restart, int multiple) if (wcm) finish_wildcard_matching(wcm); - if (!ret) - return ret; + if (!toret) + return toret; } while (multiple && i < cmd->nwords); - return ret; + return toret; } int sftp_cmd_put(struct sftp_command *cmd) { - return sftp_general_put(cmd, 0, 0); + return sftp_general_put(cmd, false, false); } int sftp_cmd_mput(struct sftp_command *cmd) { - return sftp_general_put(cmd, 0, 1); + return sftp_general_put(cmd, false, true); } int sftp_cmd_reput(struct sftp_command *cmd) { - return sftp_general_put(cmd, 1, 0); + return sftp_general_put(cmd, true, false); } int sftp_cmd_mkdir(struct sftp_command *cmd) @@ -1427,7 +1433,7 @@ int sftp_cmd_mkdir(struct sftp_command *cmd) char *dir; struct sftp_packet *pktin; struct sftp_request *req; - int result; + bool result; int i, ret; if (!backend) { @@ -1464,11 +1470,11 @@ int sftp_cmd_mkdir(struct sftp_command *cmd) return ret; } -static int sftp_action_rmdir(void *vctx, char *dir) +static bool sftp_action_rmdir(void *vctx, char *dir) { struct sftp_packet *pktin; struct sftp_request *req; - int result; + bool result; req = fxp_rmdir_send(dir); pktin = sftp_wait_for_reply(req); @@ -1476,12 +1482,12 @@ static int sftp_action_rmdir(void *vctx, char *dir) if (!result) { printf("rmdir %s: %s\n", dir, fxp_error()); - return 0; + return false; } printf("rmdir %s: OK\n", dir); - return 1; + return true; } int sftp_cmd_rmdir(struct sftp_command *cmd) @@ -1505,11 +1511,11 @@ int sftp_cmd_rmdir(struct sftp_command *cmd) return ret; } -static int sftp_action_rm(void *vctx, char *fname) +static bool sftp_action_rm(void *vctx, char *fname) { struct sftp_packet *pktin; struct sftp_request *req; - int result; + bool result; req = fxp_remove_send(fname); pktin = sftp_wait_for_reply(req); @@ -1517,12 +1523,12 @@ static int sftp_action_rm(void *vctx, char *fname) if (!result) { printf("rm %s: %s\n", fname, fxp_error()); - return 0; + return false; } printf("rm %s: OK\n", fname); - return 1; + return true; } int sftp_cmd_rm(struct sftp_command *cmd) @@ -1546,12 +1552,12 @@ int sftp_cmd_rm(struct sftp_command *cmd) return ret; } -static int check_is_dir(char *dstfname) +static bool check_is_dir(char *dstfname) { struct sftp_packet *pktin; struct sftp_request *req; struct fxp_attrs attrs; - int result; + bool result; req = fxp_stat_send(dstfname); pktin = sftp_wait_for_reply(req); @@ -1567,17 +1573,17 @@ static int check_is_dir(char *dstfname) struct sftp_context_mv { char *dstfname; - int dest_is_dir; + bool dest_is_dir; }; -static int sftp_action_mv(void *vctx, char *srcfname) +static bool sftp_action_mv(void *vctx, char *srcfname) { struct sftp_context_mv *ctx = (struct sftp_context_mv *)vctx; struct sftp_packet *pktin; struct sftp_request *req; const char *error; char *finalfname, *newcanon = NULL; - int ret, result; + bool toret, result; if (ctx->dest_is_dir) { char *p; @@ -1590,7 +1596,7 @@ static int sftp_action_mv(void *vctx, char *srcfname) if (!newcanon) { printf("%s: canonify: %s\n", newname, fxp_error()); sfree(newname); - return 0; + return false; } sfree(newname); @@ -1607,14 +1613,14 @@ static int sftp_action_mv(void *vctx, char *srcfname) if (error) { printf("mv %s %s: %s\n", srcfname, finalfname, error); - ret = 0; + toret = false; } else { printf("%s -> %s\n", srcfname, finalfname); - ret = 1; + toret = true; } sfree(newcanon); - return ret; + return toret; } int sftp_cmd_mv(struct sftp_command *cmd) @@ -1666,12 +1672,12 @@ struct sftp_context_chmod { unsigned attrs_clr, attrs_xor; }; -static int sftp_action_chmod(void *vctx, char *fname) +static bool sftp_action_chmod(void *vctx, char *fname) { struct fxp_attrs attrs; struct sftp_packet *pktin; struct sftp_request *req; - int result; + bool result; unsigned oldperms, newperms; struct sftp_context_chmod *ctx = (struct sftp_context_chmod *)vctx; @@ -1682,7 +1688,7 @@ static int sftp_action_chmod(void *vctx, char *fname) if (!result || !(attrs.flags & SSH_FILEXFER_ATTR_PERMISSIONS)) { printf("get attrs for %s: %s\n", fname, result ? "file permissions not provided" : fxp_error()); - return 0; + return false; } attrs.flags = SSH_FILEXFER_ATTR_PERMISSIONS; /* perms _only_ */ @@ -1692,7 +1698,7 @@ static int sftp_action_chmod(void *vctx, char *fname) newperms = attrs.permissions & 07777; if (oldperms == newperms) - return 1; /* no need to do anything! */ + return true; /* no need to do anything! */ req = fxp_setstat_send(fname, attrs); pktin = sftp_wait_for_reply(req); @@ -1700,12 +1706,12 @@ static int sftp_action_chmod(void *vctx, char *fname) if (!result) { printf("set attrs for %s: %s\n", fname, fxp_error()); - return 0; + return false; } printf("%s: %04o -> %04o\n", fname, oldperms, newperms); - return 1; + return true; } int sftp_cmd_chmod(struct sftp_command *cmd) @@ -1925,7 +1931,7 @@ static struct sftp_cmd_lookup { * `shorthelp' is the name of a primary command, which * contains the help that should double up for this command. */ - int listed; /* do we list this in primary help? */ + bool listed; /* do we list this in primary help? */ const char *shorthelp; const char *longhelp; int (*obey) (struct sftp_command *); @@ -2225,7 +2231,7 @@ struct sftp_command *sftp_getcmd(FILE *fp, int mode, int modeflags) char *line; struct sftp_command *cmd; char *p, *q, *r; - int quoting; + bool quoting; cmd = snew(struct sftp_command); cmd->words = NULL; @@ -2302,7 +2308,7 @@ struct sftp_command *sftp_getcmd(FILE *fp, int mode, int modeflags) break; /* mark start of word */ q = r = p; /* q sits at start, r writes word */ - quoting = 0; + quoting = false; while (*p) { if (!quoting && (*p == ' ' || *p == '\t')) break; /* reached end of word */ @@ -2461,7 +2467,7 @@ int do_sftp(int mode, int modeflags, char *batchfile) * Dirty bits: integration with PuTTY. */ -static int verbose = 0; +static bool verbose = false; void ldisc_echoedit_update(Ldisc *ldisc) { } @@ -2488,7 +2494,7 @@ static unsigned char *outptr; /* where to put the data */ static unsigned outlen; /* how much data required */ static unsigned char *pending = NULL; /* any spare data */ static unsigned pendlen = 0, pendsize = 0; /* length and phys. size of buffer */ -static int psftp_output(Seat *seat, int is_stderr, +static int psftp_output(Seat *seat, bool is_stderr, const void *data, int datalen) { unsigned char *p = (unsigned char *) data; @@ -2534,7 +2540,7 @@ static int psftp_output(Seat *seat, int is_stderr, return 0; } -static int psftp_eof(Seat *seat) +static bool psftp_eof(Seat *seat) { /* * We expect to be the party deciding when to close the @@ -2548,7 +2554,7 @@ static int psftp_eof(Seat *seat) return false; } -int sftp_recvdata(char *buf, int len) +bool sftp_recvdata(char *buf, int len) { outptr = (unsigned char *) buf; outlen = len; @@ -2572,20 +2578,20 @@ int sftp_recvdata(char *buf, int len) pending = NULL; } if (outlen == 0) - return 1; + return true; } while (outlen > 0) { if (backend_exitcode(backend) >= 0 || ssh_sftp_loop_iteration() < 0) - return 0; /* doom */ + return false; /* doom */ } - return 1; + return true; } -int sftp_senddata(char *buf, int len) +bool sftp_senddata(char *buf, int len) { backend_send(backend, buf, len); - return 1; + return true; } int sftp_sendbuffer(void) { @@ -2839,8 +2845,8 @@ void cmdline_error(const char *p, ...) exit(1); } -const int share_can_be_downstream = true; -const int share_can_be_upstream = false; +const bool share_can_be_downstream = true; +const bool share_can_be_upstream = false; /* * Main program. Parse arguments etc. @@ -2886,7 +2892,7 @@ int psftp_main(int argc, char *argv[]) } else if (ret == 1) { /* We have our own verbosity in addition to `flags'. */ if (flags & FLAG_VERBOSE) - verbose = 1; + verbose = true; } else if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "-?") == 0 || strcmp(argv[i], "--help") == 0) { @@ -2898,7 +2904,7 @@ int psftp_main(int argc, char *argv[]) strcmp(argv[i], "--version") == 0) { version(); } else if (strcmp(argv[i], "-batch") == 0) { - console_batch_mode = 1; + console_batch_mode = true; } else if (strcmp(argv[i], "-b") == 0 && i + 1 < argc) { mode = 1; batchfile = argv[++i]; diff --git a/psftp.h b/psftp.h index c41675a9..26a9d23b 100644 --- a/psftp.h +++ b/psftp.h @@ -43,7 +43,7 @@ int ssh_sftp_loop_iteration(void); * false, a back end is not (intentionally) active at all (e.g. * psftp before an `open' command). */ -char *ssh_sftp_get_cmdline(const char *prompt, int backend_required); +char *ssh_sftp_get_cmdline(const char *prompt, bool backend_required); /* * Platform-specific function called when we're about to make a @@ -149,7 +149,7 @@ void close_directory(DirHandle *dir); enum { WCTYPE_NONEXISTENT, WCTYPE_FILENAME, WCTYPE_WILDCARD }; -int test_wildcard(const char *name, int cmdline); +int test_wildcard(const char *name, bool cmdline); /* * Actually return matching file names for a local wildcard. @@ -168,12 +168,12 @@ void finish_wildcard_matching(WildcardMatcher *dir); * * Returns true if the filename is kosher, false if dangerous. */ -int vet_filename(const char *name); +bool vet_filename(const char *name); /* - * Create a directory. Returns 0 on error, !=0 on success. + * Create a directory. Returns true on success, false on error. */ -int create_directory(const char *name); +bool create_directory(const char *name); /* * Concatenate a directory name and a file name. The way this is @@ -196,6 +196,6 @@ char *dir_file_cat(const char *dir, const char *file); * pair of overloaded functions, one mapping mutable->mutable and the * other const->const :-( */ -char *stripslashes(const char *str, int local); +char *stripslashes(const char *str, bool local); #endif /* PUTTY_PSFTP_H */ diff --git a/putty.h b/putty.h index f6898aab..fdef2801 100644 --- a/putty.h +++ b/putty.h @@ -153,7 +153,7 @@ struct sesslist { struct unicode_data { char **uni_tbl; - int dbcs_screenfont; + bool dbcs_screenfont; int font_codepage; int line_codepage; wchar_t unitab_scoacs[256]; @@ -497,7 +497,7 @@ struct BackendVtable { const char *(*init) (Seat *seat, Backend **backend_out, LogContext *logctx, Conf *conf, const char *host, int port, - char **realhost, int nodelay, int keepalive); + char **realhost, bool nodelay, bool keepalive); void (*free) (Backend *be); /* Pass in a replacement configuration. */ @@ -509,13 +509,13 @@ struct BackendVtable { void (*size) (Backend *be, int width, int height); void (*special) (Backend *be, SessionSpecialCode code, int arg); const SessionSpecial *(*get_specials) (Backend *be); - int (*connected) (Backend *be); + bool (*connected) (Backend *be); int (*exitcode) (Backend *be); /* If back->sendok() returns false, the backend doesn't currently * want input data, so the frontend should avoid acquiring any if * possible (passing back-pressure on to its sender). */ - int (*sendok) (Backend *be); - int (*ldisc_option_state) (Backend *be, int); + bool (*sendok) (Backend *be); + bool (*ldisc_option_state) (Backend *be, int); void (*provide_ldisc) (Backend *be, Ldisc *ldisc); /* Tells the back end that the front end buffer is clearing. */ void (*unthrottle) (Backend *be, int bufsize); @@ -523,7 +523,7 @@ struct BackendVtable { /* Only implemented in the SSH protocol: check whether a * connection-sharing upstream exists for a given configuration. */ - int (*test_for_upstream)(const char *host, int port, Conf *conf); + bool (*test_for_upstream)(const char *host, int port, Conf *conf); const char *name; int protocol; @@ -595,7 +595,7 @@ GLOBAL int default_port; /* * This is set true by cmdline.c iff a session is loaded with "-load". */ -GLOBAL int loaded_session; +GLOBAL bool loaded_session; /* * This is set to the name of the loaded session. */ @@ -619,7 +619,7 @@ GLOBAL char *cmdline_session_name; */ typedef struct { char *prompt; - int echo; + bool echo; /* * 'result' must be a dynamically allocated array of exactly * 'resultsize' chars. The code for actually reading input may @@ -642,11 +642,11 @@ typedef struct { * information (so the caller should ensure that the supplied text is * sufficient). */ - int to_server; + bool to_server; char *name; /* Short description, perhaps for dialog box title */ - int name_reqd; /* Display of `name' required or optional? */ + bool name_reqd; /* Display of `name' required or optional? */ char *instruction; /* Long description, maybe with embedded newlines */ - int instr_reqd; /* Display of `instruction' required or optional? */ + bool instr_reqd; /* Display of `instruction' required or optional? */ size_t n_prompts; /* May be zero (in which case display the foregoing, * if any, and return success) */ prompt_t **prompts; @@ -654,7 +654,7 @@ typedef struct { * seat_get_userpass_input(); initially NULL */ } prompts_t; prompts_t *new_prompts(); -void add_prompt(prompts_t *p, char *promptstr, int echo); +void add_prompt(prompts_t *p, char *promptstr, bool echo); void prompt_set_result(prompt_t *pr, const char *newstr); void prompt_ensure_result_size(prompt_t *pr, int len); /* Burn the evidence. (Assumes _all_ strings want free()ing.) */ @@ -668,7 +668,7 @@ void free_prompts(prompts_t *p); * background. */ typedef struct optionalrgb { - unsigned char enabled; + bool enabled; unsigned char r, g, b; } optionalrgb; extern const optionalrgb optionalrgb_none; @@ -742,7 +742,7 @@ struct SeatVtable { * * The return value is the current size of the output backlog. */ - int (*output)(Seat *seat, int is_stderr, const void *data, int len); + int (*output)(Seat *seat, bool is_stderr, const void *data, int len); /* * Called when the back end wants to indicate that EOF has arrived @@ -750,7 +750,7 @@ struct SeatVtable { * we intend to keep the session open in the other direction, or * true to indicate that if they're closing so are we. */ - int (*eof)(Seat *seat); + bool (*eof)(Seat *seat); /* * Try to get answers from a set of interactive login prompts. The @@ -884,14 +884,14 @@ struct SeatVtable { * user in the UTF-8 character set. (Affects e.g. visual erase * handling in local line editing.) */ - int (*is_utf8)(Seat *seat); + bool (*is_utf8)(Seat *seat); /* * Notify the seat that the back end, and/or the ldisc between * them, have changed their idea of whether they currently want * local echo and/or local line editing enabled. */ - void (*echoedit_update)(Seat *seat, int echoing, int editing); + void (*echoedit_update)(Seat *seat, bool echoing, bool editing); /* * Return the local X display string relevant to a seat, or NULL @@ -904,7 +904,7 @@ struct SeatVtable { * by returning true and filling in the output pointer. Return * false if there isn't one or if the concept is meaningless. */ - int (*get_windowid)(Seat *seat, long *id_out); + bool (*get_windowid)(Seat *seat, long *id_out); /* * Return the size of the terminal window in pixels. If the @@ -912,7 +912,7 @@ struct SeatVtable { * return false; otherwise fill in the output pointers and return * true. */ - int (*get_window_pixel_size)(Seat *seat, int *width, int *height); + bool (*get_window_pixel_size)(Seat *seat, int *width, int *height); }; #define seat_output(seat, is_stderr, data, len) \ @@ -964,8 +964,8 @@ void seat_connection_fatal(Seat *seat, const char *fmt, ...); * These are generally obvious, except for is_utf8, where you might * plausibly want to return either fixed answer 'no' or 'yes'. */ -int nullseat_output(Seat *seat, int is_stderr, const void *data, int len); -int nullseat_eof(Seat *seat); +int nullseat_output(Seat *seat, bool is_stderr, const void *data, int len); +bool nullseat_eof(Seat *seat); int nullseat_get_userpass_input(Seat *seat, prompts_t *p, bufchain *input); void nullseat_notify_remote_exit(Seat *seat); void nullseat_connection_fatal(Seat *seat, const char *message); @@ -982,12 +982,12 @@ int nullseat_confirm_weak_crypto_primitive( int nullseat_confirm_weak_cached_hostkey( Seat *seat, const char *algname, const char *betteralgs, void (*callback)(void *ctx, int result), void *ctx); -int nullseat_is_never_utf8(Seat *seat); -int nullseat_is_always_utf8(Seat *seat); -void nullseat_echoedit_update(Seat *seat, int echoing, int editing); +bool nullseat_is_never_utf8(Seat *seat); +bool nullseat_is_always_utf8(Seat *seat); +void nullseat_echoedit_update(Seat *seat, bool echoing, bool editing); const char *nullseat_get_x_display(Seat *seat); -int nullseat_get_windowid(Seat *seat, long *id_out); -int nullseat_get_window_pixel_size(Seat *seat, int *width, int *height); +bool nullseat_get_windowid(Seat *seat, long *id_out); +bool nullseat_get_window_pixel_size(Seat *seat, int *width, int *height); /* * Seat functions provided by the platform's console-application @@ -1029,7 +1029,7 @@ struct TermWinVtable { * of TermWin handles it by loading the currently configured font * into the HDC and doing a GDI query.) */ - int (*setup_draw_ctx)(TermWin *); + bool (*setup_draw_ctx)(TermWin *); /* Draw text in the window, during a painting operation */ void (*draw_text)(TermWin *, int x, int y, wchar_t *text, int len, unsigned long attrs, int line_attrs, truecolour tc); @@ -1045,14 +1045,14 @@ struct TermWinVtable { void (*set_cursor_pos)(TermWin *, int x, int y); - void (*set_raw_mouse_mode)(TermWin *, int enable); + void (*set_raw_mouse_mode)(TermWin *, bool enable); void (*set_scrollbar)(TermWin *, int total, int start, int page); void (*bell)(TermWin *, int mode); void (*clip_write)(TermWin *, int clipboard, wchar_t *text, int *attrs, - truecolour *colours, int len, int must_deselect); + truecolour *colours, int len, bool must_deselect); void (*clip_request_paste)(TermWin *, int clipboard); void (*refresh)(TermWin *); @@ -1066,20 +1066,20 @@ struct TermWinVtable { * {min,normal,max} switch. The idea is that when you un-minimise * the window it remembers whether to go back to normal or * maximised. */ - void (*set_minimised)(TermWin *, int minimised); - int (*is_minimised)(TermWin *); - void (*set_maximised)(TermWin *, int maximised); + void (*set_minimised)(TermWin *, bool minimised); + bool (*is_minimised)(TermWin *); + void (*set_maximised)(TermWin *, bool maximised); void (*move)(TermWin *, int x, int y); - void (*set_zorder)(TermWin *, int top); + void (*set_zorder)(TermWin *, bool top); - int (*palette_get)(TermWin *, int n, int *r, int *g, int *b); + bool (*palette_get)(TermWin *, int n, int *r, int *g, int *b); void (*palette_set)(TermWin *, int n, int r, int g, int b); void (*palette_reset)(TermWin *); void (*get_pos)(TermWin *, int *x, int *y); void (*get_pixels)(TermWin *, int *x, int *y); - const char *(*get_title)(TermWin *, int icon); - int (*is_utf8)(TermWin *); + const char *(*get_title)(TermWin *, bool icon); + bool (*is_utf8)(TermWin *); }; #define win_setup_draw_ctx(win) \ @@ -1397,6 +1397,7 @@ void cleanup_exit(int); X(INT, NONE, shadowboldoffset) /* in pixels */ \ X(BOOL, NONE, crhaslf) \ X(STR, NONE, winclass) \ + /* end of list */ /* Now define the actual enum of option keywords using that macro. */ #define CONF_ENUM_DEF(valtype, keytype, keyword) CONF_ ## keyword, @@ -1439,7 +1440,7 @@ void conf_set_filename(Conf *conf, int key, const Filename *val); void conf_set_fontspec(Conf *conf, int key, const FontSpec *val); /* Serialisation functions for Duplicate Session */ void conf_serialise(BinarySink *bs, Conf *conf); -int conf_deserialise(Conf *conf, BinarySource *src);/*returns true on success*/ +bool conf_deserialise(Conf *conf, BinarySource *src);/*returns true on success*/ /* * Functions to copy, free, serialise and deserialise FontSpecs. @@ -1475,7 +1476,7 @@ char *save_settings(const char *section, Conf *conf); void save_open_settings(settings_w *sesskey, Conf *conf); void load_settings(const char *section, Conf *conf); void load_open_settings(settings_r *sesskey, Conf *conf); -void get_sesslist(struct sesslist *, int allocate); +void get_sesslist(struct sesslist *, bool allocate); void do_defaults(const char *, Conf *); void registry_cleanup(void); @@ -1507,35 +1508,35 @@ FontSpec *platform_default_fontspec(const char *name); Terminal *term_init(Conf *, struct unicode_data *, TermWin *); void term_free(Terminal *); void term_size(Terminal *, int, int, int); -void term_paint(Terminal *, int, int, int, int, int); +void term_paint(Terminal *, int, int, int, int, bool); void term_scroll(Terminal *, int, int); void term_scroll_to_selection(Terminal *, int); -void term_pwron(Terminal *, int); +void term_pwron(Terminal *, bool); void term_clrsb(Terminal *); void term_mouse(Terminal *, Mouse_Button, Mouse_Button, Mouse_Action, - int,int,int,int,int); + int, int, bool, bool, bool); void term_key(Terminal *, Key_Sym, wchar_t *, size_t, unsigned int, unsigned int); void term_lost_clipboard_ownership(Terminal *, int clipboard); void term_update(Terminal *); void term_invalidate(Terminal *); -void term_blink(Terminal *, int set_cursor); +void term_blink(Terminal *, bool set_cursor); void term_do_paste(Terminal *, const wchar_t *, int); void term_nopaste(Terminal *); -int term_ldisc(Terminal *, int option); +bool term_ldisc(Terminal *, int option); void term_copyall(Terminal *, const int *, int); void term_reconfig(Terminal *, Conf *); void term_request_copy(Terminal *, const int *clipboards, int n_clipboards); void term_request_paste(Terminal *, int clipboard); void term_seen_key_event(Terminal *); -int term_data(Terminal *, int is_stderr, const void *data, int len); +int term_data(Terminal *, bool is_stderr, const void *data, int len); void term_provide_backend(Terminal *term, Backend *backend); void term_provide_logctx(Terminal *term, LogContext *logctx); -void term_set_focus(Terminal *term, int has_focus); +void term_set_focus(Terminal *term, bool has_focus); char *term_get_ttymode(Terminal *term, const char *mode); int term_get_userpass_input(Terminal *term, prompts_t *p, bufchain *input); -int format_arrow_key(char *buf, Terminal *term, int xkey, int ctrl); +int format_arrow_key(char *buf, Terminal *term, int xkey, bool ctrl); /* * Exports from logging.c. @@ -1653,15 +1654,15 @@ extern const struct BackendVtable ssh_backend; Ldisc *ldisc_create(Conf *, Terminal *, Backend *, Seat *); void ldisc_configure(Ldisc *, Conf *); void ldisc_free(Ldisc *); -void ldisc_send(Ldisc *, const void *buf, int len, int interactive); +void ldisc_send(Ldisc *, const void *buf, int len, bool interactive); void ldisc_echoedit_update(Ldisc *); /* * Exports from ldiscucs.c. */ void lpage_send(Ldisc *, int codepage, const char *buf, int len, - int interactive); -void luni_send(Ldisc *, const wchar_t * widebuf, int len, int interactive); + bool interactive); +void luni_send(Ldisc *, const wchar_t * widebuf, int len, bool interactive); /* * Exports from sshrand.c. @@ -1690,7 +1691,7 @@ void pinger_free(Pinger *); */ #include "misc.h" -int conf_launchable(Conf *conf); +bool conf_launchable(Conf *conf); char const *conf_dest(Conf *conf); /* @@ -1701,7 +1702,7 @@ void prepare_session(Conf *conf); /* * Exports from sercfg.c. */ -void ser_setup_config_box(struct controlbox *b, int midsession, +void ser_setup_config_box(struct controlbox *b, bool midsession, int parity_mask, int flow_mask); /* @@ -1716,7 +1717,7 @@ extern const char ver[]; #define CP_UTF8 65001 #endif /* void init_ucs(void); -- this is now in platform-specific headers */ -int is_dbcs_leadbyte(int codepage, char byte); +bool is_dbcs_leadbyte(int codepage, char byte); int mb_to_wc(int codepage, int flags, const char *mbstr, int mblen, wchar_t *wcstr, int wclen); int wc_to_mb(int codepage, int flags, const wchar_t *wcstr, int wclen, @@ -1766,7 +1767,7 @@ agent_pending_query *agent_query( void (*callback)(void *, void *, int), void *callback_ctx); void agent_cancel_query(agent_pending_query *); void agent_query_synchronous(strbuf *in, void **out, int *outlen); -int agent_exists(void); +bool agent_exists(void); /* * Exports from wildcard.c @@ -1774,7 +1775,7 @@ int agent_exists(void); const char *wc_error(int value); int wc_match_pl(const char *wildcard, ptrlen target); int wc_match(const char *wildcard, const char *target); -int wc_unescape(char *output, const char *wildcard); +bool wc_unescape(char *output, const char *wildcard); /* * Exports from frontend (windlg.c etc) @@ -1784,15 +1785,15 @@ void pgp_fingerprints(void); * have_ssh_host_key() just returns true if a key of that type is * already cached and false otherwise. */ -int have_ssh_host_key(const char *host, int port, const char *keytype); +bool have_ssh_host_key(const char *host, int port, const char *keytype); /* * Exports from console frontends (wincons.c, uxcons.c) * that aren't equivalents to things in windlg.c et al. */ -extern int console_batch_mode; +extern bool console_batch_mode; int console_get_userpass_input(prompts_t *p); -int is_interactive(void); +bool is_interactive(void); void console_print_error_msg(const char *prefix, const char *msg); void console_print_error_msg_fmt_v( const char *prefix, const char *fmt, va_list ap); @@ -1824,7 +1825,7 @@ int cmdline_process_param(const char *, char *, int, Conf *); void cmdline_run_saved(Conf *); void cmdline_cleanup(void); int cmdline_get_passwd_input(prompts_t *p); -int cmdline_host_ok(Conf *); +bool cmdline_host_ok(Conf *); #define TOOLTYPE_FILETRANSFER 1 #define TOOLTYPE_NONNETWORK 2 #define TOOLTYPE_HOST_ARG 4 @@ -1852,7 +1853,7 @@ void conf_filesel_handler(union control *ctrl, dlgparam *dlg, void *data, int event); void conf_fontsel_handler(union control *ctrl, dlgparam *dlg, void *data, int event); -void setup_config_box(struct controlbox *b, int midsession, +void setup_config_box(struct controlbox *b, bool midsession, int protocol, int protcfginfo); /* @@ -1864,7 +1865,7 @@ typedef struct bidi_char { } bidi_char; int do_bidi(bidi_char *line, int count); int do_shape(bidi_char *line, bidi_char *to, int count); -int is_rtl(int c); +bool is_rtl(int c); /* * X11 auth mechanisms we know about. @@ -1895,8 +1896,8 @@ enum { */ Filename *filename_from_str(const char *string); const char *filename_to_str(const Filename *fn); -int filename_equal(const Filename *f1, const Filename *f2); -int filename_is_null(const Filename *fn); +bool filename_equal(const Filename *f1, const Filename *f2); +bool filename_is_null(const Filename *fn); Filename *filename_copy(const Filename *fn); void filename_free(Filename *fn); void filename_serialise(BinarySink *bs, const Filename *f); @@ -1904,7 +1905,7 @@ Filename *filename_deserialise(BinarySource *src); char *get_username(void); /* return value needs freeing */ char *get_random_data(int bytes, const char *device); /* used in cmdgen.c */ char filename_char_sanitise(char c); /* rewrite special pathname chars */ -int open_for_write_would_lose_data(const Filename *fn); +bool open_for_write_would_lose_data(const Filename *fn); /* * Exports and imports from timing.c. @@ -1999,7 +2000,7 @@ int open_for_write_would_lose_data(const Filename *fn); typedef void (*timer_fn_t)(void *ctx, unsigned long now); unsigned long schedule_timer(int ticks, timer_fn_t fn, void *ctx); void expire_timer_context(void *ctx); -int run_timers(unsigned long now, unsigned long *next); +bool run_timers(unsigned long now, unsigned long *next); void timer_change_notify(unsigned long next); unsigned long timing_last_clock(void); @@ -2031,8 +2032,8 @@ unsigned long timing_last_clock(void); */ typedef void (*toplevel_callback_fn_t)(void *ctx); void queue_toplevel_callback(toplevel_callback_fn_t fn, void *ctx); -int run_toplevel_callbacks(void); -int toplevel_callback_pending(void); +bool run_toplevel_callbacks(void); +bool toplevel_callback_pending(void); void delete_callbacks_for_context(void *ctx); /* @@ -2047,7 +2048,7 @@ void delete_callbacks_for_context(void *ctx); struct IdempotentCallback { toplevel_callback_fn_t fn; void *ctx; - int queued; + bool queued; }; void queue_idempotent_callback(struct IdempotentCallback *ic); diff --git a/raw.c b/raw.c index 827193ea..90dde5d8 100644 --- a/raw.c +++ b/raw.c @@ -13,11 +13,11 @@ typedef struct Raw Raw; struct Raw { Socket *s; - int closed_on_socket_error; + bool closed_on_socket_error; int bufsize; Seat *seat; LogContext *logctx; - int sent_console_eof, sent_socket_eof, session_started; + bool sent_console_eof, sent_socket_eof, session_started; Conf *conf; @@ -57,7 +57,7 @@ static void raw_check_close(Raw *raw) } static void raw_closing(Plug *plug, const char *error_msg, int error_code, - int calling_back) + bool calling_back) { Raw *raw = container_of(plug, Raw, plug); @@ -122,7 +122,7 @@ static const PlugVtable Raw_plugvt = { static const char *raw_init(Seat *seat, Backend **backend_handle, LogContext *logctx, Conf *conf, const char *host, int port, char **realhost, - int nodelay, int keepalive) + bool nodelay, bool keepalive) { SockAddr *addr; const char *err; @@ -161,8 +161,8 @@ static const char *raw_init(Seat *seat, Backend **backend_handle, /* * Open socket. */ - raw->s = new_connection(addr, *realhost, port, 0, 1, nodelay, keepalive, - &raw->plug, conf); + raw->s = new_connection(addr, *realhost, port, false, true, nodelay, + keepalive, &raw->plug, conf); if ((err = sk_socket_error(raw->s)) != NULL) return err; @@ -255,15 +255,15 @@ static const SessionSpecial *raw_get_specials(Backend *be) return NULL; } -static int raw_connected(Backend *be) +static bool raw_connected(Backend *be) { Raw *raw = container_of(be, Raw, backend); return raw->s != NULL; } -static int raw_sendok(Backend *be) +static bool raw_sendok(Backend *be) { - return 1; + return true; } static void raw_unthrottle(Backend *be, int backlog) @@ -272,11 +272,11 @@ static void raw_unthrottle(Backend *be, int backlog) sk_set_frozen(raw->s, backlog > RAW_MAX_BACKLOG); } -static int raw_ldisc(Backend *be, int option) +static bool raw_ldisc(Backend *be, int option) { if (option == LD_EDIT || option == LD_ECHO) - return 1; - return 0; + return true; + return false; } static void raw_provide_ldisc(Backend *be, Ldisc *ldisc) diff --git a/rlogin.c b/rlogin.c index 1b70443e..46bfb7eb 100644 --- a/rlogin.c +++ b/rlogin.c @@ -14,10 +14,10 @@ typedef struct Rlogin Rlogin; struct Rlogin { Socket *s; - int closed_on_socket_error; + bool closed_on_socket_error; int bufsize; - int firstbyte; - int cansize; + bool firstbyte; + bool cansize; int term_width, term_height; Seat *seat; LogContext *logctx; @@ -47,7 +47,7 @@ static void rlogin_log(Plug *plug, int type, SockAddr *addr, int port, } static void rlogin_closing(Plug *plug, const char *error_msg, int error_code, - int calling_back) + bool calling_back) { Rlogin *rlogin = container_of(plug, Rlogin, plug); @@ -80,7 +80,7 @@ static void rlogin_receive(Plug *plug, int urgent, char *data, int len) c = *data++; len--; if (c == '\x80') { - rlogin->cansize = 1; + rlogin->cansize = true; backend_size(&rlogin->backend, rlogin->term_width, rlogin->term_height); } @@ -101,7 +101,7 @@ static void rlogin_receive(Plug *plug, int urgent, char *data, int len) data++; len--; } - rlogin->firstbyte = 0; + rlogin->firstbyte = false; } if (len > 0) c_write(rlogin, data, len); @@ -153,7 +153,7 @@ static const PlugVtable Rlogin_plugvt = { static const char *rlogin_init(Seat *seat, Backend **backend_handle, LogContext *logctx, Conf *conf, const char *host, int port, char **realhost, - int nodelay, int keepalive) + bool nodelay, bool keepalive) { SockAddr *addr; const char *err; @@ -171,8 +171,8 @@ static const char *rlogin_init(Seat *seat, Backend **backend_handle, rlogin->logctx = logctx; rlogin->term_width = conf_get_int(conf, CONF_width); rlogin->term_height = conf_get_int(conf, CONF_height); - rlogin->firstbyte = 1; - rlogin->cansize = 0; + rlogin->firstbyte = true; + rlogin->cansize = false; rlogin->prompt = NULL; rlogin->conf = conf_copy(conf); *backend_handle = &rlogin->backend; @@ -194,7 +194,7 @@ static const char *rlogin_init(Seat *seat, Backend **backend_handle, /* * Open socket. */ - rlogin->s = new_connection(addr, *realhost, port, 1, 0, + rlogin->s = new_connection(addr, *realhost, port, true, false, nodelay, keepalive, &rlogin->plug, conf); if ((err = sk_socket_error(rlogin->s)) != NULL) return err; @@ -346,16 +346,16 @@ static const SessionSpecial *rlogin_get_specials(Backend *be) return NULL; } -static int rlogin_connected(Backend *be) +static bool rlogin_connected(Backend *be) { Rlogin *rlogin = container_of(be, Rlogin, backend); return rlogin->s != NULL; } -static int rlogin_sendok(Backend *be) +static bool rlogin_sendok(Backend *be) { /* Rlogin *rlogin = container_of(be, Rlogin, backend); */ - return 1; + return true; } static void rlogin_unthrottle(Backend *be, int backlog) @@ -364,10 +364,10 @@ static void rlogin_unthrottle(Backend *be, int backlog) sk_set_frozen(rlogin->s, backlog > RLOGIN_MAX_BACKLOG); } -static int rlogin_ldisc(Backend *be, int option) +static bool rlogin_ldisc(Backend *be, int option) { /* Rlogin *rlogin = container_of(be, Rlogin, backend); */ - return 0; + return false; } static void rlogin_provide_ldisc(Backend *be, Ldisc *ldisc) diff --git a/scpserver.c b/scpserver.c index 1c9912a3..42439159 100644 --- a/scpserver.c +++ b/scpserver.c @@ -256,7 +256,7 @@ typedef struct ScpReplyReceiver ScpReplyReceiver; struct ScpReplyReceiver { - int err; + bool err; unsigned code; char *errmsg; struct fxp_attrs attrs; @@ -371,12 +371,13 @@ typedef struct ScpSourceStackEntry ScpSourceStackEntry; struct ScpSource { SftpServer *sf; - int acks, expect_newline, eof, throttled, finished; + int acks; + bool expect_newline, eof, throttled, finished; SshChannel *sc; ScpSourceStackEntry *head; - int recursive; - int send_file_times; + bool recursive; + bool send_file_times; strbuf *pending_commands[3]; int n_pending_commands; @@ -482,7 +483,7 @@ static void scp_source_push_name( static void scp_source_free(ScpServer *s); static int scp_source_send(ScpServer *s, const void *data, size_t length); static void scp_source_eof(ScpServer *s); -static void scp_source_throttle(ScpServer *s, int throttled); +static void scp_source_throttle(ScpServer *s, bool throttled); static struct ScpServerVtable ScpSource_ScpServer_vt = { scp_source_free, @@ -899,7 +900,7 @@ static int scp_source_send(ScpServer *s, const void *vdata, size_t length) return 0; } -static void scp_source_throttle(ScpServer *s, int throttled) +static void scp_source_throttle(ScpServer *s, bool throttled) { ScpSource *scp = container_of(s, ScpSource, scpserver); @@ -937,10 +938,10 @@ struct ScpSink { uint64_t file_offset, file_size; unsigned long atime, mtime; - int got_file_times; + bool got_file_times; bufchain data; - int input_eof; + bool input_eof; strbuf *command; char command_chr; @@ -968,10 +969,10 @@ struct ScpSinkStackEntry { * should be created _as_ - regardless of the filename in the 'C' * command. */ - int isdir; + bool isdir; }; -static void scp_sink_push(ScpSink *scp, ptrlen pathname, int isdir) +static void scp_sink_push(ScpSink *scp, ptrlen pathname, bool isdir) { ScpSinkStackEntry *node = snew_plus(ScpSinkStackEntry, pathname.len); char *p = snew_plus_get_aux(node); @@ -995,7 +996,7 @@ static void scp_sink_pop(ScpSink *scp) static void scp_sink_free(ScpServer *s); static int scp_sink_send(ScpServer *s, const void *data, size_t length); static void scp_sink_eof(ScpServer *s); -static void scp_sink_throttle(ScpServer *s, int throttled) {} +static void scp_sink_throttle(ScpServer *s, bool throttled) {} static struct ScpServerVtable ScpSink_ScpServer_vt = { scp_sink_free, @@ -1012,7 +1013,7 @@ static void scp_sink_start_callback(void *vscp) static ScpSink *scp_sink_new( SshChannel *sc, const SftpServerVtable *sftpserver_vt, ptrlen pathname, - int pathname_is_definitely_dir) + bool pathname_is_definitely_dir) { ScpSink *scp = snew(ScpSink); memset(scp, 0, sizeof(*scp)); @@ -1295,7 +1296,7 @@ static void scp_error_free(ScpServer *s); static int scp_error_send(ScpServer *s, const void *data, size_t length) { return 0; } static void scp_error_eof(ScpServer *s) {} -static void scp_error_throttle(ScpServer *s, int throttled) {} +static void scp_error_throttle(ScpServer *s, bool throttled) {} static struct ScpServerVtable ScpError_ScpServer_vt = { scp_error_free, @@ -1353,8 +1354,8 @@ static void scp_error_free(ScpServer *s) ScpServer *scp_recognise_exec( SshChannel *sc, const SftpServerVtable *sftpserver_vt, ptrlen command) { - int recursive = false, preserve = false; - int targetshouldbedirectory = false; + bool recursive = false, preserve = false; + bool targetshouldbedirectory = false; ptrlen command_orig = command; if (!ptrlen_startswith(command, PTRLEN_LITERAL("scp "), &command)) diff --git a/sercfg.c b/sercfg.c index 71462100..2c1682f5 100644 --- a/sercfg.c +++ b/sercfg.c @@ -124,7 +124,7 @@ static void serial_flow_handler(union control *ctrl, dlgparam *dlg, } } -void ser_setup_config_box(struct controlbox *b, int midsession, +void ser_setup_config_box(struct controlbox *b, bool midsession, int parity_mask, int flow_mask) { struct controlset *s; diff --git a/sesschan.c b/sesschan.c index 4a390167..1ca085d1 100644 --- a/sesschan.c +++ b/sesschan.c @@ -23,13 +23,13 @@ typedef struct sesschan { LogPolicy logpolicy; Seat seat; - int want_pty; + bool want_pty; struct ssh_ttymodes ttymodes; int wc, hc, wp, hp; strbuf *termtype; - int ignoring_input; - int seen_eof, seen_exit; + bool ignoring_input; + bool seen_eof, seen_exit; Plug xfwd_plug; int n_x11_sockets; @@ -48,25 +48,25 @@ typedef struct sesschan { } sesschan; static void sesschan_free(Channel *chan); -static int sesschan_send(Channel *chan, int is_stderr, const void *, int); +static int sesschan_send(Channel *chan, bool is_stderr, const void *, int); static void sesschan_send_eof(Channel *chan); static char *sesschan_log_close_msg(Channel *chan); -static int sesschan_want_close(Channel *, int, int); -static void sesschan_set_input_wanted(Channel *chan, int wanted); -static int sesschan_run_shell(Channel *chan); -static int sesschan_run_command(Channel *chan, ptrlen command); -static int sesschan_run_subsystem(Channel *chan, ptrlen subsys); -static int sesschan_enable_x11_forwarding( - Channel *chan, int oneshot, ptrlen authproto, ptrlen authdata, +static bool sesschan_want_close(Channel *, bool, bool); +static void sesschan_set_input_wanted(Channel *chan, bool wanted); +static bool sesschan_run_shell(Channel *chan); +static bool sesschan_run_command(Channel *chan, ptrlen command); +static bool sesschan_run_subsystem(Channel *chan, ptrlen subsys); +static bool sesschan_enable_x11_forwarding( + Channel *chan, bool oneshot, ptrlen authproto, ptrlen authdata, unsigned screen_number); -static int sesschan_enable_agent_forwarding(Channel *chan); -static int sesschan_allocate_pty( +static bool sesschan_enable_agent_forwarding(Channel *chan); +static bool sesschan_allocate_pty( Channel *chan, ptrlen termtype, unsigned width, unsigned height, unsigned pixwidth, unsigned pixheight, struct ssh_ttymodes modes); -static int sesschan_set_env(Channel *chan, ptrlen var, ptrlen value); -static int sesschan_send_break(Channel *chan, unsigned length); -static int sesschan_send_signal(Channel *chan, ptrlen signame); -static int sesschan_change_window_size( +static bool sesschan_set_env(Channel *chan, ptrlen var, ptrlen value); +static bool sesschan_send_break(Channel *chan, unsigned length); +static bool sesschan_send_signal(Channel *chan, ptrlen signame); +static bool sesschan_change_window_size( Channel *chan, unsigned width, unsigned height, unsigned pixwidth, unsigned pixheight); @@ -95,7 +95,7 @@ static const struct ChannelVtable sesschan_channelvt = { chan_no_request_response, }; -static int sftp_chan_send(Channel *chan, int is_stderr, const void *, int); +static int sftp_chan_send(Channel *chan, bool is_stderr, const void *, int); static void sftp_chan_send_eof(Channel *chan); static char *sftp_log_close_msg(Channel *chan); @@ -124,9 +124,9 @@ static const struct ChannelVtable sftp_channelvt = { chan_no_request_response, }; -static int scp_chan_send(Channel *chan, int is_stderr, const void *, int); +static int scp_chan_send(Channel *chan, bool is_stderr, const void *, int); static void scp_chan_send_eof(Channel *chan); -static void scp_set_input_wanted(Channel *chan, int wanted); +static void scp_set_input_wanted(Channel *chan, bool wanted); static char *scp_log_close_msg(Channel *chan); static const struct ChannelVtable scp_channelvt = { @@ -166,11 +166,11 @@ static const LogPolicyVtable sesschan_logpolicy_vt = { sesschan_logging_error, }; -static int sesschan_seat_output(Seat *, int is_stderr, const void *, int); -static int sesschan_seat_eof(Seat *); +static int sesschan_seat_output(Seat *, bool is_stderr, const void *, int); +static bool sesschan_seat_eof(Seat *); static void sesschan_notify_remote_exit(Seat *seat); static void sesschan_connection_fatal(Seat *seat, const char *message); -static int sesschan_get_window_pixel_size(Seat *seat, int *width, int *height); +static bool sesschan_get_window_pixel_size(Seat *seat, int *w, int *h); static const SeatVtable sesschan_seat_vt = { sesschan_seat_output, @@ -241,7 +241,7 @@ static void sesschan_free(Channel *chan) sfree(sess); } -static int sesschan_send(Channel *chan, int is_stderr, +static int sesschan_send(Channel *chan, bool is_stderr, const void *data, int length) { sesschan *sess = container_of(chan, sesschan, chan); @@ -264,7 +264,7 @@ static char *sesschan_log_close_msg(Channel *chan) return dupstr("Session channel closed"); } -static void sesschan_set_input_wanted(Channel *chan, int wanted) +static void sesschan_set_input_wanted(Channel *chan, bool wanted) { /* I don't think we need to do anything here */ } @@ -277,7 +277,7 @@ static void sesschan_start_backend(sesschan *sess, const char *cmd) backend_size(sess->backend, sess->wc, sess->hc); } -int sesschan_run_shell(Channel *chan) +bool sesschan_run_shell(Channel *chan) { sesschan *sess = container_of(chan, sesschan, chan); @@ -288,7 +288,7 @@ int sesschan_run_shell(Channel *chan) return true; } -int sesschan_run_command(Channel *chan, ptrlen command) +bool sesschan_run_command(Channel *chan, ptrlen command) { sesschan *sess = container_of(chan, sesschan, chan); @@ -310,7 +310,7 @@ int sesschan_run_command(Channel *chan, ptrlen command) return true; } -int sesschan_run_subsystem(Channel *chan, ptrlen subsys) +bool sesschan_run_subsystem(Channel *chan, ptrlen subsys) { sesschan *sess = container_of(chan, sesschan, chan); @@ -328,7 +328,7 @@ static void fwd_log(Plug *plug, int type, SockAddr *addr, int port, const char *error_msg, int error_code) { /* don't expect any weirdnesses from a listening socket */ } static void fwd_closing(Plug *plug, const char *error_msg, int error_code, - int calling_back) + bool calling_back) { /* not here, either */ } static int xfwd_accepting(Plug *p, accept_fn_t constructor, accept_ctx_t ctx) @@ -344,13 +344,13 @@ static int xfwd_accepting(Plug *p, accept_fn_t constructor, accept_ctx_t ctx) s = constructor(ctx, plug); if ((err = sk_socket_error(s)) != NULL) { portfwd_raw_free(chan); - return true; + return 1; } pi = sk_peer_info(s); portfwd_raw_setup(chan, s, ssh_serverside_x11_open(sess->c->cl, chan, pi)); sk_free_peer_info(pi); - return false; + return 0; } static const PlugVtable xfwd_plugvt = { @@ -361,8 +361,8 @@ static const PlugVtable xfwd_plugvt = { xfwd_accepting, }; -int sesschan_enable_x11_forwarding( - Channel *chan, int oneshot, ptrlen authproto, ptrlen authdata_hex, +bool sesschan_enable_x11_forwarding( + Channel *chan, bool oneshot, ptrlen authproto, ptrlen authdata_hex, unsigned screen_number) { sesschan *sess = container_of(chan, sesschan, chan); @@ -420,11 +420,11 @@ static int agentfwd_accepting( s = constructor(ctx, plug); if ((err = sk_socket_error(s)) != NULL) { portfwd_raw_free(chan); - return true; + return 1; } portfwd_raw_setup(chan, s, ssh_serverside_agent_open(sess->c->cl, chan)); - return false; + return 0; } static const PlugVtable agentfwd_plugvt = { @@ -435,7 +435,7 @@ static const PlugVtable agentfwd_plugvt = { agentfwd_accepting, }; -int sesschan_enable_agent_forwarding(Channel *chan) +bool sesschan_enable_agent_forwarding(Channel *chan) { sesschan *sess = container_of(chan, sesschan, chan); char *error, *socketname, *dir_prefix; @@ -459,7 +459,7 @@ int sesschan_enable_agent_forwarding(Channel *chan) return sess->agentfwd_socket != NULL; } -int sesschan_allocate_pty( +bool sesschan_allocate_pty( Channel *chan, ptrlen termtype, unsigned width, unsigned height, unsigned pixwidth, unsigned pixheight, struct ssh_ttymodes modes) { @@ -483,7 +483,7 @@ int sesschan_allocate_pty( return true; } -int sesschan_set_env(Channel *chan, ptrlen var, ptrlen value) +bool sesschan_set_env(Channel *chan, ptrlen var, ptrlen value) { sesschan *sess = container_of(chan, sesschan, chan); @@ -495,7 +495,7 @@ int sesschan_set_env(Channel *chan, ptrlen var, ptrlen value) return true; } -int sesschan_send_break(Channel *chan, unsigned length) +bool sesschan_send_break(Channel *chan, unsigned length) { sesschan *sess = container_of(chan, sesschan, chan); @@ -511,7 +511,7 @@ int sesschan_send_break(Channel *chan, unsigned length) return false; } -int sesschan_send_signal(Channel *chan, ptrlen signame) +bool sesschan_send_signal(Channel *chan, ptrlen signame) { sesschan *sess = container_of(chan, sesschan, chan); @@ -533,7 +533,7 @@ int sesschan_send_signal(Channel *chan, ptrlen signame) return true; } -int sesschan_change_window_size( +bool sesschan_change_window_size( Channel *chan, unsigned width, unsigned height, unsigned pixwidth, unsigned pixheight) { @@ -554,7 +554,7 @@ int sesschan_change_window_size( } static int sesschan_seat_output( - Seat *seat, int is_stderr, const void *data, int len) + Seat *seat, bool is_stderr, const void *data, int len) { sesschan *sess = container_of(seat, sesschan, seat); return sshfwd_write_ext(sess->c, is_stderr, data, len); @@ -573,7 +573,7 @@ static void sesschan_check_close_callback(void *vctx) sshfwd_initiate_close(sess->c, NULL); } -static int sesschan_want_close(Channel *chan, int seen_eof, int rcvd_eof) +static bool sesschan_want_close(Channel *chan, bool seen_eof, bool rcvd_eof) { sesschan *sess = container_of(chan, sesschan, chan); @@ -585,7 +585,7 @@ static int sesschan_want_close(Channel *chan, int seen_eof, int rcvd_eof) return (sess->seen_eof && sess->seen_exit); } -static int sesschan_seat_eof(Seat *seat) +static bool sesschan_seat_eof(Seat *seat) { sesschan *sess = container_of(seat, sesschan, seat); @@ -633,7 +633,7 @@ static void sesschan_connection_fatal(Seat *seat, const char *message) sess->ignoring_input = true; } -static int sesschan_get_window_pixel_size(Seat *seat, int *width, int *height) +static bool sesschan_get_window_pixel_size(Seat *seat, int *width, int *height) { sesschan *sess = container_of(seat, sesschan, seat); @@ -647,7 +647,7 @@ static int sesschan_get_window_pixel_size(Seat *seat, int *width, int *height) * Built-in SFTP subsystem. */ -static int sftp_chan_send(Channel *chan, int is_stderr, +static int sftp_chan_send(Channel *chan, bool is_stderr, const void *data, int length) { sesschan *sess = container_of(chan, sesschan, chan); @@ -695,7 +695,7 @@ static char *sftp_log_close_msg(Channel *chan) * Built-in SCP subsystem. */ -static int scp_chan_send(Channel *chan, int is_stderr, +static int scp_chan_send(Channel *chan, bool is_stderr, const void *data, int length) { sesschan *sess = container_of(chan, sesschan, chan); @@ -713,7 +713,7 @@ static char *scp_log_close_msg(Channel *chan) return dupstr("Session channel (SCP) closed"); } -static void scp_set_input_wanted(Channel *chan, int wanted) +static void scp_set_input_wanted(Channel *chan, bool wanted) { sesschan *sess = container_of(chan, sesschan, chan); scp_throttle(sess->scpsrv, !wanted); diff --git a/settings.c b/settings.c index e1b16918..1e945173 100644 --- a/settings.c +++ b/settings.c @@ -153,8 +153,8 @@ static bool gppb_raw(settings_r *sesskey, const char *name, bool def) return sesskey ? read_setting_i(sesskey, name, def) != 0 : def; } -static void gppb(settings_r *sesskey, const char *name, int def, - Conf *conf, conf_BOOL_NONE primary) +static void gppb(settings_r *sesskey, const char *name, bool def, + Conf *conf, int primary) { conf_set_bool(conf, primary, gppb_raw(sesskey, name, def)); } @@ -178,8 +178,8 @@ static void gppi(settings_r *sesskey, const char *name, int def, * If there's no "=VALUE" (e.g. just NAME,NAME,NAME) then those keys * are mapped to the empty string. */ -static int gppmap(settings_r *sesskey, const char *name, - Conf *conf, int primary) +static bool gppmap(settings_r *sesskey, const char *name, + Conf *conf, int primary) { char *buf, *p, *q, *key, *val; @@ -247,7 +247,7 @@ static int gppmap(settings_r *sesskey, const char *name, * names if include_values is false. */ static void wmap(settings_w *sesskey, char const *outkey, Conf *conf, - int primary, int include_values) + int primary, bool include_values) { char *buf, *p, *key, *realkey; const char *val, *q; @@ -805,10 +805,10 @@ void load_open_settings(settings_r *sesskey, Conf *conf) gppfile(sesskey, "LogFileName", conf, CONF_logfilename); gppi(sesskey, "LogType", 0, conf, CONF_logtype); gppi(sesskey, "LogFileClash", LGXF_ASK, conf, CONF_logxfovr); - gppb(sesskey, "LogFlush", 1, conf, CONF_logflush); - gppb(sesskey, "LogHeader", 1, conf, CONF_logheader); - gppb(sesskey, "SSHLogOmitPasswords", 1, conf, CONF_logomitpass); - gppb(sesskey, "SSHLogOmitData", 0, conf, CONF_logomitdata); + gppb(sesskey, "LogFlush", true, conf, CONF_logflush); + gppb(sesskey, "LogHeader", true, conf, CONF_logheader); + gppb(sesskey, "SSHLogOmitPasswords", true, conf, CONF_logomitpass); + gppb(sesskey, "SSHLogOmitData", false, conf, CONF_logomitdata); prot = gpps_raw(sesskey, "Protocol", "default"); conf_set_int(conf, CONF_protocol, default_protocol); @@ -828,7 +828,7 @@ void load_open_settings(settings_r *sesskey, Conf *conf) /* The CloseOnExit numbers are arranged in a different order from * the standard FORCE_ON / FORCE_OFF / AUTO. */ i = gppi_raw(sesskey, "CloseOnExit", 1); conf_set_int(conf, CONF_close_on_exit, (i+1)%3); - gppb(sesskey, "WarnOnClose", 1, conf, CONF_warn_on_close); + gppb(sesskey, "WarnOnClose", true, conf, CONF_warn_on_close); { /* This is two values for backward compatibility with 0.50/0.51 */ int pingmin, pingsec; @@ -836,8 +836,8 @@ void load_open_settings(settings_r *sesskey, Conf *conf) pingsec = gppi_raw(sesskey, "PingIntervalSecs", 0); conf_set_int(conf, CONF_ping_interval, pingmin * 60 + pingsec); } - gppb(sesskey, "TCPNoDelay", 1, conf, CONF_tcp_nodelay); - gppb(sesskey, "TCPKeepalives", 0, conf, CONF_tcp_keepalives); + gppb(sesskey, "TCPNoDelay", true, conf, CONF_tcp_nodelay); + gppb(sesskey, "TCPKeepalives", false, conf, CONF_tcp_keepalives); gpps(sesskey, "TerminalType", "xterm", conf, CONF_termtype); gpps(sesskey, "TerminalSpeed", "38400,38400", conf, CONF_termspeed); if (gppmap(sesskey, "TerminalModes", conf, CONF_ttymodes)) { @@ -894,7 +894,7 @@ void load_open_settings(settings_r *sesskey, Conf *conf) /* proxy settings */ gpps(sesskey, "ProxyExcludeList", "", conf, CONF_proxy_exclude_list); i = gppi_raw(sesskey, "ProxyDNS", 1); conf_set_int(conf, CONF_proxy_dns, (i+1)%3); - gppb(sesskey, "ProxyLocalhost", 0, conf, CONF_even_proxy_localhost); + gppb(sesskey, "ProxyLocalhost", false, conf, CONF_even_proxy_localhost); gppi(sesskey, "ProxyMethod", -1, conf, CONF_proxy_type); if (conf_get_int(conf, CONF_proxy_type) == -1) { int i; @@ -924,14 +924,15 @@ void load_open_settings(settings_r *sesskey, Conf *conf) gppi(sesskey, "ProxyLogToTerm", FORCE_OFF, conf, CONF_proxy_log_to_term); gppmap(sesskey, "Environment", conf, CONF_environmt); gpps(sesskey, "UserName", "", conf, CONF_username); - gppb(sesskey, "UserNameFromEnvironment", 0, conf, CONF_username_from_env); + gppb(sesskey, "UserNameFromEnvironment", false, + conf, CONF_username_from_env); gpps(sesskey, "LocalUserName", "", conf, CONF_localusername); - gppb(sesskey, "NoPTY", 0, conf, CONF_nopty); - gppb(sesskey, "Compression", 0, conf, CONF_compression); - gppb(sesskey, "TryAgent", 1, conf, CONF_tryagent); - gppb(sesskey, "AgentFwd", 0, conf, CONF_agentfwd); - gppb(sesskey, "ChangeUsername", 0, conf, CONF_change_username); - gppb(sesskey, "GssapiFwd", 0, conf, CONF_gssapifwd); + gppb(sesskey, "NoPTY", false, conf, CONF_nopty); + gppb(sesskey, "Compression", false, conf, CONF_compression); + gppb(sesskey, "TryAgent", true, conf, CONF_tryagent); + gppb(sesskey, "AgentFwd", false, conf, CONF_agentfwd); + gppb(sesskey, "ChangeUsername", false, conf, CONF_change_username); + gppb(sesskey, "GssapiFwd", false, conf, CONF_gssapifwd); gprefs(sesskey, "Cipher", "\0", ciphernames, CIPHER_MAX, conf, CONF_ssh_cipherlist); { @@ -996,33 +997,34 @@ void load_open_settings(settings_r *sesskey, Conf *conf) conf_set_int(conf, CONF_sshprot, sshprot); } gpps(sesskey, "LogHost", "", conf, CONF_loghost); - gppb(sesskey, "SSH2DES", 0, conf, CONF_ssh2_des_cbc); - gppb(sesskey, "SshNoAuth", 0, conf, CONF_ssh_no_userauth); - gppb(sesskey, "SshBanner", 1, conf, CONF_ssh_show_banner); - gppb(sesskey, "AuthTIS", 0, conf, CONF_try_tis_auth); - gppb(sesskey, "AuthKI", 1, conf, CONF_try_ki_auth); - gppb(sesskey, "AuthGSSAPI", 1, conf, CONF_try_gssapi_auth); - gppb(sesskey, "AuthGSSAPIKEX", 1, conf, CONF_try_gssapi_kex); + gppb(sesskey, "SSH2DES", false, conf, CONF_ssh2_des_cbc); + gppb(sesskey, "SshNoAuth", false, conf, CONF_ssh_no_userauth); + gppb(sesskey, "SshBanner", true, conf, CONF_ssh_show_banner); + gppb(sesskey, "AuthTIS", false, conf, CONF_try_tis_auth); + gppb(sesskey, "AuthKI", true, conf, CONF_try_ki_auth); + gppb(sesskey, "AuthGSSAPI", true, conf, CONF_try_gssapi_auth); + gppb(sesskey, "AuthGSSAPIKEX", true, conf, CONF_try_gssapi_kex); #ifndef NO_GSSAPI gprefs(sesskey, "GSSLibs", "\0", gsslibkeywords, ngsslibs, conf, CONF_ssh_gsslist); gppfile(sesskey, "GSSCustom", conf, CONF_ssh_gss_custom); #endif - gppb(sesskey, "SshNoShell", 0, conf, CONF_ssh_no_shell); + gppb(sesskey, "SshNoShell", false, conf, CONF_ssh_no_shell); gppfile(sesskey, "PublicKeyFile", conf, CONF_keyfile); gpps(sesskey, "RemoteCommand", "", conf, CONF_remote_cmd); - gppb(sesskey, "RFCEnviron", 0, conf, CONF_rfc_environ); - gppb(sesskey, "PassiveTelnet", 0, conf, CONF_passive_telnet); - gppb(sesskey, "BackspaceIsDelete", 1, conf, CONF_bksp_is_delete); - gppb(sesskey, "RXVTHomeEnd", 0, conf, CONF_rxvt_homeend); + gppb(sesskey, "RFCEnviron", false, conf, CONF_rfc_environ); + gppb(sesskey, "PassiveTelnet", false, conf, CONF_passive_telnet); + gppb(sesskey, "BackspaceIsDelete", true, conf, CONF_bksp_is_delete); + gppb(sesskey, "RXVTHomeEnd", false, conf, CONF_rxvt_homeend); gppi(sesskey, "LinuxFunctionKeys", 0, conf, CONF_funky_type); - gppb(sesskey, "NoApplicationKeys", 0, conf, CONF_no_applic_k); - gppb(sesskey, "NoApplicationCursors", 0, conf, CONF_no_applic_c); - gppb(sesskey, "NoMouseReporting", 0, conf, CONF_no_mouse_rep); - gppb(sesskey, "NoRemoteResize", 0, conf, CONF_no_remote_resize); - gppb(sesskey, "NoAltScreen", 0, conf, CONF_no_alt_screen); - gppb(sesskey, "NoRemoteWinTitle", 0, conf, CONF_no_remote_wintitle); - gppb(sesskey, "NoRemoteClearScroll", 0, conf, CONF_no_remote_clearscroll); + gppb(sesskey, "NoApplicationKeys", false, conf, CONF_no_applic_k); + gppb(sesskey, "NoApplicationCursors", false, conf, CONF_no_applic_c); + gppb(sesskey, "NoMouseReporting", false, conf, CONF_no_mouse_rep); + gppb(sesskey, "NoRemoteResize", false, conf, CONF_no_remote_resize); + gppb(sesskey, "NoAltScreen", false, conf, CONF_no_alt_screen); + gppb(sesskey, "NoRemoteWinTitle", false, conf, CONF_no_remote_wintitle); + gppb(sesskey, "NoRemoteClearScroll", false, + conf, CONF_no_remote_clearscroll); { /* Backward compatibility */ int no_remote_qtitle = gppi_raw(sesskey, "NoRemoteQTitle", 1); @@ -1033,37 +1035,38 @@ void load_open_settings(settings_r *sesskey, Conf *conf) no_remote_qtitle ? TITLE_EMPTY : TITLE_REAL, conf, CONF_remote_qtitle_action); } - gppb(sesskey, "NoDBackspace", 0, conf, CONF_no_dbackspace); - gppb(sesskey, "NoRemoteCharset", 0, conf, CONF_no_remote_charset); - gppb(sesskey, "ApplicationCursorKeys", 0, conf, CONF_app_cursor); - gppb(sesskey, "ApplicationKeypad", 0, conf, CONF_app_keypad); - gppb(sesskey, "NetHackKeypad", 0, conf, CONF_nethack_keypad); - gppb(sesskey, "AltF4", 1, conf, CONF_alt_f4); - gppb(sesskey, "AltSpace", 0, conf, CONF_alt_space); - gppb(sesskey, "AltOnly", 0, conf, CONF_alt_only); - gppb(sesskey, "ComposeKey", 0, conf, CONF_compose_key); - gppb(sesskey, "CtrlAltKeys", 1, conf, CONF_ctrlaltkeys); + gppb(sesskey, "NoDBackspace", false, conf, CONF_no_dbackspace); + gppb(sesskey, "NoRemoteCharset", false, conf, CONF_no_remote_charset); + gppb(sesskey, "ApplicationCursorKeys", false, conf, CONF_app_cursor); + gppb(sesskey, "ApplicationKeypad", false, conf, CONF_app_keypad); + gppb(sesskey, "NetHackKeypad", false, conf, CONF_nethack_keypad); + gppb(sesskey, "AltF4", true, conf, CONF_alt_f4); + gppb(sesskey, "AltSpace", false, conf, CONF_alt_space); + gppb(sesskey, "AltOnly", false, conf, CONF_alt_only); + gppb(sesskey, "ComposeKey", false, conf, CONF_compose_key); + gppb(sesskey, "CtrlAltKeys", true, conf, CONF_ctrlaltkeys); #ifdef OSX_META_KEY_CONFIG - gppb(sesskey, "OSXOptionMeta", 1, conf, CONF_osx_option_meta); - gppb(sesskey, "OSXCommandMeta", 0, conf, CONF_osx_command_meta); + gppb(sesskey, "OSXOptionMeta", true, conf, CONF_osx_option_meta); + gppb(sesskey, "OSXCommandMeta", false, conf, CONF_osx_command_meta); #endif - gppb(sesskey, "TelnetKey", 0, conf, CONF_telnet_keyboard); - gppb(sesskey, "TelnetRet", 1, conf, CONF_telnet_newline); + gppb(sesskey, "TelnetKey", false, conf, CONF_telnet_keyboard); + gppb(sesskey, "TelnetRet", true, conf, CONF_telnet_newline); gppi(sesskey, "LocalEcho", AUTO, conf, CONF_localecho); gppi(sesskey, "LocalEdit", AUTO, conf, CONF_localedit); gpps(sesskey, "Answerback", "PuTTY", conf, CONF_answerback); - gppb(sesskey, "AlwaysOnTop", 0, conf, CONF_alwaysontop); - gppb(sesskey, "FullScreenOnAltEnter", 0, conf, CONF_fullscreenonaltenter); - gppb(sesskey, "HideMousePtr", 0, conf, CONF_hide_mouseptr); - gppb(sesskey, "SunkenEdge", 0, conf, CONF_sunken_edge); + gppb(sesskey, "AlwaysOnTop", false, conf, CONF_alwaysontop); + gppb(sesskey, "FullScreenOnAltEnter", false, + conf, CONF_fullscreenonaltenter); + gppb(sesskey, "HideMousePtr", false, conf, CONF_hide_mouseptr); + gppb(sesskey, "SunkenEdge", false, conf, CONF_sunken_edge); gppi(sesskey, "WindowBorder", 1, conf, CONF_window_border); gppi(sesskey, "CurType", 0, conf, CONF_cursor_type); - gppb(sesskey, "BlinkCur", 0, conf, CONF_blink_cur); + gppb(sesskey, "BlinkCur", false, conf, CONF_blink_cur); /* pedantic compiler tells me I can't use conf, CONF_beep as an int * :-) */ gppi(sesskey, "Beep", 1, conf, CONF_beep); gppi(sesskey, "BeepInd", 0, conf, CONF_beep_ind); gppfile(sesskey, "BellWaveFile", conf, CONF_bell_wavefile); - gppb(sesskey, "BellOverload", 1, conf, CONF_bellovl); + gppb(sesskey, "BellOverload", true, conf, CONF_bellovl); gppi(sesskey, "BellOverloadN", 5, conf, CONF_bellovl_n); i = gppi_raw(sesskey, "BellOverloadT", 2*TICKSPERSEC #ifdef PUTTY_UNIX_H @@ -1086,24 +1089,24 @@ void load_open_settings(settings_r *sesskey, Conf *conf) #endif ); gppi(sesskey, "ScrollbackLines", 2000, conf, CONF_savelines); - gppb(sesskey, "DECOriginMode", 0, conf, CONF_dec_om); - gppb(sesskey, "AutoWrapMode", 1, conf, CONF_wrap_mode); - gppb(sesskey, "LFImpliesCR", 0, conf, CONF_lfhascr); - gppb(sesskey, "CRImpliesLF", 0, conf, CONF_crhaslf); - gppb(sesskey, "DisableArabicShaping", 0, conf, CONF_arabicshaping); - gppb(sesskey, "DisableBidi", 0, conf, CONF_bidi); - gppb(sesskey, "WinNameAlways", 1, conf, CONF_win_name_always); + gppb(sesskey, "DECOriginMode", false, conf, CONF_dec_om); + gppb(sesskey, "AutoWrapMode", true, conf, CONF_wrap_mode); + gppb(sesskey, "LFImpliesCR", false, conf, CONF_lfhascr); + gppb(sesskey, "CRImpliesLF", false, conf, CONF_crhaslf); + gppb(sesskey, "DisableArabicShaping", false, conf, CONF_arabicshaping); + gppb(sesskey, "DisableBidi", false, conf, CONF_bidi); + gppb(sesskey, "WinNameAlways", true, conf, CONF_win_name_always); gpps(sesskey, "WinTitle", "", conf, CONF_wintitle); gppi(sesskey, "TermWidth", 80, conf, CONF_width); gppi(sesskey, "TermHeight", 24, conf, CONF_height); gppfont(sesskey, "Font", conf, CONF_font); gppi(sesskey, "FontQuality", FQ_DEFAULT, conf, CONF_font_quality); gppi(sesskey, "FontVTMode", VT_UNICODE, conf, CONF_vtmode); - gppb(sesskey, "UseSystemColours", 0, conf, CONF_system_colour); - gppb(sesskey, "TryPalette", 0, conf, CONF_try_palette); - gppb(sesskey, "ANSIColour", 1, conf, CONF_ansi_colour); - gppb(sesskey, "Xterm256Colour", 1, conf, CONF_xterm_256_colour); - gppb(sesskey, "TrueColour", 1, conf, CONF_true_colour); + gppb(sesskey, "UseSystemColours", false, conf, CONF_system_colour); + gppb(sesskey, "TryPalette", false, conf, CONF_try_palette); + gppb(sesskey, "ANSIColour", true, conf, CONF_ansi_colour); + gppb(sesskey, "Xterm256Colour", true, conf, CONF_xterm_256_colour); + gppb(sesskey, "TrueColour", true, conf, CONF_true_colour); i = gppi_raw(sesskey, "BoldAsColour", 1); conf_set_int(conf, CONF_bold_style, i+1); for (i = 0; i < 22; i++) { @@ -1125,13 +1128,13 @@ void load_open_settings(settings_r *sesskey, Conf *conf) } sfree(buf2); } - gppb(sesskey, "RawCNP", 0, conf, CONF_rawcnp); - gppb(sesskey, "UTF8linedraw", 0, conf, CONF_utf8linedraw); - gppb(sesskey, "PasteRTF", 0, conf, CONF_rtf_paste); + gppb(sesskey, "RawCNP", false, conf, CONF_rawcnp); + gppb(sesskey, "UTF8linedraw", false, conf, CONF_utf8linedraw); + gppb(sesskey, "PasteRTF", false, conf, CONF_rtf_paste); gppi(sesskey, "MouseIsXterm", 0, conf, CONF_mouse_is_xterm); - gppb(sesskey, "RectSelect", 0, conf, CONF_rect_select); - gppb(sesskey, "PasteControls", 0, conf, CONF_paste_controls); - gppb(sesskey, "MouseOverride", 1, conf, CONF_mouse_override); + gppb(sesskey, "RectSelect", false, conf, CONF_rect_select); + gppb(sesskey, "PasteControls", false, conf, CONF_paste_controls); + gppb(sesskey, "MouseOverride", true, conf, CONF_mouse_override); for (i = 0; i < 256; i += 32) { static const char *const defaults[] = { "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0", @@ -1171,25 +1174,26 @@ void load_open_settings(settings_r *sesskey, Conf *conf) * into a plausible default for the locale. */ gpps(sesskey, "LineCodePage", "", conf, CONF_line_codepage); - gppb(sesskey, "CJKAmbigWide", 0, conf, CONF_cjk_ambig_wide); - gppb(sesskey, "UTF8Override", 1, conf, CONF_utf8_override); + gppb(sesskey, "CJKAmbigWide", false, conf, CONF_cjk_ambig_wide); + gppb(sesskey, "UTF8Override", true, conf, CONF_utf8_override); gpps(sesskey, "Printer", "", conf, CONF_printer); - gppb(sesskey, "CapsLockCyr", 0, conf, CONF_xlat_capslockcyr); - gppb(sesskey, "ScrollBar", 1, conf, CONF_scrollbar); - gppb(sesskey, "ScrollBarFullScreen", 0, conf, CONF_scrollbar_in_fullscreen); - gppb(sesskey, "ScrollOnKey", 0, conf, CONF_scroll_on_key); - gppb(sesskey, "ScrollOnDisp", 1, conf, CONF_scroll_on_disp); - gppb(sesskey, "EraseToScrollback", 1, conf, CONF_erase_to_scrollback); + gppb(sesskey, "CapsLockCyr", false, conf, CONF_xlat_capslockcyr); + gppb(sesskey, "ScrollBar", true, conf, CONF_scrollbar); + gppb(sesskey, "ScrollBarFullScreen", false, + conf, CONF_scrollbar_in_fullscreen); + gppb(sesskey, "ScrollOnKey", false, conf, CONF_scroll_on_key); + gppb(sesskey, "ScrollOnDisp", true, conf, CONF_scroll_on_disp); + gppb(sesskey, "EraseToScrollback", true, conf, CONF_erase_to_scrollback); gppi(sesskey, "LockSize", 0, conf, CONF_resize_action); - gppb(sesskey, "BCE", 1, conf, CONF_bce); - gppb(sesskey, "BlinkText", 0, conf, CONF_blinktext); - gppb(sesskey, "X11Forward", 0, conf, CONF_x11_forward); + gppb(sesskey, "BCE", true, conf, CONF_bce); + gppb(sesskey, "BlinkText", false, conf, CONF_blinktext); + gppb(sesskey, "X11Forward", false, conf, CONF_x11_forward); gpps(sesskey, "X11Display", "", conf, CONF_x11_display); gppi(sesskey, "X11AuthType", X11_MIT, conf, CONF_x11_auth); gppfile(sesskey, "X11AuthFile", conf, CONF_xauthfile); - gppb(sesskey, "LocalPortAcceptAll", 0, conf, CONF_lport_acceptall); - gppb(sesskey, "RemotePortAcceptAll", 0, conf, CONF_rport_acceptall); + gppb(sesskey, "LocalPortAcceptAll", false, conf, CONF_lport_acceptall); + gppb(sesskey, "RemotePortAcceptAll", false, conf, CONF_rport_acceptall); gppmap(sesskey, "PortForwardings", conf, CONF_portfwd); i = gppi_raw(sesskey, "BugIgnore1", 0); conf_set_int(conf, CONF_sshbug_ignore1, 2-i); i = gppi_raw(sesskey, "BugPlainPW1", 0); conf_set_int(conf, CONF_sshbug_plainpw1, 2-i); @@ -1213,10 +1217,10 @@ void load_open_settings(settings_r *sesskey, Conf *conf) i = gppi_raw(sesskey, "BugWinadj", 0); conf_set_int(conf, CONF_sshbug_winadj, 2-i); i = gppi_raw(sesskey, "BugChanReq", 0); conf_set_int(conf, CONF_sshbug_chanreq, 2-i); conf_set_bool(conf, CONF_ssh_simple, false); - gppb(sesskey, "StampUtmp", 1, conf, CONF_stamp_utmp); - gppb(sesskey, "LoginShell", 1, conf, CONF_login_shell); - gppb(sesskey, "ScrollbarOnLeft", 0, conf, CONF_scrollbar_on_left); - gppb(sesskey, "ShadowBold", 0, conf, CONF_shadowbold); + gppb(sesskey, "StampUtmp", true, conf, CONF_stamp_utmp); + gppb(sesskey, "LoginShell", true, conf, CONF_login_shell); + gppb(sesskey, "ScrollbarOnLeft", false, conf, CONF_scrollbar_on_left); + gppb(sesskey, "ShadowBold", false, conf, CONF_shadowbold); gppfont(sesskey, "BoldFont", conf, CONF_boldfont); gppfont(sesskey, "WideFont", conf, CONF_widefont); gppfont(sesskey, "WideBoldFont", conf, CONF_wideboldfont); @@ -1228,9 +1232,12 @@ void load_open_settings(settings_r *sesskey, Conf *conf) gppi(sesskey, "SerialParity", SER_PAR_NONE, conf, CONF_serparity); gppi(sesskey, "SerialFlowControl", SER_FLOW_XONXOFF, conf, CONF_serflow); gpps(sesskey, "WindowClass", "", conf, CONF_winclass); - gppb(sesskey, "ConnectionSharing", 0, conf, CONF_ssh_connection_sharing); - gppb(sesskey, "ConnectionSharingUpstream", 1, conf, CONF_ssh_connection_sharing_upstream); - gppb(sesskey, "ConnectionSharingDownstream", 1, conf, CONF_ssh_connection_sharing_downstream); + gppb(sesskey, "ConnectionSharing", false, + conf, CONF_ssh_connection_sharing); + gppb(sesskey, "ConnectionSharingUpstream", true, + conf, CONF_ssh_connection_sharing_upstream); + gppb(sesskey, "ConnectionSharingDownstream", true, + conf, CONF_ssh_connection_sharing_downstream); gppmap(sesskey, "SSHManualHostKeys", conf, CONF_ssh_manual_hostkeys); } @@ -1259,7 +1266,7 @@ static int sessioncmp(const void *av, const void *bv) return strcmp(a, b); /* otherwise, compare normally */ } -void get_sesslist(struct sesslist *list, int allocate) +void get_sesslist(struct sesslist *list, bool allocate) { char otherbuf[2048]; int buflen, bufsize, i; diff --git a/sftp.c b/sftp.c index c6ef9fde..de02a1ad 100644 --- a/sftp.c +++ b/sftp.c @@ -21,9 +21,9 @@ static void fxp_internal_error(const char *msg); * Client-specific parts of the send- and receive-packet system. */ -int sftp_send(struct sftp_packet *pkt) +bool sftp_send(struct sftp_packet *pkt) { - int ret; + bool ret; sftp_send_prepare(pkt); ret = sftp_senddata(pkt->data, pkt->length); sftp_pkt_free(pkt); @@ -61,7 +61,7 @@ struct sftp_packet *sftp_recv(void) struct sftp_request { unsigned id; - int registered; + bool registered; void *userdata; }; @@ -132,7 +132,7 @@ static struct sftp_request *sftp_alloc_request(void) */ r = snew(struct sftp_request); r->id = low + 1 + REQUEST_ID_OFFSET; - r->registered = 0; + r->registered = false; r->userdata = NULL; add234(sftp_requests, r); return r; @@ -148,7 +148,7 @@ void sftp_cleanup_request(void) void sftp_register(struct sftp_request *req) { - req->registered = 1; + req->registered = true; } struct sftp_request *sftp_find_request(struct sftp_packet *pktin) @@ -248,7 +248,7 @@ int fxp_error_type(void) /* * Perform exchange of init/version packets. Return 0 on failure. */ -int fxp_init(void) +bool fxp_init(void) { struct sftp_packet *pktout, *pktin; unsigned long remotever; @@ -260,24 +260,24 @@ int fxp_init(void) pktin = sftp_recv(); if (!pktin) { fxp_internal_error("could not connect"); - return 0; + return false; } if (pktin->type != SSH_FXP_VERSION) { fxp_internal_error("did not receive FXP_VERSION"); sftp_pkt_free(pktin); - return 0; + return false; } remotever = get_uint32(pktin); if (get_err(pktin)) { fxp_internal_error("malformed FXP_VERSION packet"); sftp_pkt_free(pktin); - return 0; + return false; } if (remotever > SFTP_PROTO_VERSION) { fxp_internal_error ("remote protocol is more advanced than we support"); sftp_pkt_free(pktin); - return 0; + return false; } /* * In principle, this packet might also contain extension- @@ -287,7 +287,7 @@ int fxp_init(void) */ sftp_pkt_free(pktin); - return 1; + return true; } /* @@ -436,7 +436,7 @@ struct sftp_request *fxp_close_send(struct fxp_handle *handle) return req; } -int fxp_close_recv(struct sftp_packet *pktin, struct sftp_request *req) +bool fxp_close_recv(struct sftp_packet *pktin, struct sftp_request *req) { sfree(req); fxp_got_status(pktin); @@ -459,16 +459,13 @@ struct sftp_request *fxp_mkdir_send(const char *path, return req; } -int fxp_mkdir_recv(struct sftp_packet *pktin, struct sftp_request *req) +bool fxp_mkdir_recv(struct sftp_packet *pktin, struct sftp_request *req) { int id; sfree(req); id = fxp_got_status(pktin); sftp_pkt_free(pktin); - if (id != 1) { - return 0; - } - return 1; + return id == 1; } struct sftp_request *fxp_rmdir_send(const char *path) @@ -484,16 +481,13 @@ struct sftp_request *fxp_rmdir_send(const char *path) return req; } -int fxp_rmdir_recv(struct sftp_packet *pktin, struct sftp_request *req) +bool fxp_rmdir_recv(struct sftp_packet *pktin, struct sftp_request *req) { int id; sfree(req); id = fxp_got_status(pktin); sftp_pkt_free(pktin); - if (id != 1) { - return 0; - } - return 1; + return id == 1; } struct sftp_request *fxp_remove_send(const char *fname) @@ -509,16 +503,13 @@ struct sftp_request *fxp_remove_send(const char *fname) return req; } -int fxp_remove_recv(struct sftp_packet *pktin, struct sftp_request *req) +bool fxp_remove_recv(struct sftp_packet *pktin, struct sftp_request *req) { int id; sfree(req); id = fxp_got_status(pktin); sftp_pkt_free(pktin); - if (id != 1) { - return 0; - } - return 1; + return id == 1; } struct sftp_request *fxp_rename_send(const char *srcfname, @@ -536,16 +527,13 @@ struct sftp_request *fxp_rename_send(const char *srcfname, return req; } -int fxp_rename_recv(struct sftp_packet *pktin, struct sftp_request *req) +bool fxp_rename_recv(struct sftp_packet *pktin, struct sftp_request *req) { int id; sfree(req); id = fxp_got_status(pktin); sftp_pkt_free(pktin); - if (id != 1) { - return 0; - } - return 1; + return id == 1; } /* @@ -565,19 +553,19 @@ struct sftp_request *fxp_stat_send(const char *fname) return req; } -static int fxp_got_attrs(struct sftp_packet *pktin, struct fxp_attrs *attrs) +static bool fxp_got_attrs(struct sftp_packet *pktin, struct fxp_attrs *attrs) { get_fxp_attrs(pktin, attrs); if (get_err(pktin)) { fxp_internal_error("malformed SSH_FXP_ATTRS packet"); sftp_pkt_free(pktin); - return 0; + return false; } sftp_pkt_free(pktin); - return 1; + return true; } -int fxp_stat_recv(struct sftp_packet *pktin, struct sftp_request *req, +bool fxp_stat_recv(struct sftp_packet *pktin, struct sftp_request *req, struct fxp_attrs *attrs) { sfree(req); @@ -586,7 +574,7 @@ int fxp_stat_recv(struct sftp_packet *pktin, struct sftp_request *req, } else { fxp_got_status(pktin); sftp_pkt_free(pktin); - return 0; + return false; } } @@ -603,18 +591,18 @@ struct sftp_request *fxp_fstat_send(struct fxp_handle *handle) return req; } -int fxp_fstat_recv(struct sftp_packet *pktin, struct sftp_request *req, - struct fxp_attrs *attrs) +bool fxp_fstat_recv(struct sftp_packet *pktin, struct sftp_request *req, + struct fxp_attrs *attrs) { sfree(req); if (pktin->type == SSH_FXP_ATTRS) { return fxp_got_attrs(pktin, attrs); sftp_pkt_free(pktin); - return 1; + return true; } else { fxp_got_status(pktin); sftp_pkt_free(pktin); - return 0; + return false; } } @@ -636,16 +624,13 @@ struct sftp_request *fxp_setstat_send(const char *fname, return req; } -int fxp_setstat_recv(struct sftp_packet *pktin, struct sftp_request *req) +bool fxp_setstat_recv(struct sftp_packet *pktin, struct sftp_request *req) { int id; sfree(req); id = fxp_got_status(pktin); sftp_pkt_free(pktin); - if (id != 1) { - return 0; - } - return 1; + return id == 1; } struct sftp_request *fxp_fsetstat_send(struct fxp_handle *handle, @@ -663,16 +648,13 @@ struct sftp_request *fxp_fsetstat_send(struct fxp_handle *handle, return req; } -int fxp_fsetstat_recv(struct sftp_packet *pktin, struct sftp_request *req) +bool fxp_fsetstat_recv(struct sftp_packet *pktin, struct sftp_request *req) { int id; sfree(req); id = fxp_got_status(pktin); sftp_pkt_free(pktin); - if (id != 1) { - return 0; - } - return 1; + return id == 1; } /* @@ -826,7 +808,7 @@ struct sftp_request *fxp_write_send(struct fxp_handle *handle, return req; } -int fxp_write_recv(struct sftp_packet *pktin, struct sftp_request *req) +bool fxp_write_recv(struct sftp_packet *pktin, struct sftp_request *req) { sfree(req); fxp_got_status(pktin); @@ -899,7 +881,8 @@ struct req { struct fxp_xfer { uint64_t offset, furthestdata, filesize; - int req_totalsize, req_maxsize, eof, err; + int req_totalsize, req_maxsize; + bool eof, err; struct fxp_handle *fh; struct req *head, *tail; }; @@ -913,14 +896,14 @@ static struct fxp_xfer *xfer_init(struct fxp_handle *fh, uint64_t offset) xfer->head = xfer->tail = NULL; xfer->req_totalsize = 0; xfer->req_maxsize = 1048576; - xfer->err = 0; + xfer->err = false; xfer->filesize = UINT64_MAX; xfer->furthestdata = 0; return xfer; } -int xfer_done(struct fxp_xfer *xfer) +bool xfer_done(struct fxp_xfer *xfer) { /* * We're finished if we've seen EOF _and_ there are no @@ -1059,10 +1042,10 @@ int xfer_download_gotpkt(struct fxp_xfer *xfer, struct sftp_packet *pktin) void xfer_set_error(struct fxp_xfer *xfer) { - xfer->err = 1; + xfer->err = true; } -int xfer_download_data(struct fxp_xfer *xfer, void **buf, int *len) +bool xfer_download_data(struct fxp_xfer *xfer, void **buf, int *len) { void *retbuf = NULL; int retlen = 0; @@ -1098,9 +1081,9 @@ int xfer_download_data(struct fxp_xfer *xfer, void **buf, int *len) if (retbuf) { *buf = retbuf; *len = retlen; - return 1; + return true; } else - return 0; + return false; } struct fxp_xfer *xfer_upload_init(struct fxp_handle *fh, uint64_t offset) @@ -1115,17 +1098,14 @@ struct fxp_xfer *xfer_upload_init(struct fxp_handle *fh, uint64_t offset) * from us is whether the outstanding requests have been * handled once that's done. */ - xfer->eof = 1; + xfer->eof = true; return xfer; } -int xfer_upload_ready(struct fxp_xfer *xfer) +bool xfer_upload_ready(struct fxp_xfer *xfer) { - if (sftp_sendbuffer() == 0) - return 1; - else - return 0; + return sftp_sendbuffer() == 0; } void xfer_upload_data(struct fxp_xfer *xfer, char *buffer, int len) @@ -1168,7 +1148,7 @@ int xfer_upload_gotpkt(struct fxp_xfer *xfer, struct sftp_packet *pktin) { struct sftp_request *rreq; struct req *rr, *prev, *next; - int ret; + bool ret; rreq = sftp_find_request(pktin); if (!rreq) @@ -1180,7 +1160,7 @@ int xfer_upload_gotpkt(struct fxp_xfer *xfer, struct sftp_packet *pktin) } ret = fxp_write_recv(pktin, rreq); #ifdef DEBUG_UPLOAD - printf("write request %p has returned [%d]\n", rr, ret); + printf("write request %p has returned [%d]\n", rr, ret ? 1 : 0); #endif /* diff --git a/sftp.h b/sftp.h index 1fbb6fa9..95d70ff7 100644 --- a/sftp.h +++ b/sftp.h @@ -62,16 +62,17 @@ * able to get at these functions. * * sftp_recvdata must never return less than len. It either blocks - * until len is available, or it returns failure. + * until len is available and then returns true, or it returns false + * for failure. * - * Both functions return 1 on success, 0 on failure. + * sftp_senddata returns true on success, false on failure. * * sftp_sendbuffer returns the size of the backlog of data in the * transmit queue. */ -int sftp_senddata(char *data, int len); +bool sftp_senddata(char *data, int len); int sftp_sendbuffer(void); -int sftp_recvdata(char *data, int len); +bool sftp_recvdata(char *data, int len); /* * Free sftp_requests @@ -144,13 +145,13 @@ void sftp_send_prepare(struct sftp_packet *pkt); * that many bytes into pkt->data, and call sftp_recv_finish to set up * the type code and BinarySource. */ struct sftp_packet *sftp_recv_prepare(unsigned length); -int sftp_recv_finish(struct sftp_packet *pkt); +bool sftp_recv_finish(struct sftp_packet *pkt); /* Either kind of packet can be freed afterwards with sftp_pkt_free. */ void sftp_pkt_free(struct sftp_packet *pkt); void BinarySink_put_fxp_attrs(BinarySink *bs, struct fxp_attrs attrs); -int BinarySource_get_fxp_attrs(BinarySource *src, struct fxp_attrs *attrs); +bool BinarySource_get_fxp_attrs(BinarySource *src, struct fxp_attrs *attrs); #define put_fxp_attrs(bs, attrs) \ BinarySink_put_fxp_attrs(BinarySink_UPCAST(bs), attrs) #define get_fxp_attrs(bs, attrs) \ @@ -164,9 +165,9 @@ const char *fxp_error(void); int fxp_error_type(void); /* - * Perform exchange of init/version packets. Return 0 on failure. + * Perform exchange of init/version packets. Return false on failure. */ -int fxp_init(void); +bool fxp_init(void); /* * Canonify a pathname. Concatenate the two given path elements @@ -192,56 +193,56 @@ struct fxp_handle *fxp_opendir_recv(struct sftp_packet *pktin, struct sftp_request *req); /* - * Close a file/dir. Returns 1 on success, 0 on error. + * Close a file/dir. Returns true on success, false on error. */ struct sftp_request *fxp_close_send(struct fxp_handle *handle); -int fxp_close_recv(struct sftp_packet *pktin, struct sftp_request *req); +bool fxp_close_recv(struct sftp_packet *pktin, struct sftp_request *req); /* * Make a directory. */ struct sftp_request *fxp_mkdir_send(const char *path, const struct fxp_attrs *attrs); -int fxp_mkdir_recv(struct sftp_packet *pktin, struct sftp_request *req); +bool fxp_mkdir_recv(struct sftp_packet *pktin, struct sftp_request *req); /* * Remove a directory. */ struct sftp_request *fxp_rmdir_send(const char *path); -int fxp_rmdir_recv(struct sftp_packet *pktin, struct sftp_request *req); +bool fxp_rmdir_recv(struct sftp_packet *pktin, struct sftp_request *req); /* * Remove a file. */ struct sftp_request *fxp_remove_send(const char *fname); -int fxp_remove_recv(struct sftp_packet *pktin, struct sftp_request *req); +bool fxp_remove_recv(struct sftp_packet *pktin, struct sftp_request *req); /* * Rename a file. */ struct sftp_request *fxp_rename_send(const char *srcfname, const char *dstfname); -int fxp_rename_recv(struct sftp_packet *pktin, struct sftp_request *req); +bool fxp_rename_recv(struct sftp_packet *pktin, struct sftp_request *req); /* * Return file attributes. */ struct sftp_request *fxp_stat_send(const char *fname); -int fxp_stat_recv(struct sftp_packet *pktin, struct sftp_request *req, - struct fxp_attrs *attrs); +bool fxp_stat_recv(struct sftp_packet *pktin, struct sftp_request *req, + struct fxp_attrs *attrs); struct sftp_request *fxp_fstat_send(struct fxp_handle *handle); -int fxp_fstat_recv(struct sftp_packet *pktin, struct sftp_request *req, - struct fxp_attrs *attrs); +bool fxp_fstat_recv(struct sftp_packet *pktin, struct sftp_request *req, + struct fxp_attrs *attrs); /* * Set file attributes. */ struct sftp_request *fxp_setstat_send(const char *fname, struct fxp_attrs attrs); -int fxp_setstat_recv(struct sftp_packet *pktin, struct sftp_request *req); +bool fxp_setstat_recv(struct sftp_packet *pktin, struct sftp_request *req); struct sftp_request *fxp_fsetstat_send(struct fxp_handle *handle, struct fxp_attrs attrs); -int fxp_fsetstat_recv(struct sftp_packet *pktin, struct sftp_request *req); +bool fxp_fsetstat_recv(struct sftp_packet *pktin, struct sftp_request *req); /* * Read from a file. @@ -249,14 +250,14 @@ int fxp_fsetstat_recv(struct sftp_packet *pktin, struct sftp_request *req); struct sftp_request *fxp_read_send(struct fxp_handle *handle, uint64_t offset, int len); int fxp_read_recv(struct sftp_packet *pktin, struct sftp_request *req, - char *buffer, int len); + char *buffer, int len); /* - * Write to a file. Returns 0 on error, 1 on OK. + * Write to a file. */ struct sftp_request *fxp_write_send(struct fxp_handle *handle, void *buffer, uint64_t offset, int len); -int fxp_write_recv(struct sftp_packet *pktin, struct sftp_request *req); +bool fxp_write_recv(struct sftp_packet *pktin, struct sftp_request *req); /* * Read from a directory. @@ -301,14 +302,14 @@ struct fxp_xfer; struct fxp_xfer *xfer_download_init(struct fxp_handle *fh, uint64_t offset); void xfer_download_queue(struct fxp_xfer *xfer); int xfer_download_gotpkt(struct fxp_xfer *xfer, struct sftp_packet *pktin); -int xfer_download_data(struct fxp_xfer *xfer, void **buf, int *len); +bool xfer_download_data(struct fxp_xfer *xfer, void **buf, int *len); struct fxp_xfer *xfer_upload_init(struct fxp_handle *fh, uint64_t offset); -int xfer_upload_ready(struct fxp_xfer *xfer); +bool xfer_upload_ready(struct fxp_xfer *xfer); void xfer_upload_data(struct fxp_xfer *xfer, char *buffer, int len); int xfer_upload_gotpkt(struct fxp_xfer *xfer, struct sftp_packet *pktin); -int xfer_done(struct fxp_xfer *xfer); +bool xfer_done(struct fxp_xfer *xfer); void xfer_set_error(struct fxp_xfer *xfer); void xfer_cleanup(struct fxp_xfer *xfer); @@ -362,7 +363,7 @@ struct SftpServerVtable { /* Should call fxp_reply_error or fxp_reply_attrs */ void (*stat)(SftpServer *srv, SftpReplyBuilder *reply, ptrlen path, - int follow_symlinks); + bool follow_symlinks); /* Should call fxp_reply_error or fxp_reply_attrs */ void (*fstat)(SftpServer *srv, SftpReplyBuilder *reply, ptrlen handle); @@ -386,7 +387,7 @@ struct SftpServerVtable { /* Should call fxp_reply_error, or fxp_reply_name_count once and * then fxp_reply_full_name that many times */ void (*readdir)(SftpServer *srv, SftpReplyBuilder *reply, ptrlen handle, - int max_entries, int omit_longname); + int max_entries, bool omit_longname); }; #define sftpsrv_new(vt) \ @@ -494,7 +495,7 @@ struct ScpServerVtable { void (*free)(ScpServer *s); int (*send)(ScpServer *s, const void *data, size_t length); - void (*throttle)(ScpServer *s, int throttled); + void (*throttle)(ScpServer *s, bool throttled); void (*eof)(ScpServer *s); }; diff --git a/sftpcommon.c b/sftpcommon.c index 5becf3ce..57e737fc 100644 --- a/sftpcommon.c +++ b/sftpcommon.c @@ -73,7 +73,7 @@ const struct fxp_attrs no_attrs = { 0 }; #define put_fxp_attrs(bs, attrs) \ BinarySink_put_fxp_attrs(BinarySink_UPCAST(bs), attrs) -int BinarySource_get_fxp_attrs(BinarySource *src, struct fxp_attrs *attrs) +bool BinarySource_get_fxp_attrs(BinarySource *src, struct fxp_attrs *attrs) { attrs->flags = get_uint32(src); if (attrs->flags & SSH_FILEXFER_ATTR_SIZE) @@ -99,7 +99,7 @@ int BinarySource_get_fxp_attrs(BinarySource *src, struct fxp_attrs *attrs) get_string(src); } } - return 1; + return true; } void sftp_pkt_free(struct sftp_packet *pkt) @@ -131,7 +131,7 @@ struct sftp_packet *sftp_recv_prepare(unsigned length) return pkt; } -int sftp_recv_finish(struct sftp_packet *pkt) +bool sftp_recv_finish(struct sftp_packet *pkt) { BinarySource_INIT(pkt, pkt->data, pkt->length); pkt->type = get_byte(pkt); diff --git a/ssh.c b/ssh.c index 2a5dd85f..1df7028c 100644 --- a/ssh.c +++ b/ssh.c @@ -46,9 +46,9 @@ struct Ssh { /* The last list returned from get_specials. */ SessionSpecial *specials; - int bare_connection; + bool bare_connection; ssh_sharing_state *connshare; - int attempting_connshare; + bool attempting_connshare; struct ssh_connection_shared_gss_state gss_state; @@ -56,20 +56,20 @@ struct Ssh { int savedport; char *fullhostname; - int fallback_cmd; + bool fallback_cmd; int exitcode; int version; int conn_throttle_count; int overall_bufsize; - int throttled_all; - int frozen; + bool throttled_all; + bool frozen; /* in case we find these out before we have a ConnectionLayer to tell */ int term_width, term_height; bufchain in_raw, out_raw, user_input; - int pending_close; + bool pending_close; IdempotentCallback ic_out_raw; PacketLogSettings pls; @@ -105,11 +105,11 @@ struct Ssh { * It's also used to mark the point where we stop counting proxy * command diagnostics as pre-session-startup. */ - int session_started; + bool session_started; Pinger *pinger; - int need_random_unref; + bool need_random_unref; }; @@ -117,7 +117,7 @@ struct Ssh { logevent_and_free((ssh)->logctx, dupprintf params)) static void ssh_shutdown(Ssh *ssh); -static void ssh_throttle_all(Ssh *ssh, int enable, int bufsize); +static void ssh_throttle_all(Ssh *ssh, bool enable, int bufsize); static void ssh_bpp_output_raw_data_callback(void *vctx); LogContext *ssh_get_logctx(Ssh *ssh) @@ -316,7 +316,7 @@ static void ssh_bpp_output_raw_data_callback(void *vctx) bufchain_consume(&ssh->out_raw, len); if (backlog > SSH_MAX_BACKLOG) { - ssh_throttle_all(ssh, 1, backlog); + ssh_throttle_all(ssh, true, backlog); return; } } @@ -515,7 +515,7 @@ static void ssh_socket_log(Plug *plug, int type, SockAddr *addr, int port, } static void ssh_closing(Plug *plug, const char *error_msg, int error_code, - int calling_back) + bool calling_back) { Ssh *ssh = container_of(plug, Ssh, plug); if (error_msg) { @@ -550,7 +550,7 @@ static void ssh_sent(Plug *plug, int bufsize) * some more data off its bufchain. */ if (bufsize < SSH_MAX_BACKLOG) { - ssh_throttle_all(ssh, 0, bufsize); + ssh_throttle_all(ssh, false, bufsize); queue_idempotent_callback(&ssh->ic_out_raw); } } @@ -592,11 +592,11 @@ static void ssh_hostport_setup(const char *host, int port, Conf *conf, } } -static int ssh_test_for_upstream(const char *host, int port, Conf *conf) +static bool ssh_test_for_upstream(const char *host, int port, Conf *conf) { char *savedhost; int savedport; - int ret; + bool ret; random_ref(); /* platform may need this to determine share socket name */ ssh_hostport_setup(host, port, conf, &savedhost, &savedport, NULL); @@ -621,8 +621,9 @@ static const PlugVtable Ssh_plugvt = { * Also places the canonical host name into `realhost'. It must be * freed by the caller. */ -static const char *connect_to_host(Ssh *ssh, const char *host, int port, - char **realhost, int nodelay, int keepalive) +static const char *connect_to_host( + Ssh *ssh, const char *host, int port, char **realhost, + bool nodelay, bool keepalive) { SockAddr *addr; const char *err; @@ -686,7 +687,7 @@ static const char *connect_to_host(Ssh *ssh, const char *host, int port, ssh->fullhostname = dupstr(*realhost); /* save in case of GSSAPI */ ssh->s = new_connection(addr, *realhost, port, - 0, 1, nodelay, keepalive, + false, true, nodelay, keepalive, &ssh->plug, ssh->conf); if ((err = sk_socket_error(ssh->s)) != NULL) { ssh->s = NULL; @@ -739,7 +740,7 @@ static const char *connect_to_host(Ssh *ssh, const char *host, int port, void ssh_throttle_conn(Ssh *ssh, int adjust) { int old_count = ssh->conn_throttle_count; - int frozen; + bool frozen; ssh->conn_throttle_count += adjust; assert(ssh->conn_throttle_count >= 0); @@ -769,7 +770,7 @@ void ssh_throttle_conn(Ssh *ssh, int adjust) * Throttle or unthrottle _all_ local data streams (for when sends * on the SSH connection itself back up). */ -static void ssh_throttle_all(Ssh *ssh, int enable, int bufsize) +static void ssh_throttle_all(Ssh *ssh, bool enable, int bufsize) { if (enable == ssh->throttled_all) return; @@ -793,7 +794,7 @@ static void ssh_cache_conf_values(Ssh *ssh) static const char *ssh_init(Seat *seat, Backend **backend_handle, LogContext *logctx, Conf *conf, const char *host, int port, char **realhost, - int nodelay, int keepalive) + bool nodelay, bool keepalive) { const char *p; Ssh *ssh; @@ -838,7 +839,7 @@ static const char *ssh_init(Seat *seat, Backend **backend_handle, static void ssh_free(Backend *be) { Ssh *ssh = container_of(be, Ssh, backend); - int need_random_unref; + bool need_random_unref; ssh_shutdown(ssh); @@ -1015,13 +1016,13 @@ static void ssh_unthrottle(Backend *be, int bufsize) ssh_stdout_unthrottle(ssh->cl, bufsize); } -static int ssh_connected(Backend *be) +static bool ssh_connected(Backend *be) { Ssh *ssh = container_of(be, Ssh, backend); return ssh->s != NULL; } -static int ssh_sendok(Backend *be) +static bool ssh_sendok(Backend *be) { Ssh *ssh = container_of(be, Ssh, backend); return ssh->base_layer && ssh_ppl_want_user_input(ssh->base_layer); @@ -1035,7 +1036,7 @@ void ssh_ldisc_update(Ssh *ssh) ldisc_echoedit_update(ssh->ldisc); } -static int ssh_ldisc(Backend *be, int option) +static bool ssh_ldisc(Backend *be, int option) { Ssh *ssh = container_of(be, Ssh, backend); return ssh->cl ? ssh_ldisc_option(ssh->cl, option) : false; @@ -1082,7 +1083,7 @@ static int ssh_cfg_info(Backend *be) * that fails. This variable is the means by which scp.c can reach * into the SSH code and find out which one it got. */ -extern int ssh_fallback_cmd(Backend *be) +extern bool ssh_fallback_cmd(Backend *be) { Ssh *ssh = container_of(be, Ssh, backend); return ssh->fallback_cmd; diff --git a/ssh.h b/ssh.h index 91f15a2f..c657bca4 100644 --- a/ssh.h +++ b/ssh.h @@ -52,7 +52,7 @@ struct ssh_channel; typedef struct PacketQueueNode PacketQueueNode; struct PacketQueueNode { PacketQueueNode *next, *prev; - int on_free_queue; /* is this packet scheduled for freeing? */ + bool on_free_queue; /* is this packet scheduled for freeing? */ }; typedef struct PktIn { @@ -89,12 +89,12 @@ typedef struct PacketQueueBase { typedef struct PktInQueue { PacketQueueBase pqb; - PktIn *(*after)(PacketQueueBase *, PacketQueueNode *prev, int pop); + PktIn *(*after)(PacketQueueBase *, PacketQueueNode *prev, bool pop); } PktInQueue; typedef struct PktOutQueue { PacketQueueBase pqb; - PktOut *(*after)(PacketQueueBase *, PacketQueueNode *prev, int pop); + PktOut *(*after)(PacketQueueBase *, PacketQueueNode *prev, bool pop); } PktOutQueue; void pq_base_push(PacketQueueBase *pqb, PacketQueueNode *node); @@ -146,17 +146,17 @@ typedef enum { } Pkt_ACtx; typedef struct PacketLogSettings { - int omit_passwords, omit_data; + bool omit_passwords, omit_data; Pkt_KCtx kctx; Pkt_ACtx actx; } PacketLogSettings; #define MAX_BLANKS 4 /* no packet needs more censored sections than this */ int ssh1_censor_packet( - const PacketLogSettings *pls, int type, int sender_is_client, + const PacketLogSettings *pls, int type, bool sender_is_client, ptrlen pkt, logblank_t *blanks); int ssh2_censor_packet( - const PacketLogSettings *pls, int type, int sender_is_client, + const PacketLogSettings *pls, int type, bool sender_is_client, ptrlen pkt, logblank_t *blanks); PktOut *ssh_new_packet(void); @@ -167,7 +167,7 @@ Socket *ssh_connection_sharing_init( Plug *sshplug, ssh_sharing_state **state); void ssh_connshare_provide_connlayer(ssh_sharing_state *sharestate, ConnectionLayer *cl); -int ssh_share_test_for_upstream(const char *host, int port, Conf *conf); +bool ssh_share_test_for_upstream(const char *host, int port, Conf *conf); void share_got_pkt_from_server(ssh_sharing_connstate *ctx, int type, const void *pkt, int pktlen); void share_activate(ssh_sharing_state *sharestate, @@ -259,7 +259,7 @@ struct ConnectionLayerVtable { void (*sharing_no_more_downstreams)(ConnectionLayer *cl); /* Query whether the connection layer is doing agent forwarding */ - int (*agent_forwarding_permitted)(ConnectionLayer *cl); + bool (*agent_forwarding_permitted)(ConnectionLayer *cl); /* Set the size of the main terminal window (if any) */ void (*terminal_size)(ConnectionLayer *cl, int width, int height); @@ -274,15 +274,15 @@ struct ConnectionLayerVtable { * backed up, so it should tell all currently open channels to * cease reading from their local input sources if they can. (Or * tell it that that state of affairs has gone away again.) */ - void (*throttle_all_channels)(ConnectionLayer *cl, int throttled); + void (*throttle_all_channels)(ConnectionLayer *cl, bool throttled); /* Ask the connection layer about its current preference for * line-discipline options. */ - int (*ldisc_option)(ConnectionLayer *cl, int option); + bool (*ldisc_option)(ConnectionLayer *cl, int option); /* Communicate _to_ the connection layer (from the main session * channel) what its preference for line-discipline options is. */ - void (*set_ldisc_option)(ConnectionLayer *cl, int option, int value); + void (*set_ldisc_option)(ConnectionLayer *cl, int option, bool value); /* Communicate to the connection layer whether X and agent * forwarding were successfully enabled (for purposes of @@ -292,7 +292,7 @@ struct ConnectionLayerVtable { /* Communicate to the connection layer whether the main session * channel currently wants user input. */ - void (*set_wants_user_input)(ConnectionLayer *cl, int wanted); + void (*set_wants_user_input)(ConnectionLayer *cl, bool wanted); }; struct ConnectionLayer { @@ -354,9 +354,9 @@ void portfwdmgr_close_all(PortFwdManager *mgr); char *portfwdmgr_connect(PortFwdManager *mgr, Channel **chan_ret, char *hostname, int port, SshChannel *c, int addressfamily); -int portfwdmgr_listen(PortFwdManager *mgr, const char *host, int port, - const char *keyhost, int keyport, Conf *conf); -int portfwdmgr_unlisten(PortFwdManager *mgr, const char *host, int port); +bool portfwdmgr_listen(PortFwdManager *mgr, const char *host, int port, + const char *keyhost, int keyport, Conf *conf); +bool portfwdmgr_unlisten(PortFwdManager *mgr, const char *host, int port); Channel *portfwd_raw_new(ConnectionLayer *cl, Plug **plug); void portfwd_raw_free(Channel *pfchan); void portfwd_raw_setup(Channel *pfchan, Socket *s, SshChannel *sc); @@ -415,7 +415,7 @@ struct ec_point { const struct ec_curve *curve; Bignum x, y; Bignum z; /* Jacobian denominator */ - unsigned char infinity; + bool infinity; }; void ec_point_free(struct ec_point *point); @@ -464,12 +464,12 @@ const ssh_keyalg *ec_alg_by_oid(int len, const void *oid, const struct ec_curve **curve); const unsigned char *ec_alg_oid(const ssh_keyalg *alg, int *oidlen); extern const int ec_nist_curve_lengths[], n_ec_nist_curve_lengths; -int ec_nist_alg_and_curve_by_bits(int bits, - const struct ec_curve **curve, - const ssh_keyalg **alg); -int ec_ed_alg_and_curve_by_bits(int bits, - const struct ec_curve **curve, - const ssh_keyalg **alg); +bool ec_nist_alg_and_curve_by_bits(int bits, + const struct ec_curve **curve, + const ssh_keyalg **alg); +bool ec_ed_alg_and_curve_by_bits(int bits, + const struct ec_curve **curve, + const ssh_keyalg **alg); struct ec_key { struct ec_point publicKey; @@ -493,14 +493,14 @@ void BinarySource_get_rsa_ssh1_pub( BinarySource *src, struct RSAKey *result, RsaSsh1Order order); void BinarySource_get_rsa_ssh1_priv( BinarySource *src, struct RSAKey *rsa); -int rsa_ssh1_encrypt(unsigned char *data, int length, struct RSAKey *key); +bool rsa_ssh1_encrypt(unsigned char *data, int length, struct RSAKey *key); Bignum rsa_ssh1_decrypt(Bignum input, struct RSAKey *key); -int rsa_ssh1_decrypt_pkcs1(Bignum input, struct RSAKey *key, strbuf *outbuf); +bool rsa_ssh1_decrypt_pkcs1(Bignum input, struct RSAKey *key, strbuf *outbuf); void rsasanitise(struct RSAKey *key); int rsastr_len(struct RSAKey *key); void rsastr_fmt(char *str, struct RSAKey *key); char *rsa_ssh1_fingerprint(struct RSAKey *key); -int rsa_verify(struct RSAKey *key); +bool rsa_verify(struct RSAKey *key); void rsa_ssh1_public_blob(BinarySink *bs, struct RSAKey *key, RsaSsh1Order order); int rsa_ssh1_public_blob_len(void *data, int maxlen); @@ -513,8 +513,8 @@ unsigned long crc32_update(unsigned long crc_input, const void *s, size_t len); struct crcda_ctx; struct crcda_ctx *crcda_make_context(void); void crcda_free_context(struct crcda_ctx *ctx); -int detect_attack(struct crcda_ctx *ctx, unsigned char *buf, uint32_t len, - unsigned char *IV); +bool detect_attack(struct crcda_ctx *ctx, unsigned char *buf, uint32_t len, + unsigned char *IV); /* * SSH2 RSA key exchange functions @@ -575,7 +575,7 @@ void hmacmd5_key(struct hmacmd5_context *ctx, void const *key, int len); void hmacmd5_do_hmac(struct hmacmd5_context *ctx, const void *blk, int len, unsigned char *hmac); -int supports_sha_ni(void); +bool supports_sha_ni(void); typedef struct SHA_State { uint32_t h[5]; @@ -718,9 +718,9 @@ struct ssh2_macalg { #define ssh2_mac_alg(ctx) ((ctx)->vt) /* Centralised 'methods' for ssh2_mac, defined in sshmac.c */ -int ssh2_mac_verresult(ssh2_mac *, const void *); +bool ssh2_mac_verresult(ssh2_mac *, const void *); void ssh2_mac_generate(ssh2_mac *, void *, int, unsigned long seq); -int ssh2_mac_verify(ssh2_mac *, const void *, int, unsigned long seq); +bool ssh2_mac_verify(ssh2_mac *, const void *, int, unsigned long seq); typedef struct ssh_hash { const struct ssh_hashalg *vt; @@ -763,7 +763,7 @@ struct ssh_keyalg { /* Methods that operate on an existing ssh_key */ void (*freekey) (ssh_key *key); void (*sign) (ssh_key *key, const void *data, int datalen, BinarySink *); - int (*verify) (ssh_key *key, ptrlen sig, ptrlen data); + bool (*verify) (ssh_key *key, ptrlen sig, ptrlen data); void (*public_blob)(ssh_key *key, BinarySink *); void (*private_blob)(ssh_key *key, BinarySink *); void (*openssh_blob) (ssh_key *key, BinarySink *); @@ -815,8 +815,8 @@ struct ssh_compression_alg { int minlen); ssh_decompressor *(*decompress_new)(void); void (*decompress_free)(ssh_decompressor *); - int (*decompress)(ssh_decompressor *, unsigned char *block, int len, - unsigned char **outblock, int *outlen); + bool (*decompress)(ssh_decompressor *, unsigned char *block, int len, + unsigned char **outblock, int *outlen); const char *text_name; }; @@ -893,7 +893,7 @@ extern const char sshver[]; * that fails. This variable is the means by which scp.c can reach * into the SSH code and find out which one it got. */ -extern int ssh_fallback_cmd(Backend *backend); +extern bool ssh_fallback_cmd(Backend *backend); void SHATransform(uint32_t *digest, uint32_t *data); @@ -930,7 +930,7 @@ enum { }; struct X11Display { /* Broken-down components of the display name itself */ - int unixdomain; + bool unixdomain; char *hostname; int displaynum; int screennum; @@ -996,12 +996,12 @@ struct X11FakeAuth *x11_invent_fake_auth(tree234 *t, int authtype); void x11_free_fake_auth(struct X11FakeAuth *auth); Channel *x11_new_channel(tree234 *authtree, SshChannel *c, const char *peeraddr, int peerport, - int connection_sharing_possible); + bool connection_sharing_possible); char *x11_display(const char *display); /* Platform-dependent X11 functions */ extern void platform_get_x11_auth(struct X11Display *display, Conf *); /* examine a mostly-filled-in X11Display and fill in localauth* */ -extern const int platform_uses_x11_unix_by_default; +extern const bool platform_uses_x11_unix_by_default; /* choose default X transport in the absence of a specified one */ SockAddr *platform_get_x11_unix_address(const char *path, int displaynum); /* make up a SockAddr naming the address for displaynum */ @@ -1074,7 +1074,7 @@ Bignum BinarySource_get_mp_ssh2(BinarySource *); void diagbn(char *prefix, Bignum md); #endif -int dh_is_gex(const struct ssh_kex *kex); +bool dh_is_gex(const struct ssh_kex *kex); struct dh_ctx; struct dh_ctx *dh_setup_group(const struct ssh_kex *kex); struct dh_ctx *dh_setup_gex(Bignum pval, Bignum gval); @@ -1083,13 +1083,13 @@ Bignum dh_create_e(struct dh_ctx *, int nbits); const char *dh_validate_f(struct dh_ctx *, Bignum f); Bignum dh_find_K(struct dh_ctx *, Bignum f); -int rsa_ssh1_encrypted(const Filename *filename, char **comment); +bool rsa_ssh1_encrypted(const Filename *filename, char **comment); int rsa_ssh1_loadpub(const Filename *filename, BinarySink *bs, char **commentptr, const char **errorstr); int rsa_ssh1_loadkey(const Filename *filename, struct RSAKey *key, const char *passphrase, const char **errorstr); -int rsa_ssh1_savekey(const Filename *filename, struct RSAKey *key, - char *passphrase); +bool rsa_ssh1_savekey(const Filename *filename, struct RSAKey *key, + char *passphrase); extern int base64_decode_atom(const char *atom, unsigned char *out); extern int base64_lines(int datalen); @@ -1101,15 +1101,15 @@ extern void base64_encode(FILE *fp, const unsigned char *data, int datalen, extern struct ssh2_userkey ssh2_wrong_passphrase; #define SSH2_WRONG_PASSPHRASE (&ssh2_wrong_passphrase) -int ssh2_userkey_encrypted(const Filename *filename, char **comment); +bool ssh2_userkey_encrypted(const Filename *filename, char **comment); struct ssh2_userkey *ssh2_load_userkey(const Filename *filename, const char *passphrase, const char **errorstr); -int ssh2_userkey_loadpub(const Filename *filename, char **algorithm, - BinarySink *bs, - char **commentptr, const char **errorstr); -int ssh2_save_userkey(const Filename *filename, struct ssh2_userkey *key, - char *passphrase); +bool ssh2_userkey_loadpub(const Filename *filename, char **algorithm, + BinarySink *bs, + char **commentptr, const char **errorstr); +bool ssh2_save_userkey(const Filename *filename, struct ssh2_userkey *key, + char *passphrase); const ssh_keyalg *find_pubkey_alg(const char *name); const ssh_keyalg *find_pubkey_alg_len(ptrlen name); @@ -1167,17 +1167,17 @@ char *ssh2_fingerprint(ssh_key *key); int key_type(const Filename *filename); const char *key_type_to_str(int type); -int import_possible(int type); +bool import_possible(int type); int import_target_type(int type); -int import_encrypted(const Filename *filename, int type, char **comment); +bool import_encrypted(const Filename *filename, int type, char **comment); int import_ssh1(const Filename *filename, int type, struct RSAKey *key, char *passphrase, const char **errmsg_p); struct ssh2_userkey *import_ssh2(const Filename *filename, int type, char *passphrase, const char **errmsg_p); -int export_ssh1(const Filename *filename, int type, - struct RSAKey *key, char *passphrase); -int export_ssh2(const Filename *filename, int type, - struct ssh2_userkey *key, char *passphrase); +bool export_ssh1(const Filename *filename, int type, + struct RSAKey *key, char *passphrase); +bool export_ssh2(const Filename *filename, int type, + struct ssh2_userkey *key, char *passphrase); void des3_decrypt_pubkey(const void *key, void *blk, int len); void des3_encrypt_pubkey(const void *key, void *blk, int len); @@ -1231,7 +1231,7 @@ enum { SHARE_NONE, SHARE_DOWNSTREAM, SHARE_UPSTREAM }; int platform_ssh_share(const char *name, Conf *conf, Plug *downplug, Plug *upplug, Socket **sock, char **logtext, char **ds_err, char **us_err, - int can_upstream, int can_downstream); + bool can_upstream, bool can_downstream); void platform_ssh_share_cleanup(const char *name); /* @@ -1449,7 +1449,7 @@ enum { struct ssh_ttymodes { /* A boolean per mode, indicating whether it's set. */ - int have_mode[TTYMODE_LIMIT]; + bool have_mode[TTYMODE_LIMIT]; /* The actual value for each mode. */ unsigned mode_val[TTYMODE_LIMIT]; @@ -1463,7 +1463,7 @@ void write_ttymodes_to_packet(BinarySink *bs, int ssh_version, const char *ssh1_pkt_type(int type); const char *ssh2_pkt_type(Pkt_KCtx pkt_kctx, Pkt_ACtx pkt_actx, int type); -int ssh2_pkt_type_code_valid(unsigned type); +bool ssh2_pkt_type_code_valid(unsigned type); /* * Need this to warn about support for the original SSH-2 keyfile @@ -1505,11 +1505,11 @@ unsigned alloc_channel_id_general(tree234 *channels, size_t localid_offset); TYPECHECK(&((type *)0)->localid == (unsigned *)0, \ alloc_channel_id_general(tree, offsetof(type, localid))) -int first_in_commasep_string(char const *needle, char const *haystack, - int haylen); -int in_commasep_string(char const *needle, char const *haystack, int haylen); +bool first_in_commasep_string(char const *needle, char const *haystack, + int haylen); +bool in_commasep_string(char const *needle, char const *haystack, int haylen); void add_to_commasep(strbuf *buf, const char *data); -int get_commasep_word(ptrlen *list, ptrlen *word); +bool get_commasep_word(ptrlen *list, ptrlen *word); int verify_ssh_manual_host_key( Conf *conf, const char *fingerprint, ssh_key *key); @@ -1519,8 +1519,8 @@ ssh_transient_hostkey_cache *ssh_transient_hostkey_cache_new(void); void ssh_transient_hostkey_cache_free(ssh_transient_hostkey_cache *thc); void ssh_transient_hostkey_cache_add( ssh_transient_hostkey_cache *thc, ssh_key *key); -int ssh_transient_hostkey_cache_verify( +bool ssh_transient_hostkey_cache_verify( ssh_transient_hostkey_cache *thc, ssh_key *key); -int ssh_transient_hostkey_cache_has( +bool ssh_transient_hostkey_cache_has( ssh_transient_hostkey_cache *thc, const ssh_keyalg *alg); -int ssh_transient_hostkey_cache_non_empty(ssh_transient_hostkey_cache *thc); +bool ssh_transient_hostkey_cache_non_empty(ssh_transient_hostkey_cache *thc); diff --git a/ssh1bpp.c b/ssh1bpp.c index f4abd98f..2938e405 100644 --- a/ssh1bpp.c +++ b/ssh1bpp.c @@ -21,7 +21,7 @@ struct ssh1_bpp_state { struct crcda_ctx *crcda_ctx; - int pending_compression_request; + bool pending_compression_request; ssh_compressor *compctx; ssh_decompressor *decompctx; diff --git a/ssh1censor.c b/ssh1censor.c index 755ce3d8..780dc046 100644 --- a/ssh1censor.c +++ b/ssh1censor.c @@ -10,7 +10,7 @@ #include "ssh.h" int ssh1_censor_packet( - const PacketLogSettings *pls, int type, int sender_is_client, + const PacketLogSettings *pls, int type, bool sender_is_client, ptrlen pkt, logblank_t *blanks) { int nblanks = 0; diff --git a/ssh1connection-client.c b/ssh1connection-client.c index 6c7c224f..a2c5e423 100644 --- a/ssh1connection-client.c +++ b/ssh1connection-client.c @@ -29,7 +29,7 @@ void ssh1_connection_direction_specific_setup( } typedef void (*sf_handler_fn_t)(struct ssh1_connection_state *s, - int success, void *ctx); + bool success, void *ctx); struct outstanding_succfail { sf_handler_fn_t handler; @@ -43,14 +43,14 @@ struct outstanding_succfail { * expect to get an acknowledgment regardless, so we arrange to * send that ack immediately after the rest of the queue empties. */ - int trivial; + bool trivial; }; static void ssh1_connection_process_trivial_succfails(void *vs); static void ssh1_queue_succfail_handler( struct ssh1_connection_state *s, sf_handler_fn_t handler, void *ctx, - int trivial) + bool trivial) { struct outstanding_succfail *osf = snew(struct outstanding_succfail); osf->handler = handler; @@ -71,7 +71,7 @@ static void ssh1_queue_succfail_handler( } static void ssh1_connection_process_succfail( - struct ssh1_connection_state *s, int success) + struct ssh1_connection_state *s, bool success) { struct outstanding_succfail *prevhead = s->succfail_head; s->succfail_head = s->succfail_head->next; @@ -88,7 +88,7 @@ static void ssh1_connection_process_trivial_succfails(void *vs) ssh1_connection_process_succfail(s, true); } -int ssh1_handle_direction_specific_packet( +bool ssh1_handle_direction_specific_packet( struct ssh1_connection_state *s, PktIn *pktin) { PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */ @@ -233,7 +233,7 @@ int ssh1_handle_direction_specific_packet( s->ppl.seat, pktin->type == SSH1_SMSG_STDERR_DATA, data.ptr, data.len); if (!s->stdout_throttling && bufsize > SSH1_BUFFER_LIMIT) { - s->stdout_throttling = 1; + s->stdout_throttling = true; ssh_throttle_conn(s->ppl.ssh, +1); } } @@ -256,18 +256,18 @@ int ssh1_handle_direction_specific_packet( } static void ssh1mainchan_succfail_wantreply(struct ssh1_connection_state *s, - int success, void *ctx) + bool success, void *ctx) { chan_request_response(s->mainchan_chan, success); } static void ssh1mainchan_succfail_nowantreply(struct ssh1_connection_state *s, - int success, void *ctx) + bool success, void *ctx) { } static void ssh1mainchan_queue_response(struct ssh1_connection_state *s, - int want_reply, int trivial) + bool want_reply, bool trivial) { sf_handler_fn_t handler = (want_reply ? ssh1mainchan_succfail_wantreply : ssh1mainchan_succfail_nowantreply); @@ -275,8 +275,8 @@ static void ssh1mainchan_queue_response(struct ssh1_connection_state *s, } static void ssh1mainchan_request_x11_forwarding( - SshChannel *sc, int want_reply, const char *authproto, - const char *authdata, int screen_number, int oneshot) + SshChannel *sc, bool want_reply, const char *authproto, + const char *authdata, int screen_number, bool oneshot) { struct ssh1_connection_state *s = container_of(sc, struct ssh1_connection_state, mainchan_sc); @@ -293,7 +293,7 @@ static void ssh1mainchan_request_x11_forwarding( } static void ssh1mainchan_request_agent_forwarding( - SshChannel *sc, int want_reply) + SshChannel *sc, bool want_reply) { struct ssh1_connection_state *s = container_of(sc, struct ssh1_connection_state, mainchan_sc); @@ -307,7 +307,7 @@ static void ssh1mainchan_request_agent_forwarding( } static void ssh1mainchan_request_pty( - SshChannel *sc, int want_reply, Conf *conf, int w, int h) + SshChannel *sc, bool want_reply, Conf *conf, int w, int h) { struct ssh1_connection_state *s = container_of(sc, struct ssh1_connection_state, mainchan_sc); @@ -327,14 +327,13 @@ static void ssh1mainchan_request_pty( ssh1mainchan_queue_response(s, want_reply, false); } -static int ssh1mainchan_send_env_var( - SshChannel *sc, int want_reply, const char *var, const char *value) +static bool ssh1mainchan_send_env_var( + SshChannel *sc, bool want_reply, const char *var, const char *value) { return false; /* SSH-1 doesn't support this at all */ } -static void ssh1mainchan_start_shell( - SshChannel *sc, int want_reply) +static void ssh1mainchan_start_shell(SshChannel *sc, bool want_reply) { struct ssh1_connection_state *s = container_of(sc, struct ssh1_connection_state, mainchan_sc); @@ -347,7 +346,7 @@ static void ssh1mainchan_start_shell( } static void ssh1mainchan_start_command( - SshChannel *sc, int want_reply, const char *command) + SshChannel *sc, bool want_reply, const char *command) { struct ssh1_connection_state *s = container_of(sc, struct ssh1_connection_state, mainchan_sc); @@ -360,20 +359,20 @@ static void ssh1mainchan_start_command( ssh1mainchan_queue_response(s, want_reply, true); } -static int ssh1mainchan_start_subsystem( - SshChannel *sc, int want_reply, const char *subsystem) +static bool ssh1mainchan_start_subsystem( + SshChannel *sc, bool want_reply, const char *subsystem) { return false; /* SSH-1 doesn't support this at all */ } -static int ssh1mainchan_send_serial_break( - SshChannel *sc, int want_reply, int length) +static bool ssh1mainchan_send_serial_break( + SshChannel *sc, bool want_reply, int length) { return false; /* SSH-1 doesn't support this at all */ } -static int ssh1mainchan_send_signal( - SshChannel *sc, int want_reply, const char *signame) +static bool ssh1mainchan_send_signal( + SshChannel *sc, bool want_reply, const char *signame) { return false; /* SSH-1 doesn't support this at all */ } @@ -398,7 +397,7 @@ static void ssh1mainchan_hint_channel_is_simple(SshChannel *sc) } static int ssh1mainchan_write( - SshChannel *sc, int is_stderr, const void *data, int len) + SshChannel *sc, bool is_stderr, const void *data, int len) { struct ssh1_connection_state *s = container_of(sc, struct ssh1_connection_state, mainchan_sc); @@ -463,7 +462,7 @@ SshChannel *ssh1_session_open(ConnectionLayer *cl, Channel *chan) } static void ssh1_rportfwd_response(struct ssh1_connection_state *s, - int success, void *ctx) + bool success, void *ctx) { PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */ struct ssh_rportfwd *rpf = (struct ssh_rportfwd *)ctx; diff --git a/ssh1connection-server.c b/ssh1connection-server.c index 1e8ddeea..bdbec47e 100644 --- a/ssh1connection-server.c +++ b/ssh1connection-server.c @@ -13,12 +13,13 @@ #include "ssh1connection.h" #include "sshserver.h" -static int ssh1sesschan_write(SshChannel *c, int is_stderr, const void *, int); +static int ssh1sesschan_write(SshChannel *c, bool is_stderr, + const void *, int); static void ssh1sesschan_write_eof(SshChannel *c); static void ssh1sesschan_initiate_close(SshChannel *c, const char *err); static void ssh1sesschan_send_exit_status(SshChannel *c, int status); static void ssh1sesschan_send_exit_signal( - SshChannel *c, ptrlen signame, int core_dumped, ptrlen msg); + SshChannel *c, ptrlen signame, bool core_dumped, ptrlen msg); static const struct SshChannelVtable ssh1sesschan_vtable = { ssh1sesschan_write, @@ -54,7 +55,7 @@ void ssh1_connection_direction_specific_setup( } } -int ssh1_handle_direction_specific_packet( +bool ssh1_handle_direction_specific_packet( struct ssh1_connection_state *s, PktIn *pktin) { PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */ @@ -63,7 +64,8 @@ int ssh1_handle_direction_specific_packet( unsigned remid; ptrlen host, cmd, data; char *host_str, *err; - int port, listenport, success; + int port, listenport; + bool success; switch (pktin->type) { case SSH1_CMSG_EXEC_SHELL: @@ -264,7 +266,7 @@ struct ssh_rportfwd *ssh1_rportfwd_alloc( return NULL; } -static int ssh1sesschan_write(SshChannel *sc, int is_stderr, +static int ssh1sesschan_write(SshChannel *sc, bool is_stderr, const void *data, int len) { struct ssh1_connection_state *s = @@ -303,7 +305,7 @@ static void ssh1sesschan_send_exit_status(SshChannel *sc, int status) } static void ssh1sesschan_send_exit_signal( - SshChannel *sc, ptrlen signame, int core_dumped, ptrlen msg) + SshChannel *sc, ptrlen signame, bool core_dumped, ptrlen msg) { /* SSH-1 has no separate representation for signals */ ssh1sesschan_send_exit_status(sc, 128); diff --git a/ssh1connection.c b/ssh1connection.c index a7e09dfc..4d43299c 100644 --- a/ssh1connection.c +++ b/ssh1connection.c @@ -31,7 +31,7 @@ static void ssh1_connection_free(PacketProtocolLayer *); static void ssh1_connection_process_queue(PacketProtocolLayer *); static void ssh1_connection_special_cmd(PacketProtocolLayer *ppl, SessionSpecialCode code, int arg); -static int ssh1_connection_want_user_input(PacketProtocolLayer *ppl); +static bool ssh1_connection_want_user_input(PacketProtocolLayer *ppl); static void ssh1_connection_got_user_input(PacketProtocolLayer *ppl); static void ssh1_connection_reconfigure(PacketProtocolLayer *ppl, Conf *conf); @@ -53,16 +53,16 @@ static SshChannel *ssh1_lportfwd_open( const char *description, const SocketPeerInfo *pi, Channel *chan); static struct X11FakeAuth *ssh1_add_x11_display( ConnectionLayer *cl, int authtype, struct X11Display *disp); -static int ssh1_agent_forwarding_permitted(ConnectionLayer *cl); +static bool ssh1_agent_forwarding_permitted(ConnectionLayer *cl); static void ssh1_terminal_size(ConnectionLayer *cl, int width, int height); static void ssh1_stdout_unthrottle(ConnectionLayer *cl, int bufsize); static int ssh1_stdin_backlog(ConnectionLayer *cl); -static void ssh1_throttle_all_channels(ConnectionLayer *cl, int throttled); -static int ssh1_ldisc_option(ConnectionLayer *cl, int option); -static void ssh1_set_ldisc_option(ConnectionLayer *cl, int option, int value); +static void ssh1_throttle_all_channels(ConnectionLayer *cl, bool throttled); +static bool ssh1_ldisc_option(ConnectionLayer *cl, int option); +static void ssh1_set_ldisc_option(ConnectionLayer *cl, int option, bool value); static void ssh1_enable_x_fwd(ConnectionLayer *cl); static void ssh1_enable_agent_fwd(ConnectionLayer *cl); -static void ssh1_set_wants_user_input(ConnectionLayer *cl, int wanted); +static void ssh1_set_wants_user_input(ConnectionLayer *cl, bool wanted); static const struct ConnectionLayerVtable ssh1_connlayer_vtable = { ssh1_rportfwd_alloc, @@ -92,7 +92,7 @@ static const struct ConnectionLayerVtable ssh1_connlayer_vtable = { }; static int ssh1channel_write( - SshChannel *c, int is_stderr, const void *buf, int len); + SshChannel *c, bool is_stderr, const void *buf, int len); static void ssh1channel_write_eof(SshChannel *c); static void ssh1channel_initiate_close(SshChannel *c, const char *err); static void ssh1channel_unthrottle(SshChannel *c, int bufsize); @@ -224,13 +224,13 @@ void ssh1_connection_set_protoflags(PacketProtocolLayer *ppl, s->remote_protoflags = remote; } -static int ssh1_connection_filter_queue(struct ssh1_connection_state *s) +static bool ssh1_connection_filter_queue(struct ssh1_connection_state *s) { PktIn *pktin; ptrlen data; struct ssh1_channel *c; unsigned localid; - int expect_halfopen; + bool expect_halfopen; while (1) { if (ssh1_common_filter_queue(&s->ppl)) @@ -511,7 +511,7 @@ static void ssh1_channel_destroy(struct ssh1_channel *c) queue_toplevel_callback(ssh1_check_termination_callback, s); } -int ssh1_check_termination(struct ssh1_connection_state *s) +bool ssh1_check_termination(struct ssh1_connection_state *s) { /* * Decide whether we should terminate the SSH connection now. @@ -584,13 +584,13 @@ static void ssh1channel_unthrottle(SshChannel *sc, int bufsize) struct ssh1_connection_state *s = c->connlayer; if (c->throttling_conn && bufsize <= SSH1_BUFFER_LIMIT) { - c->throttling_conn = 0; + c->throttling_conn = false; ssh_throttle_conn(s->ppl.ssh, -1); } } static int ssh1channel_write( - SshChannel *sc, int is_stderr, const void *buf, int len) + SshChannel *sc, bool is_stderr, const void *buf, int len) { struct ssh1_channel *c = container_of(sc, struct ssh1_channel, sc); struct ssh1_connection_state *s = c->connlayer; @@ -659,7 +659,7 @@ static void ssh1_rportfwd_remove(ConnectionLayer *cl, struct ssh_rportfwd *rpf) */ } -static int ssh1_agent_forwarding_permitted(ConnectionLayer *cl) +static bool ssh1_agent_forwarding_permitted(ConnectionLayer *cl) { struct ssh1_connection_state *s = container_of(cl, struct ssh1_connection_state, cl); @@ -701,7 +701,7 @@ static void ssh1_stdout_unthrottle(ConnectionLayer *cl, int bufsize) container_of(cl, struct ssh1_connection_state, cl); if (s->stdout_throttling && bufsize < SSH1_BUFFER_LIMIT) { - s->stdout_throttling = 0; + s->stdout_throttling = false; ssh_throttle_conn(s->ppl.ssh, -1); } } @@ -711,7 +711,7 @@ static int ssh1_stdin_backlog(ConnectionLayer *cl) return 0; } -static void ssh1_throttle_all_channels(ConnectionLayer *cl, int throttled) +static void ssh1_throttle_all_channels(ConnectionLayer *cl, bool throttled) { struct ssh1_connection_state *s = container_of(cl, struct ssh1_connection_state, cl); @@ -722,7 +722,7 @@ static void ssh1_throttle_all_channels(ConnectionLayer *cl, int throttled) chan_set_input_wanted(c->chan, !throttled); } -static int ssh1_ldisc_option(ConnectionLayer *cl, int option) +static bool ssh1_ldisc_option(ConnectionLayer *cl, int option) { struct ssh1_connection_state *s = container_of(cl, struct ssh1_connection_state, cl); @@ -730,7 +730,7 @@ static int ssh1_ldisc_option(ConnectionLayer *cl, int option) return s->ldisc_opts[option]; } -static void ssh1_set_ldisc_option(ConnectionLayer *cl, int option, int value) +static void ssh1_set_ldisc_option(ConnectionLayer *cl, int option, bool value) { struct ssh1_connection_state *s = container_of(cl, struct ssh1_connection_state, cl); @@ -754,7 +754,7 @@ static void ssh1_enable_agent_fwd(ConnectionLayer *cl) s->agent_fwd_enabled = true; } -static void ssh1_set_wants_user_input(ConnectionLayer *cl, int wanted) +static void ssh1_set_wants_user_input(ConnectionLayer *cl, bool wanted) { struct ssh1_connection_state *s = container_of(cl, struct ssh1_connection_state, cl); @@ -763,7 +763,7 @@ static void ssh1_set_wants_user_input(ConnectionLayer *cl, int wanted) s->finished_setup = true; } -static int ssh1_connection_want_user_input(PacketProtocolLayer *ppl) +static bool ssh1_connection_want_user_input(PacketProtocolLayer *ppl) { struct ssh1_connection_state *s = container_of(ppl, struct ssh1_connection_state, ppl); diff --git a/ssh1connection.h b/ssh1connection.h index 7d5194da..fe4c6157 100644 --- a/ssh1connection.h +++ b/ssh1connection.h @@ -21,25 +21,25 @@ struct ssh1_connection_state { Channel *mainchan_chan; /* the other end of mainchan_sc */ mainchan *mainchan; /* and its subtype */ - int got_pty; - int ldisc_opts[LD_N_OPTIONS]; - int stdout_throttling; - int want_user_input; - int session_terminated; + bool got_pty; + bool ldisc_opts[LD_N_OPTIONS]; + bool stdout_throttling; + bool want_user_input; + bool session_terminated; int term_width, term_height, term_width_orig, term_height_orig; - int X11_fwd_enabled; + bool X11_fwd_enabled; struct X11Display *x11disp; struct X11FakeAuth *x11auth; tree234 *x11authtree; - int agent_fwd_enabled; + bool agent_fwd_enabled; tree234 *rportfwds; PortFwdManager *portfwdmgr; - int portfwdmgr_configured; + bool portfwdmgr_configured; - int finished_setup; + bool finished_setup; /* * These store the list of requests that we're waiting for @@ -49,7 +49,7 @@ struct ssh1_connection_state { */ struct outstanding_succfail *succfail_head, *succfail_tail; - int compressing; /* used in server mode only */ + bool compressing; /* used in server mode only */ ConnectionLayer cl; PacketProtocolLayer ppl; @@ -61,7 +61,7 @@ struct ssh1_channel { unsigned remoteid, localid; int type; /* True if we opened this channel but server hasn't confirmed. */ - int halfopen; + bool halfopen; /* Bitmap of whether we've sent/received CHANNEL_CLOSE and * CHANNEL_CLOSE_CONFIRMATION. */ @@ -79,13 +79,13 @@ struct ssh1_channel { * we set this flag instead to remind us to do so once our buffer * is clear. */ - int pending_eof; + bool pending_eof; /* * True if this channel is causing the underlying connection to be * throttled. */ - int throttling_conn; + bool throttling_conn; /* * True if we currently have backed-up data on the direction of @@ -93,7 +93,7 @@ struct ssh1_channel { * would prefer the 'Channel' implementation not to read further * local input if possible. */ - int throttled_by_backlog; + bool throttled_by_backlog; Channel *chan; /* handle the client side of this channel, if not */ SshChannel sc; /* entry point for chan to talk back to */ @@ -113,7 +113,7 @@ SshChannel *ssh1_serverside_agent_open(ConnectionLayer *cl, Channel *chan); void ssh1_connection_direction_specific_setup( struct ssh1_connection_state *s); -int ssh1_handle_direction_specific_packet( +bool ssh1_handle_direction_specific_packet( struct ssh1_connection_state *s, PktIn *pktin); -int ssh1_check_termination(struct ssh1_connection_state *s); +bool ssh1_check_termination(struct ssh1_connection_state *s); diff --git a/ssh1login-server.c b/ssh1login-server.c index 4e0c7ca0..6689bf64 100644 --- a/ssh1login-server.c +++ b/ssh1login-server.c @@ -28,14 +28,14 @@ struct ssh1_login_server_state { ptrlen username; struct RSAKey *servkey, *hostkey; - int servkey_generated_here; + bool servkey_generated_here; Bignum sesskey; AuthPolicy *authpolicy; unsigned ap_methods, current_method; unsigned char auth_rsa_expected_response[16]; struct RSAKey *authkey; - int auth_successful; + bool auth_successful; PacketProtocolLayer ppl; }; @@ -43,12 +43,12 @@ struct ssh1_login_server_state { static void ssh1_login_server_free(PacketProtocolLayer *); static void ssh1_login_server_process_queue(PacketProtocolLayer *); -static int ssh1_login_server_get_specials( +static bool ssh1_login_server_get_specials( PacketProtocolLayer *ppl, add_special_fn_t add_special, void *ctx) { return false; } static void ssh1_login_server_special_cmd(PacketProtocolLayer *ppl, SessionSpecialCode code, int arg) {} -static int ssh1_login_server_want_user_input( +static bool ssh1_login_server_want_user_input( PacketProtocolLayer *ppl) { return false; } static void ssh1_login_server_got_user_input(PacketProtocolLayer *ppl) {} static void ssh1_login_server_reconfigure( @@ -101,7 +101,7 @@ static void ssh1_login_server_free(PacketProtocolLayer *ppl) sfree(s); } -static int ssh1_login_server_filter_queue(struct ssh1_login_server_state *s) +static bool ssh1_login_server_filter_queue(struct ssh1_login_server_state *s) { return ssh1_common_filter_queue(&s->ppl); } diff --git a/ssh1login.c b/ssh1login.c index 7efc068c..a85209a3 100644 --- a/ssh1login.c +++ b/ssh1login.c @@ -20,7 +20,7 @@ struct ssh1_login_state { char *savedhost; int savedport; - int try_agent_auth; + bool try_agent_auth; int remote_protoflags; int local_protoflags; @@ -31,14 +31,14 @@ struct ssh1_login_state { int len; unsigned char *rsabuf; unsigned long supported_ciphers_mask, supported_auths_mask; - int tried_publickey, tried_agent; - int tis_auth_refused, ccard_auth_refused; + bool tried_publickey, tried_agent; + bool tis_auth_refused, ccard_auth_refused; unsigned char cookie[8]; unsigned char session_id[16]; int cipher_type; strbuf *publickey_blob; char *publickey_comment; - int privatekey_available, privatekey_encrypted; + bool privatekey_available, privatekey_encrypted; prompts_t *cur_prompt; int userpass_ret; char c; @@ -47,14 +47,14 @@ struct ssh1_login_state { ptrlen agent_response; BinarySource asrc[1]; /* response from SSH agent */ int keyi, nkeys; - int authed; + bool authed; struct RSAKey key; Bignum challenge; ptrlen comment; int dlgret; Filename *keyfile; struct RSAKey servkey, hostkey; - int want_user_input; + bool want_user_input; PacketProtocolLayer ppl; }; @@ -64,7 +64,7 @@ static void ssh1_login_process_queue(PacketProtocolLayer *); static void ssh1_login_dialog_callback(void *, int); static void ssh1_login_special_cmd(PacketProtocolLayer *ppl, SessionSpecialCode code, int arg); -static int ssh1_login_want_user_input(PacketProtocolLayer *ppl); +static bool ssh1_login_want_user_input(PacketProtocolLayer *ppl); static void ssh1_login_got_user_input(PacketProtocolLayer *ppl); static void ssh1_login_reconfigure(PacketProtocolLayer *ppl, Conf *conf); @@ -120,7 +120,7 @@ static void ssh1_login_free(PacketProtocolLayer *ppl) sfree(s); } -static int ssh1_login_filter_queue(struct ssh1_login_state *s) +static bool ssh1_login_filter_queue(struct ssh1_login_state *s) { return ssh1_common_filter_queue(&s->ppl); } @@ -279,7 +279,7 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl) ppl_logevent(("Encrypted session key")); { - int cipher_chosen = 0, warn = 0; + bool cipher_chosen = false, warn = false; const char *cipher_string = NULL; int i; for (i = 0; !cipher_chosen && i < CIPHER_MAX; i++) { @@ -287,7 +287,7 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl) s->conf, CONF_ssh_cipherlist, i); if (next_cipher == CIPHER_WARN) { /* If/when we choose a cipher, warn about it */ - warn = 1; + warn = true; } else if (next_cipher == CIPHER_AES) { /* XXX Probably don't need to mention this. */ ppl_logevent(("AES not supported in SSH-1, skipping")); @@ -301,7 +301,7 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl) cipher_string = "single-DES"; break; } if (s->supported_ciphers_mask & (1 << s->cipher_type)) - cipher_chosen = 1; + cipher_chosen = true; } } if (!cipher_chosen) { @@ -492,7 +492,7 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl) * Attempt RSA authentication using Pageant. */ s->authed = false; - s->tried_agent = 1; + s->tried_agent = true; ppl_logevent(("Pageant is running. Requesting keys.")); /* Request the keys held by the agent. */ @@ -535,7 +535,7 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl) s->publickey_blob->len)) { ppl_logevent(("Pageant key #%d matches " "configured key file", s->keyi)); - s->tried_publickey = 1; + s->tried_publickey = true; } else /* Skip non-configured key */ continue; @@ -632,12 +632,12 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl) * Try public key authentication with the specified * key file. */ - int got_passphrase; /* need not be kept over crReturn */ + bool got_passphrase; /* need not be kept over crReturn */ if (flags & FLAG_VERBOSE) ppl_printf(("Trying public key authentication.\r\n")); ppl_logevent(("Trying public key \"%s\"", filename_to_str(s->keyfile))); - s->tried_publickey = 1; + s->tried_publickey = true; got_passphrase = false; while (!got_passphrase) { /* @@ -805,7 +805,7 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl) ppl_logevent(("TIS authentication declined")); if (flags & FLAG_INTERACTIVE) ppl_printf(("TIS authentication refused.\r\n")); - s->tis_auth_refused = 1; + s->tis_auth_refused = true; continue; } else if (pktin->type == SSH1_SMSG_AUTH_TIS_CHALLENGE) { ptrlen challenge; @@ -853,7 +853,7 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl) if (pktin->type == SSH1_SMSG_FAILURE) { ppl_logevent(("CryptoCard authentication declined")); ppl_printf(("CryptoCard authentication refused.\r\n")); - s->ccard_auth_refused = 1; + s->ccard_auth_refused = true; continue; } else if (pktin->type == SSH1_SMSG_AUTH_CCARD_CHALLENGE) { ptrlen challenge; @@ -1145,7 +1145,7 @@ static void ssh1_login_special_cmd(PacketProtocolLayer *ppl, } } -static int ssh1_login_want_user_input(PacketProtocolLayer *ppl) +static bool ssh1_login_want_user_input(PacketProtocolLayer *ppl) { struct ssh1_login_state *s = container_of(ppl, struct ssh1_login_state, ppl); diff --git a/ssh2bpp.c b/ssh2bpp.c index fddfce00..4d117878 100644 --- a/ssh2bpp.c +++ b/ssh2bpp.c @@ -13,7 +13,7 @@ struct ssh2_bpp_direction { unsigned long sequence; ssh2_cipher *cipher; ssh2_mac *mac; - int etm_mode; + bool etm_mode; const struct ssh_compression_alg *pending_compression; }; @@ -26,7 +26,7 @@ struct ssh2_bpp_state { unsigned cipherblk; PktIn *pktin; struct DataTransferStats *stats; - int cbc_ignore_workaround; + bool cbc_ignore_workaround; struct ssh2_bpp_direction in, out; /* comp and decomp logically belong in the per-direction @@ -34,9 +34,9 @@ struct ssh2_bpp_state { ssh_decompressor *in_decomp; ssh_compressor *out_comp; - int is_server; - int pending_newkeys; - int pending_compression, seen_userauth_success; + bool is_server; + bool pending_newkeys; + bool pending_compression, seen_userauth_success; BinaryPacketProtocol bpp; }; @@ -55,7 +55,7 @@ static const struct BinaryPacketProtocolVtable ssh2_bpp_vtable = { }; BinaryPacketProtocol *ssh2_bpp_new( - LogContext *logctx, struct DataTransferStats *stats, int is_server) + LogContext *logctx, struct DataTransferStats *stats, bool is_server) { struct ssh2_bpp_state *s = snew(struct ssh2_bpp_state); memset(s, 0, sizeof(*s)); @@ -90,8 +90,8 @@ static void ssh2_bpp_free(BinaryPacketProtocol *bpp) void ssh2_bpp_new_outgoing_crypto( BinaryPacketProtocol *bpp, const struct ssh2_cipheralg *cipher, const void *ckey, const void *iv, - const struct ssh2_macalg *mac, int etm_mode, const void *mac_key, - const struct ssh_compression_alg *compression, int delayed_compression) + const struct ssh2_macalg *mac, bool etm_mode, const void *mac_key, + const struct ssh_compression_alg *compression, bool delayed_compression) { struct ssh2_bpp_state *s; assert(bpp->vt == &ssh2_bpp_vtable); @@ -157,8 +157,8 @@ void ssh2_bpp_new_outgoing_crypto( void ssh2_bpp_new_incoming_crypto( BinaryPacketProtocol *bpp, const struct ssh2_cipheralg *cipher, const void *ckey, const void *iv, - const struct ssh2_macalg *mac, int etm_mode, const void *mac_key, - const struct ssh_compression_alg *compression, int delayed_compression) + const struct ssh2_macalg *mac, bool etm_mode, const void *mac_key, + const struct ssh_compression_alg *compression, bool delayed_compression) { struct ssh2_bpp_state *s; assert(bpp->vt == &ssh2_bpp_vtable); @@ -224,7 +224,7 @@ void ssh2_bpp_new_incoming_crypto( queue_idempotent_callback(&s->bpp.ic_in_raw); } -int ssh2_bpp_rekey_inadvisable(BinaryPacketProtocol *bpp) +bool ssh2_bpp_rekey_inadvisable(BinaryPacketProtocol *bpp) { struct ssh2_bpp_state *s; assert(bpp->vt == &ssh2_bpp_vtable); diff --git a/ssh2censor.c b/ssh2censor.c index 3d13589d..68d9d61c 100644 --- a/ssh2censor.c +++ b/ssh2censor.c @@ -10,7 +10,7 @@ #include "ssh.h" int ssh2_censor_packet( - const PacketLogSettings *pls, int type, int sender_is_client, + const PacketLogSettings *pls, int type, bool sender_is_client, ptrlen pkt, logblank_t *blanks) { int nblanks = 0; diff --git a/ssh2connection-client.c b/ssh2connection-client.c index 8a481f50..d332c677 100644 --- a/ssh2connection-client.c +++ b/ssh2connection-client.c @@ -124,7 +124,7 @@ ChanopenResult ssh2_connection_parse_channel_open( } } -int ssh2_connection_parse_global_request( +bool ssh2_connection_parse_global_request( struct ssh2_connection_state *s, ptrlen type, PktIn *pktin) { /* @@ -240,7 +240,7 @@ struct ssh_rportfwd *ssh2_rportfwd_alloc( PktOut *pktout = ssh_bpp_new_pktout( s->ppl.bpp, SSH2_MSG_GLOBAL_REQUEST); put_stringz(pktout, "tcpip-forward"); - put_bool(pktout, 1); /* want reply */ + put_bool(pktout, true); /* want reply */ put_stringz(pktout, rpf->shost); put_uint32(pktout, rpf->sport); pq_push(s->ppl.out_pq, pktout); @@ -268,7 +268,7 @@ void ssh2_rportfwd_remove(ConnectionLayer *cl, struct ssh_rportfwd *rpf) PktOut *pktout = ssh_bpp_new_pktout( s->ppl.bpp, SSH2_MSG_GLOBAL_REQUEST); put_stringz(pktout, "cancel-tcpip-forward"); - put_bool(pktout, 0); /* _don't_ want reply */ + put_bool(pktout, false); /* _don't_ want reply */ put_stringz(pktout, rpf->shost); put_uint32(pktout, rpf->sport); pq_push(s->ppl.out_pq, pktout); @@ -320,7 +320,7 @@ static void ssh2_channel_response( chan_request_response(c->chan, pkt->type == SSH2_MSG_CHANNEL_SUCCESS); } -void ssh2channel_start_shell(SshChannel *sc, int want_reply) +void ssh2channel_start_shell(SshChannel *sc, bool want_reply) { struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc); struct ssh2_connection_state *s = c->connlayer; @@ -331,7 +331,7 @@ void ssh2channel_start_shell(SshChannel *sc, int want_reply) } void ssh2channel_start_command( - SshChannel *sc, int want_reply, const char *command) + SshChannel *sc, bool want_reply, const char *command) { struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc); struct ssh2_connection_state *s = c->connlayer; @@ -342,8 +342,8 @@ void ssh2channel_start_command( pq_push(s->ppl.out_pq, pktout); } -int ssh2channel_start_subsystem( - SshChannel *sc, int want_reply, const char *subsystem) +bool ssh2channel_start_subsystem( + SshChannel *sc, bool want_reply, const char *subsystem) { struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc); struct ssh2_connection_state *s = c->connlayer; @@ -362,20 +362,20 @@ void ssh2channel_send_exit_status(SshChannel *sc, int status) } void ssh2channel_send_exit_signal( - SshChannel *sc, ptrlen signame, int core_dumped, ptrlen msg) + SshChannel *sc, ptrlen signame, bool core_dumped, ptrlen msg) { assert(false && "Should never be called in the client"); } void ssh2channel_send_exit_signal_numeric( - SshChannel *sc, int signum, int core_dumped, ptrlen msg) + SshChannel *sc, int signum, bool core_dumped, ptrlen msg) { assert(false && "Should never be called in the client"); } void ssh2channel_request_x11_forwarding( - SshChannel *sc, int want_reply, const char *authproto, - const char *authdata, int screen_number, int oneshot) + SshChannel *sc, bool want_reply, const char *authproto, + const char *authdata, int screen_number, bool oneshot) { struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc); struct ssh2_connection_state *s = c->connlayer; @@ -389,7 +389,7 @@ void ssh2channel_request_x11_forwarding( pq_push(s->ppl.out_pq, pktout); } -void ssh2channel_request_agent_forwarding(SshChannel *sc, int want_reply) +void ssh2channel_request_agent_forwarding(SshChannel *sc, bool want_reply) { struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc); struct ssh2_connection_state *s = c->connlayer; @@ -401,7 +401,7 @@ void ssh2channel_request_agent_forwarding(SshChannel *sc, int want_reply) } void ssh2channel_request_pty( - SshChannel *sc, int want_reply, Conf *conf, int w, int h) + SshChannel *sc, bool want_reply, Conf *conf, int w, int h) { struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc); struct ssh2_connection_state *s = c->connlayer; @@ -422,8 +422,8 @@ void ssh2channel_request_pty( pq_push(s->ppl.out_pq, pktout); } -int ssh2channel_send_env_var( - SshChannel *sc, int want_reply, const char *var, const char *value) +bool ssh2channel_send_env_var( + SshChannel *sc, bool want_reply, const char *var, const char *value) { struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc); struct ssh2_connection_state *s = c->connlayer; @@ -437,7 +437,7 @@ int ssh2channel_send_env_var( return true; } -int ssh2channel_send_serial_break(SshChannel *sc, int want_reply, int length) +bool ssh2channel_send_serial_break(SshChannel *sc, bool want_reply, int length) { struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc); struct ssh2_connection_state *s = c->connlayer; @@ -450,8 +450,8 @@ int ssh2channel_send_serial_break(SshChannel *sc, int want_reply, int length) return true; } -int ssh2channel_send_signal( - SshChannel *sc, int want_reply, const char *signame) +bool ssh2channel_send_signal( + SshChannel *sc, bool want_reply, const char *signame) { struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc); struct ssh2_connection_state *s = c->connlayer; diff --git a/ssh2connection-server.c b/ssh2connection-server.c index e49f591e..7cd7441a 100644 --- a/ssh2connection-server.c +++ b/ssh2connection-server.c @@ -79,7 +79,7 @@ ChanopenResult ssh2_connection_parse_channel_open( } } -int ssh2_connection_parse_global_request( +bool ssh2_connection_parse_global_request( struct ssh2_connection_state *s, ptrlen type, PktIn *pktin) { if (ptrlen_eq_string(type, "tcpip-forward")) { @@ -88,14 +88,14 @@ int ssh2_connection_parse_global_request( /* In SSH-2, the host/port we listen on are the same host/port * we want reported back to us when a connection comes in, * because that's what we tell the client */ - int toret = portfwdmgr_listen( + bool toret = portfwdmgr_listen( s->portfwdmgr, host, port, host, port, s->conf); sfree(host); return toret; } else if (ptrlen_eq_string(type, "cancel-tcpip-forward")) { char *host = mkstr(get_string(pktin)); unsigned port = get_uint32(pktin); - int toret = portfwdmgr_unlisten(s->portfwdmgr, host, port); + bool toret = portfwdmgr_unlisten(s->portfwdmgr, host, port); sfree(host); return toret; } else { @@ -200,19 +200,19 @@ SshChannel *ssh2_serverside_agent_open(ConnectionLayer *cl, Channel *chan) return &c->sc; } -void ssh2channel_start_shell(SshChannel *sc, int want_reply) +void ssh2channel_start_shell(SshChannel *sc, bool want_reply) { assert(false && "Should never be called in the server"); } void ssh2channel_start_command( - SshChannel *sc, int want_reply, const char *command) + SshChannel *sc, bool want_reply, const char *command) { assert(false && "Should never be called in the server"); } -int ssh2channel_start_subsystem( - SshChannel *sc, int want_reply, const char *subsystem) +bool ssh2channel_start_subsystem( + SshChannel *sc, bool want_reply, const char *subsystem) { assert(false && "Should never be called in the server"); } @@ -229,7 +229,7 @@ void ssh2channel_send_exit_status(SshChannel *sc, int status) } void ssh2channel_send_exit_signal( - SshChannel *sc, ptrlen signame, int core_dumped, ptrlen msg) + SshChannel *sc, ptrlen signame, bool core_dumped, ptrlen msg) { struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc); struct ssh2_connection_state *s = c->connlayer; @@ -244,7 +244,7 @@ void ssh2channel_send_exit_signal( } void ssh2channel_send_exit_signal_numeric( - SshChannel *sc, int signum, int core_dumped, ptrlen msg) + SshChannel *sc, int signum, bool core_dumped, ptrlen msg) { struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc); struct ssh2_connection_state *s = c->connlayer; @@ -259,36 +259,36 @@ void ssh2channel_send_exit_signal_numeric( } void ssh2channel_request_x11_forwarding( - SshChannel *sc, int want_reply, const char *authproto, - const char *authdata, int screen_number, int oneshot) + SshChannel *sc, bool want_reply, const char *authproto, + const char *authdata, int screen_number, bool oneshot) { assert(false && "Should never be called in the server"); } -void ssh2channel_request_agent_forwarding(SshChannel *sc, int want_reply) +void ssh2channel_request_agent_forwarding(SshChannel *sc, bool want_reply) { assert(false && "Should never be called in the server"); } void ssh2channel_request_pty( - SshChannel *sc, int want_reply, Conf *conf, int w, int h) + SshChannel *sc, bool want_reply, Conf *conf, int w, int h) { assert(false && "Should never be called in the server"); } -int ssh2channel_send_env_var( - SshChannel *sc, int want_reply, const char *var, const char *value) +bool ssh2channel_send_env_var( + SshChannel *sc, bool want_reply, const char *var, const char *value) { assert(false && "Should never be called in the server"); } -int ssh2channel_send_serial_break(SshChannel *sc, int want_reply, int length) +bool ssh2channel_send_serial_break(SshChannel *sc, bool want_reply, int length) { assert(false && "Should never be called in the server"); } -int ssh2channel_send_signal( - SshChannel *sc, int want_reply, const char *signame) +bool ssh2channel_send_signal( + SshChannel *sc, bool want_reply, const char *signame) { assert(false && "Should never be called in the server"); } diff --git a/ssh2connection.c b/ssh2connection.c index f717ae84..0be08aa6 100644 --- a/ssh2connection.c +++ b/ssh2connection.c @@ -14,11 +14,11 @@ static void ssh2_connection_free(PacketProtocolLayer *); static void ssh2_connection_process_queue(PacketProtocolLayer *); -static int ssh2_connection_get_specials( +static bool ssh2_connection_get_specials( PacketProtocolLayer *ppl, add_special_fn_t add_special, void *ctx); static void ssh2_connection_special_cmd(PacketProtocolLayer *ppl, SessionSpecialCode code, int arg); -static int ssh2_connection_want_user_input(PacketProtocolLayer *ppl); +static bool ssh2_connection_want_user_input(PacketProtocolLayer *ppl); static void ssh2_connection_got_user_input(PacketProtocolLayer *ppl); static void ssh2_connection_reconfigure(PacketProtocolLayer *ppl, Conf *conf); @@ -53,16 +53,16 @@ static void ssh2_delete_sharing_channel( static void ssh2_sharing_queue_global_request( ConnectionLayer *cl, ssh_sharing_connstate *share_ctx); static void ssh2_sharing_no_more_downstreams(ConnectionLayer *cl); -static int ssh2_agent_forwarding_permitted(ConnectionLayer *cl); +static bool ssh2_agent_forwarding_permitted(ConnectionLayer *cl); static void ssh2_terminal_size(ConnectionLayer *cl, int width, int height); static void ssh2_stdout_unthrottle(ConnectionLayer *cl, int bufsize); static int ssh2_stdin_backlog(ConnectionLayer *cl); -static void ssh2_throttle_all_channels(ConnectionLayer *cl, int throttled); -static int ssh2_ldisc_option(ConnectionLayer *cl, int option); -static void ssh2_set_ldisc_option(ConnectionLayer *cl, int option, int value); +static void ssh2_throttle_all_channels(ConnectionLayer *cl, bool throttled); +static bool ssh2_ldisc_option(ConnectionLayer *cl, int option); +static void ssh2_set_ldisc_option(ConnectionLayer *cl, int option, bool value); static void ssh2_enable_x_fwd(ConnectionLayer *cl); static void ssh2_enable_agent_fwd(ConnectionLayer *cl); -static void ssh2_set_wants_user_input(ConnectionLayer *cl, int wanted); +static void ssh2_set_wants_user_input(ConnectionLayer *cl, bool wanted); static const struct ConnectionLayerVtable ssh2_connlayer_vtable = { ssh2_rportfwd_alloc, @@ -119,7 +119,7 @@ static char *ssh2_channel_open_failure_error_text(PktIn *pktin) } static int ssh2channel_write( - SshChannel *c, int is_stderr, const void *buf, int len); + SshChannel *c, bool is_stderr, const void *buf, int len); static void ssh2channel_write_eof(SshChannel *c); static void ssh2channel_initiate_close(SshChannel *c, const char *err); static void ssh2channel_unthrottle(SshChannel *c, int bufsize); @@ -239,7 +239,7 @@ static void ssh2_channel_free(struct ssh2_channel *c) } PacketProtocolLayer *ssh2_connection_new( - Ssh *ssh, ssh_sharing_state *connshare, int is_simple, + Ssh *ssh, ssh_sharing_state *connshare, bool is_simple, Conf *conf, const char *peer_verstring, ConnectionLayer **cl_out) { struct ssh2_connection_state *s = snew(struct ssh2_connection_state); @@ -313,7 +313,7 @@ static void ssh2_connection_free(PacketProtocolLayer *ppl) sfree(s); } -static int ssh2_connection_filter_queue(struct ssh2_connection_state *s) +static bool ssh2_connection_filter_queue(struct ssh2_connection_state *s) { PktIn *pktin; PktOut *pktout; @@ -321,7 +321,7 @@ static int ssh2_connection_filter_queue(struct ssh2_connection_state *s) struct ssh2_channel *c; struct outstanding_channel_request *ocr; unsigned localid, remid, winsize, pktsize, ext_type; - int want_reply, reply_success, expect_halfopen; + bool want_reply, reply_success, expect_halfopen; ChanopenResult chanopen_result; PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */ @@ -330,7 +330,7 @@ static int ssh2_connection_filter_queue(struct ssh2_connection_state *s) * we have an instance of ssh2transport below us, then those * messages won't come here anyway, but they could if we're * running in bare ssh2-connection mode. */ - extern int ssh2_common_filter_queue(PacketProtocolLayer *ppl); + extern bool ssh2_common_filter_queue(PacketProtocolLayer *ppl); while (1) { if (ssh2_common_filter_queue(&s->ppl)) @@ -610,7 +610,7 @@ static int ssh2_connection_filter_queue(struct ssh2_connection_state *s) } else if (ptrlen_eq_string(type, "exit-signal")) { ptrlen signame; int signum; - int core = false; + bool core = false; ptrlen errmsg; int format; @@ -669,7 +669,7 @@ static int ssh2_connection_filter_queue(struct ssh2_connection_state *s) ptrlen subsys = get_string(pktin); reply_success = chan_run_subsystem(c->chan, subsys); } else if (ptrlen_eq_string(type, "x11-req")) { - int oneshot = get_bool(pktin); + bool oneshot = get_bool(pktin); ptrlen authproto = get_string(pktin); ptrlen authdata = get_string(pktin); unsigned screen_number = get_uint32(pktin); @@ -1341,13 +1341,13 @@ static void ssh2channel_unthrottle(SshChannel *sc, int bufsize) ssh2_set_window(c, buflimit - bufsize); if (c->throttling_conn && bufsize <= buflimit) { - c->throttling_conn = 0; + c->throttling_conn = false; ssh_throttle_conn(s->ppl.ssh, -1); } } static int ssh2channel_write( - SshChannel *sc, int is_stderr, const void *buf, int len) + SshChannel *sc, bool is_stderr, const void *buf, int len) { struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc); assert(!(c->closes & CLOSES_SENT_EOF)); @@ -1522,19 +1522,19 @@ static void ssh2_send_packet_from_downstream( pq_push(s->ppl.out_pq, pkt); } -static int ssh2_agent_forwarding_permitted(ConnectionLayer *cl) +static bool ssh2_agent_forwarding_permitted(ConnectionLayer *cl) { struct ssh2_connection_state *s = container_of(cl, struct ssh2_connection_state, cl); return conf_get_bool(s->conf, CONF_agentfwd) && agent_exists(); } -static int ssh2_connection_get_specials( +static bool ssh2_connection_get_specials( PacketProtocolLayer *ppl, add_special_fn_t add_special, void *ctx) { struct ssh2_connection_state *s = container_of(ppl, struct ssh2_connection_state, ppl); - int toret = false; + bool toret = false; if (s->mainchan) { mainchan_get_specials(s->mainchan, add_special, ctx); @@ -1608,7 +1608,7 @@ static int ssh2_stdin_backlog(ConnectionLayer *cl) bufchain_size(&c->outbuffer) + bufchain_size(&c->errbuffer) : 0; } -static void ssh2_throttle_all_channels(ConnectionLayer *cl, int throttled) +static void ssh2_throttle_all_channels(ConnectionLayer *cl, bool throttled) { struct ssh2_connection_state *s = container_of(cl, struct ssh2_connection_state, cl); @@ -1621,7 +1621,7 @@ static void ssh2_throttle_all_channels(ConnectionLayer *cl, int throttled) ssh2_channel_check_throttle(c); } -static int ssh2_ldisc_option(ConnectionLayer *cl, int option) +static bool ssh2_ldisc_option(ConnectionLayer *cl, int option) { struct ssh2_connection_state *s = container_of(cl, struct ssh2_connection_state, cl); @@ -1629,7 +1629,7 @@ static int ssh2_ldisc_option(ConnectionLayer *cl, int option) return s->ldisc_opts[option]; } -static void ssh2_set_ldisc_option(ConnectionLayer *cl, int option, int value) +static void ssh2_set_ldisc_option(ConnectionLayer *cl, int option, bool value) { struct ssh2_connection_state *s = container_of(cl, struct ssh2_connection_state, cl); @@ -1653,7 +1653,7 @@ static void ssh2_enable_agent_fwd(ConnectionLayer *cl) s->agent_fwd_enabled = true; } -static void ssh2_set_wants_user_input(ConnectionLayer *cl, int wanted) +static void ssh2_set_wants_user_input(ConnectionLayer *cl, bool wanted) { struct ssh2_connection_state *s = container_of(cl, struct ssh2_connection_state, cl); @@ -1661,7 +1661,7 @@ static void ssh2_set_wants_user_input(ConnectionLayer *cl, int wanted) s->want_user_input = wanted; } -static int ssh2_connection_want_user_input(PacketProtocolLayer *ppl) +static bool ssh2_connection_want_user_input(PacketProtocolLayer *ppl) { struct ssh2_connection_state *s = container_of(ppl, struct ssh2_connection_state, ppl); diff --git a/ssh2connection.h b/ssh2connection.h index 058efb57..1c70aca4 100644 --- a/ssh2connection.h +++ b/ssh2connection.h @@ -14,28 +14,28 @@ struct ssh2_connection_state { mainchan *mainchan; SshChannel *mainchan_sc; - int ldisc_opts[LD_N_OPTIONS]; + bool ldisc_opts[LD_N_OPTIONS]; int session_attempt, session_status; int term_width, term_height; - int want_user_input; + bool want_user_input; - int ssh_is_simple; - int persistent; + bool ssh_is_simple; + bool persistent; Conf *conf; tree234 *channels; /* indexed by local id */ - int all_channels_throttled; + bool all_channels_throttled; - int X11_fwd_enabled; + bool X11_fwd_enabled; tree234 *x11authtree; - int got_pty; - int agent_fwd_enabled; + bool got_pty; + bool agent_fwd_enabled; tree234 *rportfwds; PortFwdManager *portfwdmgr; - int portfwdmgr_configured; + bool portfwdmgr_configured; const SftpServerVtable *sftpserver_vt; @@ -62,7 +62,7 @@ struct ssh2_channel { unsigned remoteid, localid; int type; /* True if we opened this channel but server hasn't confirmed. */ - int halfopen; + bool halfopen; /* Bitmap of whether we've sent/received CHANNEL_EOF and * CHANNEL_CLOSE. */ @@ -80,13 +80,13 @@ struct ssh2_channel { * we set this flag instead to remind us to do so once our buffer * is clear. */ - int pending_eof; + bool pending_eof; /* * True if this channel is causing the underlying connection to be * throttled. */ - int throttling_conn; + bool throttling_conn; /* * True if we currently have backed-up data on the direction of @@ -94,7 +94,7 @@ struct ssh2_channel { * would prefer the 'Channel' implementation not to read further * local input if possible. */ - int throttled_by_backlog; + bool throttled_by_backlog; bufchain outbuffer, errbuffer; unsigned remwindow, remmaxpkt; @@ -172,28 +172,28 @@ SshChannel *ssh2_serverside_agent_open(ConnectionLayer *cl, Channel *chan); void ssh2channel_send_exit_status(SshChannel *c, int status); void ssh2channel_send_exit_signal( - SshChannel *c, ptrlen signame, int core_dumped, ptrlen msg); + SshChannel *c, ptrlen signame, bool core_dumped, ptrlen msg); void ssh2channel_send_exit_signal_numeric( - SshChannel *c, int signum, int core_dumped, ptrlen msg); + SshChannel *c, int signum, bool core_dumped, ptrlen msg); void ssh2channel_request_x11_forwarding( - SshChannel *c, int want_reply, const char *authproto, - const char *authdata, int screen_number, int oneshot); -void ssh2channel_request_agent_forwarding(SshChannel *c, int want_reply); + SshChannel *c, bool want_reply, const char *authproto, + const char *authdata, int screen_number, bool oneshot); +void ssh2channel_request_agent_forwarding(SshChannel *c, bool want_reply); void ssh2channel_request_pty( - SshChannel *c, int want_reply, Conf *conf, int w, int h); -int ssh2channel_send_env_var( - SshChannel *c, int want_reply, const char *var, const char *value); -void ssh2channel_start_shell(SshChannel *c, int want_reply); + SshChannel *c, bool want_reply, Conf *conf, int w, int h); +bool ssh2channel_send_env_var( + SshChannel *c, bool want_reply, const char *var, const char *value); +void ssh2channel_start_shell(SshChannel *c, bool want_reply); void ssh2channel_start_command( - SshChannel *c, int want_reply, const char *command); -int ssh2channel_start_subsystem( - SshChannel *c, int want_reply, const char *subsystem); -int ssh2channel_send_env_var( - SshChannel *c, int want_reply, const char *var, const char *value); -int ssh2channel_send_serial_break( - SshChannel *c, int want_reply, int length); -int ssh2channel_send_signal( - SshChannel *c, int want_reply, const char *signame); + SshChannel *c, bool want_reply, const char *command); +bool ssh2channel_start_subsystem( + SshChannel *c, bool want_reply, const char *subsystem); +bool ssh2channel_send_env_var( + SshChannel *c, bool want_reply, const char *var, const char *value); +bool ssh2channel_send_serial_break( + SshChannel *c, bool want_reply, int length); +bool ssh2channel_send_signal( + SshChannel *c, bool want_reply, const char *signame); void ssh2channel_send_terminal_size_change(SshChannel *c, int w, int h); #define CHANOPEN_RETURN_FAILURE(code, msgparams) do \ @@ -225,7 +225,7 @@ ChanopenResult ssh2_connection_parse_channel_open( struct ssh2_connection_state *s, ptrlen type, PktIn *pktin, SshChannel *sc); -int ssh2_connection_parse_global_request( +bool ssh2_connection_parse_global_request( struct ssh2_connection_state *s, ptrlen type, PktIn *pktin); #endif /* PUTTY_SSH2CONNECTION_H */ diff --git a/ssh2kex-client.c b/ssh2kex-client.c index a83f32ec..bff5b284 100644 --- a/ssh2kex-client.c +++ b/ssh2kex-client.c @@ -230,8 +230,8 @@ void ssh2kex_coroutine(struct ssh2_transport_state *s) ptrlen data; s->ppl.bpp->pls->kctx = SSH2_PKTCTX_GSSKEX; - s->init_token_sent = 0; - s->complete_rcvd = 0; + s->init_token_sent = false; + s->complete_rcvd = false; s->hkey = NULL; s->fingerprint = NULL; s->keystr = NULL; @@ -349,7 +349,7 @@ void ssh2kex_coroutine(struct ssh2_transport_state *s) s->gss_stat == SSH_GSS_S_CONTINUE_NEEDED); if (!s->init_token_sent) { - s->init_token_sent = 1; + s->init_token_sent = true; pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH2_MSG_KEXGSS_INIT); if (s->gss_sndtok.length == 0) { @@ -385,7 +385,7 @@ void ssh2kex_coroutine(struct ssh2_transport_state *s) s->gss_rcvtok.length = data.len; continue; case SSH2_MSG_KEXGSS_COMPLETE: - s->complete_rcvd = 1; + s->complete_rcvd = true; s->f = get_mp_ssh2(pktin); data = get_string(pktin); s->mic.value = (char *)data.ptr; diff --git a/ssh2transhk.c b/ssh2transhk.c index 46e2cf58..e6803c56 100644 --- a/ssh2transhk.c +++ b/ssh2transhk.c @@ -87,11 +87,11 @@ void ssh_transient_hostkey_cache_add( assert(retd == ent); } -int ssh_transient_hostkey_cache_verify( +bool ssh_transient_hostkey_cache_verify( ssh_transient_hostkey_cache *thc, ssh_key *key) { struct ssh_transient_hostkey_cache_entry *ent; - int toret = false; + bool toret = false; if ((ent = find234(thc->cache, (void *)ssh_key_alg(key), ssh_transient_hostkey_cache_find)) != NULL) { @@ -109,7 +109,7 @@ int ssh_transient_hostkey_cache_verify( return toret; } -int ssh_transient_hostkey_cache_has( +bool ssh_transient_hostkey_cache_has( ssh_transient_hostkey_cache *thc, const ssh_keyalg *alg) { struct ssh_transient_hostkey_cache_entry *ent = @@ -118,7 +118,7 @@ int ssh_transient_hostkey_cache_has( return ent != NULL; } -int ssh_transient_hostkey_cache_non_empty(ssh_transient_hostkey_cache *thc) +bool ssh_transient_hostkey_cache_non_empty(ssh_transient_hostkey_cache *thc) { return count234(thc->cache) > 0; } diff --git a/ssh2transport.c b/ssh2transport.c index 58886991..2a713413 100644 --- a/ssh2transport.c +++ b/ssh2transport.c @@ -44,11 +44,11 @@ static void ssh_comp_none_block(ssh_compressor *handle, int minlen) { } -static int ssh_decomp_none_block(ssh_decompressor *handle, - unsigned char *block, int len, - unsigned char **outblock, int *outlen) +static bool ssh_decomp_none_block(ssh_decompressor *handle, + unsigned char *block, int len, + unsigned char **outblock, int *outlen) { - return 0; + return false; } const static struct ssh_compression_alg ssh_comp_none = { "none", NULL, @@ -62,11 +62,11 @@ const static struct ssh_compression_alg *const compressions[] = { static void ssh2_transport_free(PacketProtocolLayer *); static void ssh2_transport_process_queue(PacketProtocolLayer *); -static int ssh2_transport_get_specials( +static bool ssh2_transport_get_specials( PacketProtocolLayer *ppl, add_special_fn_t add_special, void *ctx); static void ssh2_transport_special_cmd(PacketProtocolLayer *ppl, SessionSpecialCode code, int arg); -static int ssh2_transport_want_user_input(PacketProtocolLayer *ppl); +static bool ssh2_transport_want_user_input(PacketProtocolLayer *ppl); static void ssh2_transport_got_user_input(PacketProtocolLayer *ppl); static void ssh2_transport_reconfigure(PacketProtocolLayer *ppl, Conf *conf); @@ -87,11 +87,11 @@ static const struct PacketProtocolLayerVtable ssh2_transport_vtable = { #ifndef NO_GSSAPI static void ssh2_transport_gss_update(struct ssh2_transport_state *s, - int definitely_rekeying); + bool definitely_rekeying); #endif -static int ssh2_transport_timer_update(struct ssh2_transport_state *s, - unsigned long rekey_time); +static bool ssh2_transport_timer_update(struct ssh2_transport_state *s, + unsigned long rekey_time); static const char *const kexlist_descr[NKEXLIST] = { "key exchange algorithm", @@ -109,7 +109,7 @@ PacketProtocolLayer *ssh2_transport_new( const char *client_greeting, const char *server_greeting, struct ssh_connection_shared_gss_state *shgss, struct DataTransferStats *stats, PacketProtocolLayer *higher_layer, - int is_server) + bool is_server) { struct ssh2_transport_state *s = snew(struct ssh2_transport_state); memset(s, 0, sizeof(*s)); @@ -298,7 +298,7 @@ static struct kexinit_algorithm *ssh2_kexinit_addalg(struct kexinit_algorithm return NULL; } -int ssh2_common_filter_queue(PacketProtocolLayer *ppl) +bool ssh2_common_filter_queue(PacketProtocolLayer *ppl) { static const char *const ssh2_disconnect_reasons[] = { NULL, @@ -359,7 +359,7 @@ int ssh2_common_filter_queue(PacketProtocolLayer *ppl) return false; } -static int ssh2_transport_filter_queue(struct ssh2_transport_state *s) +static bool ssh2_transport_filter_queue(struct ssh2_transport_state *s) { PktIn *pktin; @@ -407,9 +407,10 @@ static void ssh2_write_kexinit_lists( const char *hk_host, int hk_port, const ssh_keyalg *hk_prev, ssh_transient_hostkey_cache *thc, ssh_key *const *our_hostkeys, int our_nhostkeys, - int first_time, int can_gssapi_keyex, int transient_hostkey_mode) + bool first_time, bool can_gssapi_keyex, bool transient_hostkey_mode) { - int i, j, k, warn; + int i, j, k; + bool warn; int n_preferred_kex; const struct ssh_kexes *preferred_kex[KEX_MAX + 1]; /* +1 for GSSAPI */ @@ -735,18 +736,18 @@ static void ssh2_write_kexinit_lists( put_stringz(pktout, ""); } -static int ssh2_scan_kexinits( +static bool ssh2_scan_kexinits( ptrlen client_kexinit, ptrlen server_kexinit, struct kexinit_algorithm kexlists[NKEXLIST][MAXKEXLIST], const struct ssh_kex **kex_alg, const ssh_keyalg **hostkey_alg, transport_direction *cs, transport_direction *sc, - int *warn_kex, int *warn_hk, int *warn_cscipher, int *warn_sccipher, - Ssh *ssh, int *ignore_guess_cs_packet, int *ignore_guess_sc_packet, + bool *warn_kex, bool *warn_hk, bool *warn_cscipher, bool *warn_sccipher, + Ssh *ssh, bool *ignore_guess_cs_packet, bool *ignore_guess_sc_packet, int *n_server_hostkeys, int server_hostkeys[MAXKEXLIST]) { BinarySource client[1], server[1]; int i; - int guess_correct; + bool guess_correct; ptrlen clists[NKEXLIST], slists[NKEXLIST]; const struct kexinit_algorithm *selected[NKEXLIST]; @@ -763,7 +764,8 @@ static int ssh2_scan_kexinits( * kexinit_algorithm structure. */ for (i = 0; i < NKEXLIST; i++) { ptrlen clist, slist, cword, sword, found; - int cfirst, sfirst, j; + bool cfirst, sfirst; + int j; clists[i] = get_string(client); slists[i] = get_string(server); @@ -1025,7 +1027,7 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) * fresh ones. */ if (!s->got_session_id && (s->gss_status & GSS_CTXT_MAYFAIL) != 0) - s->can_gssapi_keyex = 0; + s->can_gssapi_keyex = false; s->gss_delegate = conf_get_bool(s->conf, CONF_gssapifwd); } else { s->can_gssapi_keyex = false; @@ -1147,7 +1149,7 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) for (j = 0; j < s->n_uncert_hostkeys; j++) { const struct ssh_signkey_with_user_pref_id *hktype = &ssh2_hostkey_algs[s->uncert_hostkeys[j]]; - int better = false; + bool better = false; for (k = 0; k < HK_MAX; k++) { int id = conf_get_int_int(s->conf, CONF_ssh_hklist, k); if (id == HK_WARN) { @@ -1575,11 +1577,12 @@ static void ssh2_transport_timer(void *ctx, unsigned long now) /* * The rekey_time is zero except when re-configuring. * - * We either schedule the next timer and return 0, or return 1 to run the - * callback now, which will call us again to re-schedule on completion. + * We either schedule the next timer and return false, or return true + * to run the callback now, which will call us again to re-schedule on + * completion. */ -static int ssh2_transport_timer_update(struct ssh2_transport_state *s, - unsigned long rekey_time) +static bool ssh2_transport_timer_update(struct ssh2_transport_state *s, + unsigned long rekey_time) { unsigned long mins; unsigned long ticks; @@ -1598,7 +1601,7 @@ static int ssh2_transport_timer_update(struct ssh2_transport_state *s, /* If overdue, caller will rekey synchronously now */ if (now - s->last_rekey > ticks) - return 1; + return true; ticks = next - now; } @@ -1633,7 +1636,7 @@ static int ssh2_transport_timer_update(struct ssh2_transport_state *s, /* Schedule the next timer */ s->next_rekey = schedule_timer(ticks, ssh2_transport_timer, s); - return 0; + return false; } void ssh2_transport_dialog_callback(void *loginv, int ret) @@ -1658,7 +1661,7 @@ void ssh2_transport_dialog_callback(void *loginv, int ret) * newly obtained context as a proxy for the expiration of the TGT. */ static void ssh2_transport_gss_update(struct ssh2_transport_state *s, - int definitely_rekeying) + bool definitely_rekeying) { PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */ int gss_stat; @@ -1754,7 +1757,7 @@ static void ssh2_transport_gss_update(struct ssh2_transport_state *s, * refresh them. We must avoid setting GSS_CRED_UPDATED or * GSS_CTXT_EXPIRES when credential delegation is disabled. */ - if (conf_get_bool(s->conf, CONF_gssapifwd) == 0) + if (!conf_get_bool(s->conf, CONF_gssapifwd)) return; if (s->gss_cred_expiry != GSS_NO_EXPIRATION && @@ -1792,13 +1795,13 @@ void ssh2_transport_notify_auth_done(PacketProtocolLayer *ppl) #endif /* NO_GSSAPI */ -static int ssh2_transport_get_specials( +static bool ssh2_transport_get_specials( PacketProtocolLayer *ppl, add_special_fn_t add_special, void *ctx) { struct ssh2_transport_state *s = container_of(ppl, struct ssh2_transport_state, ppl); - int need_separator = false; - int toret; + bool need_separator = false; + bool toret; if (ssh_ppl_get_specials(s->higher_layer, add_special, ctx)) { need_separator = true; @@ -1884,7 +1887,7 @@ static void ssh2_transport_reconfigure(PacketProtocolLayer *ppl, Conf *conf) { struct ssh2_transport_state *s; const char *rekey_reason = NULL; - int rekey_mandatory = false; + bool rekey_mandatory = false; unsigned long old_max_data_size, rekey_time; int i; @@ -1905,8 +1908,8 @@ static void ssh2_transport_reconfigure(PacketProtocolLayer *ppl, Conf *conf) /* We must decrement both counters, so avoid short-circuit * evaluation skipping one */ - int out_expired = DTS_CONSUME(s->stats, out, diff) != 0; - int in_expired = DTS_CONSUME(s->stats, in, diff) != 0; + bool out_expired = DTS_CONSUME(s->stats, out, diff); + bool in_expired = DTS_CONSUME(s->stats, in, diff); if (out_expired || in_expired) rekey_reason = "data limit lowered"; } else { @@ -1953,7 +1956,7 @@ static void ssh2_transport_reconfigure(PacketProtocolLayer *ppl, Conf *conf) ssh_ppl_reconfigure(s->higher_layer, conf); } -static int ssh2_transport_want_user_input(PacketProtocolLayer *ppl) +static bool ssh2_transport_want_user_input(PacketProtocolLayer *ppl) { struct ssh2_transport_state *s = container_of(ppl, struct ssh2_transport_state, ppl); diff --git a/ssh2transport.h b/ssh2transport.h index a86b6ee1..de6a6fe1 100644 --- a/ssh2transport.h +++ b/ssh2transport.h @@ -29,23 +29,23 @@ struct kexinit_algorithm { union { struct { const struct ssh_kex *kex; - int warn; + bool warn; } kex; struct { const ssh_keyalg *hostkey; - int warn; + bool warn; } hk; struct { const struct ssh2_cipheralg *cipher; - int warn; + bool warn; } cipher; struct { const struct ssh2_macalg *mac; - int etm; + bool etm; } mac; struct { const struct ssh_compression_alg *comp; - int delayed; + bool delayed; } comp; } u; }; @@ -105,9 +105,9 @@ typedef enum RekeyClass { typedef struct transport_direction { const struct ssh2_cipheralg *cipher; const struct ssh2_macalg *mac; - int etm_mode; + bool etm_mode; const struct ssh_compression_alg *comp; - int comp_delayed; + bool comp_delayed; int mkkey_adjust; } transport_direction; @@ -132,7 +132,8 @@ struct ssh2_transport_state { char *hostkey_str; /* string representation, for easy checking in rekeys */ unsigned char session_id[SSH2_KEX_MAX_HASH_LEN]; int session_id_len; - int dh_min_size, dh_max_size, dh_got_size_bounds; + int dh_min_size, dh_max_size; + bool dh_got_size_bounds; struct dh_ctx *dh_ctx; ssh_hash *exhash; @@ -140,10 +141,10 @@ struct ssh2_transport_state { char *client_greeting, *server_greeting; - int kex_in_progress; + bool kex_in_progress; unsigned long next_rekey, last_rekey; const char *deferred_rekey_reason; - int higher_layer_ok; + bool higher_layer_ok; /* * Fully qualified host name, which we need if doing GSSAPI. @@ -161,9 +162,10 @@ struct ssh2_transport_state { #endif ssh_transient_hostkey_cache *thc; - int gss_kex_used; + bool gss_kex_used; - int nbits, pbits, warn_kex, warn_hk, warn_cscipher, warn_sccipher; + int nbits, pbits; + bool warn_kex, warn_hk, warn_cscipher, warn_sccipher; Bignum p, g, e, f, K; strbuf *outgoing_kexinit, *incoming_kexinit; strbuf *client_kexinit, *server_kexinit; /* aliases to the above */ @@ -176,22 +178,22 @@ struct ssh2_transport_state { struct RSAKey *rsa_kex_key; /* for RSA kex */ struct ec_key *ecdh_key; /* for ECDH kex */ unsigned char exchange_hash[SSH2_KEX_MAX_HASH_LEN]; - int can_gssapi_keyex; - int need_gss_transient_hostkey; - int warned_about_no_gss_transient_hostkey; - int got_session_id; + bool can_gssapi_keyex; + bool need_gss_transient_hostkey; + bool warned_about_no_gss_transient_hostkey; + bool got_session_id; int dlgret; - int guessok; - int ignorepkt; + bool guessok; + bool ignorepkt; struct kexinit_algorithm kexlists[NKEXLIST][MAXKEXLIST]; #ifndef NO_GSSAPI Ssh_gss_buf gss_buf; Ssh_gss_buf gss_rcvtok, gss_sndtok; Ssh_gss_stat gss_stat; Ssh_gss_buf mic; - int init_token_sent; - int complete_rcvd; - int gss_delegate; + bool init_token_sent; + bool complete_rcvd; + bool gss_delegate; #endif /* @@ -205,7 +207,7 @@ struct ssh2_transport_state { * Flag indicating that the current rekey is intended to finish * with a newly cross-certified host key. */ - int cross_certifying; + bool cross_certifying; ssh_key *const *hostkeys; int nhostkeys; diff --git a/ssh2userauth-server.c b/ssh2userauth-server.c index 685cf5c0..d28176ea 100644 --- a/ssh2userauth-server.c +++ b/ssh2userauth-server.c @@ -27,7 +27,7 @@ struct ssh2_userauth_server_state { ptrlen username, service, method; unsigned methods, this_method; - int partial_success; + bool partial_success; AuthKbdInt *aki; @@ -162,7 +162,7 @@ static void ssh2_userauth_server_process_queue(PacketProtocolLayer *ppl) if (!auth_none(s->authpolicy, s->username)) goto failure; } else if (ptrlen_eq_string(s->method, "password")) { - int changing; + bool changing; ptrlen password, new_password, *new_password_ptr; s->this_method = AUTHMETHOD_PASSWORD; @@ -192,7 +192,7 @@ static void ssh2_userauth_server_process_queue(PacketProtocolLayer *ppl) goto failure; } } else if (ptrlen_eq_string(s->method, "publickey")) { - int has_signature, success; + bool has_signature, success; ptrlen algorithm, blob, signature; const ssh_keyalg *keyalg; ssh_key *key; diff --git a/ssh2userauth.c b/ssh2userauth.c index c667ab5e..8e4b88dc 100644 --- a/ssh2userauth.c +++ b/ssh2userauth.c @@ -23,10 +23,10 @@ struct ssh2_userauth_state { PacketProtocolLayer *transport_layer, *successor_layer; Filename *keyfile; - int tryagent, change_username; + bool tryagent, change_username; char *hostname, *fullhostname; char *default_username; - int try_ki_auth, try_gssapi_auth, try_gssapi_kex_auth, gssapi_fwd; + bool try_ki_auth, try_gssapi_auth, try_gssapi_kex_auth, gssapi_fwd; ptrlen session_id; enum { @@ -39,28 +39,28 @@ struct ssh2_userauth_state { AUTH_TYPE_KEYBOARD_INTERACTIVE, AUTH_TYPE_KEYBOARD_INTERACTIVE_QUIET } type; - int need_pw, can_pubkey, can_passwd, can_keyb_inter; + bool need_pw, can_pubkey, can_passwd, can_keyb_inter; int userpass_ret; - int tried_pubkey_config, done_agent; + bool tried_pubkey_config, done_agent; struct ssh_connection_shared_gss_state *shgss; #ifndef NO_GSSAPI - int can_gssapi; - int can_gssapi_keyex_auth; - int tried_gssapi; - int tried_gssapi_keyex_auth; + bool can_gssapi; + bool can_gssapi_keyex_auth; + bool tried_gssapi; + bool tried_gssapi_keyex_auth; time_t gss_cred_expiry; Ssh_gss_buf gss_buf; Ssh_gss_buf gss_rcvtok, gss_sndtok; Ssh_gss_stat gss_stat; #endif - int kbd_inter_refused; + bool kbd_inter_refused; prompts_t *cur_prompt; int num_prompts; char *username; char *password; - int got_username; + bool got_username; strbuf *publickey_blob; - int privatekey_available, privatekey_encrypted; + bool privatekey_available, privatekey_encrypted; char *publickey_algorithm; char *publickey_comment; void *agent_response_to_free; @@ -71,7 +71,7 @@ struct ssh2_userauth_state { ptrlen pk, alg, comment; int len; PktOut *pktout; - int want_user_input; + bool want_user_input; agent_pending_query *auth_agent_query; bufchain banner; @@ -81,11 +81,11 @@ struct ssh2_userauth_state { static void ssh2_userauth_free(PacketProtocolLayer *); static void ssh2_userauth_process_queue(PacketProtocolLayer *); -static int ssh2_userauth_get_specials( +static bool ssh2_userauth_get_specials( PacketProtocolLayer *ppl, add_special_fn_t add_special, void *ctx); static void ssh2_userauth_special_cmd(PacketProtocolLayer *ppl, SessionSpecialCode code, int arg); -static int ssh2_userauth_want_user_input(PacketProtocolLayer *ppl); +static bool ssh2_userauth_want_user_input(PacketProtocolLayer *ppl); static void ssh2_userauth_got_user_input(PacketProtocolLayer *ppl); static void ssh2_userauth_reconfigure(PacketProtocolLayer *ppl, Conf *conf); @@ -114,11 +114,10 @@ static const struct PacketProtocolLayerVtable ssh2_userauth_vtable = { PacketProtocolLayer *ssh2_userauth_new( PacketProtocolLayer *successor_layer, const char *hostname, const char *fullhostname, - Filename *keyfile, int tryagent, - const char *default_username, int change_username, - int try_ki_auth, - int try_gssapi_auth, int try_gssapi_kex_auth, - int gssapi_fwd, struct ssh_connection_shared_gss_state *shgss) + Filename *keyfile, bool tryagent, + const char *default_username, bool change_username, + bool try_ki_auth, bool try_gssapi_auth, bool try_gssapi_kex_auth, + bool gssapi_fwd, struct ssh_connection_shared_gss_state *shgss) { struct ssh2_userauth_state *s = snew(struct ssh2_userauth_state); memset(s, 0, sizeof(*s)); @@ -1101,7 +1100,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) s->num_prompts = get_uint32(pktin); for (i = 0; i < s->num_prompts; i++) { ptrlen prompt; - int echo; + bool echo; static char noprompt[] = ": "; @@ -1213,7 +1212,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) /* * Plain old password authentication. */ - int changereq_first_time; /* not live over crReturn */ + bool changereq_first_time; /* not live over crReturn */ s->ppl.bpp->pls->actx = SSH2_PKTCTX_PASSWORD; @@ -1296,7 +1295,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) * Loop until the server accepts it. */ - int got_new = false; /* not live over crReturn */ + bool got_new = false; /* not live over crReturn */ ptrlen prompt; /* not live over crReturn */ { @@ -1634,7 +1633,7 @@ static PktOut *ssh2_userauth_gss_packet( } #endif -static int ssh2_userauth_get_specials( +static bool ssh2_userauth_get_specials( PacketProtocolLayer *ppl, add_special_fn_t add_special, void *ctx) { /* No specials provided by this layer. */ @@ -1647,7 +1646,7 @@ static void ssh2_userauth_special_cmd(PacketProtocolLayer *ppl, /* No specials provided by this layer. */ } -static int ssh2_userauth_want_user_input(PacketProtocolLayer *ppl) +static bool ssh2_userauth_want_user_input(PacketProtocolLayer *ppl) { struct ssh2_userauth_state *s = container_of(ppl, struct ssh2_userauth_state, ppl); diff --git a/sshaes.c b/sshaes.c index 45a9eba3..fad9ff4f 100644 --- a/sshaes.c +++ b/sshaes.c @@ -57,14 +57,14 @@ struct AESContext { void (*encrypt_cbc)(unsigned char*, int, AESContext*); void (*decrypt_cbc)(unsigned char*, int, AESContext*); void (*sdctr)(unsigned char*, int, AESContext*); - int isNI; + bool isNI; }; static void aes_encrypt_cbc_sw(unsigned char*, int, AESContext*); static void aes_decrypt_cbc_sw(unsigned char*, int, AESContext*); static void aes_sdctr_sw(unsigned char*, int, AESContext*); -INLINE static int supports_aes_ni(); +INLINE static bool supports_aes_ni(); static void aes_setup_ni(AESContext * ctx, const unsigned char *key, int keylen); @@ -1219,7 +1219,7 @@ const struct ssh2_ciphers ssh2_aes = { #if defined(__clang__) || defined(__GNUC__) #include -INLINE static int supports_aes_ni() +INLINE static bool supports_aes_ni() { unsigned int CPUInfo[4]; __cpuid(1, CPUInfo[0], CPUInfo[1], CPUInfo[2], CPUInfo[3]); @@ -1228,7 +1228,7 @@ INLINE static int supports_aes_ni() #else /* defined(__clang__) || defined(__GNUC__) */ -INLINE static int supports_aes_ni() +INLINE static bool supports_aes_ni() { unsigned int CPUInfo[4]; __cpuid(CPUInfo, 1); @@ -1755,9 +1755,9 @@ static void aes_setup_ni(AESContext * ctx, const unsigned char *key, int keylen) assert(0); } -INLINE static int supports_aes_ni() +INLINE static bool supports_aes_ni() { - return 0; + return false; } #endif /* COMPILER_SUPPORTS_AES_NI */ diff --git a/sshbn.c b/sshbn.c index 17293762..d61e3ab6 100644 --- a/sshbn.c +++ b/sshbn.c @@ -2085,7 +2085,8 @@ Bignum modinv(Bignum number, Bignum modulus) char *bignum_decimal(Bignum x) { int ndigits, ndigit; - int i, iszero; + int i; + bool iszero; BignumInt carry; char *ret; BignumInt *workspace; @@ -2130,7 +2131,7 @@ char *bignum_decimal(Bignum x) ndigit = ndigits - 1; ret[ndigit] = '\0'; do { - iszero = 1; + iszero = true; carry = 0; for (i = 0; i < (int)x[0]; i++) { /* @@ -2159,7 +2160,7 @@ char *bignum_decimal(Bignum x) carry = r; if (workspace[i]) - iszero = 0; + iszero = false; } ret[--ndigit] = (char) (carry + '0'); } while (!iszero); diff --git a/sshbpp.h b/sshbpp.h index 2b09fdea..26ff477d 100644 --- a/sshbpp.h +++ b/sshbpp.h @@ -17,7 +17,7 @@ struct BinaryPacketProtocolVtable { struct BinaryPacketProtocol { const struct BinaryPacketProtocolVtable *vt; bufchain *in_raw, *out_raw; - int input_eof; /* set this if in_raw will never be added to again */ + bool input_eof; /* set this if in_raw will never be added to again */ PktInQueue in_pq; PktOutQueue out_pq; PacketLogSettings *pls; @@ -39,7 +39,7 @@ struct BinaryPacketProtocol { * error message (either because it's not to be treated as an * error at all, or because some other error message has already * been emitted). */ - int expect_close; + bool expect_close; }; #define ssh_bpp_handle_input(bpp) ((bpp)->vt->handle_input(bpp)) @@ -68,7 +68,7 @@ void ssh_bpp_common_setup(BinaryPacketProtocol *); /* Common helper functions between the SSH-2 full and bare BPPs */ void ssh2_bpp_queue_disconnect(BinaryPacketProtocol *bpp, const char *msg, int category); -int ssh2_bpp_check_unimplemented(BinaryPacketProtocol *bpp, PktIn *pktin); +bool ssh2_bpp_check_unimplemented(BinaryPacketProtocol *bpp, PktIn *pktin); /* Convenience macro for BPPs to send formatted strings to the Event * Log. Assumes a function parameter called 'bpp' is in scope, and @@ -92,7 +92,7 @@ int ssh2_bpp_check_unimplemented(BinaryPacketProtocol *bpp, PktIn *pktin); */ struct DataTransferStats { struct { - int running; + bool running; unsigned long remaining; } in, out; }; @@ -103,17 +103,17 @@ struct DataTransferStats { ((stats)->direction.remaining -= (size), false)) BinaryPacketProtocol *ssh2_bpp_new( - LogContext *logctx, struct DataTransferStats *stats, int is_server); + LogContext *logctx, struct DataTransferStats *stats, bool is_server); void ssh2_bpp_new_outgoing_crypto( BinaryPacketProtocol *bpp, const struct ssh2_cipheralg *cipher, const void *ckey, const void *iv, - const struct ssh2_macalg *mac, int etm_mode, const void *mac_key, - const struct ssh_compression_alg *compression, int delayed_compression); + const struct ssh2_macalg *mac, bool etm_mode, const void *mac_key, + const struct ssh_compression_alg *compression, bool delayed_compression); void ssh2_bpp_new_incoming_crypto( BinaryPacketProtocol *bpp, const struct ssh2_cipheralg *cipher, const void *ckey, const void *iv, - const struct ssh2_macalg *mac, int etm_mode, const void *mac_key, - const struct ssh_compression_alg *compression, int delayed_compression); + const struct ssh2_macalg *mac, bool etm_mode, const void *mac_key, + const struct ssh_compression_alg *compression, bool delayed_compression); /* * A query method specific to the interface between ssh2transport and @@ -124,7 +124,7 @@ void ssh2_bpp_new_incoming_crypto( * to start a rekey because then we'd stop responding to anything * _other_ than transport-layer packets and deadlock the protocol. */ -int ssh2_bpp_rekey_inadvisable(BinaryPacketProtocol *bpp); +bool ssh2_bpp_rekey_inadvisable(BinaryPacketProtocol *bpp); BinaryPacketProtocol *ssh2_bare_bpp_new(LogContext *logctx); @@ -139,9 +139,9 @@ struct ssh_version_receiver { int major_version); }; BinaryPacketProtocol *ssh_verstring_new( - Conf *conf, LogContext *logctx, int bare_connection_mode, + Conf *conf, LogContext *logctx, bool bare_connection_mode, const char *protoversion, struct ssh_version_receiver *rcv, - int server_mode, const char *impl_name); + bool server_mode, const char *impl_name); const char *ssh_verstring_get_remote(BinaryPacketProtocol *); const char *ssh_verstring_get_local(BinaryPacketProtocol *); int ssh_verstring_get_bugs(BinaryPacketProtocol *); diff --git a/sshchan.h b/sshchan.h index dd82fd63..9ec256d6 100644 --- a/sshchan.h +++ b/sshchan.h @@ -19,42 +19,42 @@ struct ChannelVtable { void (*open_confirmation)(Channel *); void (*open_failed)(Channel *, const char *error_text); - int (*send)(Channel *, int is_stderr, const void *buf, int len); + int (*send)(Channel *, bool is_stderr, const void *buf, int len); void (*send_eof)(Channel *); - void (*set_input_wanted)(Channel *, int wanted); + void (*set_input_wanted)(Channel *, bool wanted); char *(*log_close_msg)(Channel *); - int (*want_close)(Channel *, int sent_local_eof, int rcvd_remote_eof); + bool (*want_close)(Channel *, bool sent_local_eof, bool rcvd_remote_eof); /* A method for every channel request we know of. All of these * return true for success or false for failure. */ - int (*rcvd_exit_status)(Channel *, int status); - int (*rcvd_exit_signal)( - Channel *chan, ptrlen signame, int core_dumped, ptrlen msg); - int (*rcvd_exit_signal_numeric)( - Channel *chan, int signum, int core_dumped, ptrlen msg); - int (*run_shell)(Channel *chan); - int (*run_command)(Channel *chan, ptrlen command); - int (*run_subsystem)(Channel *chan, ptrlen subsys); - int (*enable_x11_forwarding)( - Channel *chan, int oneshot, ptrlen authproto, ptrlen authdata, + bool (*rcvd_exit_status)(Channel *, int status); + bool (*rcvd_exit_signal)( + Channel *chan, ptrlen signame, bool core_dumped, ptrlen msg); + bool (*rcvd_exit_signal_numeric)( + Channel *chan, int signum, bool core_dumped, ptrlen msg); + bool (*run_shell)(Channel *chan); + bool (*run_command)(Channel *chan, ptrlen command); + bool (*run_subsystem)(Channel *chan, ptrlen subsys); + bool (*enable_x11_forwarding)( + Channel *chan, bool oneshot, ptrlen authproto, ptrlen authdata, unsigned screen_number); - int (*enable_agent_forwarding)(Channel *chan); - int (*allocate_pty)( + bool (*enable_agent_forwarding)(Channel *chan); + bool (*allocate_pty)( Channel *chan, ptrlen termtype, unsigned width, unsigned height, unsigned pixwidth, unsigned pixheight, struct ssh_ttymodes modes); - int (*set_env)(Channel *chan, ptrlen var, ptrlen value); - int (*send_break)(Channel *chan, unsigned length); - int (*send_signal)(Channel *chan, ptrlen signame); - int (*change_window_size)( + bool (*set_env)(Channel *chan, ptrlen var, ptrlen value); + bool (*send_break)(Channel *chan, unsigned length); + bool (*send_signal)(Channel *chan, ptrlen signame); + bool (*change_window_size)( Channel *chan, unsigned width, unsigned height, unsigned pixwidth, unsigned pixheight); /* A method for signalling success/failure responses to channel * requests initiated from the SshChannel vtable with want_reply * true. */ - void (*request_response)(Channel *, int success); + void (*request_response)(Channel *, bool success); }; struct Channel { @@ -111,31 +111,31 @@ void chan_remotely_opened_failure(Channel *chan, const char *errtext); /* want_close for any channel that wants the default behaviour of not * closing until both directions have had an EOF */ -int chan_default_want_close(Channel *, int, int); +bool chan_default_want_close(Channel *, bool, bool); /* default implementations that refuse all the channel requests */ -int chan_no_exit_status(Channel *, int); -int chan_no_exit_signal(Channel *, ptrlen, int, ptrlen); -int chan_no_exit_signal_numeric(Channel *, int, int, ptrlen); -int chan_no_run_shell(Channel *chan); -int chan_no_run_command(Channel *chan, ptrlen command); -int chan_no_run_subsystem(Channel *chan, ptrlen subsys); -int chan_no_enable_x11_forwarding( - Channel *chan, int oneshot, ptrlen authproto, ptrlen authdata, +bool chan_no_exit_status(Channel *, int); +bool chan_no_exit_signal(Channel *, ptrlen, bool, ptrlen); +bool chan_no_exit_signal_numeric(Channel *, int, bool, ptrlen); +bool chan_no_run_shell(Channel *chan); +bool chan_no_run_command(Channel *chan, ptrlen command); +bool chan_no_run_subsystem(Channel *chan, ptrlen subsys); +bool chan_no_enable_x11_forwarding( + Channel *chan, bool oneshot, ptrlen authproto, ptrlen authdata, unsigned screen_number); -int chan_no_enable_agent_forwarding(Channel *chan); -int chan_no_allocate_pty( +bool chan_no_enable_agent_forwarding(Channel *chan); +bool chan_no_allocate_pty( Channel *chan, ptrlen termtype, unsigned width, unsigned height, unsigned pixwidth, unsigned pixheight, struct ssh_ttymodes modes); -int chan_no_set_env(Channel *chan, ptrlen var, ptrlen value); -int chan_no_send_break(Channel *chan, unsigned length); -int chan_no_send_signal(Channel *chan, ptrlen signame); -int chan_no_change_window_size( +bool chan_no_set_env(Channel *chan, ptrlen var, ptrlen value); +bool chan_no_send_break(Channel *chan, unsigned length); +bool chan_no_send_signal(Channel *chan, ptrlen signame); +bool chan_no_change_window_size( Channel *chan, unsigned width, unsigned height, unsigned pixwidth, unsigned pixheight); /* default implementation that never expects to receive a response */ -void chan_no_request_response(Channel *, int); +void chan_no_request_response(Channel *, bool); /* * Constructor for a trivial do-nothing implementation of @@ -156,7 +156,7 @@ Channel *zombiechan_new(void); */ struct SshChannelVtable { - int (*write)(SshChannel *c, int is_stderr, const void *, int); + int (*write)(SshChannel *c, bool is_stderr, const void *, int); void (*write_eof)(SshChannel *c); void (*initiate_close)(SshChannel *c, const char *err); void (*unthrottle)(SshChannel *c, int bufsize); @@ -174,7 +174,7 @@ struct SshChannelVtable { * want_reply flag, which will cause a callback to * chan_request_response when the result is available. * - * The ones that return 'int' use it to indicate that the SSH + * The ones that return 'bool' use it to indicate that the SSH * protocol in use doesn't support this request at all. * * (It's also intentional that not all of them have a want_reply @@ -185,28 +185,28 @@ struct SshChannelVtable { */ void (*send_exit_status)(SshChannel *c, int status); void (*send_exit_signal)( - SshChannel *c, ptrlen signame, int core_dumped, ptrlen msg); + SshChannel *c, ptrlen signame, bool core_dumped, ptrlen msg); void (*send_exit_signal_numeric)( - SshChannel *c, int signum, int core_dumped, ptrlen msg); + SshChannel *c, int signum, bool core_dumped, ptrlen msg); void (*request_x11_forwarding)( - SshChannel *c, int want_reply, const char *authproto, - const char *authdata, int screen_number, int oneshot); + SshChannel *c, bool want_reply, const char *authproto, + const char *authdata, int screen_number, bool oneshot); void (*request_agent_forwarding)( - SshChannel *c, int want_reply); + SshChannel *c, bool want_reply); void (*request_pty)( - SshChannel *c, int want_reply, Conf *conf, int w, int h); - int (*send_env_var)( - SshChannel *c, int want_reply, const char *var, const char *value); + SshChannel *c, bool want_reply, Conf *conf, int w, int h); + bool (*send_env_var)( + SshChannel *c, bool want_reply, const char *var, const char *value); void (*start_shell)( - SshChannel *c, int want_reply); + SshChannel *c, bool want_reply); void (*start_command)( - SshChannel *c, int want_reply, const char *command); - int (*start_subsystem)( - SshChannel *c, int want_reply, const char *subsystem); - int (*send_serial_break)( - SshChannel *c, int want_reply, int length); /* length=0 for default */ - int (*send_signal)( - SshChannel *c, int want_reply, const char *signame); + SshChannel *c, bool want_reply, const char *command); + bool (*start_subsystem)( + SshChannel *c, bool want_reply, const char *subsystem); + bool (*send_serial_break)( + SshChannel *c, bool want_reply, int length); /* length=0 for default */ + bool (*send_signal)( + SshChannel *c, bool want_reply, const char *signame); void (*send_terminal_size_change)( SshChannel *c, int w, int h); void (*hint_channel_is_simple)(SshChannel *c); @@ -265,7 +265,7 @@ struct SshChannel { mainchan *mainchan_new( PacketProtocolLayer *ppl, ConnectionLayer *cl, Conf *conf, - int term_width, int term_height, int is_simple, SshChannel **sc_out); + int term_width, int term_height, bool is_simple, SshChannel **sc_out); void mainchan_get_specials( mainchan *mc, add_special_fn_t add_special, void *ctx); void mainchan_special_cmd(mainchan *mc, SessionSpecialCode code, int arg); diff --git a/sshcommon.c b/sshcommon.c index 4f3622a7..563e4130 100644 --- a/sshcommon.c +++ b/sshcommon.c @@ -72,7 +72,7 @@ static IdempotentCallback ic_pktin_free = { }; static PktIn *pq_in_after(PacketQueueBase *pqb, - PacketQueueNode *prev, int pop) + PacketQueueNode *prev, bool pop) { PacketQueueNode *node = prev->next; if (node == &pqb->end) @@ -94,7 +94,7 @@ static PktIn *pq_in_after(PacketQueueBase *pqb, } static PktOut *pq_out_after(PacketQueueBase *pqb, - PacketQueueNode *prev, int pop) + PacketQueueNode *prev, bool pop) { PacketQueueNode *node = prev->next; if (node == &pqb->end) @@ -261,11 +261,11 @@ void ssh_free_pktout(PktOut *pkt) */ static void zombiechan_free(Channel *chan); -static int zombiechan_send(Channel *chan, int is_stderr, const void *, int); -static void zombiechan_set_input_wanted(Channel *chan, int wanted); +static int zombiechan_send(Channel *chan, bool is_stderr, const void *, int); +static void zombiechan_set_input_wanted(Channel *chan, bool wanted); static void zombiechan_do_nothing(Channel *chan); static void zombiechan_open_failure(Channel *chan, const char *); -static int zombiechan_want_close(Channel *chan, int sent_eof, int rcvd_eof); +static bool zombiechan_want_close(Channel *chan, bool sent_eof, bool rcvd_eof); static char *zombiechan_log_close_msg(Channel *chan) { return NULL; } static const struct ChannelVtable zombiechan_channelvt = { @@ -317,19 +317,19 @@ static void zombiechan_open_failure(Channel *chan, const char *errtext) assert(chan->vt == &zombiechan_channelvt); } -static int zombiechan_send(Channel *chan, int is_stderr, +static int zombiechan_send(Channel *chan, bool is_stderr, const void *data, int length) { assert(chan->vt == &zombiechan_channelvt); return 0; } -static void zombiechan_set_input_wanted(Channel *chan, int enable) +static void zombiechan_set_input_wanted(Channel *chan, bool enable) { assert(chan->vt == &zombiechan_channelvt); } -static int zombiechan_want_close(Channel *chan, int sent_eof, int rcvd_eof) +static bool zombiechan_want_close(Channel *chan, bool sent_eof, bool rcvd_eof) { return true; } @@ -349,8 +349,8 @@ void chan_remotely_opened_failure(Channel *chan, const char *errtext) assert(0 && "this channel type should never receive OPEN_FAILURE"); } -int chan_default_want_close( - Channel *chan, int sent_local_eof, int rcvd_remote_eof) +bool chan_default_want_close( + Channel *chan, bool sent_local_eof, bool rcvd_remote_eof) { /* * Default close policy: we start initiating the CHANNEL_CLOSE @@ -359,80 +359,80 @@ int chan_default_want_close( return sent_local_eof && rcvd_remote_eof; } -int chan_no_exit_status(Channel *chan, int status) +bool chan_no_exit_status(Channel *chan, int status) { return false; } -int chan_no_exit_signal( - Channel *chan, ptrlen signame, int core_dumped, ptrlen msg) +bool chan_no_exit_signal( + Channel *chan, ptrlen signame, bool core_dumped, ptrlen msg) { return false; } -int chan_no_exit_signal_numeric( - Channel *chan, int signum, int core_dumped, ptrlen msg) +bool chan_no_exit_signal_numeric( + Channel *chan, int signum, bool core_dumped, ptrlen msg) { return false; } -int chan_no_run_shell(Channel *chan) +bool chan_no_run_shell(Channel *chan) { return false; } -int chan_no_run_command(Channel *chan, ptrlen command) +bool chan_no_run_command(Channel *chan, ptrlen command) { return false; } -int chan_no_run_subsystem(Channel *chan, ptrlen subsys) +bool chan_no_run_subsystem(Channel *chan, ptrlen subsys) { return false; } -int chan_no_enable_x11_forwarding( - Channel *chan, int oneshot, ptrlen authproto, ptrlen authdata, +bool chan_no_enable_x11_forwarding( + Channel *chan, bool oneshot, ptrlen authproto, ptrlen authdata, unsigned screen_number) { return false; } -int chan_no_enable_agent_forwarding(Channel *chan) +bool chan_no_enable_agent_forwarding(Channel *chan) { return false; } -int chan_no_allocate_pty( +bool chan_no_allocate_pty( Channel *chan, ptrlen termtype, unsigned width, unsigned height, unsigned pixwidth, unsigned pixheight, struct ssh_ttymodes modes) { return false; } -int chan_no_set_env(Channel *chan, ptrlen var, ptrlen value) +bool chan_no_set_env(Channel *chan, ptrlen var, ptrlen value) { return false; } -int chan_no_send_break(Channel *chan, unsigned length) +bool chan_no_send_break(Channel *chan, unsigned length) { return false; } -int chan_no_send_signal(Channel *chan, ptrlen signame) +bool chan_no_send_signal(Channel *chan, ptrlen signame) { return false; } -int chan_no_change_window_size( +bool chan_no_change_window_size( Channel *chan, unsigned width, unsigned height, unsigned pixwidth, unsigned pixheight) { return false; } -void chan_no_request_response(Channel *chan, int success) +void chan_no_request_response(Channel *chan, bool success) { assert(0 && "this channel type should never send a want-reply request"); } @@ -687,12 +687,12 @@ unsigned alloc_channel_id_general(tree234 *channels, size_t localid_offset) * lists of protocol identifiers in SSH-2. */ -int first_in_commasep_string(char const *needle, char const *haystack, - int haylen) +bool first_in_commasep_string(char const *needle, char const *haystack, + int haylen) { int needlen; if (!needle || !haystack) /* protect against null pointers */ - return 0; + return false; needlen = strlen(needle); if (haylen >= needlen && /* haystack is long enough */ @@ -700,11 +700,11 @@ int first_in_commasep_string(char const *needle, char const *haystack, (haylen == needlen || haystack[needlen] == ',') /* either , or EOS follows */ ) - return 1; - return 0; + return true; + return false; } -int in_commasep_string(char const *needle, char const *haystack, int haylen) +bool in_commasep_string(char const *needle, char const *haystack, int haylen) { char *p; @@ -733,7 +733,7 @@ void add_to_commasep(strbuf *buf, const char *data) put_data(buf, data, strlen(data)); } -int get_commasep_word(ptrlen *list, ptrlen *word) +bool get_commasep_word(ptrlen *list, ptrlen *word) { const char *comma; @@ -905,7 +905,7 @@ void ssh2_bpp_queue_disconnect(BinaryPacketProtocol *bpp, (0 SSH2_MESSAGE_TYPES(BITMAP_UNIVERSAL, BITMAP_CONDITIONAL, \ BITMAP_CONDITIONAL, (32*y))) -int ssh2_bpp_check_unimplemented(BinaryPacketProtocol *bpp, PktIn *pktin) +bool ssh2_bpp_check_unimplemented(BinaryPacketProtocol *bpp, PktIn *pktin) { static const unsigned valid_bitmap[] = { SSH2_BITMAP_WORD(0), @@ -992,7 +992,7 @@ int verify_ssh_manual_host_key( * Common functions shared between SSH-1 layers. */ -int ssh1_common_get_specials( +bool ssh1_common_get_specials( PacketProtocolLayer *ppl, add_special_fn_t add_special, void *ctx) { /* @@ -1008,7 +1008,7 @@ int ssh1_common_get_specials( return false; } -int ssh1_common_filter_queue(PacketProtocolLayer *ppl) +bool ssh1_common_filter_queue(PacketProtocolLayer *ppl) { PktIn *pktin; ptrlen msg; diff --git a/sshcrcda.c b/sshcrcda.c index 2813ceed..ddc70ab8 100644 --- a/sshcrcda.c +++ b/sshcrcda.c @@ -75,7 +75,7 @@ static void crc_update(uint32_t *a, void *b) } /* detect if a block is used in a particular pattern */ -static int check_crc(uint8_t *S, uint8_t *buf, uint32_t len, uint8_t *IV) +static bool check_crc(uint8_t *S, uint8_t *buf, uint32_t len, uint8_t *IV) { uint32_t crc; uint8_t *c; @@ -98,7 +98,7 @@ static int check_crc(uint8_t *S, uint8_t *buf, uint32_t len, uint8_t *IV) } /* Detect a crc32 compensation attack on a packet */ -int detect_attack( +bool detect_attack( struct crcda_ctx *ctx, uint8_t *buf, uint32_t len, uint8_t *IV) { register uint32_t i, j; @@ -125,20 +125,20 @@ int detect_attack( for (c = buf; c < buf + len; c += SSH_BLOCKSIZE) { if (IV && (!CMP(c, IV))) { if ((check_crc(c, buf, len, IV))) - return 1; /* attack detected */ + return true; /* attack detected */ else break; } for (d = buf; d < c; d += SSH_BLOCKSIZE) { if (!CMP(c, d)) { if ((check_crc(c, buf, len, IV))) - return 1; /* attack detected */ + return true; /* attack detected */ else break; } } } - return 0; /* ok */ + return false; /* ok */ } memset(ctx->h, HASH_UNUSEDCHAR, ctx->n * HASH_ENTRYSIZE); @@ -151,18 +151,18 @@ int detect_attack( if (ctx->h[i] == HASH_IV) { if (!CMP(c, IV)) { if (check_crc(c, buf, len, IV)) - return 1; /* attack detected */ + return true; /* attack detected */ else break; } } else if (!CMP(c, buf + ctx->h[i] * SSH_BLOCKSIZE)) { if (check_crc(c, buf, len, IV)) - return 1; /* attack detected */ + return true; /* attack detected */ else break; } } ctx->h[i] = j; } - return 0; /* ok */ + return false; /* ok */ } diff --git a/sshdh.c b/sshdh.c index c18da320..84173e80 100644 --- a/sshdh.c +++ b/sshdh.c @@ -178,7 +178,7 @@ static void dh_init(struct dh_ctx *ctx) ctx->x = ctx->e = NULL; } -int dh_is_gex(const struct ssh_kex *kex) +bool dh_is_gex(const struct ssh_kex *kex) { const struct dh_extra *extra = (const struct dh_extra *)kex->extra; return extra->pdata == NULL; diff --git a/sshdss.c b/sshdss.c index 3aa462b8..1ed1a2ad 100644 --- a/sshdss.c +++ b/sshdss.c @@ -104,16 +104,16 @@ static char *dss_cache_str(ssh_key *key) return p; } -static int dss_verify(ssh_key *key, ptrlen sig, ptrlen data) +static bool dss_verify(ssh_key *key, ptrlen sig, ptrlen data) { struct dss_key *dss = container_of(key, struct dss_key, sshk); BinarySource src[1]; unsigned char hash[20]; Bignum r, s, w, gu1p, yu2p, gu1yu2p, u1, u2, sha, v; - int ret; + bool toret; if (!dss->p) - return 0; + return false; BinarySource_BARE_INIT(src, sig.ptr, sig.len); @@ -134,7 +134,7 @@ static int dss_verify(ssh_key *key, ptrlen sig, ptrlen data) if (get_err(src) || !ptrlen_eq_string(type, "ssh-dss") || sig.len != 40) - return 0; + return false; } /* Now we're sitting on a 40-byte string for sure. */ @@ -145,13 +145,13 @@ static int dss_verify(ssh_key *key, ptrlen sig, ptrlen data) freebn(r); if (s) freebn(s); - return 0; + return false; } if (!bignum_cmp(s, Zero)) { freebn(r); freebn(s); - return 0; + return false; } /* @@ -161,7 +161,7 @@ static int dss_verify(ssh_key *key, ptrlen sig, ptrlen data) if (!w) { freebn(r); freebn(s); - return 0; + return false; } /* @@ -188,7 +188,7 @@ static int dss_verify(ssh_key *key, ptrlen sig, ptrlen data) * Step 5. v should now be equal to r. */ - ret = !bignum_cmp(v, r); + toret = !bignum_cmp(v, r); freebn(w); freebn(sha); @@ -201,7 +201,7 @@ static int dss_verify(ssh_key *key, ptrlen sig, ptrlen data) freebn(r); freebn(s); - return ret; + return toret; } static void dss_public_blob(ssh_key *key, BinarySink *bs) diff --git a/sshecc.c b/sshecc.c index 13e432e2..947b64a9 100644 --- a/sshecc.c +++ b/sshecc.c @@ -64,7 +64,7 @@ static void initialise_wcurve(struct ec_curve *curve, int bits, curve->w.G.x = bignum_from_bytes(Gx, length); curve->w.G.y = bignum_from_bytes(Gy, length); curve->w.G.curve = curve; - curve->w.G.infinity = 0; + curve->w.G.infinity = false; } static void initialise_mcurve(struct ec_curve *curve, int bits, @@ -89,7 +89,7 @@ static void initialise_mcurve(struct ec_curve *curve, int bits, curve->m.G.y = NULL; curve->m.G.z = NULL; curve->m.G.curve = curve; - curve->m.G.infinity = 0; + curve->m.G.infinity = false; } static void initialise_ecurve(struct ec_curve *curve, int bits, @@ -113,13 +113,13 @@ static void initialise_ecurve(struct ec_curve *curve, int bits, curve->e.B.x = bignum_from_bytes(Bx, length); curve->e.B.y = bignum_from_bytes(By, length); curve->e.B.curve = curve; - curve->e.B.infinity = 0; + curve->e.B.infinity = false; } static struct ec_curve *ec_p256(void) { static struct ec_curve curve = { 0 }; - static unsigned char initialised = 0; + static bool initialised = false; if (!initialised) { @@ -164,7 +164,7 @@ static struct ec_curve *ec_p256(void) curve.textname = curve.name = "nistp256"; /* Now initialised, no need to do it again */ - initialised = 1; + initialised = true; } return &curve; @@ -173,7 +173,7 @@ static struct ec_curve *ec_p256(void) static struct ec_curve *ec_p384(void) { static struct ec_curve curve = { 0 }; - static unsigned char initialised = 0; + static bool initialised = false; if (!initialised) { @@ -230,7 +230,7 @@ static struct ec_curve *ec_p384(void) curve.textname = curve.name = "nistp384"; /* Now initialised, no need to do it again */ - initialised = 1; + initialised = true; } return &curve; @@ -239,7 +239,7 @@ static struct ec_curve *ec_p384(void) static struct ec_curve *ec_p521(void) { static struct ec_curve curve = { 0 }; - static unsigned char initialised = 0; + static bool initialised = false; if (!initialised) { @@ -314,7 +314,7 @@ static struct ec_curve *ec_p521(void) curve.textname = curve.name = "nistp521"; /* Now initialised, no need to do it again */ - initialised = 1; + initialised = true; } return &curve; @@ -323,7 +323,7 @@ static struct ec_curve *ec_p521(void) static struct ec_curve *ec_curve25519(void) { static struct ec_curve curve = { 0 }; - static unsigned char initialised = 0; + static bool initialised = false; if (!initialised) { @@ -359,7 +359,7 @@ static struct ec_curve *ec_curve25519(void) curve.textname = "Curve25519"; /* Now initialised, no need to do it again */ - initialised = 1; + initialised = true; } return &curve; @@ -368,7 +368,7 @@ static struct ec_curve *ec_curve25519(void) static struct ec_curve *ec_ed25519(void) { static struct ec_curve curve = { 0 }; - static unsigned char initialised = 0; + static bool initialised = false; if (!initialised) { @@ -411,7 +411,7 @@ static struct ec_curve *ec_ed25519(void) curve.textname = "Ed25519"; /* Now initialised, no need to do it again */ - initialised = 1; + initialised = true; } return &curve; @@ -419,13 +419,13 @@ static struct ec_curve *ec_ed25519(void) /* Return 1 if a is -3 % p, otherwise return 0 * This is used because there are some maths optimisations */ -static int ec_aminus3(const struct ec_curve *curve) +static bool ec_aminus3(const struct ec_curve *curve) { - int ret; + bool ret; Bignum _p; if (curve->type != EC_WEIERSTRASS) { - return 0; + return false; } _p = bignum_add_long(curve->w.a, 3); @@ -512,20 +512,20 @@ void ec_point_free(struct ec_point *point) if (point->x) freebn(point->x); if (point->y) freebn(point->y); if (point->z) freebn(point->z); - point->infinity = 0; + point->infinity = false; sfree(point); } static struct ec_point *ec_point_new(const struct ec_curve *curve, const Bignum x, const Bignum y, const Bignum z, - unsigned char infinity) + bool infinity) { struct ec_point *point = snewn(1, struct ec_point); point->curve = curve; point->x = x; point->y = y; point->z = z; - point->infinity = infinity ? 1 : 0; + point->infinity = infinity; return point; } @@ -539,14 +539,14 @@ static struct ec_point *ec_point_copy(const struct ec_point *a) a->infinity); } -static int ec_point_verify(const struct ec_point *a) +static bool ec_point_verify(const struct ec_point *a) { if (a->infinity) { - return 1; + return true; } else if (a->curve->type == EC_EDWARDS) { /* Check y^2 - x^2 - 1 - d * x^2 * y^2 == 0 */ Bignum y2, x2, tmp, tmp2, tmp3; - int ret; + bool ret; y2 = ecf_square(a->y, a->curve); x2 = ecf_square(a->x, a->curve); @@ -564,7 +564,7 @@ static int ec_point_verify(const struct ec_point *a) return ret; } else if (a->curve->type == EC_WEIERSTRASS) { /* Verify y^2 = x^3 + ax + b */ - int ret = 0; + bool ret = false; Bignum lhs = NULL, x3 = NULL, ax = NULL, x3ax = NULL, x3axm = NULL, x3axb = NULL, rhs = NULL; @@ -586,13 +586,13 @@ static int ec_point_verify(const struct ec_point *a) rhs = bigmod(x3axb, a->curve->p); freebn(x3axb); - ret = bignum_cmp(lhs, rhs) ? 0 : 1; + ret = !bignum_cmp(lhs, rhs); freebn(lhs); freebn(rhs); return ret; } else { - return 0; + return false; } } @@ -600,17 +600,17 @@ static int ec_point_verify(const struct ec_point *a) * Elliptic curve point maths */ -/* Returns 1 on success and 0 on memory error */ -static int ecp_normalise(struct ec_point *a) +/* Returns true on success and false on memory error */ +static bool ecp_normalise(struct ec_point *a) { if (!a) { /* No point */ - return 0; + return false; } if (a->infinity) { /* Point is at infinity - i.e. normalised */ - return 1; + return true; } if (a->curve->type == EC_WEIERSTRASS) { @@ -621,17 +621,17 @@ static int ecp_normalise(struct ec_point *a) if (!a->x || !a->y) { /* No point defined */ - return 0; + return false; } else if (!a->z) { /* Already normalised */ - return 1; + return true; } Z2 = ecf_square(a->z, a->curve); Z2inv = modinv(Z2, a->curve->p); if (!Z2inv) { freebn(Z2); - return 0; + return false; } tx = modmul(a->x, Z2inv, a->curve->p); freebn(Z2inv); @@ -642,7 +642,7 @@ static int ecp_normalise(struct ec_point *a) freebn(Z3); if (!Z3inv) { freebn(tx); - return 0; + return false; } ty = modmul(a->y, Z3inv, a->curve->p); freebn(Z3inv); @@ -653,7 +653,7 @@ static int ecp_normalise(struct ec_point *a) a->y = ty; freebn(a->z); a->z = NULL; - return 1; + return true; } else if (a->curve->type == EC_MONTGOMERY) { /* In Montgomery (X : Z) represents the x co-ord (X / Z, ?) */ @@ -661,15 +661,15 @@ static int ecp_normalise(struct ec_point *a) if (!a->x) { /* No point defined */ - return 0; + return false; } else if (!a->z) { /* Already normalised */ - return 1; + return true; } tmp = modinv(a->z, a->curve->p); if (!tmp) { - return 0; + return false; } tmp2 = modmul(a->x, tmp, a->curve->p); freebn(tmp); @@ -678,23 +678,23 @@ static int ecp_normalise(struct ec_point *a) a->z = NULL; freebn(a->x); a->x = tmp2; - return 1; + return true; } else if (a->curve->type == EC_EDWARDS) { /* Always normalised */ - return 1; + return true; } else { - return 0; + return false; } } -static struct ec_point *ecp_doublew(const struct ec_point *a, const int aminus3) +static struct ec_point *ecp_doublew(const struct ec_point *a, bool aminus3) { Bignum S, M, outx, outy, outz; if (bignum_cmp(a->y, Zero) == 0) { /* Identity */ - return ec_point_new(a->curve, NULL, NULL, NULL, 1); + return ec_point_new(a->curve, NULL, NULL, NULL, true); } /* S = 4*X*Y^2 */ @@ -802,7 +802,7 @@ static struct ec_point *ecp_doublew(const struct ec_point *a, const int aminus3) freebn(YZ); } - return ec_point_new(a->curve, outx, outy, outz, 0); + return ec_point_new(a->curve, outx, outy, outz, false); } static struct ec_point *ecp_doublem(const struct ec_point *a) @@ -865,20 +865,20 @@ static struct ec_point *ecp_doublem(const struct ec_point *a) freebn(tmp); } - return ec_point_new(a->curve, outx, NULL, outz, 0); + return ec_point_new(a->curve, outx, NULL, outz, false); } /* Forward declaration for Edwards curve doubling */ static struct ec_point *ecp_add(const struct ec_point *a, const struct ec_point *b, - const int aminus3); + bool aminus3); -static struct ec_point *ecp_double(const struct ec_point *a, const int aminus3) +static struct ec_point *ecp_double(const struct ec_point *a, bool aminus3) { if (a->infinity) { /* Identity */ - return ec_point_new(a->curve, NULL, NULL, NULL, 1); + return ec_point_new(a->curve, NULL, NULL, NULL, true); } if (a->curve->type == EC_EDWARDS) @@ -897,7 +897,7 @@ static struct ec_point *ecp_double(const struct ec_point *a, const int aminus3) static struct ec_point *ecp_addw(const struct ec_point *a, const struct ec_point *b, - const int aminus3) + bool aminus3) { Bignum U1, U2, S1, S2, outx, outy, outz; @@ -949,7 +949,7 @@ static struct ec_point *ecp_addw(const struct ec_point *a, freebn(S1); freebn(S2); /* Infinity */ - return ec_point_new(a->curve, NULL, NULL, NULL, 1); + return ec_point_new(a->curve, NULL, NULL, NULL, true); } } @@ -1019,7 +1019,7 @@ static struct ec_point *ecp_addw(const struct ec_point *a, } } - return ec_point_new(a->curve, outx, outy, outz, 0); + return ec_point_new(a->curve, outx, outy, outz, false); } static struct ec_point *ecp_addm(const struct ec_point *a, @@ -1070,7 +1070,7 @@ static struct ec_point *ecp_addm(const struct ec_point *a, freebn(tmp2); } - return ec_point_new(a->curve, outx, NULL, outz, 0); + return ec_point_new(a->curve, outx, NULL, outz, false); } static struct ec_point *ecp_adde(const struct ec_point *a, @@ -1135,12 +1135,12 @@ static struct ec_point *ecp_adde(const struct ec_point *a, freebn(tmp2); } - return ec_point_new(a->curve, outx, outy, NULL, 0); + return ec_point_new(a->curve, outx, outy, NULL, false); } static struct ec_point *ecp_add(const struct ec_point *a, const struct ec_point *b, - const int aminus3) + bool aminus3) { if (a->curve != b->curve) { return NULL; @@ -1163,13 +1163,14 @@ static struct ec_point *ecp_add(const struct ec_point *a, return NULL; } -static struct ec_point *ecp_mul_(const struct ec_point *a, const Bignum b, int aminus3) +static struct ec_point *ecp_mul_( + const struct ec_point *a, const Bignum b, bool aminus3) { struct ec_point *A, *ret; int bits, i; A = ec_point_copy(a); - ret = ec_point_new(a->curve, NULL, NULL, NULL, 1); + ret = ec_point_new(a->curve, NULL, NULL, NULL, true); bits = bignum_bitcount(b); for (i = 0; i < bits; ++i) @@ -1209,18 +1210,18 @@ static struct ec_point *ecp_mule(const struct ec_point *a, const Bignum b) int i; struct ec_point *ret; - ret = ec_point_new(a->curve, NULL, NULL, NULL, 1); + ret = ec_point_new(a->curve, NULL, NULL, NULL, true); for (i = bignum_bitcount(b); i >= 0 && ret; --i) { { - struct ec_point *tmp = ecp_double(ret, 0); + struct ec_point *tmp = ecp_double(ret, false); ec_point_free(ret); ret = tmp; } if (ret && bignum_bit(b, i)) { - struct ec_point *tmp = ecp_add(ret, a, 0); + struct ec_point *tmp = ecp_add(ret, a, false); ec_point_free(ret); ret = tmp; } @@ -1235,7 +1236,7 @@ static struct ec_point *ecp_mulm(const struct ec_point *p, const Bignum n) int bits, i; /* P1 <- P and P2 <- [2]P */ - P2 = ecp_double(p, 0); + P2 = ecp_double(p, false); P1 = ec_point_copy(p); /* for i = bits − 2 down to 0 */ @@ -1250,7 +1251,7 @@ static struct ec_point *ecp_mulm(const struct ec_point *p, const Bignum n) P2 = tmp; /* P1 <- [2]P1 */ - tmp = ecp_double(P1, 0); + tmp = ecp_double(P1, false); ec_point_free(P1); P1 = tmp; } @@ -1262,7 +1263,7 @@ static struct ec_point *ecp_mulm(const struct ec_point *p, const Bignum n) P1 = tmp; /* P2 <- [2]P2 */ - tmp = ecp_double(P2, 0); + tmp = ecp_double(P2, false); ec_point_free(P2); P2 = tmp; } @@ -1294,7 +1295,7 @@ static struct ec_point *ecp_summul(const Bignum a, const Bignum b, const struct ec_point *point) { struct ec_point *aG, *bP, *ret; - int aminus3; + bool aminus3; if (point->curve->type != EC_WEIERSTRASS) { return NULL; @@ -1446,23 +1447,23 @@ struct ec_point *ec_public(const Bignum privateKey, const struct ec_curve *curve * Basic sign and verify routines */ -static int _ecdsa_verify(const struct ec_point *publicKey, - const unsigned char *data, const int dataLen, - const Bignum r, const Bignum s) +static bool _ecdsa_verify(const struct ec_point *publicKey, + const unsigned char *data, const int dataLen, + const Bignum r, const Bignum s) { int z_bits, n_bits; Bignum z; - int valid = 0; + bool valid = false; if (publicKey->curve->type != EC_WEIERSTRASS) { - return 0; + return false; } /* Sanity checks */ if (bignum_cmp(r, Zero) == 0 || bignum_cmp(r, publicKey->curve->w.n) >= 0 || bignum_cmp(s, Zero) == 0 || bignum_cmp(s, publicKey->curve->w.n) >= 0) { - return 0; + return false; } /* z = left most bitlen(curve->n) of data */ @@ -1491,7 +1492,7 @@ static int _ecdsa_verify(const struct ec_point *publicKey, w = modinv(s, publicKey->curve->w.n); if (!w) { freebn(z); - return 0; + return false; } u1 = modmul(z, w, publicKey->curve->w.n); u2 = modmul(r, w, publicKey->curve->w.n); @@ -1502,13 +1503,13 @@ static int _ecdsa_verify(const struct ec_point *publicKey, freebn(u2); if (!tmp) { freebn(z); - return 0; + return false; } x = bigmod(tmp->x, publicKey->curve->w.n); ec_point_free(tmp); - valid = (bignum_cmp(r, x) == 0) ? 1 : 0; + valid = (bignum_cmp(r, x) == 0); freebn(x); } @@ -1597,16 +1598,16 @@ static Bignum BinarySource_get_mp_le(BinarySource *src) } #define get_mp_le(src) BinarySource_get_mp_le(BinarySource_UPCAST(src)) -static int decodepoint_ed(const char *p, int length, struct ec_point *point) +static bool decodepoint_ed(const char *p, int length, struct ec_point *point) { /* Got some conversion to do, first read in the y co-ord */ - int negative; + bool negative; point->y = bignum_from_bytes_le((const unsigned char*)p, length); if ((unsigned)bignum_bitcount(point->y) > point->curve->fieldBits) { freebn(point->y); point->y = NULL; - return 0; + return false; } /* Read x bit and then reset it */ negative = bignum_bit(point->y, point->curve->fieldBits - 1); @@ -1618,7 +1619,7 @@ static int decodepoint_ed(const char *p, int length, struct ec_point *point) if (!point->x) { freebn(point->y); point->y = NULL; - return 0; + return false; } if (negative) { Bignum tmp = modsub(point->curve->p, point->x, point->curve->p); @@ -1632,20 +1633,20 @@ static int decodepoint_ed(const char *p, int length, struct ec_point *point) point->x = NULL; freebn(point->y); point->y = NULL; - return 0; + return false; } - return 1; + return true; } -static int decodepoint(const char *p, int length, struct ec_point *point) +static bool decodepoint(const char *p, int length, struct ec_point *point) { if (point->curve->type == EC_EDWARDS) { return decodepoint_ed(p, length, point); } if (length < 1 || p[0] != 0x04) /* Only support uncompressed point */ - return 0; + return false; /* Skip compression flag */ ++p; --length; @@ -1654,7 +1655,7 @@ static int decodepoint(const char *p, int length, struct ec_point *point) point->x = NULL; point->y = NULL; point->z = NULL; - return 0; + return false; } length = length / 2; point->x = bignum_from_bytes(p, length); @@ -1668,16 +1669,16 @@ static int decodepoint(const char *p, int length, struct ec_point *point) point->x = NULL; freebn(point->y); point->y = NULL; - return 0; + return false; } - return 1; + return true; } -static int BinarySource_get_point(BinarySource *src, struct ec_point *point) +static bool BinarySource_get_point(BinarySource *src, struct ec_point *point) { ptrlen str = get_string(src); - if (get_err(src)) return 0; + if (get_err(src)) return false; return decodepoint(str.ptr, str.len, point); } #define get_point(src, pt) BinarySource_get_point(BinarySource_UPCAST(src), pt) @@ -1737,7 +1738,7 @@ static ssh_key *ecdsa_new_pub(const ssh_keyalg *self, ptrlen data) ec->sshk = self; ec->publicKey.curve = curve; - ec->publicKey.infinity = 0; + ec->publicKey.infinity = false; ec->publicKey.x = NULL; ec->publicKey.y = NULL; ec->publicKey.z = NULL; @@ -1925,7 +1926,7 @@ static ssh_key *ed25519_new_priv_openssh(const ssh_keyalg *self, ec->sshk = self; ec->publicKey.curve = ec_ed25519(); - ec->publicKey.infinity = 0; + ec->publicKey.infinity = false; ec->privateKey = NULL; ec->publicKey.x = NULL; ec->publicKey.z = NULL; @@ -2019,7 +2020,7 @@ static ssh_key *ecdsa_new_priv_openssh(const ssh_keyalg *self, ec->sshk = self; ec->publicKey.curve = curve; - ec->publicKey.infinity = 0; + ec->publicKey.infinity = false; ec->publicKey.x = NULL; ec->publicKey.y = NULL; ec->publicKey.z = NULL; @@ -2106,27 +2107,27 @@ static int ecdsa_pubkey_bits(const ssh_keyalg *self, ptrlen blob) return ret; } -static int ecdsa_verify(ssh_key *key, ptrlen sig, ptrlen data) +static bool ecdsa_verify(ssh_key *key, ptrlen sig, ptrlen data) { struct ec_key *ec = container_of(key, struct ec_key, sshk); const struct ecsign_extra *extra = (const struct ecsign_extra *)ec->sshk->extra; BinarySource src[1]; ptrlen sigstr; - int ret; + bool ret; if (!ec->publicKey.x || !ec->publicKey.y || !ec->publicKey.curve) - return 0; + return false; BinarySource_BARE_INIT(src, sig.ptr, sig.len); /* Check the signature starts with the algorithm name */ if (!ptrlen_eq_string(get_string(src), ec->sshk->ssh_id)) - return 0; + return false; sigstr = get_string(src); if (get_err(src)) - return 0; + return false; if (ec->publicKey.curve->type == EC_EDWARDS) { struct ec_point *r; @@ -2135,22 +2136,22 @@ static int ecdsa_verify(ssh_key *key, ptrlen sig, ptrlen data) /* Check that the signature is two times the length of a point */ if (sigstr.len != pointlen * 2) { - return 0; + return false; } /* Check it's the 256 bit field so that SHA512 is the correct hash */ if (ec->publicKey.curve->fieldBits != 256) { - return 0; + return false; } /* Get the signature */ - r = ec_point_new(ec->publicKey.curve, NULL, NULL, NULL, 0); + r = ec_point_new(ec->publicKey.curve, NULL, NULL, NULL, false); if (!r) { - return 0; + return false; } if (!decodepoint(sigstr.ptr, pointlen, r)) { ec_point_free(r); - return 0; + return false; } s = bignum_from_bytes_le( (const char *)sigstr.ptr + pointlen, pointlen); @@ -2193,7 +2194,7 @@ static int ecdsa_verify(ssh_key *key, ptrlen sig, ptrlen data) if (!lhs) { ec_point_free(r); freebn(h); - return 0; + return false; } /* rhs = r + h*publicKey */ @@ -2202,14 +2203,14 @@ static int ecdsa_verify(ssh_key *key, ptrlen sig, ptrlen data) if (!tmp) { ec_point_free(lhs); ec_point_free(r); - return 0; + return false; } - rhs = ecp_add(r, tmp, 0); + rhs = ecp_add(r, tmp, false); ec_point_free(r); ec_point_free(tmp); if (!rhs) { ec_point_free(lhs); - return 0; + return false; } /* Check the point is the same */ @@ -2217,7 +2218,7 @@ static int ecdsa_verify(ssh_key *key, ptrlen sig, ptrlen data) if (ret) { ret = !bignum_cmp(lhs->y, rhs->y); if (ret) { - ret = 1; + ret = true; } } ec_point_free(lhs); @@ -2236,7 +2237,7 @@ static int ecdsa_verify(ssh_key *key, ptrlen sig, ptrlen data) if (get_err(src)) { freebn(r); freebn(s); - return 0; + return false; } digestLen = extra->hash->hlen; @@ -2643,7 +2644,7 @@ Bignum ssh_ecdhkex_getkey(struct ec_key *ec, if (ec->publicKey.curve->type == EC_WEIERSTRASS) { remote.curve = ec->publicKey.curve; - remote.infinity = 0; + remote.infinity = false; if (!decodepoint(remoteKey, remoteKeyLen, &remote)) { return NULL; } @@ -2654,7 +2655,7 @@ Bignum ssh_ecdhkex_getkey(struct ec_key *ec, } remote.curve = ec->publicKey.curve; - remote.infinity = 0; + remote.infinity = false; remote.x = bignum_from_bytes_le((const unsigned char *)remoteKey, remoteKeyLen); remote.y = NULL; @@ -2746,9 +2747,8 @@ const unsigned char *ec_alg_oid(const ssh_keyalg *alg, const int ec_nist_curve_lengths[] = { 256, 384, 521 }; const int n_ec_nist_curve_lengths = lenof(ec_nist_curve_lengths); -int ec_nist_alg_and_curve_by_bits(int bits, - const struct ec_curve **curve, - const ssh_keyalg **alg) +bool ec_nist_alg_and_curve_by_bits( + int bits, const struct ec_curve **curve, const ssh_keyalg **alg) { switch (bits) { case 256: *alg = &ssh_ecdsa_nistp256; break; @@ -2760,9 +2760,8 @@ int ec_nist_alg_and_curve_by_bits(int bits, return true; } -int ec_ed_alg_and_curve_by_bits(int bits, - const struct ec_curve **curve, - const ssh_keyalg **alg) +bool ec_ed_alg_and_curve_by_bits( + int bits, const struct ec_curve **curve, const ssh_keyalg **alg) { switch (bits) { case 256: *alg = &ssh_ecdsa_ed25519; break; diff --git a/sshmac.c b/sshmac.c index e3b74b38..3d597418 100644 --- a/sshmac.c +++ b/sshmac.c @@ -7,10 +7,10 @@ #include "ssh.h" -int ssh2_mac_verresult(ssh2_mac *mac, const void *candidate) +bool ssh2_mac_verresult(ssh2_mac *mac, const void *candidate) { unsigned char correct[64]; /* at least as big as all known MACs */ - int toret; + bool toret; assert(mac->vt->len <= sizeof(correct)); ssh2_mac_genresult(mac, correct); @@ -35,7 +35,8 @@ void ssh2_mac_generate(ssh2_mac *mac, void *blk, int len, unsigned long seq) return ssh2_mac_genresult(mac, (unsigned char *)blk + len); } -int ssh2_mac_verify(ssh2_mac *mac, const void *blk, int len, unsigned long seq) +bool ssh2_mac_verify( + ssh2_mac *mac, const void *blk, int len, unsigned long seq) { ssh2_mac_prepare(mac, blk, len, seq); return ssh2_mac_verresult(mac, (const unsigned char *)blk + len); diff --git a/sshppl.h b/sshppl.h index a44ba02c..5069f871 100644 --- a/sshppl.h +++ b/sshppl.h @@ -12,11 +12,11 @@ typedef void (*packet_handler_fn_t)(PacketProtocolLayer *ppl, PktIn *pktin); struct PacketProtocolLayerVtable { void (*free)(PacketProtocolLayer *); void (*process_queue)(PacketProtocolLayer *ppl); - int (*get_specials)( + bool (*get_specials)( PacketProtocolLayer *ppl, add_special_fn_t add_special, void *ctx); void (*special_cmd)( PacketProtocolLayer *ppl, SessionSpecialCode code, int arg); - int (*want_user_input)(PacketProtocolLayer *ppl); + bool (*want_user_input)(PacketProtocolLayer *ppl); void (*got_user_input)(PacketProtocolLayer *ppl); void (*reconfigure)(PacketProtocolLayer *ppl, Conf *conf); @@ -97,17 +97,17 @@ PacketProtocolLayer *ssh2_transport_new( const char *client_greeting, const char *server_greeting, struct ssh_connection_shared_gss_state *shgss, struct DataTransferStats *stats, PacketProtocolLayer *higher_layer, - int is_server); + bool is_server); PacketProtocolLayer *ssh2_userauth_new( PacketProtocolLayer *successor_layer, const char *hostname, const char *fullhostname, - Filename *keyfile, int tryagent, - const char *default_username, int change_username, - int try_ki_auth, - int try_gssapi_auth, int try_gssapi_kex_auth, - int gssapi_fwd, struct ssh_connection_shared_gss_state *shgss); + Filename *keyfile, bool tryagent, + const char *default_username, bool change_username, + bool try_ki_auth, + bool try_gssapi_auth, bool try_gssapi_kex_auth, + bool gssapi_fwd, struct ssh_connection_shared_gss_state *shgss); PacketProtocolLayer *ssh2_connection_new( - Ssh *ssh, ssh_sharing_state *connshare, int is_simple, + Ssh *ssh, ssh_sharing_state *connshare, bool is_simple, Conf *conf, const char *peer_verstring, ConnectionLayer **cl_out); /* Can't put this in the userauth constructor without having a @@ -139,10 +139,10 @@ void ssh1_connection_set_protoflags( PacketProtocolLayer *ppl, int local, int remote); /* Shared get_specials method between the two ssh1 layers */ -int ssh1_common_get_specials(PacketProtocolLayer *, add_special_fn_t, void *); +bool ssh1_common_get_specials(PacketProtocolLayer *, add_special_fn_t, void *); /* Other shared functions between ssh1 layers */ -int ssh1_common_filter_queue(PacketProtocolLayer *ppl); +bool ssh1_common_filter_queue(PacketProtocolLayer *ppl); void ssh1_compute_session_id( unsigned char *session_id, const unsigned char *cookie, struct RSAKey *hostkey, struct RSAKey *servkey); diff --git a/sshpubk.c b/sshpubk.c index a0d73c78..5072ff63 100644 --- a/sshpubk.c +++ b/sshpubk.c @@ -23,7 +23,7 @@ static int key_type_fp(FILE *fp); -static int rsa_ssh1_load_main(FILE * fp, struct RSAKey *key, int pub_only, +static int rsa_ssh1_load_main(FILE * fp, struct RSAKey *key, bool pub_only, char **commentptr, const char *passphrase, const char **error) { @@ -184,14 +184,14 @@ int rsa_ssh1_loadkey(const Filename *filename, struct RSAKey *key, * See whether an RSA key is encrypted. Return its comment field as * well. */ -int rsa_ssh1_encrypted(const Filename *filename, char **comment) +bool rsa_ssh1_encrypted(const Filename *filename, char **comment) { FILE *fp; char buf[64]; fp = f_open(filename, "rb", false); if (!fp) - return 0; /* doesn't even exist */ + return false; /* doesn't even exist */ /* * Read the first line of the file and see if it's a v1 private @@ -202,10 +202,10 @@ int rsa_ssh1_encrypted(const Filename *filename, char **comment) /* * This routine will take care of calling fclose() for us. */ - return rsa_ssh1_load_main(fp, NULL, false, comment, NULL, &dummy); + return rsa_ssh1_load_main(fp, NULL, false, comment, NULL, &dummy) == 1; } fclose(fp); - return 0; /* wasn't the right kind of file */ + return false; /* wasn't the right kind of file */ } /* @@ -222,7 +222,7 @@ int rsa_ssh1_loadpub(const Filename *filename, BinarySink *bs, const char *error = NULL; /* Default return if we fail. */ - ret = false; + ret = 0; fp = f_open(filename, "rb", false); if (!fp) { @@ -239,7 +239,7 @@ int rsa_ssh1_loadpub(const Filename *filename, BinarySink *bs, if (rsa_ssh1_load_main(fp, &key, true, commentptr, NULL, &error)) { rsa_ssh1_public_blob(bs, &key, RSA_SSH1_EXPONENT_FIRST); freersakey(&key); - ret = true; + ret = 1; } fp = NULL; /* rsa_ssh1_load_main unconditionally closes fp */ } else { @@ -291,7 +291,7 @@ int rsa_ssh1_loadpub(const Filename *filename, BinarySink *bs, freersakey(&key); sfree(line); fclose(fp); - return true; + return 1; not_public_either: sfree(line); @@ -307,10 +307,10 @@ int rsa_ssh1_loadpub(const Filename *filename, BinarySink *bs, } /* - * Save an RSA key file. Return nonzero on success. + * Save an RSA key file. Return true on success. */ -int rsa_ssh1_savekey(const Filename *filename, struct RSAKey *key, - char *passphrase) +bool rsa_ssh1_savekey(const Filename *filename, struct RSAKey *key, + char *passphrase) { strbuf *buf = strbuf_new(); int estart; @@ -377,12 +377,12 @@ int rsa_ssh1_savekey(const Filename *filename, struct RSAKey *key, */ fp = f_open(filename, "wb", true); if (fp) { - int ret = (fwrite(buf->u, 1, buf->len, fp) == (size_t) (buf->len)); + bool ret = (fwrite(buf->u, 1, buf->len, fp) == (size_t) (buf->len)); if (fclose(fp)) - ret = 0; + ret = false; return ret; } else - return 0; + return false; } /* ---------------------------------------------------------------------- @@ -468,7 +468,7 @@ int rsa_ssh1_savekey(const Filename *filename, struct RSAKey *key, * an HMAC (this was generated for unencrypted keys). */ -static int read_header(FILE * fp, char *header) +static bool read_header(FILE * fp, char *header) { int len = 39; int c; @@ -476,20 +476,20 @@ static int read_header(FILE * fp, char *header) while (1) { c = fgetc(fp); if (c == '\n' || c == '\r' || c == EOF) - return 0; /* failure */ + return false; /* failure */ if (c == ':') { c = fgetc(fp); if (c != ' ') - return 0; + return false; *header = '\0'; - return 1; /* success! */ + return true; /* success! */ } if (len == 0) - return 0; /* failure */ + return false; /* failure */ *header++ = c; len--; } - return 0; /* failure */ + return false; /* failure */ } static char *read_body(FILE * fp) @@ -523,7 +523,7 @@ static char *read_body(FILE * fp) } } -static int read_blob(FILE *fp, int nlines, BinarySink *bs) +static bool read_blob(FILE *fp, int nlines, BinarySink *bs) { unsigned char *blob; char *line; @@ -597,7 +597,8 @@ struct ssh2_userkey *ssh2_load_userkey(const Filename *filename, struct ssh2_userkey *ret; int cipher, cipherblk; strbuf *public_blob, *private_blob; - int i, is_mac, old_fmt; + int i; + bool is_mac, old_fmt; int passlen = passphrase ? strlen(passphrase) : 0; const char *error = NULL; @@ -617,11 +618,11 @@ struct ssh2_userkey *ssh2_load_userkey(const Filename *filename, goto error; } if (0 == strcmp(header, "PuTTY-User-Key-File-2")) { - old_fmt = 0; + old_fmt = false; } else if (0 == strcmp(header, "PuTTY-User-Key-File-1")) { /* this is an old key file; warn and then continue */ old_keyfile_warning(); - old_fmt = 1; + old_fmt = true; } else if (0 == strncmp(header, "PuTTY-User-Key-File-", 20)) { /* this is a key file FROM THE FUTURE; refuse it, but with a * more specific error message than the generic one below */ @@ -691,11 +692,11 @@ struct ssh2_userkey *ssh2_load_userkey(const Filename *filename, if (0 == strcmp(header, "Private-MAC")) { if ((mac = read_body(fp)) == NULL) goto error; - is_mac = 1; + is_mac = true; } else if (0 == strcmp(header, "Private-Hash") && old_fmt) { if ((mac = read_body(fp)) == NULL) goto error; - is_mac = 0; + is_mac = false; } else goto error; @@ -732,7 +733,7 @@ struct ssh2_userkey *ssh2_load_userkey(const Filename *filename, char realmac[41]; unsigned char binary[20]; strbuf *macdata; - int free_macdata; + bool free_macdata; if (old_fmt) { /* MAC (or hash) only covers the private blob. */ @@ -834,9 +835,9 @@ struct ssh2_userkey *ssh2_load_userkey(const Filename *filename, return ret; } -int rfc4716_loadpub(FILE *fp, char **algorithm, - BinarySink *bs, - char **commentptr, const char **errorstr) +bool rfc4716_loadpub(FILE *fp, char **algorithm, + BinarySink *bs, + char **commentptr, const char **errorstr) { const char *error; char *line, *colon, *value; @@ -968,9 +969,9 @@ int rfc4716_loadpub(FILE *fp, char **algorithm, return false; } -int openssh_loadpub(FILE *fp, char **algorithm, - BinarySink *bs, - char **commentptr, const char **errorstr) +bool openssh_loadpub(FILE *fp, char **algorithm, + BinarySink *bs, + char **commentptr, const char **errorstr) { const char *error; char *line, *base64; @@ -1044,9 +1045,9 @@ int openssh_loadpub(FILE *fp, char **algorithm, return false; } -int ssh2_userkey_loadpub(const Filename *filename, char **algorithm, - BinarySink *bs, - char **commentptr, const char **errorstr) +bool ssh2_userkey_loadpub(const Filename *filename, char **algorithm, + BinarySink *bs, + char **commentptr, const char **errorstr) { FILE *fp; char header[40], *b; @@ -1065,11 +1066,11 @@ int ssh2_userkey_loadpub(const Filename *filename, char **algorithm, * we'll be asked to read a public blob from one of those. */ type = key_type_fp(fp); if (type == SSH_KEYTYPE_SSH2_PUBLIC_RFC4716) { - int ret = rfc4716_loadpub(fp, algorithm, bs, commentptr, errorstr); + bool ret = rfc4716_loadpub(fp, algorithm, bs, commentptr, errorstr); fclose(fp); return ret; } else if (type == SSH_KEYTYPE_SSH2_PUBLIC_OPENSSH) { - int ret = openssh_loadpub(fp, algorithm, bs, commentptr, errorstr); + bool ret = openssh_loadpub(fp, algorithm, bs, commentptr, errorstr); fclose(fp); return ret; } else if (type != SSH_KEYTYPE_SSH2) { @@ -1145,49 +1146,49 @@ int ssh2_userkey_loadpub(const Filename *filename, char **algorithm, return false; } -int ssh2_userkey_encrypted(const Filename *filename, char **commentptr) +bool ssh2_userkey_encrypted(const Filename *filename, char **commentptr) { FILE *fp; char header[40], *b, *comment; - int ret; + bool ret; if (commentptr) *commentptr = NULL; fp = f_open(filename, "rb", false); if (!fp) - return 0; + return false; if (!read_header(fp, header) || (0 != strcmp(header, "PuTTY-User-Key-File-2") && 0 != strcmp(header, "PuTTY-User-Key-File-1"))) { fclose(fp); - return 0; + return false; } if ((b = read_body(fp)) == NULL) { fclose(fp); - return 0; + return false; } sfree(b); /* we don't care about key type here */ /* Read the Encryption header line. */ if (!read_header(fp, header) || 0 != strcmp(header, "Encryption")) { fclose(fp); - return 0; + return false; } if ((b = read_body(fp)) == NULL) { fclose(fp); - return 0; + return false; } /* Read the Comment header line. */ if (!read_header(fp, header) || 0 != strcmp(header, "Comment")) { fclose(fp); sfree(b); - return 1; + return true; } if ((comment = read_body(fp)) == NULL) { fclose(fp); sfree(b); - return 1; + return true; } if (commentptr) @@ -1197,9 +1198,9 @@ int ssh2_userkey_encrypted(const Filename *filename, char **commentptr) fclose(fp); if (!strcmp(b, "aes256-cbc")) - ret = 1; + ret = true; else - ret = 0; + ret = false; sfree(b); return ret; } @@ -1233,8 +1234,8 @@ void base64_encode(FILE *fp, const unsigned char *data, int datalen, int cpl) fputc('\n', fp); } -int ssh2_save_userkey(const Filename *filename, struct ssh2_userkey *key, - char *passphrase) +bool ssh2_save_userkey(const Filename *filename, struct ssh2_userkey *key, + char *passphrase) { FILE *fp; strbuf *pub_blob, *priv_blob; @@ -1329,7 +1330,7 @@ int ssh2_save_userkey(const Filename *filename, struct ssh2_userkey *key, strbuf_free(priv_blob); smemclr(priv_blob_encrypted, priv_encrypted_len); sfree(priv_blob_encrypted); - return 0; + return false; } fprintf(fp, "PuTTY-User-Key-File-2: %s\n", ssh_key_ssh_id(key->key)); fprintf(fp, "Encryption: %s\n", cipherstr); @@ -1348,7 +1349,7 @@ int ssh2_save_userkey(const Filename *filename, struct ssh2_userkey *key, strbuf_free(priv_blob); smemclr(priv_blob_encrypted, priv_encrypted_len); sfree(priv_blob_encrypted); - return 1; + return true; } /* ---------------------------------------------------------------------- diff --git a/sshrand.c b/sshrand.c index d0448703..63211693 100644 --- a/sshrand.c +++ b/sshrand.c @@ -42,7 +42,7 @@ struct RandPool { unsigned char incomingb[HASHINPUT]; int incomingpos; - int stir_pending; + bool stir_pending; }; int random_active = 0; diff --git a/sshrsa.c b/sshrsa.c index c033bb94..2d508777 100644 --- a/sshrsa.c +++ b/sshrsa.c @@ -42,14 +42,14 @@ void BinarySource_get_rsa_ssh1_priv( rsa->private_exponent = get_mp_ssh1(src); } -int rsa_ssh1_encrypt(unsigned char *data, int length, struct RSAKey *key) +bool rsa_ssh1_encrypt(unsigned char *data, int length, struct RSAKey *key) { Bignum b1, b2; int i; unsigned char *p; if (key->bytes < length + 4) - return 0; /* RSA key too short! */ + return false; /* RSA key too short! */ memmove(data + key->bytes - length, data, length); data[0] = 0; @@ -74,7 +74,7 @@ int rsa_ssh1_encrypt(unsigned char *data, int length, struct RSAKey *key) freebn(b1); freebn(b2); - return 1; + return true; } /* @@ -285,10 +285,10 @@ Bignum rsa_ssh1_decrypt(Bignum input, struct RSAKey *key) return rsa_privkey_op(input, key); } -int rsa_ssh1_decrypt_pkcs1(Bignum input, struct RSAKey *key, strbuf *outbuf) +bool rsa_ssh1_decrypt_pkcs1(Bignum input, struct RSAKey *key, strbuf *outbuf) { strbuf *data = strbuf_new(); - int success = false; + bool success = false; BinarySource src[1]; { @@ -391,7 +391,7 @@ char *rsa_ssh1_fingerprint(struct RSAKey *key) * data. We also check the private data itself: we ensure that p > * q and that iqmp really is the inverse of q mod p. */ -int rsa_verify(struct RSAKey *key) +bool rsa_verify(struct RSAKey *key) { Bignum n, ed, pm1, qm1; int cmp; @@ -401,7 +401,7 @@ int rsa_verify(struct RSAKey *key) cmp = bignum_cmp(n, key->modulus); freebn(n); if (cmp != 0) - return 0; + return false; /* e * d must be congruent to 1, modulo (p-1) and modulo (q-1). */ pm1 = copybn(key->p); @@ -411,7 +411,7 @@ int rsa_verify(struct RSAKey *key) cmp = bignum_cmp(ed, One); freebn(ed); if (cmp != 0) - return 0; + return false; qm1 = copybn(key->q); decbn(qm1); @@ -420,7 +420,7 @@ int rsa_verify(struct RSAKey *key) cmp = bignum_cmp(ed, One); freebn(ed); if (cmp != 0) - return 0; + return false; /* * Ensure p > q. @@ -438,7 +438,7 @@ int rsa_verify(struct RSAKey *key) freebn(key->iqmp); key->iqmp = modinv(key->q, key->p); if (!key->iqmp) - return 0; + return false; } /* @@ -448,9 +448,9 @@ int rsa_verify(struct RSAKey *key) cmp = bignum_cmp(n, One); freebn(n); if (cmp != 0) - return 0; + return false; - return 1; + return true; } void rsa_ssh1_public_blob(BinarySink *bs, struct RSAKey *key, @@ -683,13 +683,14 @@ static const unsigned char asn1_weird_stuff[] = { #define ASN1_LEN ( (int) sizeof(asn1_weird_stuff) ) -static int rsa2_verify(ssh_key *key, ptrlen sig, ptrlen data) +static bool rsa2_verify(ssh_key *key, ptrlen sig, ptrlen data) { struct RSAKey *rsa = container_of(key, struct RSAKey, sshk); BinarySource src[1]; ptrlen type, in_pl; Bignum in, out; - int bytes, i, j, ret; + int bytes, i, j; + bool toret; unsigned char hash[20]; BinarySource_BARE_INIT(src, sig.ptr, sig.len); @@ -706,40 +707,40 @@ static int rsa2_verify(ssh_key *key, ptrlen sig, ptrlen data) */ in_pl = get_string(src); if (get_err(src) || !ptrlen_eq_string(type, "ssh-rsa")) - return 0; + return false; in = bignum_from_bytes(in_pl.ptr, in_pl.len); out = modpow(in, rsa->exponent, rsa->modulus); freebn(in); - ret = 1; + toret = true; bytes = (bignum_bitcount(rsa->modulus)+7) / 8; /* Top (partial) byte should be zero. */ if (bignum_byte(out, bytes - 1) != 0) - ret = 0; + toret = false; /* First whole byte should be 1. */ if (bignum_byte(out, bytes - 2) != 1) - ret = 0; + toret = false; /* Most of the rest should be FF. */ for (i = bytes - 3; i >= 20 + ASN1_LEN; i--) { if (bignum_byte(out, i) != 0xFF) - ret = 0; + toret = false; } /* Then we expect to see the asn1_weird_stuff. */ for (i = 20 + ASN1_LEN - 1, j = 0; i >= 20; i--, j++) { if (bignum_byte(out, i) != asn1_weird_stuff[j]) - ret = 0; + toret = false; } /* Finally, we expect to see the SHA-1 hash of the signed data. */ SHA_Simple(data.ptr, data.len, hash); for (i = 19, j = 0; i >= 0; i--, j++) { if (bignum_byte(out, i) != hash[j]) - ret = 0; + toret = false; } freebn(out); - return ret; + return toret; } static void rsa2_sign(ssh_key *key, const void *data, int datalen, diff --git a/sshserver.c b/sshserver.c index a97dc86d..b43432dc 100644 --- a/sshserver.c +++ b/sshserver.c @@ -33,7 +33,7 @@ struct server { Socket *socket; Plug plug; int conn_throttle_count; - int frozen; + bool frozen; Conf *conf; ssh_key *const *hostkeys; @@ -74,7 +74,7 @@ void share_setup_x11_channel(ssh_sharing_connstate *cs, share_channel *chan, int protomajor, int protominor, const void *initial_data, int initial_len) {} Channel *agentf_new(SshChannel *c) { return NULL; } -int agent_exists(void) { return false; } +bool agent_exists(void) { return false; } void ssh_got_exitcode(Ssh *ssh, int exitcode) {} mainchan *mainchan_new( @@ -122,7 +122,7 @@ static void server_socket_log(Plug *plug, int type, SockAddr *addr, int port, } static void server_closing(Plug *plug, const char *error_msg, int error_code, - int calling_back) + bool calling_back) { server *srv = container_of(plug, server, plug); if (error_msg) { @@ -175,7 +175,7 @@ void ssh_throttle_conn(Ssh *ssh, int adjust) { server *srv = container_of(ssh, server, ssh); int old_count = srv->conn_throttle_count; - int frozen; + bool frozen; srv->conn_throttle_count += adjust; assert(srv->conn_throttle_count >= 0); diff --git a/sshserver.h b/sshserver.h index 348004ed..2dc43d95 100644 --- a/sshserver.h +++ b/sshserver.h @@ -33,18 +33,18 @@ struct AuthKbdInt { }; struct AuthKbdIntPrompt { char *prompt; /* needs freeing */ - int echo; + bool echo; }; unsigned auth_methods(AuthPolicy *); -int auth_none(AuthPolicy *, ptrlen username); +bool auth_none(AuthPolicy *, ptrlen username); int auth_password(AuthPolicy *, ptrlen username, ptrlen password, ptrlen *opt_new_password); /* auth_password returns 1 for 'accepted', 0 for 'rejected', and 2 for * 'ok but now you need to change your password' */ -int auth_publickey(AuthPolicy *, ptrlen username, ptrlen public_blob); +bool auth_publickey(AuthPolicy *, ptrlen username, ptrlen public_blob); /* auth_publickey_ssh1 must return the whole public key given the modulus, * because the SSH-1 client never transmits the exponent over the wire. * The key remains owned by the AuthPolicy. */ @@ -59,12 +59,12 @@ int auth_kbdint_responses(AuthPolicy *, const ptrlen *responses); /* The very similar SSH-1 TIS and CryptoCard methods are combined into * a single API for AuthPolicy, which takes a method argument */ char *auth_ssh1int_challenge(AuthPolicy *, unsigned method, ptrlen username); -int auth_ssh1int_response(AuthPolicy *, ptrlen response); +bool auth_ssh1int_response(AuthPolicy *, ptrlen response); struct RSAKey *auth_publickey_ssh1( AuthPolicy *ap, ptrlen username, Bignum rsa_modulus); /* auth_successful returns false if further authentication is needed */ -int auth_successful(AuthPolicy *, ptrlen username, unsigned method); +bool auth_successful(AuthPolicy *, ptrlen username, unsigned method); PacketProtocolLayer *ssh2_userauth_server_new( PacketProtocolLayer *successor_layer, AuthPolicy *authpolicy); @@ -83,7 +83,7 @@ Channel *sesschan_new(SshChannel *c, LogContext *logctx, Backend *pty_backend_create( Seat *seat, LogContext *logctx, Conf *conf, char **argv, const char *cmd, - struct ssh_ttymodes ttymodes, int pipes_instead_of_pty); + struct ssh_ttymodes ttymodes, bool pipes_instead_of_pty); ptrlen pty_backend_exit_signame(Backend *be, char **aux_msg); /* diff --git a/sshsha.c b/sshsha.c index 4e832e50..66d9aca5 100644 --- a/sshsha.c +++ b/sshsha.c @@ -436,12 +436,12 @@ const struct ssh2_macalg ssh_hmac_sha1_96_buggy = { #if defined(__clang__) || defined(__GNUC__) #include -int supports_sha_ni(void) +bool supports_sha_ni(void) { unsigned int CPUInfo[4]; __cpuid(0, CPUInfo[0], CPUInfo[1], CPUInfo[2], CPUInfo[3]); if (CPUInfo[0] < 7) - return 0; + return false; __cpuid_count(7, 0, CPUInfo[0], CPUInfo[1], CPUInfo[2], CPUInfo[3]); return CPUInfo[1] & (1 << 29); /* SHA */ @@ -449,12 +449,12 @@ int supports_sha_ni(void) #else /* defined(__clang__) || defined(__GNUC__) */ -int supports_sha_ni(void) +bool supports_sha_ni(void) { unsigned int CPUInfo[4]; __cpuid(CPUInfo, 0); if (CPUInfo[0] < 7) - return 0; + return false; __cpuidex(CPUInfo, 7, 0); return CPUInfo[1] & (1 << 29); /* Check SHA */ @@ -686,9 +686,9 @@ static void sha1_ni(SHA_State * s, const unsigned char *q, int len) assert(0); } -int supports_sha_ni(void) +bool supports_sha_ni(void) { - return 0; + return false; } #endif /* COMPILER_SUPPORTS_AES_NI */ diff --git a/sshshare.c b/sshshare.c index dd44a5c3..48a0ca36 100644 --- a/sshshare.c +++ b/sshshare.c @@ -160,7 +160,8 @@ struct ssh_sharing_connstate { int crLine; /* coroutine state for share_receive */ - int sent_verstring, got_verstring, curr_packetlen; + bool sent_verstring, got_verstring; + int curr_packetlen; unsigned char recvbuf[0x4010]; int recvlen; @@ -235,13 +236,13 @@ struct share_channel { int x11_auth_proto; char *x11_auth_data; int x11_auth_datalen; - int x11_one_shot; + bool x11_one_shot; }; struct share_forwarding { char *host; int port; - int active; /* has the server sent REQUEST_SUCCESS? */ + bool active; /* has the server sent REQUEST_SUCCESS? */ struct ssh_rportfwd *rpf; }; @@ -263,7 +264,7 @@ struct share_xchannel { * channel messages from the server until such time as the server * sends us CHANNEL_CLOSE. */ - int live; + bool live; /* * When we receive OPEN_CONFIRMATION, we will need to send a @@ -291,7 +292,7 @@ enum { struct share_globreq { struct share_globreq *next; int type; - int want_reply; + bool want_reply; struct share_forwarding *fwd; }; @@ -571,7 +572,7 @@ static struct share_channel *share_add_channel chan->x11_auth_data = NULL; chan->x11_auth_proto = -1; chan->x11_auth_datalen = 0; - chan->x11_one_shot = 0; + chan->x11_one_shot = false; if (add234(cs->channels_by_us, chan) != chan) { sfree(chan); return NULL; @@ -936,7 +937,7 @@ static void share_disconnect(struct ssh_sharing_connstate *cs, } static void share_closing(Plug *plug, const char *error_msg, int error_code, - int calling_back) + bool calling_back) { struct ssh_sharing_connstate *cs = container_of( plug, struct ssh_sharing_connstate, plug); @@ -997,7 +998,7 @@ void share_dead_xchannel_respond(struct ssh_sharing_connstate *cs, * Handle queued incoming messages from the server destined for an * xchannel which is dead (i.e. downstream sent OPEN_FAILURE). */ - int delete = false; + bool delete = false; while (xc->msghead) { struct share_xchannel_message *msg = xc->msghead; xc->msghead = msg->next; @@ -1157,7 +1158,7 @@ void share_setup_x11_channel(ssh_sharing_connstate *cs, share_channel *chan, sfree(chan->x11_auth_data); chan->x11_auth_proto = -1; chan->x11_auth_datalen = 0; - chan->x11_one_shot = 0; + chan->x11_one_shot = false; } } @@ -1312,7 +1313,7 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs, char *err = NULL; BinarySource src[1]; size_t wantreplypos; - int orig_wantreply; + bool orig_wantreply; BinarySource_BARE_INIT(src, pkt, pktlen); @@ -1635,7 +1636,8 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs, * a downstream, and if the latter, which one. */ if (ptrlen_eq_string(request_name, "x11-req")) { - int want_reply, single_connection, screen; + bool want_reply, single_connection; + int screen; ptrlen auth_data; int auth_proto; @@ -1844,7 +1846,7 @@ static void share_sent(Plug *plug, int bufsize) } static void share_listen_closing(Plug *plug, const char *error_msg, - int error_code, int calling_back) + int error_code, bool calling_back) { ssh_sharing_state *sharestate = container_of(plug, ssh_sharing_state, plug); @@ -1968,8 +1970,8 @@ static int share_listen_accepting(Plug *plug, /* Per-application overrides for what roles we can take (e.g. pscp * will never be an upstream) */ -extern const int share_can_be_downstream; -extern const int share_can_be_upstream; +extern const bool share_can_be_downstream; +extern const bool share_can_be_upstream; /* * Decide on the string used to identify the connection point between @@ -2015,7 +2017,7 @@ char *ssh_share_sockname(const char *host, int port, Conf *conf) return sockname; } -int ssh_share_test_for_upstream(const char *host, int port, Conf *conf) +bool ssh_share_test_for_upstream(const char *host, int port, Conf *conf) { char *sockname, *logtext, *ds_err, *us_err; int result; @@ -2071,7 +2073,8 @@ Socket *ssh_connection_sharing_init( const char *host, int port, Conf *conf, LogContext *logctx, Plug *sshplug, ssh_sharing_state **state) { - int result, can_upstream, can_downstream; + int result; + bool can_upstream, can_downstream; char *logtext, *ds_err, *us_err; char *sockname; Socket *sock, *toret = NULL; diff --git a/sshverstring.c b/sshverstring.c index 578ee99f..529b5964 100644 --- a/sshverstring.c +++ b/sshverstring.c @@ -21,9 +21,9 @@ struct ssh_verstring_state { char *our_protoversion; struct ssh_version_receiver *receiver; - int send_early; + bool send_early; - int found_prefix; + bool found_prefix; int major_protoversion; int remote_bugs; char prefix[PREFIX_MAXLEN]; @@ -55,13 +55,13 @@ static const struct BinaryPacketProtocolVtable ssh_verstring_vtable = { }; static void ssh_detect_bugs(struct ssh_verstring_state *s); -static int ssh_version_includes_v1(const char *ver); -static int ssh_version_includes_v2(const char *ver); +static bool ssh_version_includes_v1(const char *ver); +static bool ssh_version_includes_v2(const char *ver); BinaryPacketProtocol *ssh_verstring_new( - Conf *conf, LogContext *logctx, int bare_connection_mode, + Conf *conf, LogContext *logctx, bool bare_connection_mode, const char *protoversion, struct ssh_version_receiver *rcv, - int server_mode, const char *impl_name) + bool server_mode, const char *impl_name) { struct ssh_verstring_state *s = snew(struct ssh_verstring_state); @@ -141,12 +141,12 @@ static int ssh_versioncmp(const char *a, const char *b) return 0; } -static int ssh_version_includes_v1(const char *ver) +static bool ssh_version_includes_v1(const char *ver) { return ssh_versioncmp(ver, "2.0") < 0; } -static int ssh_version_includes_v2(const char *ver) +static bool ssh_version_includes_v2(const char *ver) { return ssh_versioncmp(ver, "1.99") >= 0; } diff --git a/sshzlib.c b/sshzlib.c index ae3e28d2..8171ee11 100644 --- a/sshzlib.c +++ b/sshzlib.c @@ -94,7 +94,7 @@ static int lz77_init(struct LZ77Context *ctx); * instead call literal() for everything. */ static void lz77_compress(struct LZ77Context *ctx, - unsigned char *data, int len, int compress); + unsigned char *data, int len, bool compress); /* * Modifiable parameters. @@ -199,7 +199,7 @@ static void lz77_advance(struct LZ77InternalContext *st, #define CHARAT(k) ( (k)<0 ? st->data[(st->winpos+k)&(WINSIZE-1)] : data[k] ) static void lz77_compress(struct LZ77Context *ctx, - unsigned char *data, int len, int compress) + unsigned char *data, int len, bool compress) { struct LZ77InternalContext *st = ctx->ictx; int i, distance, off, nmatch, matchlen, advance; @@ -370,7 +370,7 @@ struct Outbuf { int outlen, outsize; unsigned long outbits; int noutbits; - int firstblock; + bool firstblock; }; static void outbits(struct Outbuf *out, unsigned long bits, int nbits) @@ -614,7 +614,7 @@ ssh_compressor *zlib_compress_init(void) out = snew(struct Outbuf); out->outbits = out->noutbits = 0; - out->firstblock = 1; + out->firstblock = true; comp->ectx.userdata = out; return &comp->sc; @@ -636,7 +636,7 @@ void zlib_compress_block(ssh_compressor *sc, unsigned char *block, int len, struct ssh_zlib_compressor *comp = container_of(sc, struct ssh_zlib_compressor, sc); struct Outbuf *out = (struct Outbuf *) comp->ectx.userdata; - int in_block; + bool in_block; out->outbuf = NULL; out->outlen = out->outsize = 0; @@ -648,7 +648,7 @@ void zlib_compress_block(ssh_compressor *sc, unsigned char *block, int len, */ if (out->firstblock) { outbits(out, 0x9C78, 16); - out->firstblock = 0; + out->firstblock = false; in_block = false; } else @@ -967,8 +967,8 @@ static void zlib_emit_char(struct zlib_decompress_ctx *dctx, int c) #define EATBITS(n) ( dctx->nbits -= (n), dctx->bits >>= (n) ) -int zlib_decompress_block(ssh_decompressor *dc, unsigned char *block, int len, - unsigned char **outblock, int *outlen) +bool zlib_decompress_block(ssh_decompressor *dc, unsigned char *block, int len, + unsigned char **outblock, int *outlen) { struct zlib_decompress_ctx *dctx = container_of(dc, struct zlib_decompress_ctx, dc); @@ -1209,13 +1209,13 @@ int zlib_decompress_block(ssh_decompressor *dc, unsigned char *block, int len, finished: *outblock = dctx->outblk; *outlen = dctx->outlen; - return 1; + return true; decode_error: sfree(dctx->outblk); *outblock = dctx->outblk = NULL; *outlen = 0; - return 0; + return false; } #ifdef ZLIB_STANDALONE diff --git a/telnet.c b/telnet.c index 97bd8e5c..1287bd2d 100644 --- a/telnet.c +++ b/telnet.c @@ -171,7 +171,7 @@ static const struct Opt *const opts[] = { typedef struct Telnet Telnet; struct Telnet { Socket *s; - int closed_on_socket_error; + bool closed_on_socket_error; Seat *seat; LogContext *logctx; @@ -180,14 +180,14 @@ struct Telnet { int opt_states[NUM_OPTS]; - int echoing, editing; - int activated; + bool echoing, editing; + bool activated; int bufsize; - int in_synch; + bool in_synch; int sb_opt, sb_len; unsigned char *sb_buf; int sb_size; - int session_started; + bool session_started; enum { TOP_LEVEL, SEENIAC, SEENWILL, SEENWONT, SEENDO, SEENDONT, @@ -248,7 +248,8 @@ static void deactivate_option(Telnet *telnet, const struct Opt *o) /* * Generate side effects of enabling or disabling an option. */ -static void option_side_effects(Telnet *telnet, const struct Opt *o, int enabled) +static void option_side_effects( + Telnet *telnet, const struct Opt *o, bool enabled) { if (o->option == TELOPT_ECHO && o->send == DO) telnet->echoing = !enabled; @@ -290,7 +291,7 @@ static void activate_option(Telnet *telnet, const struct Opt *o) deactivate_option(telnet, o->option == TELOPT_NEW_ENVIRON ? &o_oenv : &o_nenv); } - option_side_effects(telnet, o, 1); + option_side_effects(telnet, o, true); } static void refused_option(Telnet *telnet, const struct Opt *o) @@ -300,7 +301,7 @@ static void refused_option(Telnet *telnet, const struct Opt *o) send_opt(telnet, WILL, TELOPT_OLD_ENVIRON); telnet->opt_states[o_oenv.index] = REQUESTED; } - option_side_effects(telnet, o, 0); + option_side_effects(telnet, o, false); } static void proc_rec_opt(Telnet *telnet, int cmd, int option) @@ -336,7 +337,7 @@ static void proc_rec_opt(Telnet *telnet, int cmd, int option) case ACTIVE: telnet->opt_states[(*o)->index] = INACTIVE; send_opt(telnet, (*o)->nsend, option); - option_side_effects(telnet, *o, 0); + option_side_effects(telnet, *o, false); break; case INACTIVE: case REALLY_INACTIVE: @@ -542,7 +543,7 @@ static void do_telnet_read(Telnet *telnet, char *buf, int len) * just stop hiding on the next 0xf2 and hope for the best. */ else if (c == DM) - telnet->in_synch = 0; + telnet->in_synch = false; #endif if (c == CR && telnet->opt_states[o_they_bin.index] != ACTIVE) telnet->state = SEENCR; @@ -562,7 +563,7 @@ static void do_telnet_read(Telnet *telnet, char *buf, int len) else if (c == SB) telnet->state = SEENSB; else if (c == DM) { - telnet->in_synch = 0; + telnet->in_synch = false; telnet->state = TOP_LEVEL; } else { /* ignore everything else; print it if it's IAC */ @@ -633,7 +634,7 @@ static void telnet_log(Plug *plug, int type, SockAddr *addr, int port, } static void telnet_closing(Plug *plug, const char *error_msg, int error_code, - int calling_back) + bool calling_back) { Telnet *telnet = container_of(plug, Telnet, plug); @@ -690,7 +691,7 @@ static const PlugVtable Telnet_plugvt = { static const char *telnet_init(Seat *seat, Backend **backend_handle, LogContext *logctx, Conf *conf, const char *host, int port, - char **realhost, int nodelay, int keepalive) + char **realhost, bool nodelay, bool keepalive) { SockAddr *addr; const char *err; @@ -736,8 +737,8 @@ static const char *telnet_init(Seat *seat, Backend **backend_handle, /* * Open socket. */ - telnet->s = new_connection(addr, *realhost, port, 0, 1, nodelay, keepalive, - &telnet->plug, telnet->conf); + telnet->s = new_connection(addr, *realhost, port, false, true, nodelay, + keepalive, &telnet->plug, telnet->conf); if ((err = sk_socket_error(telnet->s)) != NULL) return err; @@ -1000,16 +1001,16 @@ static const SessionSpecial *telnet_get_specials(Backend *be) return specials; } -static int telnet_connected(Backend *be) +static bool telnet_connected(Backend *be) { Telnet *telnet = container_of(be, Telnet, backend); return telnet->s != NULL; } -static int telnet_sendok(Backend *be) +static bool telnet_sendok(Backend *be) { /* Telnet *telnet = container_of(be, Telnet, backend); */ - return 1; + return true; } static void telnet_unthrottle(Backend *be, int backlog) @@ -1018,7 +1019,7 @@ static void telnet_unthrottle(Backend *be, int backlog) sk_set_frozen(telnet->s, backlog > TELNET_MAX_BACKLOG); } -static int telnet_ldisc(Backend *be, int option) +static bool telnet_ldisc(Backend *be, int option) { Telnet *telnet = container_of(be, Telnet, backend); if (option == LD_ECHO) diff --git a/terminal.c b/terminal.c index e99edea0..ae0f3917 100644 --- a/terminal.c +++ b/terminal.c @@ -22,8 +22,12 @@ #define posPlt(p1,p2) ( (p1).y <= (p2).y && (p1).x < (p2).x ) #define posPle(p1,p2) ( (p1).y <= (p2).y && (p1).x <= (p2).x ) -#define incpos(p) ( (p).x == term->cols ? ((p).x = 0, (p).y++, 1) : ((p).x++, 0) ) -#define decpos(p) ( (p).x == 0 ? ((p).x = term->cols, (p).y--, 1) : ((p).x--, 0) ) +#define incpos(p) ( (p).x == term->cols ? \ + ((p).x = 0, (p).y++, true) : \ + ((p).x++, false) ) +#define decpos(p) ( (p).x == 0 ? \ + ((p).x = term->cols, (p).y--, true) : \ + ((p).x--, false) ) #define VT52_PLUS @@ -102,16 +106,16 @@ static termline *lineptr(Terminal *, int, int, int); static void unlineptr(termline *); static void check_line_size(Terminal *, termline *); static void do_paint(Terminal *); -static void erase_lots(Terminal *, int, int, int); +static void erase_lots(Terminal *, bool, bool, bool); static int find_last_nonempty_line(Terminal *, tree234 *); -static void swap_screen(Terminal *, int, int, int); +static void swap_screen(Terminal *, int, bool, bool); static void update_sbar(Terminal *); static void deselect(Terminal *); static void term_print_finish(Terminal *); -static void scroll(Terminal *, int, int, int, int); +static void scroll(Terminal *, int, int, int, bool); static void parse_optionalrgb(optionalrgb *out, unsigned *values); -static termline *newline(Terminal *term, int cols, int bce) +static termline *newline(Terminal *term, int cols, bool bce) { termline *line; int j; @@ -278,8 +282,8 @@ static void clear_cc(termline *line, int col) * in do_paint() where we override what we expect the chr and attr * fields to be. */ -static int termchars_equal_override(termchar *a, termchar *b, - unsigned long bchr, unsigned long battr) +static bool termchars_equal_override(termchar *a, termchar *b, + unsigned long bchr, unsigned long battr) { /* FULL-TERMCHAR */ if (!truecolour_equal(a->truecolour, b->truecolour)) @@ -299,7 +303,7 @@ static int termchars_equal_override(termchar *a, termchar *b, return true; } -static int termchars_equal(termchar *a, termchar *b) +static bool termchars_equal(termchar *a, termchar *b) { return termchars_equal_override(a, b, b->chr, b->attr); } @@ -375,7 +379,8 @@ static void makerle(struct buf *b, termline *ldata, void (*makeliteral)(struct buf *b, termchar *c, unsigned long *state)) { - int hdrpos, hdrsize, n, prevlen, prevpos, thislen, thispos, prev2; + int hdrpos, hdrsize, n, prevlen, prevpos, thislen, thispos; + bool prev2; termchar *c = ldata->chars; unsigned long state = 0, oldstate; @@ -1132,8 +1137,8 @@ static termline *lineptr(Terminal *term, int y, int lineno, int screen) return line; } -#define lineptr(x) (lineptr)(term,x,__LINE__,false) -#define scrlineptr(x) (lineptr)(term,x,__LINE__,true) +#define lineptr(x) (lineptr)(term,x,__LINE__,0) +#define scrlineptr(x) (lineptr)(term,x,__LINE__,1) /* * Coerce a termline to the terminal's current width. Unlike the @@ -1157,7 +1162,7 @@ static void term_schedule_cblink(Terminal *term); static void term_timer(void *ctx, unsigned long now) { Terminal *term = (Terminal *)ctx; - int update = false; + bool update = false; if (term->tblink_pending && now == term->next_tblink) { term->tblinker = !term->tblinker; @@ -1212,7 +1217,7 @@ static void term_schedule_tblink(Terminal *term) term->next_tblink = schedule_timer(TBLINK_DELAY, term_timer, term); term->tblink_pending = true; } else { - term->tblinker = 1; /* reset when not in use */ + term->tblinker = true; /* reset when not in use */ term->tblink_pending = false; } } @@ -1227,7 +1232,7 @@ static void term_schedule_cblink(Terminal *term) term->next_cblink = schedule_timer(CBLINK_DELAY, term_timer, term); term->cblink_pending = true; } else { - term->cblinker = 1; /* reset when not in use */ + term->cblinker = true; /* reset when not in use */ term->cblink_pending = false; } } @@ -1238,7 +1243,7 @@ static void term_schedule_cblink(Terminal *term) static void term_reset_cblink(Terminal *term) { seen_disp_event(term); - term->cblinker = 1; + term->cblinker = true; term->cblink_pending = false; term_schedule_cblink(term); } @@ -1246,7 +1251,7 @@ static void term_reset_cblink(Terminal *term) /* * Call to begin a visual bell. */ -static void term_schedule_vbell(Terminal *term, int already_started, +static void term_schedule_vbell(Terminal *term, bool already_started, long startpoint) { long ticks_already_gone; @@ -1271,7 +1276,7 @@ static void term_schedule_vbell(Terminal *term, int already_started, * position the cursor below the last non-blank line (scrolling if * necessary). */ -static void power_on(Terminal *term, int clear) +static void power_on(Terminal *term, bool clear) { term->alt_x = term->alt_y = 0; term->savecurs.x = term->savecurs.y = 0; @@ -1287,21 +1292,27 @@ static void power_on(Terminal *term, int clear) term->tabs[i] = (i % 8 == 0 ? true : false); } term->alt_om = term->dec_om = conf_get_bool(term->conf, CONF_dec_om); - term->alt_ins = term->insert = false; - term->alt_wnext = term->wrapnext = - term->save_wnext = term->alt_save_wnext = false; + term->alt_ins = false; + term->insert = false; + term->alt_wnext = false; + term->wrapnext = false; + term->save_wnext = false; + term->alt_save_wnext = false; term->alt_wrap = term->wrap = conf_get_bool(term->conf, CONF_wrap_mode); term->alt_cset = term->cset = term->save_cset = term->alt_save_cset = 0; - term->alt_utf = term->utf = term->save_utf = term->alt_save_utf = 0; + term->alt_utf = false; + term->utf = false; + term->save_utf = false; + term->alt_save_utf = false; term->utf_state = 0; term->alt_sco_acs = term->sco_acs = term->save_sco_acs = term->alt_save_sco_acs = 0; term->cset_attr[0] = term->cset_attr[1] = term->save_csattr = term->alt_save_csattr = CSET_ASCII; - term->rvideo = 0; + term->rvideo = false; term->in_vbell = false; - term->cursor_on = 1; - term->big_cursor = 0; + term->cursor_on = true; + term->big_cursor = false; term->default_attr = term->save_attr = term->alt_save_attr = term->curr_attr = ATTR_DEFAULT; term->curr_truecolour.fg = term->curr_truecolour.bg = optionalrgb_none; @@ -1315,8 +1326,8 @@ static void power_on(Terminal *term, int clear) term->alt_which = 0; term_print_finish(term); term->xterm_mouse = 0; - term->xterm_extended_mouse = 0; - term->urxvt_extended_mouse = 0; + term->xterm_extended_mouse = false; + term->urxvt_extended_mouse = false; win_set_raw_mouse_mode(term->win, false); term->bracketed_paste = false; { @@ -1351,10 +1362,10 @@ void term_update(Terminal *term) term->window_update_pending = false; if (win_setup_draw_ctx(term->win)) { - int need_sbar_update = term->seen_disp_event; + bool need_sbar_update = term->seen_disp_event; if (term->seen_disp_event && term->scroll_on_disp) { term->disptop = 0; /* return to main screen */ - term->seen_disp_event = 0; + term->seen_disp_event = false; need_sbar_update = true; } @@ -1401,7 +1412,7 @@ void term_seen_key_event(Terminal *term) /* * Same as power_on(), but an external function. */ -void term_pwron(Terminal *term, int clear) +void term_pwron(Terminal *term, bool clear) { power_on(term, clear); if (term->ldisc) /* cause ldisc to notice changes */ @@ -1509,7 +1520,7 @@ void term_reconfig(Terminal *term, Conf *conf) * default one. The full list is: Auto wrap mode, DEC Origin * Mode, BCE, blinking text, character classes. */ - int reset_wrap, reset_decom, reset_bce, reset_tblink, reset_charclass; + bool reset_wrap, reset_decom, reset_bce, reset_tblink, reset_charclass; int i; reset_wrap = (conf_get_bool(term->conf, CONF_wrap_mode) != @@ -1520,11 +1531,11 @@ void term_reconfig(Terminal *term, Conf *conf) conf_get_bool(conf, CONF_bce)); reset_tblink = (conf_get_bool(term->conf, CONF_blinktext) != conf_get_bool(conf, CONF_blinktext)); - reset_charclass = 0; + reset_charclass = false; for (i = 0; i < 256; i++) if (conf_get_int_int(term->conf, CONF_wordness, i) != conf_get_int_int(conf, CONF_wordness, i)) - reset_charclass = 1; + reset_charclass = true; /* * If the bidi or shaping settings have changed, flush the bidi @@ -1571,7 +1582,7 @@ void term_reconfig(Terminal *term, Conf *conf) if (conf_get_bool(term->conf, CONF_no_remote_charset)) { term->cset_attr[0] = term->cset_attr[1] = CSET_ASCII; term->sco_acs = term->alt_sco_acs = 0; - term->utf = 0; + term->utf = false; } if (!conf_get_str(term->conf, CONF_printer)) { term_print_finish(term); @@ -1658,10 +1669,11 @@ Terminal *term_init(Conf *myconf, struct unicode_data *ucsdata, TermWin *win) term->vt52_mode = false; term->cr_lf_return = false; term->seen_disp_event = false; - term->mouse_is_down = false; + term->mouse_is_down = 0; term->reset_132 = false; - term->cblinker = term->tblinker = 0; - term->has_focus = 1; + term->cblinker = false; + term->tblinker = false; + term->has_focus = true; term->repeat_off = false; term->termstate = TOPLEVEL; term->selstate = NO_SELECTION; @@ -1944,7 +1956,8 @@ void term_size(Terminal *term, int newrows, int newcols, int newsavelines) if (term->alt_x >= newcols) term->alt_x = newcols - 1; term->alt_x = term->alt_y = 0; - term->wrapnext = term->alt_wnext = false; + term->wrapnext = false; + term->alt_wnext = false; term->rows = newrows; term->cols = newcols; @@ -1993,9 +2006,11 @@ static int find_last_nonempty_line(Terminal * term, tree234 * screen) * alternate screen completely. (This is even true if we're already * on it! Blame xterm.) */ -static void swap_screen(Terminal *term, int which, int reset, int keep_cur_pos) +static void swap_screen(Terminal *term, int which, + bool reset, bool keep_cur_pos) { int t; + bool bt; pos tp; truecolour ttc; tree234 *ttr; @@ -2024,24 +2039,24 @@ static void swap_screen(Terminal *term, int which, int reset, int keep_cur_pos) t = term->marg_b; if (!reset) term->marg_b = term->alt_b; term->alt_b = t; - t = term->dec_om; + bt = term->dec_om; if (!reset) term->dec_om = term->alt_om; - term->alt_om = t; - t = term->wrap; + term->alt_om = bt; + bt = term->wrap; if (!reset) term->wrap = term->alt_wrap; - term->alt_wrap = t; - t = term->wrapnext; + term->alt_wrap = bt; + bt = term->wrapnext; if (!reset) term->wrapnext = term->alt_wnext; - term->alt_wnext = t; - t = term->insert; + term->alt_wnext = bt; + bt = term->insert; if (!reset) term->insert = term->alt_ins; - term->alt_ins = t; + term->alt_ins = bt; t = term->cset; if (!reset) term->cset = term->alt_cset; term->alt_cset = t; - t = term->utf; + bt = term->utf; if (!reset) term->utf = term->alt_utf; - term->alt_utf = t; + term->alt_utf = bt; t = term->sco_acs; if (!reset) term->sco_acs = term->alt_sco_acs; term->alt_sco_acs = t; @@ -2066,14 +2081,14 @@ static void swap_screen(Terminal *term, int which, int reset, int keep_cur_pos) if (!reset && !keep_cur_pos) term->save_truecolour = term->alt_save_truecolour; term->alt_save_truecolour = ttc; - t = term->save_utf; + bt = term->save_utf; if (!reset && !keep_cur_pos) term->save_utf = term->alt_save_utf; - term->alt_save_utf = t; - t = term->save_wnext; + term->alt_save_utf = bt; + bt = term->save_wnext; if (!reset && !keep_cur_pos) term->save_wnext = term->alt_save_wnext; - term->alt_save_wnext = t; + term->alt_save_wnext = bt; t = term->save_sco_acs; if (!reset && !keep_cur_pos) term->save_sco_acs = term->alt_save_sco_acs; @@ -2113,7 +2128,8 @@ static void check_selection(Terminal *term, pos from, pos to) * for backward.) `sb' is true if the scrolling is permitted to * affect the scrollback buffer. */ -static void scroll(Terminal *term, int topline, int botline, int lines, int sb) +static void scroll(Terminal *term, int topline, int botline, + int lines, bool sb) { termline *line; int i, seltop, scrollwinsize; @@ -2275,7 +2291,7 @@ static void move(Terminal *term, int x, int y, int marg_clip) /* * Save or restore the cursor and SGR mode. */ -static void save_cursor(Terminal *term, int save) +static void save_cursor(Terminal *term, bool save) { if (save) { term->savecurs = term->curs; @@ -2357,11 +2373,11 @@ static void check_boundary(Terminal *term, int x, int y) * whole line, or parts thereof. */ static void erase_lots(Terminal *term, - int line_only, int from_begin, int to_end) + bool line_only, bool from_begin, bool to_end) { pos start, end; - int erase_lattr; - int erasing_lines_from_top = 0; + bool erase_lattr; + bool erasing_lines_from_top = false; if (line_only) { start.y = term->curs.y; @@ -2394,7 +2410,7 @@ static void erase_lots(Terminal *term, /* Lines scrolled away shouldn't be brought back on if the terminal * resizes. */ if (start.y == 0 && start.x == 0 && end.x == 0 && erase_lattr) - erasing_lines_from_top = 1; + erasing_lines_from_top = true; if (term->erase_to_scrollback && erasing_lines_from_top) { /* If it's a whole number of lines, starting at the top, and @@ -2510,9 +2526,9 @@ static void insch(Terminal *term, int n) * Toggle terminal mode `mode' to state `state'. (`query' indicates * whether the mode is a DEC private one or a normal one.) */ -static void toggle_mode(Terminal *term, int mode, int query, int state) +static void toggle_mode(Terminal *term, int mode, int query, bool state) { - if (query) + if (query == 1) { switch (mode) { case 1: /* DECCKM: application cursor keys */ term->app_cursor_keys = state; @@ -2589,10 +2605,10 @@ static void toggle_mode(Terminal *term, int mode, int query, int state) win_set_raw_mouse_mode(term->win, state); break; case 1006: /* xterm extended mouse */ - term->xterm_extended_mouse = state ? 1 : 0; + term->xterm_extended_mouse = state; break; case 1015: /* urxvt extended mouse */ - term->urxvt_extended_mouse = state ? 1 : 0; + term->urxvt_extended_mouse = state; break; case 1047: /* alternate screen */ compatibility(OTHER); @@ -2621,7 +2637,8 @@ static void toggle_mode(Terminal *term, int mode, int query, int state) case 2004: /* xterm bracketed paste */ term->bracketed_paste = state ? true : false; break; - } else + } + } else if (query == 0) { switch (mode) { case 4: /* IRM: set insert mode */ compatibility(VT102); @@ -2639,6 +2656,7 @@ static void toggle_mode(Terminal *term, int mode, int query, int state) compatibility2(OTHER, VT220); term->big_cursor = !state; } + } } /* @@ -2676,7 +2694,8 @@ static void do_osc(Terminal *term) (unsigned)r * 0x0101, (unsigned)g * 0x0101, (unsigned)b * 0x0101); - ldisc_send(term->ldisc, reply_buf, strlen(reply_buf), 0); + ldisc_send(term->ldisc, reply_buf, strlen(reply_buf), + false); sfree(reply_buf); } } @@ -3088,7 +3107,7 @@ static void term_out(Terminal *term) c = 0; else { term->termstate = SEEN_ESC; - term->esc_query = false; + term->esc_query = 0; c = '@' + (c & 0x1F); } } @@ -3120,7 +3139,7 @@ static void term_out(Terminal *term) compatibility(ANSIMIN); if (term->ldisc) { lpage_send(term->ldisc, DEFAULT_CODEPAGE, - term->answerback, term->answerbacklen, 0); + term->answerback, term->answerbacklen, false); } break; case '\007': /* BEL: Bell */ @@ -3189,8 +3208,7 @@ static void term_out(Terminal *term) } break; case '\b': /* BS: Back space */ - if (term->curs.x == 0 && - (term->curs.y == 0 || term->wrap == 0)) + if (term->curs.x == 0 && (term->curs.y == 0 || term->wrap)) /* do nothing */ ; else if (term->curs.x == 0 && term->curs.y > 0) term->curs.x = term->cols - 1, term->curs.y--; @@ -3214,7 +3232,7 @@ static void term_out(Terminal *term) else { compatibility(ANSIMIN); term->termstate = SEEN_ESC; - term->esc_query = false; + term->esc_query = 0; } break; case '\015': /* CR: Carriage return */ @@ -3313,7 +3331,7 @@ static void term_out(Terminal *term) term->termstate = SEEN_CSI; term->esc_nargs = 1; term->esc_args[0] = ARG_DEFAULT; - term->esc_query = false; + term->esc_query = 0; break; case ']': /* OSC: xterm escape sequences */ /* Compatibility is nasty here, xterm, linux, decterm yuk! */ @@ -3371,7 +3389,7 @@ static void term_out(Terminal *term) compatibility(VT100); if (term->ldisc && term->id_string[0]) ldisc_send(term->ldisc, term->id_string, - strlen(term->id_string), 0); + strlen(term->id_string), false); break; case 'c': /* RIS: restore power-on settings */ compatibility(VT100); @@ -3381,7 +3399,7 @@ static void term_out(Terminal *term) if (term->reset_132) { if (!term->no_remote_resize) win_request_resize(term->win, 80, term->rows); - term->reset_132 = 0; + term->reset_132 = false; } if (term->scroll_on_disp) term->disptop = 0; @@ -3494,12 +3512,12 @@ static void term_out(Terminal *term) case ANSI('G', '%'): compatibility(OTHER); if (!term->no_remote_charset) - term->utf = 1; + term->utf = true; break; case ANSI('@', '%'): compatibility(OTHER); if (!term->no_remote_charset) - term->utf = 0; + term->utf = false; break; } break; @@ -3528,7 +3546,7 @@ static void term_out(Terminal *term) if (term->esc_query) term->esc_query = -1; else if (c == '?') - term->esc_query = true; + term->esc_query = 1; else term->esc_query = c; term->termstate = SEEN_CSI; @@ -3564,7 +3582,8 @@ static void term_out(Terminal *term) /* this reports xterm version 136 so that VIM can use the drag messages from the mouse reporting */ if (term->ldisc) - ldisc_send(term->ldisc, "\033[>0;136;0c", 11, 0); + ldisc_send(term->ldisc, "\033[>0;136;0c", 11, + false); break; case 'a': /* HPR: move right N cols */ compatibility(ANSI); @@ -3687,7 +3706,7 @@ static void term_out(Terminal *term) /* This is the response for a VT102 */ if (term->ldisc && term->id_string[0]) ldisc_send(term->ldisc, term->id_string, - strlen(term->id_string), 0); + strlen(term->id_string), false); break; case 'n': /* DSR: cursor position query */ if (term->ldisc) { @@ -3695,9 +3714,10 @@ static void term_out(Terminal *term) char buf[32]; sprintf(buf, "\033[%d;%dR", term->curs.y + 1, term->curs.x + 1); - ldisc_send(term->ldisc, buf, strlen(buf), 0); + ldisc_send(term->ldisc, buf, strlen(buf), + false); } else if (term->esc_args[0] == 5) { - ldisc_send(term->ldisc, "\033[0n", 4, 0); + ldisc_send(term->ldisc, "\033[0n", 4, false); } } break; @@ -4088,7 +4108,8 @@ static void term_out(Terminal *term) if (term->ldisc) ldisc_send(term->ldisc, win_is_minimised(term->win) ? - "\033[2t" : "\033[1t", 4, 0); + "\033[2t" : "\033[1t", 4, + false); break; case 13: if (term->ldisc) { @@ -4096,21 +4117,21 @@ static void term_out(Terminal *term) len = sprintf(buf, "\033[3;%u;%ut", (unsigned)x, (unsigned)y); - ldisc_send(term->ldisc, buf, len, 0); + ldisc_send(term->ldisc, buf, len, false); } break; case 14: if (term->ldisc) { win_get_pixels(term->win, &x, &y); len = sprintf(buf, "\033[4;%d;%dt", y, x); - ldisc_send(term->ldisc, buf, len, 0); + ldisc_send(term->ldisc, buf, len, false); } break; case 18: if (term->ldisc) { len = sprintf(buf, "\033[8;%d;%dt", term->rows, term->cols); - ldisc_send(term->ldisc, buf, len, 0); + ldisc_send(term->ldisc, buf, len, false); } break; case 19: @@ -4138,10 +4159,12 @@ static void term_out(Terminal *term) else p = EMPTY_WINDOW_TITLE; len = strlen(p); - ldisc_send(term->ldisc, "\033]L", 3, 0); + ldisc_send(term->ldisc, "\033]L", 3, + false); if (len > 0) - ldisc_send(term->ldisc, p, len, 0); - ldisc_send(term->ldisc, "\033\\", 2, 0); + ldisc_send(term->ldisc, p, len, false); + ldisc_send(term->ldisc, "\033\\", 2, + false); } break; case 21: @@ -4152,10 +4175,12 @@ static void term_out(Terminal *term) else p = EMPTY_WINDOW_TITLE; len = strlen(p); - ldisc_send(term->ldisc, "\033]l", 3, 0); + ldisc_send(term->ldisc, "\033]l", 3, + false); if (len > 0) - ldisc_send(term->ldisc, p, len, 0); - ldisc_send(term->ldisc, "\033\\", 2, 0); + ldisc_send(term->ldisc, p, len, false); + ldisc_send(term->ldisc, "\033\\", 2, + false); } break; } @@ -4241,7 +4266,7 @@ static void term_out(Terminal *term) if (i == 0 || i == 1) { strcpy(buf, "\033[2;1;1;112;112;1;0x"); buf[2] += i; - ldisc_send(term->ldisc, buf, 20, 0); + ldisc_send(term->ldisc, buf, 20, false); } } break; @@ -4657,7 +4682,7 @@ static void term_out(Terminal *term) break; case 'Z': if (term->ldisc) - ldisc_send(term->ldisc, "\033/Z", 3, 0); + ldisc_send(term->ldisc, "\033/Z", 3, false); break; case '=': term->app_keypad_keys = true; @@ -4748,11 +4773,11 @@ static void term_out(Terminal *term) break; case 'v': /* wrap Autowrap on - Wyse style */ /* compatibility(ATARI) */ - term->wrap = 1; + term->wrap = true; break; case 'w': /* Autowrap off */ /* compatibility(ATARI) */ - term->wrap = 0; + term->wrap = false; break; case 'R': @@ -4841,8 +4866,8 @@ static void parse_optionalrgb(optionalrgb *out, unsigned *values) * too many times, we maintain a cache of the last lineful of data * fed to the algorithm on each line of the display. */ -static int term_bidi_cache_hit(Terminal *term, int line, - termchar *lbefore, int width) +static bool term_bidi_cache_hit(Terminal *term, int line, + termchar *lbefore, int width) { int i; @@ -5115,12 +5140,13 @@ static void do_paint(Terminal *term) for (i = 0; i < term->rows; i++) { termline *ldata; termchar *lchars; - int dirty_line, dirty_run, selected; + bool dirty_line, dirty_run, selected; unsigned long attr = 0, cset = 0; int start = 0; int ccount = 0; - int last_run_dirty = 0; - int laststart, dirtyrect; + bool last_run_dirty = false; + int laststart; + bool dirtyrect; int *backward; truecolour tc; @@ -5280,7 +5306,7 @@ static void do_paint(Terminal *term) tc = term->erase_char.truecolour; for (j = 0; j < term->cols; j++) { unsigned long tattr, tchar; - int break_run, do_copy; + bool break_run, do_copy; termchar *d = lchars + j; tattr = newline[j].attr; @@ -5458,7 +5484,7 @@ void term_invalidate(Terminal *term) * Paint the window in response to a WM_PAINT message. */ void term_paint(Terminal *term, - int left, int top, int right, int bottom, int immediately) + int left, int top, int right, int bottom, bool immediately) { int i, j; if (left < 0) left = 0; @@ -5558,7 +5584,7 @@ static void clip_addchar(clip_workbuf *b, wchar_t chr, int attr, truecolour tc) b->bufpos++; } -static void clipme(Terminal *term, pos top, pos bottom, int rect, int desel, +static void clipme(Terminal *term, pos top, pos bottom, bool rect, bool desel, const int *clipboards, int n_clipboards) { clip_workbuf buf; @@ -5575,7 +5601,7 @@ static void clipme(Terminal *term, pos top, pos bottom, int rect, int desel, old_top_x = top.x; /* needed for rect==1 */ while (poslt(top, bottom)) { - int nl = false; + bool nl = false; termline *ldata = lineptr(top.y); pos nlpos; @@ -5722,7 +5748,7 @@ static void clipme(Terminal *term, pos top, pos bottom, int rect, int desel, /* Finally, transfer all that to the clipboard(s). */ { int i; - int clip_local = false; + bool clip_local = false; for (i = 0; i < n_clipboards; i++) { if (clipboards[i] == CLIP_LOCAL) { clip_local = true; @@ -5757,7 +5783,7 @@ void term_copyall(Terminal *term, const int *clipboards, int n_clipboards) top.x = 0; bottom.y = find_last_nonempty_line(term, screen); bottom.x = term->cols; - clipme(term, top, bottom, 0, true, clipboards, n_clipboards); + clipme(term, top, bottom, false, true, clipboards, n_clipboards); } static void paste_from_clip_local(void *vterm) @@ -6038,7 +6064,8 @@ static void term_paste_callback(void *vterm) break; } if (term->ldisc) - luni_send(term->ldisc, term->paste_buffer + term->paste_pos, n, 0); + luni_send(term->ldisc, term->paste_buffer + term->paste_pos, n, + false); term->paste_pos += n; if (term->paste_pos < term->paste_len) { @@ -6056,7 +6083,7 @@ static void term_paste_callback(void *vterm) * alen wide characters starting at a has as a prefix the buffer of * blen characters starting at b. */ -static int wstartswith(const wchar_t *a, size_t alen, +static bool wstartswith(const wchar_t *a, size_t alen, const wchar_t *b, size_t blen) { return alen >= blen && !wcsncmp(a, b, blen); @@ -6065,7 +6092,7 @@ static int wstartswith(const wchar_t *a, size_t alen, void term_do_paste(Terminal *term, const wchar_t *data, int len) { const wchar_t *p; - int paste_controls = conf_get_bool(term->conf, CONF_paste_controls); + bool paste_controls = conf_get_bool(term->conf, CONF_paste_controls); /* * Pasting data into the terminal counts as a keyboard event (for @@ -6142,7 +6169,7 @@ void term_do_paste(Terminal *term, const wchar_t *data, int len) /* Assume a small paste will be OK in one go. */ if (term->paste_len < 256) { if (term->ldisc) - luni_send(term->ldisc, term->paste_buffer, term->paste_len, 0); + luni_send(term->ldisc, term->paste_buffer, term->paste_len, false); if (term->paste_buffer) sfree(term->paste_buffer); term->paste_buffer = 0; @@ -6153,13 +6180,13 @@ void term_do_paste(Terminal *term, const wchar_t *data, int len) } void term_mouse(Terminal *term, Mouse_Button braw, Mouse_Button bcooked, - Mouse_Action a, int x, int y, int shift, int ctrl, int alt) + Mouse_Action a, int x, int y, bool shift, bool ctrl, bool alt) { pos selpoint; termline *ldata; - int raw_mouse = (term->xterm_mouse && - !term->no_mouse_rep && - !(term->mouse_override && shift)); + bool raw_mouse = (term->xterm_mouse && + !term->no_mouse_rep && + !(term->mouse_override && shift)); int default_seltype; if (y < 0) { @@ -6220,7 +6247,8 @@ void term_mouse(Terminal *term, Mouse_Button braw, Mouse_Button bcooked, */ if (raw_mouse && (term->selstate != ABOUT_TO) && (term->selstate != DRAGGING)) { - int encstate = 0, r, c, wheel; + int encstate = 0, r, c; + bool wheel; char abuf[32]; int len = 0; @@ -6293,7 +6321,7 @@ void term_mouse(Terminal *term, Mouse_Button braw, Mouse_Button bcooked, len = sprintf(abuf, "\033[M%c%c%c", encstate + 32, c + 32, r + 32); } if (len > 0) - ldisc_send(term->ldisc, abuf, len, 0); + ldisc_send(term->ldisc, abuf, len, false); } return; } @@ -6437,14 +6465,14 @@ void term_mouse(Terminal *term, Mouse_Button braw, Mouse_Button bcooked, term_update(term); } -int format_arrow_key(char *buf, Terminal *term, int xkey, int ctrl) +int format_arrow_key(char *buf, Terminal *term, int xkey, bool ctrl) { char *p = buf; if (term->vt52_mode) p += sprintf((char *) p, "\x1B%c", xkey); else { - int app_flg = (term->app_cursor_keys && !term->no_applic_c); + bool app_flg = (term->app_cursor_keys && !term->no_applic_c); #if 0 /* * RDB: VT100 & VT102 manuals both state the app cursor @@ -6506,7 +6534,7 @@ void term_lost_clipboard_ownership(Terminal *term, int clipboard) term_out(term); } -int term_ldisc(Terminal *term, int option) +bool term_ldisc(Terminal *term, int option) { if (option == LD_ECHO) return term->term_echoing; @@ -6531,7 +6559,7 @@ static void term_added_data(Terminal *term) } } -int term_data(Terminal *term, int is_stderr, const void *data, int len) +int term_data(Terminal *term, bool is_stderr, const void *data, int len) { bufchain_add(&term->inbuf, data, len); term_added_data(term); @@ -6569,7 +6597,7 @@ void term_provide_logctx(Terminal *term, LogContext *logctx) term->logctx = logctx; } -void term_set_focus(Terminal *term, int has_focus) +void term_set_focus(Terminal *term, bool has_focus) { term->has_focus = has_focus; term_schedule_cblink(term); @@ -6594,7 +6622,7 @@ char *term_get_ttymode(Terminal *term, const char *mode) struct term_userpass_state { size_t curr_prompt; - int done_prompt; /* printed out prompt yet? */ + bool done_prompt; /* printed out prompt yet? */ size_t pos; /* cursor position */ }; @@ -6611,7 +6639,7 @@ int term_get_userpass_input(Terminal *term, prompts_t *p, bufchain *input) */ p->data = s = snew(struct term_userpass_state); s->curr_prompt = 0; - s->done_prompt = 0; + s->done_prompt = false; /* We only print the `name' caption if we have to... */ if (p->name_reqd && p->name) { size_t l = strlen(p->name); @@ -6639,11 +6667,11 @@ int term_get_userpass_input(Terminal *term, prompts_t *p, bufchain *input) while (s->curr_prompt < p->n_prompts) { prompt_t *pr = p->prompts[s->curr_prompt]; - int finished_prompt = 0; + bool finished_prompt = false; if (!s->done_prompt) { term_data_untrusted(term, pr->prompt, strlen(pr->prompt)); - s->done_prompt = 1; + s->done_prompt = true; s->pos = 0; } @@ -6658,19 +6686,19 @@ int term_get_userpass_input(Terminal *term, prompts_t *p, bufchain *input) switch (c) { case 10: case 13: - term_data(term, 0, "\r\n", 2); + term_data(term, false, "\r\n", 2); prompt_ensure_result_size(pr, s->pos + 1); pr->result[s->pos] = '\0'; /* go to next prompt, if any */ s->curr_prompt++; - s->done_prompt = 0; - finished_prompt = 1; /* break out */ + s->done_prompt = false; + finished_prompt = true; /* break out */ break; case 8: case 127: if (s->pos > 0) { if (pr->echo) - term_data(term, 0, "\b \b", 3); + term_data(term, false, "\b \b", 3); s->pos--; } break; @@ -6678,14 +6706,14 @@ int term_get_userpass_input(Terminal *term, prompts_t *p, bufchain *input) case 27: while (s->pos > 0) { if (pr->echo) - term_data(term, 0, "\b \b", 3); + term_data(term, false, "\b \b", 3); s->pos--; } break; case 3: case 4: /* Immediate abort. */ - term_data(term, 0, "\r\n", 2); + term_data(term, false, "\r\n", 2); sfree(s); p->data = NULL; return 0; /* user abort */ @@ -6700,7 +6728,7 @@ int term_get_userpass_input(Terminal *term, prompts_t *p, bufchain *input) prompt_ensure_result_size(pr, s->pos + 1); pr->result[s->pos++] = c; if (pr->echo) - term_data(term, 0, &c, 1); + term_data(term, false, &c, 1); } break; } diff --git a/terminal.h b/terminal.h index d569f5f4..e39090bb 100644 --- a/terminal.h +++ b/terminal.h @@ -52,7 +52,7 @@ struct termline { int cols; /* number of real columns on the line */ int size; /* number of allocated termchars * (cc-lists may make this > cols) */ - int temporary; /* true if decompressed from scrollback */ + bool temporary; /* true if decompressed from scrollback */ int cc_free; /* offset to first cc in free list */ struct termchar *chars; }; @@ -83,7 +83,7 @@ struct terminal_tag { struct beeptime *beephead, *beeptail; int nbeeps; - int beep_overloaded; + bool beep_overloaded; long lastbeep; #define TTYPE termchar @@ -97,29 +97,29 @@ struct terminal_tag { pos curs; /* cursor */ pos savecurs; /* saved cursor position */ int marg_t, marg_b; /* scroll margins */ - int dec_om; /* DEC origin mode flag */ - int wrap, wrapnext; /* wrap flags */ - int insert; /* insert-mode flag */ + bool dec_om; /* DEC origin mode flag */ + bool wrap, wrapnext; /* wrap flags */ + bool insert; /* insert-mode flag */ int cset; /* 0 or 1: which char set */ int save_cset, save_csattr; /* saved with cursor position */ - int save_utf, save_wnext; /* saved with cursor position */ - int rvideo; /* global reverse video flag */ + bool save_utf, save_wnext; /* saved with cursor position */ + bool rvideo; /* global reverse video flag */ unsigned long rvbell_startpoint; /* for ESC[?5hESC[?5l vbell */ - int cursor_on; /* cursor enabled flag */ - int reset_132; /* Flag ESC c resets to 80 cols */ - int use_bce; /* Use Background coloured erase */ - int cblinker; /* When blinking is the cursor on ? */ - int tblinker; /* When the blinking text is on */ - int blink_is_real; /* Actually blink blinking text */ - int term_echoing; /* Does terminal want local echo? */ - int term_editing; /* Does terminal want local edit? */ + bool cursor_on; /* cursor enabled flag */ + bool reset_132; /* Flag ESC c resets to 80 cols */ + bool use_bce; /* Use Background coloured erase */ + bool cblinker; /* When blinking is the cursor on ? */ + bool tblinker; /* When the blinking text is on */ + bool blink_is_real; /* Actually blink blinking text */ + bool term_echoing; /* Does terminal want local echo? */ + bool term_editing; /* Does terminal want local edit? */ int sco_acs, save_sco_acs; /* CSI 10,11,12m -> OEM charset */ - int vt52_bold; /* Force bold on non-bold colours */ - int utf; /* Are we in toggleable UTF-8 mode? */ + bool vt52_bold; /* Force bold on non-bold colours */ + bool utf; /* Are we in toggleable UTF-8 mode? */ int utf_state; /* Is there a pending UTF-8 character */ int utf_char; /* and what is it so far. */ int utf_size; /* The size of the UTF character. */ - int printing, only_printing; /* Are we doing ANSI printing? */ + bool printing, only_printing; /* Are we doing ANSI printing? */ int print_state; /* state of print-end-sequence scan */ bufchain printer_buf; /* buffered data for printer */ printer_job *print_job; @@ -129,32 +129,36 @@ struct terminal_tag { int alt_save_attr; truecolour alt_save_truecolour; int alt_save_cset, alt_save_csattr; - int alt_save_utf, alt_save_wnext; + bool alt_save_utf; + bool alt_save_wnext; int alt_save_sco_acs; int rows, cols, savelines; - int has_focus; - int in_vbell; + bool has_focus; + bool in_vbell; long vbell_end; - int app_cursor_keys, app_keypad_keys, vt52_mode; - int repeat_off, cr_lf_return; - int seen_disp_event; - int big_cursor; + bool app_cursor_keys, app_keypad_keys, vt52_mode; + bool repeat_off, cr_lf_return; + bool seen_disp_event; + bool big_cursor; int xterm_mouse; /* send mouse messages to host */ - int xterm_extended_mouse; - int urxvt_extended_mouse; + bool xterm_extended_mouse; + bool urxvt_extended_mouse; int mouse_is_down; /* used while tracking mouse buttons */ - int bracketed_paste; + bool bracketed_paste; int cset_attr[2]; /* * Saved settings on the alternate screen. */ - int alt_x, alt_y, alt_om, alt_wrap, alt_wnext, alt_ins; - int alt_cset, alt_sco_acs, alt_utf; + int alt_x, alt_y; + bool alt_wnext, alt_ins; + bool alt_om, alt_wrap; + int alt_cset, alt_sco_acs; + bool alt_utf; int alt_t, alt_b; int alt_which; int alt_sblines; /* # of lines on alternate screen that should be used for scrollback. */ @@ -166,12 +170,12 @@ struct terminal_tag { int esc_nargs; int esc_query; #define ANSI(x,y) ((x)+((y)<<8)) -#define ANSI_QUE(x) ANSI(x,true) +#define ANSI_QUE(x) ANSI(x,1) #define OSC_STR_MAX 2048 int osc_strlen; char osc_string[OSC_STR_MAX + 1]; - int osc_w; + bool osc_w; char id_string[1024]; @@ -243,19 +247,19 @@ struct terminal_tag { * data to the end of the buffer term_out is in the process of * working through. */ - int in_term_out; + bool in_term_out; /* * We schedule a window update shortly after receiving terminal * data. This tracks whether one is currently pending. */ - int window_update_pending; + bool window_update_pending; long next_update; /* * Track pending blinks and tblinks. */ - int tblink_pending, cblink_pending; + bool tblink_pending, cblink_pending; long next_tblink, next_cblink; /* @@ -274,48 +278,48 @@ struct terminal_tag { * tree234 lookups which would be involved in fetching them from * the former every time. */ - int ansi_colour; + bool ansi_colour; char *answerback; int answerbacklen; - int arabicshaping; + bool arabicshaping; int beep; - int bellovl; + bool bellovl; int bellovl_n; int bellovl_s; int bellovl_t; - int bidi; - int bksp_is_delete; - int blink_cur; - int blinktext; - int cjk_ambig_wide; + bool bidi; + bool bksp_is_delete; + bool blink_cur; + bool blinktext; + bool cjk_ambig_wide; int conf_height; int conf_width; - int crhaslf; - int erase_to_scrollback; + bool crhaslf; + bool erase_to_scrollback; int funky_type; - int lfhascr; - int logflush; + bool lfhascr; + bool logflush; int logtype; - int mouse_override; - int nethack_keypad; - int no_alt_screen; - int no_applic_c; - int no_applic_k; - int no_dbackspace; - int no_mouse_rep; - int no_remote_charset; - int no_remote_resize; - int no_remote_wintitle; - int no_remote_clearscroll; - int rawcnp; - int utf8linedraw; - int rect_select; + bool mouse_override; + bool nethack_keypad; + bool no_alt_screen; + bool no_applic_c; + bool no_applic_k; + bool no_dbackspace; + bool no_mouse_rep; + bool no_remote_charset; + bool no_remote_resize; + bool no_remote_wintitle; + bool no_remote_clearscroll; + bool rawcnp; + bool utf8linedraw; + bool rect_select; int remote_qtitle_action; - int rxvt_homeend; - int scroll_on_disp; - int scroll_on_key; - int xterm_256_colour; - int true_colour; + bool rxvt_homeend; + bool scroll_on_disp; + bool scroll_on_key; + bool xterm_256_colour; + bool true_colour; wchar_t *last_selected_text; int *last_selected_attr; diff --git a/testbn.c b/testbn.c index 29f6b753..364f704a 100644 --- a/testbn.c +++ b/testbn.c @@ -37,7 +37,7 @@ void queue_idempotent_callback(IdempotentCallback *ic) { assert(0); } #define fromxdigit(c) ( (c)>'9' ? ((c)&0xDF) - 'A' + 10 : (c) - '0' ) /* For Unix in particular, but harmless if this main() is reused elsewhere */ -const int buildinfo_gtk_relevant = false; +const bool buildinfo_gtk_relevant = false; int main(int argc, char **argv) { @@ -201,7 +201,7 @@ int main(int argc, char **argv) freebn(answer); } else if (!strcmp(buf, "divmod")) { Bignum n, d, expect_q, expect_r, answer_q, answer_r; - int fail; + bool fail; if (ptrnum != 4) { printf("%d: divmod with %d parameters, expected 4\n", line, ptrnum); diff --git a/timing.c b/timing.c index 0aad374a..8036e438 100644 --- a/timing.c +++ b/timing.c @@ -164,7 +164,7 @@ unsigned long timing_last_clock(void) * Returns the time (in ticks) expected until the next timer after * that triggers. */ -int run_timers(unsigned long anow, unsigned long *next) +bool run_timers(unsigned long anow, unsigned long *next) { struct timer *first; diff --git a/tree234.c b/tree234.c index ea8ff9ee..4cf9cb1e 100644 --- a/tree234.c +++ b/tree234.c @@ -29,6 +29,7 @@ #include #include +#include "defs.h" #include "tree234.h" #ifdef TEST @@ -529,7 +530,7 @@ void *findrelpos234(tree234 * t, void *e, cmpfn234 cmp, search234_state ss; int reldir = (relation == REL234_LT || relation == REL234_LE ? -1 : relation == REL234_GT || relation == REL234_GE ? +1 : 0); - int equal_permitted = (relation != REL234_LT && relation != REL234_GT); + bool equal_permitted = (relation != REL234_LT && relation != REL234_GT); void *toret; /* Only LT / GT relations are permitted with a null query element. */ diff --git a/unix/gtkapp.c b/unix/gtkapp.c index a9f6b02c..70dc7d3c 100644 --- a/unix/gtkapp.c +++ b/unix/gtkapp.c @@ -88,7 +88,7 @@ I suppose I'll have to look into OS X code signing. char *x_get_default(const char *key) { return NULL; } -const int buildinfo_gtk_relevant = true; +const bool buildinfo_gtk_relevant = true; #if !GTK_CHECK_VERSION(3,0,0) /* This front end only works in GTK 3. If that's not what we've got, @@ -107,7 +107,7 @@ void session_window_closed(void) {} void window_setup_error(const char *errmsg) {} #else /* GTK_CHECK_VERSION(3,0,0) */ -extern const int use_event_log; +extern const bool use_event_log; static void startup(GApplication *app, gpointer user_data) { @@ -216,7 +216,7 @@ GtkWidget *make_gtk_toplevel_window(GtkFrontend *frontend) void launch_duplicate_session(Conf *conf) { - extern const int dup_check_launchable; + extern const bool dup_check_launchable; assert(!dup_check_launchable || conf_launchable(conf)); g_application_hold(G_APPLICATION(app)); new_session_window(conf_copy(conf), NULL); @@ -318,7 +318,7 @@ int main(int argc, char **argv) { /* Call the function in ux{putty,pterm}.c to do app-type * specific setup */ - extern void setup(int); + extern void setup(bool); setup(false); /* false means we are not a one-session process */ } diff --git a/unix/gtkask.c b/unix/gtkask.c index defc98f0..532b260d 100644 --- a/unix/gtkask.c +++ b/unix/gtkask.c @@ -14,6 +14,7 @@ #include #endif +#include "defs.h" #include "gtkfont.h" #include "gtkcompat.h" #include "gtkmisc.h" @@ -501,13 +502,13 @@ static void gtk_askpass_cleanup(struct askpass_ctx *ctx) gtk_widget_destroy(ctx->dialog); } -static int setup_gtk(const char *display) +static bool setup_gtk(const char *display) { - static int gtk_initialised = false; + static bool gtk_initialised = false; int argc; char *real_argv[3]; char **argv = real_argv; - int ret; + bool ret; if (gtk_initialised) return true; @@ -524,10 +525,10 @@ static int setup_gtk(const char *display) return ret; } -const int buildinfo_gtk_relevant = true; +const bool buildinfo_gtk_relevant = true; char *gtk_askpass_main(const char *display, const char *wintitle, - const char *prompt, int *success) + const char *prompt, bool *success) { struct askpass_ctx actx, *ctx = &actx; const char *err; @@ -571,7 +572,8 @@ void modalfatalbox(const char *p, ...) int main(int argc, char **argv) { - int success, exitcode; + bool success; + int exitcode; char *ret; gtk_init(&argc, &argv); diff --git a/unix/gtkcfg.c b/unix/gtkcfg.c index bbde8d2a..8b0ea31f 100644 --- a/unix/gtkcfg.c +++ b/unix/gtkcfg.c @@ -18,7 +18,7 @@ static void about_handler(union control *ctrl, dlgparam *dlg, } } -void gtk_setup_config_box(struct controlbox *b, int midsession, void *win) +void gtk_setup_config_box(struct controlbox *b, bool midsession, void *win) { struct controlset *s, *s2; union control *c; diff --git a/unix/gtkcols.c b/unix/gtkcols.c index fe8005f5..4b963f6e 100644 --- a/unix/gtkcols.c +++ b/unix/gtkcols.c @@ -331,7 +331,7 @@ static void columns_remove(GtkContainer *container, GtkWidget *widget) ColumnsChild *child; GtkWidget *childw; GList *children; - gboolean was_visible; + bool was_visible; g_return_if_fail(container != NULL); g_return_if_fail(IS_COLUMNS(container)); diff --git a/unix/gtkcols.h b/unix/gtkcols.h index b7410cb4..32653b8d 100644 --- a/unix/gtkcols.h +++ b/unix/gtkcols.h @@ -41,7 +41,7 @@ struct ColumnsChild_tag { /* If `widget' is non-NULL, this entry represents an actual widget. */ GtkWidget *widget; gint colstart, colspan; - gboolean force_left; /* for recalcitrant GtkLabels */ + bool force_left; /* for recalcitrant GtkLabels */ ColumnsChild *same_height_as; /* Otherwise, this entry represents a change in the column setup. */ gint ncols; diff --git a/unix/gtkcomm.c b/unix/gtkcomm.c index 15da36d5..6100990e 100644 --- a/unix/gtkcomm.c +++ b/unix/gtkcomm.c @@ -199,7 +199,7 @@ void timer_change_notify(unsigned long next) */ static guint toplevel_callback_idle_id; -static int idle_fn_scheduled; +static bool idle_fn_scheduled; static void notify_toplevel_callback(void *); diff --git a/unix/gtkdlg.c b/unix/gtkdlg.c index d988f9fb..d2fd6f64 100644 --- a/unix/gtkdlg.c +++ b/unix/gtkdlg.c @@ -79,7 +79,10 @@ struct uctrl { struct dlgparam { tree234 *byctrl, *bywidget; void *data; - struct { unsigned char r, g, b, ok; } coloursel_result; /* 0-255 */ + struct { + unsigned char r, g, b; /* 0-255 */ + bool ok; + } coloursel_result; /* `flags' are set to indicate when a GTK signal handler is being called * due to automatic processing and should not flag a user event. */ int flags; @@ -281,14 +284,14 @@ int dlg_radiobutton_get(union control *ctrl, dlgparam *dp) return 0; /* got to return something */ } -void dlg_checkbox_set(union control *ctrl, dlgparam *dp, int checked) +void dlg_checkbox_set(union control *ctrl, dlgparam *dp, bool checked) { struct uctrl *uc = dlg_find_byctrl(dp, ctrl); assert(uc->ctrl->generic.type == CTRL_CHECKBOX); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(uc->toplevel), checked); } -int dlg_checkbox_get(union control *ctrl, dlgparam *dp) +bool dlg_checkbox_get(union control *ctrl, dlgparam *dp) { struct uctrl *uc = dlg_find_byctrl(dp, ctrl); assert(uc->ctrl->generic.type == CTRL_CHECKBOX); @@ -707,7 +710,7 @@ int dlg_listbox_index(union control *ctrl, dlgparam *dp) return -1; /* placate dataflow analysis */ } -int dlg_listbox_issel(union control *ctrl, dlgparam *dp, int index) +bool dlg_listbox_issel(union control *ctrl, dlgparam *dp, int index) { struct uctrl *uc = dlg_find_byctrl(dp, ctrl); @@ -748,7 +751,7 @@ int dlg_listbox_issel(union control *ctrl, dlgparam *dp, int index) if (uc->treeview) { GtkTreeSelection *treesel; GtkTreePath *path; - int ret; + bool ret; assert(uc->treeview != NULL); treesel = gtk_tree_view_get_selection(GTK_TREE_VIEW(uc->treeview)); @@ -761,7 +764,7 @@ int dlg_listbox_issel(union control *ctrl, dlgparam *dp, int index) } #endif assert(!"We shouldn't get here"); - return -1; /* placate dataflow analysis */ + return false; /* placate dataflow analysis */ } void dlg_listbox_select(union control *ctrl, dlgparam *dp, int index) @@ -790,7 +793,7 @@ void dlg_listbox_select(union control *ctrl, dlgparam *dp, int index) items = gtk_container_children(GTK_CONTAINER(uc->list)); nitems = g_list_length(items); if (nitems > 0) { - int modified = false; + bool modified = false; g_list_free(items); newtop = uc->adj->lower + (uc->adj->upper - uc->adj->lower) * index / nitems; @@ -1181,16 +1184,16 @@ void dlg_coloursel_start(union control *ctrl, dlgparam *dp, int r, int g, int b) gtk_widget_show(coloursel); } -int dlg_coloursel_results(union control *ctrl, dlgparam *dp, - int *r, int *g, int *b) +bool dlg_coloursel_results(union control *ctrl, dlgparam *dp, + int *r, int *g, int *b) { if (dp->coloursel_result.ok) { *r = dp->coloursel_result.r; *g = dp->coloursel_result.g; *b = dp->coloursel_result.b; - return 1; + return true; } else - return 0; + return false; } /* ---------------------------------------------------------------------- @@ -1279,7 +1282,7 @@ static gboolean editbox_lostfocus(GtkWidget *ed, GdkEventFocus *event, */ static gboolean listitem_key(GtkWidget *item, GdkEventKey *event, - gpointer data, int multiple) + gpointer data, bool multiple) { GtkAdjustment *adj = GTK_ADJUSTMENT(data); @@ -1877,7 +1880,7 @@ GtkWidget *layout_ctrls(struct dlgparam *dp, struct Shortcuts *scs, for (i = 0; i < s->ncontrols; i++) { union control *ctrl = s->ctrls[i]; struct uctrl *uc; - int left = false; + bool left = false; GtkWidget *w = NULL; switch (ctrl->generic.type) { @@ -2555,7 +2558,7 @@ static void treeitem_sel(GtkItem *item, gpointer data) #endif #if !GTK_CHECK_VERSION(2,0,0) -static int tree_grab_focus(struct dlgparam *dp) +static bool tree_grab_focus(struct dlgparam *dp) { int i, f; @@ -2592,7 +2595,7 @@ gint tree_focus(GtkContainer *container, GtkDirectionType direction, } #endif -int win_key_press(GtkWidget *widget, GdkEventKey *event, gpointer data) +gint win_key_press(GtkWidget *widget, GdkEventKey *event, gpointer data) { struct dlgparam *dp = (struct dlgparam *)data; @@ -2717,7 +2720,7 @@ int win_key_press(GtkWidget *widget, GdkEventKey *event, gpointer data) } #if !GTK_CHECK_VERSION(2,0,0) -int tree_key_press(GtkWidget *widget, GdkEventKey *event, gpointer data) +gint tree_key_press(GtkWidget *widget, GdkEventKey *event, gpointer data) { struct dlgparam *dp = (struct dlgparam *)data; @@ -2742,7 +2745,7 @@ int tree_key_press(GtkWidget *widget, GdkEventKey *event, gpointer data) */ { GtkWidget *w = dp->treeitems[i]; - int vis = true; + bool vis = true; while (w && (GTK_IS_TREE_ITEM(w) || GTK_IS_TREE(w))) { if (!GTK_WIDGET_VISIBLE(w)) { vis = false; @@ -2893,7 +2896,7 @@ void treeview_map_event(GtkWidget *tree, gpointer data) #endif GtkWidget *create_config_box(const char *title, Conf *conf, - int midsession, int protcfginfo, + bool midsession, int protcfginfo, post_dialog_fn_t after, void *afterctx) { GtkWidget *window, *hbox, *vbox, *cols, *label, @@ -2999,7 +3002,7 @@ GtkWidget *create_config_box(const char *title, Conf *conf, #else GtkWidget *treeitem; #endif - int first; + bool first; /* * We expect never to find an implicit path @@ -3213,7 +3216,7 @@ GtkWidget *create_config_box(const char *title, Conf *conf, */ for (index = 0; index < dp->ctrlbox->nctrlsets; index++) { struct controlset *s = dp->ctrlbox->ctrlsets[index]; - int done = 0; + bool done = false; int j; if (*s->pathname) { @@ -3223,7 +3226,7 @@ GtkWidget *create_config_box(const char *title, Conf *conf, s->ctrls[j]->generic.type != CTRL_TEXT) { dlg_set_focus(s->ctrls[j], dp); dp->lastfocus = s->ctrls[j]; - done = 1; + done = true; break; } } @@ -3280,7 +3283,7 @@ const struct message_box_buttons buttons_ok = { GtkWidget *create_message_box( GtkWidget *parentwin, const char *title, const char *msg, int minwid, - int selectable, const struct message_box_buttons *buttons, + bool selectable, const struct message_box_buttons *buttons, post_dialog_fn_t after, void *afterctx) { GtkWidget *window, *w0, *w1; @@ -3770,7 +3773,7 @@ struct eventlog_stuff { int ninitial, ncircular, circular_first; char *seldata; int sellen; - int ignore_selchange; + bool ignore_selchange; }; static void eventlog_destroy(GtkWidget *widget, gpointer data) @@ -3887,7 +3890,7 @@ gint eventlog_selection_clear(GtkWidget *widget, GdkEventSelection *seldata, * Deselect everything in the list box. */ uc = dlg_find_byctrl(&es->dp, es->listctrl); - es->ignore_selchange = 1; + es->ignore_selchange = true; #if !GTK_CHECK_VERSION(2,0,0) assert(uc->list); gtk_list_unselect_all(GTK_LIST(uc->list)); @@ -3896,7 +3899,7 @@ gint eventlog_selection_clear(GtkWidget *widget, GdkEventSelection *seldata, gtk_tree_selection_unselect_all (gtk_tree_view_get_selection(GTK_TREE_VIEW(uc->treeview))); #endif - es->ignore_selchange = 0; + es->ignore_selchange = false; sfree(es->seldata); es->sellen = 0; diff --git a/unix/gtkfont.c b/unix/gtkfont.c index 074b61f9..ad29034e 100644 --- a/unix/gtkfont.c +++ b/unix/gtkfont.c @@ -73,22 +73,23 @@ struct UnifontVtable { /* * `Methods' of the `class'. */ - unifont *(*create)(GtkWidget *widget, const char *name, int wide, int bold, - int shadowoffset, int shadowalways); - unifont *(*create_fallback)(GtkWidget *widget, int height, int wide, - int bold, int shadowoffset, int shadowalways); + unifont *(*create)(GtkWidget *widget, const char *name, bool wide, + bool bold, int shadowoffset, bool shadowalways); + unifont *(*create_fallback)(GtkWidget *widget, int height, bool wide, + bool bold, int shadowoffset, + bool shadowalways); void (*destroy)(unifont *font); - int (*has_glyph)(unifont *font, wchar_t glyph); + bool (*has_glyph)(unifont *font, wchar_t glyph); void (*draw_text)(unifont_drawctx *ctx, unifont *font, int x, int y, const wchar_t *string, int len, - int wide, int bold, int cellwidth); + bool wide, bool bold, int cellwidth); void (*draw_combining)(unifont_drawctx *ctx, unifont *font, int x, int y, const wchar_t *string, int len, - int wide, int bold, int cellwidth); + bool wide, bool bold, int cellwidth); void (*enum_fonts)(GtkWidget *widget, fontsel_add_entry callback, void *callback_ctx); char *(*canonify_fontname)(GtkWidget *widget, const char *name, int *size, - int *flags, int resolve_aliases); + int *flags, bool resolve_aliases); char *(*scale_fontname)(GtkWidget *widget, const char *name, int size); char *(*size_increment)(unifont *font, int increment); @@ -106,22 +107,23 @@ struct UnifontVtable { * back end other than X). */ -static int x11font_has_glyph(unifont *font, wchar_t glyph); +static bool x11font_has_glyph(unifont *font, wchar_t glyph); static void x11font_draw_text(unifont_drawctx *ctx, unifont *font, int x, int y, const wchar_t *string, int len, - int wide, int bold, int cellwidth); + bool wide, bool bold, int cellwidth); static void x11font_draw_combining(unifont_drawctx *ctx, unifont *font, int x, int y, const wchar_t *string, - int len, int wide, int bold, int cellwidth); + int len, bool wide, bool bold, + int cellwidth); static unifont *x11font_create(GtkWidget *widget, const char *name, - int wide, int bold, - int shadowoffset, int shadowalways); + bool wide, bool bold, + int shadowoffset, bool shadowalways); static void x11font_destroy(unifont *font); static void x11font_enum_fonts(GtkWidget *widget, fontsel_add_entry callback, void *callback_ctx); static char *x11font_canonify_fontname(GtkWidget *widget, const char *name, int *size, int *flags, - int resolve_aliases); + bool resolve_aliases); static char *x11font_scale_fontname(GtkWidget *widget, const char *name, int size); static char *x11font_size_increment(unifont *font, int increment); @@ -147,7 +149,7 @@ typedef struct x11font_individual { * haven't tried yet from xfs==NULL because we tried and failed, * so that we don't keep trying and failing subsequently). */ - int allocated; + bool allocated; #ifdef DRAW_TEXT_CAIRO /* @@ -190,13 +192,13 @@ struct x11font { * values larger than a byte. That is, this flag tells us * whether we use XDrawString or XDrawString16, etc. */ - int sixteen_bit; + bool sixteen_bit; /* * `variable' is true iff the font is non-fixed-pitch. This * enables some code which takes greater care over character * positioning during text drawing. */ - int variable; + bool variable; /* * real_charset is the charset used when translating text into the * font's internal encoding inside draw_text(). This need not be @@ -208,7 +210,8 @@ struct x11font { /* * Data passed in to unifont_create(). */ - int wide, bold, shadowoffset, shadowalways; + int shadowoffset; + bool wide, bold, shadowalways; unifont u; }; @@ -312,7 +315,7 @@ static char *xlfd_recompose(const struct xlfd_decomposed *dec) } static char *x11_guess_derived_font_name(Display *disp, XFontStruct *xfs, - int bold, int wide) + bool bold, bool wide) { Atom fontprop = XInternAtom(disp, "FONT", False); unsigned long ret; @@ -343,7 +346,7 @@ static char *x11_guess_derived_font_name(Display *disp, XFontStruct *xfs, return NULL; } -static int x11_font_width(XFontStruct *xfs, int sixteen_bit) +static int x11_font_width(XFontStruct *xfs, bool sixteen_bit) { if (sixteen_bit) { XChar2b space; @@ -406,7 +409,7 @@ static const XCharStruct *x11_char_struct( return &xfs->per_char[index]; } -static int x11_font_has_glyph( +static bool x11_font_has_glyph( XFontStruct *xfs, unsigned char byte1, unsigned char byte2) { /* @@ -426,15 +429,16 @@ static int x11_font_has_glyph( } static unifont *x11font_create(GtkWidget *widget, const char *name, - int wide, int bold, - int shadowoffset, int shadowalways) + bool wide, bool bold, + int shadowoffset, bool shadowalways) { struct x11font *xfont; XFontStruct *xfs; Display *disp; Atom charset_registry, charset_encoding, spacing; unsigned long registry_ret, encoding_ret, spacing_ret; - int pubcs, realcs, sixteen_bit, variable; + int pubcs, realcs; + bool sixteen_bit, variable; int i; if ((disp = get_x11_display()) == NULL) @@ -577,7 +581,7 @@ static void x11_alloc_subfont(struct x11font *xfont, int sfid) /* Note that xfont->fonts[sfid].xfs may still be NULL, if XLQF failed. */ } -static int x11font_has_glyph(unifont *font, wchar_t glyph) +static bool x11font_has_glyph(unifont *font, wchar_t glyph) { struct x11font *xfont = container_of(font, struct x11font, u); @@ -851,9 +855,10 @@ static void x11font_really_draw_text( const struct x11font_drawfuncs *dfns, unifont_drawctx *ctx, x11font_individual *xfi, Display *disp, int x, int y, const void *string, int nchars, - int shadowoffset, int fontvariable, int cellwidth) + int shadowoffset, bool fontvariable, int cellwidth) { - int start = 0, step, nsteps, centre; + int start = 0, step, nsteps; + bool centre; if (fontvariable) { /* @@ -891,7 +896,7 @@ static void x11font_really_draw_text( static void x11font_draw_text(unifont_drawctx *ctx, unifont *font, int x, int y, const wchar_t *string, int len, - int wide, int bold, int cellwidth) + bool wide, bool bold, int cellwidth) { struct x11font *xfont = container_of(font, struct x11font, u); int sfid; @@ -899,8 +904,8 @@ static void x11font_draw_text(unifont_drawctx *ctx, unifont *font, int mult = (wide ? 2 : 1); int index = 2 * (int)ctx->type; - wide -= xfont->wide; - bold -= xfont->bold; + wide = wide && !xfont->wide; + bold = bold && !xfont->bold; /* * Decide which subfont we're using, and whether we have to @@ -908,13 +913,13 @@ static void x11font_draw_text(unifont_drawctx *ctx, unifont *font, */ if (xfont->shadowalways && bold) { shadowoffset = xfont->shadowoffset; - bold = 0; + bold = false; } sfid = 2 * wide + bold; if (!xfont->fonts[sfid].allocated) x11_alloc_subfont(xfont, sfid); if (bold && !xfont->fonts[sfid].xfs) { - bold = 0; + bold = false; shadowoffset = xfont->shadowoffset; sfid = 2 * wide + bold; if (!xfont->fonts[sfid].allocated) @@ -961,7 +966,8 @@ static void x11font_draw_text(unifont_drawctx *ctx, unifont *font, static void x11font_draw_combining(unifont_drawctx *ctx, unifont *font, int x, int y, const wchar_t *string, - int len, int wide, int bold, int cellwidth) + int len, bool wide, bool bold, + int cellwidth) { /* * For server-side fonts, there's no sophisticated system for @@ -1138,7 +1144,7 @@ static void x11font_enum_fonts(GtkWidget *widget, static char *x11font_canonify_fontname(GtkWidget *widget, const char *name, int *size, int *flags, - int resolve_aliases) + bool resolve_aliases) { /* * When given an X11 font name to try to make sense of for a @@ -1298,26 +1304,26 @@ static char *x11font_size_increment(unifont *font, int increment) #define PANGO_PRE_1POINT6 /* make life easier for pre-1.4 folk */ #endif -static int pangofont_has_glyph(unifont *font, wchar_t glyph); +static bool pangofont_has_glyph(unifont *font, wchar_t glyph); static void pangofont_draw_text(unifont_drawctx *ctx, unifont *font, int x, int y, const wchar_t *string, int len, - int wide, int bold, int cellwidth); + bool wide, bool bold, int cellwidth); static void pangofont_draw_combining(unifont_drawctx *ctx, unifont *font, int x, int y, const wchar_t *string, - int len, int wide, int bold, + int len, bool wide, bool bold, int cellwidth); static unifont *pangofont_create(GtkWidget *widget, const char *name, - int wide, int bold, - int shadowoffset, int shadowalways); + bool wide, bool bold, + int shadowoffset, bool shadowalways); static unifont *pangofont_create_fallback(GtkWidget *widget, int height, - int wide, int bold, - int shadowoffset, int shadowalways); + bool wide, bool bold, + int shadowoffset, bool shadowalways); static void pangofont_destroy(unifont *font); static void pangofont_enum_fonts(GtkWidget *widget, fontsel_add_entry callback, void *callback_ctx); static char *pangofont_canonify_fontname(GtkWidget *widget, const char *name, int *size, int *flags, - int resolve_aliases); + bool resolve_aliases); static char *pangofont_scale_fontname(GtkWidget *widget, const char *name, int size); static char *pangofont_size_increment(unifont *font, int increment); @@ -1335,7 +1341,8 @@ struct pangofont { /* * Data passed in to unifont_create(). */ - int bold, shadowoffset, shadowalways; + int shadowoffset; + bool bold, shadowalways; /* * Cache of character widths, indexed by Unicode code point. In * pixels; -1 means we haven't asked Pango about this character @@ -1374,14 +1381,15 @@ static const struct UnifontVtable pangofont_vtable = { * if it doesn't. So we check that the font family is actually one * supported by Pango. */ -static int pangofont_check_desc_makes_sense(PangoContext *ctx, - PangoFontDescription *desc) +static bool pangofont_check_desc_makes_sense(PangoContext *ctx, + PangoFontDescription *desc) { #ifndef PANGO_PRE_1POINT6 PangoFontMap *map; #endif PangoFontFamily **families; - int i, nfamilies, matched; + int i, nfamilies; + bool matched; /* * Ask Pango for a list of font families, and iterate through @@ -1413,8 +1421,8 @@ static int pangofont_check_desc_makes_sense(PangoContext *ctx, static unifont *pangofont_create_internal(GtkWidget *widget, PangoContext *ctx, PangoFontDescription *desc, - int wide, int bold, - int shadowoffset, int shadowalways) + bool wide, bool bold, + int shadowoffset, bool shadowalways) { struct pangofont *pfont; #ifndef PANGO_PRE_1POINT6 @@ -1479,8 +1487,8 @@ static unifont *pangofont_create_internal(GtkWidget *widget, } static unifont *pangofont_create(GtkWidget *widget, const char *name, - int wide, int bold, - int shadowoffset, int shadowalways) + bool wide, bool bold, + int shadowoffset, bool shadowalways) { PangoContext *ctx; PangoFontDescription *desc; @@ -1502,8 +1510,8 @@ static unifont *pangofont_create(GtkWidget *widget, const char *name, } static unifont *pangofont_create_fallback(GtkWidget *widget, int height, - int wide, int bold, - int shadowoffset, int shadowalways) + bool wide, bool bold, + int shadowoffset, bool shadowalways) { PangoContext *ctx; PangoFontDescription *desc; @@ -1559,7 +1567,7 @@ static int pangofont_char_width(PangoLayout *layout, struct pangofont *pfont, return pfont->widthcache[uchr]; } -static int pangofont_has_glyph(unifont *font, wchar_t glyph) +static bool pangofont_has_glyph(unifont *font, wchar_t glyph) { /* Pango implements font fallback, so assume it has everything */ return true; @@ -1584,15 +1592,15 @@ static void pango_cairo_draw_layout(unifont_drawctx *ctx, static void pangofont_draw_internal(unifont_drawctx *ctx, unifont *font, int x, int y, const wchar_t *string, - int len, int wide, int bold, int cellwidth, - int combining) + int len, bool wide, bool bold, + int cellwidth, bool combining) { struct pangofont *pfont = container_of(font, struct pangofont, u); PangoLayout *layout; PangoRectangle rect; char *utfstring, *utfptr; int utflen; - int shadowbold = false; + bool shadowbold = false; void (*draw_layout)(unifont_drawctx *ctx, gint x, gint y, PangoLayout *layout) = NULL; @@ -1614,7 +1622,7 @@ static void pangofont_draw_internal(unifont_drawctx *ctx, unifont *font, layout = pango_layout_new(gtk_widget_get_pango_context(pfont->widget)); pango_layout_set_font_description(layout, pfont->desc); - if (bold > pfont->bold) { + if (bold && !pfont->bold) { if (pfont->shadowalways) shadowbold = true; else { @@ -1740,7 +1748,7 @@ static void pangofont_draw_internal(unifont_drawctx *ctx, unifont *font, static void pangofont_draw_text(unifont_drawctx *ctx, unifont *font, int x, int y, const wchar_t *string, int len, - int wide, int bold, int cellwidth) + bool wide, bool bold, int cellwidth) { pangofont_draw_internal(ctx, font, x, y, string, len, wide, bold, cellwidth, false); @@ -1748,7 +1756,7 @@ static void pangofont_draw_text(unifont_drawctx *ctx, unifont *font, static void pangofont_draw_combining(unifont_drawctx *ctx, unifont *font, int x, int y, const wchar_t *string, - int len, int wide, int bold, + int len, bool wide, bool bold, int cellwidth) { wchar_t *tmpstring = NULL; @@ -1932,7 +1940,7 @@ static void pangofont_enum_fonts(GtkWidget *widget, fontsel_add_entry callback, static char *pangofont_canonify_fontname(GtkWidget *widget, const char *name, int *size, int *flags, - int resolve_aliases) + bool resolve_aliases) { /* * When given a Pango font name to try to make sense of for a @@ -2112,8 +2120,8 @@ static const char *unifont_do_prefix(const char *name, int *start, int *end) } } -unifont *unifont_create(GtkWidget *widget, const char *name, int wide, - int bold, int shadowoffset, int shadowalways) +unifont *unifont_create(GtkWidget *widget, const char *name, bool wide, + bool bold, int shadowoffset, bool shadowalways) { int i, start, end; @@ -2135,14 +2143,14 @@ void unifont_destroy(unifont *font) void unifont_draw_text(unifont_drawctx *ctx, unifont *font, int x, int y, const wchar_t *string, int len, - int wide, int bold, int cellwidth) + bool wide, bool bold, int cellwidth) { font->vt->draw_text(ctx, font, x, y, string, len, wide, bold, cellwidth); } void unifont_draw_combining(unifont_drawctx *ctx, unifont *font, int x, int y, const wchar_t *string, int len, - int wide, int bold, int cellwidth) + bool wide, bool bold, int cellwidth) { font->vt->draw_combining(ctx, font, x, y, string, len, wide, bold, cellwidth); @@ -2168,10 +2176,10 @@ char *unifont_size_increment(unifont *font, int increment) static void multifont_draw_text(unifont_drawctx *ctx, unifont *font, int x, int y, const wchar_t *string, int len, - int wide, int bold, int cellwidth); + bool wide, bool bold, int cellwidth); static void multifont_draw_combining(unifont_drawctx *ctx, unifont *font, int x, int y, const wchar_t *string, - int len, int wide, int bold, + int len, bool wide, bool bold, int cellwidth); static void multifont_destroy(unifont *font); static char *multifont_size_increment(unifont *font, int increment); @@ -2198,8 +2206,8 @@ static const struct UnifontVtable multifont_vtable = { }; unifont *multifont_create(GtkWidget *widget, const char *name, - int wide, int bold, - int shadowoffset, int shadowalways) + bool wide, bool bold, + int shadowoffset, bool shadowalways) { int i; unifont *font, *fallback; @@ -2253,17 +2261,18 @@ static void multifont_destroy(unifont *font) typedef void (*unifont_draw_func_t)(unifont_drawctx *ctx, unifont *font, int x, int y, const wchar_t *string, - int len, int wide, int bold, + int len, bool wide, bool bold, int cellwidth); static void multifont_draw_main(unifont_drawctx *ctx, unifont *font, int x, int y, const wchar_t *string, int len, - int wide, int bold, int cellwidth, + bool wide, bool bold, int cellwidth, int cellinc, unifont_draw_func_t draw) { struct multifont *mfont = container_of(font, struct multifont, u); unifont *f; - int ok, i; + bool ok; + int i; while (len > 0) { /* @@ -2290,7 +2299,7 @@ static void multifont_draw_main(unifont_drawctx *ctx, unifont *font, int x, static void multifont_draw_text(unifont_drawctx *ctx, unifont *font, int x, int y, const wchar_t *string, int len, - int wide, int bold, int cellwidth) + bool wide, bool bold, int cellwidth) { multifont_draw_main(ctx, font, x, y, string, len, wide, bold, cellwidth, cellwidth, unifont_draw_text); @@ -2298,7 +2307,7 @@ static void multifont_draw_text(unifont_drawctx *ctx, unifont *font, int x, static void multifont_draw_combining(unifont_drawctx *ctx, unifont *font, int x, int y, const wchar_t *string, - int len, int wide, int bold, + int len, bool wide, bool bold, int cellwidth) { multifont_draw_main(ctx, font, x, y, string, len, wide, bold, @@ -2335,7 +2344,7 @@ typedef struct unifontsel_internal { tree234 *fonts_by_realname, *fonts_by_selorder; fontinfo *selected; int selsize, intendedsize; - int inhibit_response; /* inhibit callbacks when we change GUI controls */ + bool inhibit_response; /* inhibit callbacks when we change GUI controls */ unifontsel u; } unifontsel_internal; @@ -2529,7 +2538,8 @@ static void unifontsel_setup_stylelist(unifontsel_internal *fs, int start, int end) { GtkTreeIter iter; - int i, listindex, minpos = -1, maxpos = -1, started = false; + int i, listindex, minpos = -1, maxpos = -1; + bool started = false; char *currcs = NULL, *currstyle = NULL; fontinfo *info; @@ -2808,7 +2818,7 @@ static void unifontsel_draw_preview_text(unifontsel_internal *fs) static void unifontsel_select_font(unifontsel_internal *fs, fontinfo *info, int size, int leftlist, - int size_is_explicit) + bool size_is_explicit) { int index; int minval, maxval; @@ -2946,7 +2956,7 @@ static void unifontsel_select_font(unifontsel_internal *fs, static void unifontsel_button_toggled(GtkToggleButton *tb, gpointer data) { unifontsel_internal *fs = (unifontsel_internal *)data; - int newstate = gtk_toggle_button_get_active(tb); + bool newstate = gtk_toggle_button_get_active(tb); int newflags; int flagbit = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(tb), "user-data")); diff --git a/unix/gtkfont.h b/unix/gtkfont.h index 249828b4..ff91929e 100644 --- a/unix/gtkfont.h +++ b/unix/gtkfont.h @@ -74,7 +74,7 @@ typedef struct unifont { * missing glyphs from other fonts), or whether it would like a * fallback font to cope with missing glyphs. */ - int want_fallback; + bool want_fallback; /* * Preferred drawing API to use when this class of font is active. @@ -134,18 +134,18 @@ typedef struct unifont_drawctx { } unifont_drawctx; unifont *unifont_create(GtkWidget *widget, const char *name, - int wide, int bold, - int shadowoffset, int shadowalways); + bool wide, bool bold, + int shadowoffset, bool shadowalways); void unifont_destroy(unifont *font); void unifont_draw_text(unifont_drawctx *ctx, unifont *font, int x, int y, const wchar_t *string, int len, - int wide, int bold, int cellwidth); + bool wide, bool bold, int cellwidth); /* Same as unifont_draw_text, but expects 'string' to contain one * normal char plus combining chars, and overdraws them all in the * same character cell. */ void unifont_draw_combining(unifont_drawctx *ctx, unifont *font, int x, int y, const wchar_t *string, int len, - int wide, int bold, int cellwidth); + bool wide, bool bold, int cellwidth); /* Return a name that will select a bigger/smaller font than this one, * or NULL if no such name is available. */ char *unifont_size_increment(unifont *font, int increment); @@ -159,8 +159,8 @@ char *unifont_size_increment(unifont *font, int increment); * as if it were an ordinary unifont. */ unifont *multifont_create(GtkWidget *widget, const char *name, - int wide, int bold, - int shadowoffset, int shadowalways); + bool wide, bool bold, + int shadowoffset, bool shadowalways); /* * Unified font selector dialog. I can't be bothered to do a diff --git a/unix/gtkmain.c b/unix/gtkmain.c index cacf56b8..e51b5c43 100644 --- a/unix/gtkmain.c +++ b/unix/gtkmain.c @@ -48,7 +48,7 @@ static char *progname, **gtkargvstart; static int ngtkargs; extern char **pty_argv; /* declared in pty.c */ -extern int use_pty_argv; +extern bool use_pty_argv; static const char *app_name = "pterm"; @@ -312,9 +312,9 @@ void window_setup_error(const char *errmsg) exit(1); } -int do_cmdline(int argc, char **argv, int do_everything, Conf *conf) +bool do_cmdline(int argc, char **argv, bool do_everything, Conf *conf) { - int err = 0; + bool err = false; char *val; /* @@ -327,7 +327,7 @@ int do_cmdline(int argc, char **argv, int do_everything, Conf *conf) */ #define EXPECTS_ARG { \ if (--argc <= 0) { \ - err = 1; \ + err = true; \ fprintf(stderr, "%s: %s expects an argument\n", appname, p); \ continue; \ } else \ @@ -417,14 +417,14 @@ int do_cmdline(int argc, char **argv, int do_everything, Conf *conf) { #if GTK_CHECK_VERSION(3,0,0) GdkRGBA rgba; - int success = gdk_rgba_parse(&rgba, val); + bool success = gdk_rgba_parse(&rgba, val); #else GdkColor col; - int success = gdk_color_parse(val, &col); + bool success = gdk_color_parse(val, &col); #endif if (!success) { - err = 1; + err = true; fprintf(stderr, "%s: unable to parse colour \"%s\"\n", appname, val); } else { @@ -467,7 +467,7 @@ int do_cmdline(int argc, char **argv, int do_everything, Conf *conf) pty_argv[argc] = NULL; break; /* finished command-line processing */ } else - err = 1, fprintf(stderr, "%s: -e expects an argument\n", + err = true, fprintf(stderr, "%s: -e expects an argument\n", appname); } else if (!strcmp(p, "-title")) { @@ -535,13 +535,13 @@ int do_cmdline(int argc, char **argv, int do_everything, Conf *conf) } else if (p[0] != '-') { /* Non-option arguments not handled by cmdline.c are errors. */ if (do_everything) { - err = 1; + err = true; fprintf(stderr, "%s: unexpected non-option argument '%s'\n", appname, p); } } else { - err = 1; + err = true; fprintf(stderr, "%s: unrecognized option '%s'\n", appname, p); } } @@ -554,7 +554,7 @@ GtkWidget *make_gtk_toplevel_window(GtkFrontend *frontend) return gtk_window_new(GTK_WINDOW_TOPLEVEL); } -const int buildinfo_gtk_relevant = true; +const bool buildinfo_gtk_relevant = true; struct post_initial_config_box_ctx { Conf *conf; @@ -586,14 +586,14 @@ void session_window_closed(void) int main(int argc, char **argv) { Conf *conf; - int need_config_box; + bool need_config_box; setlocale(LC_CTYPE, ""); { /* Call the function in ux{putty,pterm}.c to do app-type * specific setup */ - extern void setup(int); + extern void setup(bool); setup(true); /* true means we are a one-session process */ } @@ -623,10 +623,10 @@ int main(int argc, char **argv) * terminating the main pterm/PuTTY. However, we'll have to * unblock it again when pterm forks. */ - block_signal(SIGPIPE, 1); + block_signal(SIGPIPE, true); if (argc > 1 && !strncmp(argv[1], "---", 3)) { - extern const int dup_check_launchable; + extern const bool dup_check_launchable; read_dupsession_data(conf, argv[1]); /* Splatter this argument so it doesn't clutter a ps listing */ @@ -635,10 +635,10 @@ int main(int argc, char **argv) assert(!dup_check_launchable || conf_launchable(conf)); need_config_box = false; } else { - if (do_cmdline(argc, argv, 0, conf)) + if (do_cmdline(argc, argv, false, conf)) exit(1); /* pre-defaults pass to get -class */ do_defaults(NULL, conf); - if (do_cmdline(argc, argv, 1, conf)) + if (do_cmdline(argc, argv, true, conf)) exit(1); /* post-defaults, do everything */ cmdline_run_saved(conf); diff --git a/unix/gtkmisc.c b/unix/gtkmisc.c index 05379415..c0c9682a 100644 --- a/unix/gtkmisc.c +++ b/unix/gtkmisc.c @@ -190,8 +190,7 @@ GtkBox *our_dialog_make_action_hbox(GtkWindow *dlg) } void our_dialog_add_to_content_area(GtkWindow *dlg, GtkWidget *w, - gboolean expand, gboolean fill, - guint padding) + bool expand, bool fill, guint padding) { #if GTK_CHECK_VERSION(3,0,0) /* GtkWindow is a GtkBin, hence contains exactly one child, which diff --git a/unix/gtkmisc.h b/unix/gtkmisc.h index e670d9d4..3d2d1f36 100644 --- a/unix/gtkmisc.h +++ b/unix/gtkmisc.h @@ -12,8 +12,7 @@ void align_label_left(GtkLabel *label); GtkWidget *our_dialog_new(void); void our_dialog_add_to_content_area(GtkWindow *dlg, GtkWidget *w, - gboolean expand, gboolean fill, - guint padding); + bool expand, bool fill, guint padding); void our_dialog_set_action_area(GtkWindow *dlg, GtkWidget *w); GtkBox *our_dialog_make_action_hbox(GtkWindow *dlg); diff --git a/unix/gtkwin.c b/unix/gtkwin.c index f88cba75..67068f06 100644 --- a/unix/gtkwin.c +++ b/unix/gtkwin.c @@ -133,13 +133,14 @@ struct GtkFrontend { GtkIMContext *imc; #endif unifont *fonts[4]; /* normal, bold, wide, widebold */ - int xpos, ypos, gotpos, gravity; + int xpos, ypos, gravity; + bool gotpos; GdkCursor *rawcursor, *textcursor, *blankcursor, *waitcursor, *currcursor; GdkColor cols[NALLCOLOURS]; #if !GTK_CHECK_VERSION(3,0,0) GdkColormap *colmap; #endif - int direct_to_font; + bool direct_to_font; struct clipboard_state clipstates[N_CLIPBOARDS]; #ifdef JUST_USE_GTK_CLIPBOARD_UTF8 /* Remember all clipboard_data_instance structures currently @@ -150,8 +151,8 @@ struct GtkFrontend { int clipboard_ctrlshiftins, clipboard_ctrlshiftcv; int font_width, font_height; int width, height, scale; - int ignore_sbar; - int mouseptr_visible; + bool ignore_sbar; + bool mouseptr_visible; BusyStatus busy_status; int alt_keycode; int alt_digits; @@ -162,7 +163,7 @@ struct GtkFrontend { Backend *backend; Terminal *term; LogContext *logctx; - int exited; + bool exited; struct unicode_data ucsdata; Conf *conf; eventlog_stuff *eventlogstuff; @@ -204,7 +205,7 @@ static void cache_conf_values(GtkFrontend *inst) #endif } -static int send_raw_mouse; +static bool send_raw_mouse; static void start_backend(GtkFrontend *inst); static void exit_callback(void *vinst); @@ -314,14 +315,14 @@ static char *gtk_seat_get_ttymode(Seat *seat, const char *mode) return term_get_ttymode(inst->term, mode); } -static int gtk_seat_output(Seat *seat, int is_stderr, +static int gtk_seat_output(Seat *seat, bool is_stderr, const void *data, int len) { GtkFrontend *inst = container_of(seat, GtkFrontend, seat); return term_data(inst->term, is_stderr, data, len); } -static int gtk_seat_eof(Seat *seat) +static bool gtk_seat_eof(Seat *seat) { /* GtkFrontend *inst = container_of(seat, GtkFrontend, seat); */ return true; /* do respond to incoming EOF with outgoing */ @@ -338,13 +339,13 @@ static int gtk_seat_get_userpass_input(Seat *seat, prompts_t *p, return ret; } -static int gtk_seat_is_utf8(Seat *seat) +static bool gtk_seat_is_utf8(Seat *seat) { GtkFrontend *inst = container_of(seat, GtkFrontend, seat); return win_is_utf8(&inst->termwin); } -static int gtk_seat_get_window_pixel_size(Seat *seat, int *w, int *h) +static bool gtk_seat_get_window_pixel_size(Seat *seat, int *w, int *h) { GtkFrontend *inst = container_of(seat, GtkFrontend, seat); win_get_pixels(&inst->termwin, w, h); @@ -356,7 +357,7 @@ static void gtk_seat_update_specials_menu(Seat *seat); static void gtk_seat_set_busy_status(Seat *seat, BusyStatus status); static const char *gtk_seat_get_x_display(Seat *seat); #ifndef NOT_X_WINDOWS -static int gtk_seat_get_windowid(Seat *seat, long *id); +static bool gtk_seat_get_windowid(Seat *seat, long *id); #endif static const SeatVtable gtk_seat_vt = { @@ -469,7 +470,7 @@ void unregister_dialog(Seat *seat, enum DialogSlot slot) * Minimise or restore the window in response to a server-side * request. */ -static void gtkwin_set_minimised(TermWin *tw, int minimised) +static void gtkwin_set_minimised(TermWin *tw, bool minimised) { /* * GTK 1.2 doesn't know how to do this. @@ -507,7 +508,7 @@ static void gtkwin_move(TermWin *tw, int x, int y) * Move the window to the top or bottom of the z-order in response * to a server-side request. */ -static void gtkwin_set_zorder(TermWin *tw, int top) +static void gtkwin_set_zorder(TermWin *tw, bool top) { GtkFrontend *inst = container_of(tw, GtkFrontend, termwin); if (top) @@ -529,7 +530,7 @@ static void gtkwin_refresh(TermWin *tw) * Maximise or restore the window in response to a server-side * request. */ -static void gtkwin_set_maximised(TermWin *tw, int maximised) +static void gtkwin_set_maximised(TermWin *tw, bool maximised) { /* * GTK 1.2 doesn't know how to do this. @@ -546,7 +547,7 @@ static void gtkwin_set_maximised(TermWin *tw, int maximised) /* * Report whether the window is minimised, for terminal reports. */ -static int gtkwin_is_minimised(TermWin *tw) +static bool gtkwin_is_minimised(TermWin *tw) { GtkFrontend *inst = container_of(tw, GtkFrontend, termwin); return !gdk_window_is_viewable(gtk_widget_get_window(inst->window)); @@ -594,7 +595,7 @@ static void gtkwin_get_pixels(TermWin *tw, int *x, int *y) * raise it, so that the user realises they've already been asked this * question. */ -static int find_and_raise_dialog(GtkFrontend *inst, enum DialogSlot slot) +static bool find_and_raise_dialog(GtkFrontend *inst, enum DialogSlot slot) { GtkWidget *dialog = inst->dialogs[slot]; if (!dialog) @@ -610,7 +611,7 @@ static int find_and_raise_dialog(GtkFrontend *inst, enum DialogSlot slot) /* * Return the window or icon title. */ -static const char *gtkwin_get_title(TermWin *tw, int icon) +static const char *gtkwin_get_title(TermWin *tw, bool icon) { GtkFrontend *inst = container_of(tw, GtkFrontend, termwin); return icon ? inst->icontitle : inst->wintitle; @@ -683,10 +684,10 @@ static void update_mouseptr(GtkFrontend *inst) } } -static void show_mouseptr(GtkFrontend *inst, int show) +static void show_mouseptr(GtkFrontend *inst, bool show) { if (!conf_get_bool(inst->conf, CONF_hide_mouseptr)) - show = 1; + show = true; inst->mouseptr_visible = show; update_mouseptr(inst); } @@ -695,7 +696,8 @@ static void draw_backing_rect(GtkFrontend *inst); static void drawing_area_setup(GtkFrontend *inst, int width, int height) { - int w, h, new_scale, need_size = 0; + int w, h, new_scale; + bool need_size = false; /* * See if the terminal size has changed. @@ -979,7 +981,8 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) GtkFrontend *inst = (GtkFrontend *)data; char output[256]; wchar_t ucsoutput[2]; - int ucsval, start, end, special, output_charset, use_ucsoutput; + int ucsval, start, end, output_charset; + bool special, use_ucsoutput; bool nethack_mode, app_keypad_mode; bool generated_something = false; @@ -1327,8 +1330,8 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) (event->keyval == GDK_KEY_C || event->keyval == GDK_KEY_c || event->keyval == GDK_KEY_V || event->keyval == GDK_KEY_v)) { int cfgval = conf_get_int(inst->conf, CONF_ctrlshiftcv); - int paste = (event->keyval == GDK_KEY_V || - event->keyval == GDK_KEY_v); + bool paste = (event->keyval == GDK_KEY_V || + event->keyval == GDK_KEY_v); switch (cfgval) { case CLIPUI_IMPLICIT: @@ -1454,7 +1457,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) event->keyval == GDK_KEY_KP_Page_Up)) { /* nethack mode; do nothing */ } else { - int try_filter = true; + bool try_filter = true; #ifdef META_MANUAL_MASK if (event->state & META_MANUAL_MASK & inst->meta_mod_mask) { @@ -2129,7 +2132,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) output[end] = '\0'; /* NUL-terminate */ generated_something = true; if (inst->ldisc) - ldisc_send(inst->ldisc, output+start, -2, 1); + ldisc_send(inst->ldisc, output+start, -2, true); } else if (!inst->direct_to_font) { if (!use_ucsoutput) { #ifdef KEY_EVENT_DIAGNOSTICS @@ -2150,7 +2153,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) generated_something = true; if (inst->ldisc) lpage_send(inst->ldisc, output_charset, output+start, - end-start, 1); + end-start, true); } else { #ifdef KEY_EVENT_DIAGNOSTICS char *string_string = dupstr(""); @@ -2174,7 +2177,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) */ generated_something = true; if (inst->ldisc) - luni_send(inst->ldisc, ucsoutput+start, end-start, 1); + luni_send(inst->ldisc, ucsoutput+start, end-start, true); } } else { /* @@ -2198,10 +2201,10 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) #endif generated_something = true; if (inst->ldisc) - ldisc_send(inst->ldisc, output+start, end-start, 1); + ldisc_send(inst->ldisc, output+start, end-start, true); } - show_mouseptr(inst, 0); + show_mouseptr(inst, false); term_seen_key_event(inst->term); } @@ -2231,8 +2234,8 @@ void input_method_commit_event(GtkIMContext *imc, gchar *str, gpointer data) #endif if (inst->ldisc) - lpage_send(inst->ldisc, CS_UTF8, str, strlen(str), 1); - show_mouseptr(inst, 0); + lpage_send(inst->ldisc, CS_UTF8, str, strlen(str), true); + show_mouseptr(inst, false); term_seen_key_event(inst->term); key_pressed(inst); } @@ -2244,9 +2247,10 @@ void input_method_commit_event(GtkIMContext *imc, gchar *str, gpointer data) gboolean scroll_internal(GtkFrontend *inst, gdouble delta, guint state, gdouble ex, gdouble ey) { - int shift, ctrl, alt, x, y, raw_mouse_mode; + int x, y; + bool shift, ctrl, alt, raw_mouse_mode; - show_mouseptr(inst, 1); + show_mouseptr(inst, true); shift = state & GDK_SHIFT_MASK; ctrl = state & GDK_CONTROL_MASK; @@ -2295,12 +2299,13 @@ gboolean scroll_internal(GtkFrontend *inst, gdouble delta, guint state, static gboolean button_internal(GtkFrontend *inst, GdkEventButton *event) { - int shift, ctrl, alt, x, y, button, act, raw_mouse_mode; + bool shift, ctrl, alt, raw_mouse_mode; + int x, y, button, act; /* Remember the timestamp. */ inst->input_event_time = event->time; - show_mouseptr(inst, 1); + show_mouseptr(inst, true); shift = event->state & GDK_SHIFT_MASK; ctrl = event->state & GDK_CONTROL_MASK; @@ -2420,12 +2425,13 @@ gboolean scroll_event(GtkWidget *widget, GdkEventScroll *event, gpointer data) gint motion_event(GtkWidget *widget, GdkEventMotion *event, gpointer data) { GtkFrontend *inst = (GtkFrontend *)data; - int shift, ctrl, alt, x, y, button; + bool shift, ctrl, alt; + int x, y, button; /* Remember the timestamp. */ inst->input_event_time = event->time; - show_mouseptr(inst, 1); + show_mouseptr(inst, true); shift = event->state & GDK_SHIFT_MASK; ctrl = event->state & GDK_CONTROL_MASK; @@ -2583,7 +2589,7 @@ gint focus_event(GtkWidget *widget, GdkEventFocus *event, gpointer data) GtkFrontend *inst = (GtkFrontend *)data; term_set_focus(inst->term, event->in); term_update(inst->term); - show_mouseptr(inst, 1); + show_mouseptr(inst, true); return false; } @@ -2597,7 +2603,7 @@ static void gtk_seat_set_busy_status(Seat *seat, BusyStatus status) /* * set or clear the "raw mouse message" mode */ -static void gtkwin_set_raw_mouse_mode(TermWin *tw, int activate) +static void gtkwin_set_raw_mouse_mode(TermWin *tw, bool activate) { GtkFrontend *inst = container_of(tw, GtkFrontend, termwin); activate = activate && !conf_get_bool(inst->conf, CONF_no_mouse_rep); @@ -2779,7 +2785,7 @@ static void gtkwin_palette_set(TermWin *tw, int n, int r, int g, int b) } } -static int gtkwin_palette_get(TermWin *tw, int n, int *r, int *g, int *b) +static bool gtkwin_palette_get(TermWin *tw, int n, int *r, int *g, int *b) { GtkFrontend *inst = container_of(tw, GtkFrontend, termwin); if (n < 0 || n >= NALLCOLOURS) @@ -2939,7 +2945,7 @@ static void clipboard_clear(GtkClipboard *clipboard, gpointer data) static void gtkwin_clip_write( TermWin *tw, int clipboard, wchar_t *data, int *attr, - truecolour *truecolour, int len, int must_deselect) + truecolour *truecolour, int len, bool must_deselect) { GtkFrontend *inst = container_of(tw, GtkFrontend, termwin); struct clipboard_state *state = &inst->clipstates[clipboard]; @@ -3087,7 +3093,7 @@ static char *retrieve_cutbuffer(GtkFrontend *inst, int *nbytes) static void gtkwin_clip_write( TermWin *tw, int clipboard, wchar_t *data, int *attr, - truecolour *truecolour, int len, int must_deselect) + truecolour *truecolour, int len, bool must_deselect) { GtkFrontend *inst = container_of(tw, GtkFrontend, termwin); struct clipboard_state *state = &inst->clipstates[clipboard]; @@ -3279,8 +3285,8 @@ static void selection_received(GtkWidget *widget, GtkSelectionData *seldata, int length; #ifndef NOT_X_WINDOWS char **list; - int free_list_required = 0; - int free_required = 0; + bool free_list_required = false; + bool free_required = false; #endif int charset; GdkAtom seldata_target = gtk_selection_data_get_target(seldata); @@ -3338,7 +3344,7 @@ static void selection_received(GtkWidget *widget, GtkSelectionData *seldata, /* Xterm is rumoured to expect Latin-1, though I havn't checked the * source, so use that as a de-facto standard. */ charset = CS_ISO8859_1; - free_required = 1; + free_required = true; #else return; #endif @@ -3361,7 +3367,7 @@ static void selection_received(GtkWidget *widget, GtkSelectionData *seldata, text = list[0]; length = strlen(list[0]); charset = CS_UTF8; - free_list_required = 1; + free_list_required = true; } else #endif { @@ -3572,7 +3578,7 @@ static int gtkwin_char_width(TermWin *tw, int uc) return 1; } -static int gtkwin_setup_draw_ctx(TermWin *tw) +static bool gtkwin_setup_draw_ctx(TermWin *tw) { GtkFrontend *inst = container_of(tw, GtkFrontend, termwin); @@ -3649,7 +3655,7 @@ static void draw_update(GtkFrontend *inst, int x, int y, int w, int h) #ifdef DRAW_TEXT_CAIRO static void cairo_set_source_rgb_dim(cairo_t *cr, double r, double g, double b, - int dim) + bool dim) { if (dim) cairo_set_source_rgb(cr, r * 2 / 3, g * 2 / 3, b * 2 / 3); @@ -3658,7 +3664,7 @@ static void cairo_set_source_rgb_dim(cairo_t *cr, double r, double g, double b, } #endif -static void draw_set_colour(GtkFrontend *inst, int col, int dim) +static void draw_set_colour(GtkFrontend *inst, int col, bool dim) { #ifdef DRAW_TEXT_GDK if (inst->uctx.type == DRAWTYPE_GDK) { @@ -3688,7 +3694,7 @@ static void draw_set_colour(GtkFrontend *inst, int col, int dim) #endif } -static void draw_set_colour_rgb(GtkFrontend *inst, optionalrgb orgb, int dim) +static void draw_set_colour_rgb(GtkFrontend *inst, optionalrgb orgb, bool dim) { #ifdef DRAW_TEXT_GDK if (inst->uctx.type == DRAWTYPE_GDK) { @@ -3717,7 +3723,7 @@ static void draw_set_colour_rgb(GtkFrontend *inst, optionalrgb orgb, int dim) #endif } -static void draw_rectangle(GtkFrontend *inst, int filled, +static void draw_rectangle(GtkFrontend *inst, bool filled, int x, int y, int w, int h) { #ifdef DRAW_TEXT_GDK @@ -3801,8 +3807,8 @@ static void draw_line(GtkFrontend *inst, int x0, int y0, int x1, int y1) } static void draw_stretch_before(GtkFrontend *inst, int x, int y, - int w, int wdouble, - int h, int hdouble, int hbothalf) + int w, bool wdouble, + int h, bool hdouble, bool hbothalf) { #ifdef DRAW_TEXT_CAIRO if (inst->uctx.type == DRAWTYPE_CAIRO) { @@ -3836,8 +3842,8 @@ static void draw_stretch_before(GtkFrontend *inst, int x, int y, } static void draw_stretch_after(GtkFrontend *inst, int x, int y, - int w, int wdouble, - int h, int hdouble, int hbothalf) + int w, bool wdouble, + int h, bool hdouble, bool hbothalf) { #ifdef DRAW_TEXT_GDK #ifndef NO_BACKING_PIXMAPS @@ -3902,7 +3908,7 @@ static void draw_backing_rect(GtkFrontend *inst) w = inst->width * inst->font_width + 2*inst->window_border; h = inst->height * inst->font_height + 2*inst->window_border; draw_set_colour(inst, 258, false); - draw_rectangle(inst, 1, 0, 0, w, h); + draw_rectangle(inst, true, 0, 0, w, h); draw_update(inst, 0, 0, w, h); win_free_draw_ctx(&inst->termwin); } @@ -3918,8 +3924,9 @@ static void do_text_internal( unsigned long attr, int lattr, truecolour truecolour) { int ncombining; - int nfg, nbg, t, fontid, shadow, rlen, widefactor, bold; - int monochrome = + int nfg, nbg, t, fontid, rlen, widefactor; + bool bold; + bool monochrome = gdk_visual_get_depth(gtk_widget_get_visual(inst->area)) == 1; if (attr & TATTR_COMBINING) { @@ -3959,7 +3966,7 @@ static void do_text_internal( attr &= ~ATTR_DIM; /* don't dim the cursor */ } - fontid = shadow = 0; + fontid = 0; if (attr & ATTR_WIDE) { widefactor = 2; @@ -3969,10 +3976,10 @@ static void do_text_internal( } if ((attr & ATTR_BOLD) && (inst->bold_style & 1)) { - bold = 1; + bold = true; fontid |= 1; } else { - bold = 0; + bold = false; } if (!inst->fonts[fontid]) { @@ -4104,18 +4111,19 @@ static void gtkwin_draw_cursor( unsigned long attr, int lattr, truecolour truecolour) { GtkFrontend *inst = container_of(tw, GtkFrontend, termwin); - int active, passive, widefactor; + bool active, passive; + int widefactor; if (attr & TATTR_PASCURS) { attr &= ~TATTR_PASCURS; - passive = 1; + passive = true; } else - passive = 0; + passive = false; if ((attr & TATTR_ACTCURS) && inst->cursor_type != 0) { attr &= ~TATTR_ACTCURS; - active = 1; + active = true; } else - active = 0; + active = false; do_text_internal(inst, x, y, text, len, attr, lattr, truecolour); if (attr & TATTR_COMBINING) @@ -4257,7 +4265,7 @@ static const char *gtk_seat_get_x_display(Seat *seat) } #ifndef NOT_X_WINDOWS -static int gtk_seat_get_windowid(Seat *seat, long *id) +static bool gtk_seat_get_windowid(Seat *seat, long *id) { GtkFrontend *inst = container_of(seat, GtkFrontend, seat); GdkWindow *window = gtk_widget_get_window(inst->area); @@ -4268,7 +4276,7 @@ static int gtk_seat_get_windowid(Seat *seat, long *id) } #endif -static int gtkwin_is_utf8(TermWin *tw) +static bool gtkwin_is_utf8(TermWin *tw) { GtkFrontend *inst = container_of(tw, GtkFrontend, termwin); return inst->ucsdata.line_codepage == CS_UTF8; @@ -4276,7 +4284,7 @@ static int gtkwin_is_utf8(TermWin *tw) char *setup_fonts_ucs(GtkFrontend *inst) { - int shadowbold = conf_get_bool(inst->conf, CONF_shadowbold); + bool shadowbold = conf_get_bool(inst->conf, CONF_shadowbold); int shadowboldoffset = conf_get_int(inst->conf, CONF_shadowboldoffset); FontSpec *fs; unifont *fonts[4]; @@ -4643,7 +4651,7 @@ void change_settings_menuitem(GtkMenuItem *item, gpointer data) ctx->newconf = conf_copy(inst->conf); dialog = create_config_box( - title, ctx->newconf, 1, + title, ctx->newconf, true, inst->backend ? backend_cfg_info(inst->backend) : 0, after_change_settings_dialog, ctx); register_dialog(&inst->seat, DIALOG_SLOT_RECONFIGURE, dialog); @@ -4663,7 +4671,8 @@ static void after_change_settings_dialog(void *vctx, int retval) *(struct after_change_settings_dialog_ctx *)vctx; GtkFrontend *inst = ctx.inst; Conf *oldconf = inst->conf, *newconf = ctx.newconf; - int i, j, need_size; + int i, j; + bool need_size; sfree(vctx); /* we've copied this already */ @@ -5476,7 +5485,7 @@ void new_session_window(Conf *conf, const char *geometry_string) { GtkWidget *menuitem; char *s; - extern const int use_event_log, new_session, saved_sessions; + extern const bool use_event_log, new_session, saved_sessions; inst->menu = gtk_menu_new(); @@ -5552,7 +5561,7 @@ void new_session_window(Conf *conf, const char *geometry_string) inst->waitcursor = make_mouse_ptr(inst, GDK_WATCH); inst->blankcursor = make_mouse_ptr(inst, -1); inst->currcursor = inst->textcursor; - show_mouseptr(inst, 1); + show_mouseptr(inst, true); inst->eventlogstuff = eventlogstuff_new(); diff --git a/unix/unix.h b/unix/unix.h index 48e727b6..1ce587bd 100644 --- a/unix/unix.h +++ b/unix/unix.h @@ -49,7 +49,7 @@ * pure-CLI utilities, so that Unix Plink, PSFTP etc don't announce * themselves incongruously as having something to do with GTK. */ #define BUILDINFO_PLATFORM_CLI "Unix" -extern const int buildinfo_gtk_relevant; +extern const bool buildinfo_gtk_relevant; #define BUILDINFO_PLATFORM (buildinfo_gtk_relevant ? \ BUILDINFO_PLATFORM_GTK : BUILDINFO_PLATFORM_CLI) @@ -58,7 +58,7 @@ char *buildinfo_gtk_version(void); struct Filename { char *path; }; -FILE *f_open(const struct Filename *, char const *, int); +FILE *f_open(const struct Filename *, char const *, bool); struct FontSpec { char *name; /* may be "" to indicate no selected font at all */ @@ -207,7 +207,7 @@ void unregister_dialog(Seat *seat, enum DialogSlot slot); /* Things pterm.c needs from gtkdlg.c */ #ifdef MAY_REFER_TO_GTK_IN_HEADERS GtkWidget *create_config_box(const char *title, Conf *conf, - int midsession, int protcfginfo, + bool midsession, int protcfginfo, post_dialog_fn_t after, void *afterctx); #endif void nonfatal_message_box(void *window, const char *msg); @@ -243,7 +243,7 @@ struct message_box_buttons { extern const struct message_box_buttons buttons_yn, buttons_ok; GtkWidget *create_message_box( GtkWidget *parentwin, const char *title, const char *msg, int minwid, - int selectable, const struct message_box_buttons *buttons, + bool selectable, const struct message_box_buttons *buttons, post_dialog_fn_t after, void *afterctx); #endif @@ -280,10 +280,12 @@ void uxsel_input_remove(uxsel_id *id); /* uxcfg.c */ struct controlbox; -void unix_setup_config_box(struct controlbox *b, int midsession, int protocol); +void unix_setup_config_box( + struct controlbox *b, bool midsession, int protocol); /* gtkcfg.c */ -void gtk_setup_config_box(struct controlbox *b, int midsession, void *window); +void gtk_setup_config_box( + struct controlbox *b, bool midsession, void *window); /* * In the Unix Unicode layer, DEFAULT_CODEPAGE is a special value @@ -301,13 +303,13 @@ void gtk_setup_config_box(struct controlbox *b, int midsession, void *window); /* BSD-semantics version of signal(), and another helpful function */ void (*putty_signal(int sig, void (*func)(int)))(int); -void block_signal(int sig, int block_it); +void block_signal(int sig, bool block_it); /* uxmisc.c */ void cloexec(int); void noncloexec(int); -int nonblock(int); -int no_nonblock(int); +bool nonblock(int); +bool no_nonblock(int); char *make_dir_and_check_ours(const char *dirname); char *make_dir_path(const char *path, mode_t mode); @@ -315,8 +317,8 @@ char *make_dir_path(const char *path, mode_t mode); * Exports from unicode.c. */ struct unicode_data; -int init_ucs(struct unicode_data *ucsdata, char *line_codepage, - int utf8_override, int font_charset, int vtmode); +bool init_ucs(struct unicode_data *ucsdata, char *line_codepage, + bool utf8_override, int font_charset, int vtmode); /* * Spare functions exported directly from uxnet.c. @@ -342,7 +344,7 @@ extern const struct BackendVtable serial_backend; /* * uxpeer.c, wrapping getsockopt(SO_PEERCRED). */ -int so_peercred(int fd, int *pid, int *uid, int *gid); +bool so_peercred(int fd, int *pid, int *uid, int *gid); /* * uxfdsock.c. diff --git a/unix/ux_x11.c b/unix/ux_x11.c index fb5c4949..16acbab4 100644 --- a/unix/ux_x11.c +++ b/unix/ux_x11.c @@ -17,7 +17,7 @@ void platform_get_x11_auth(struct X11Display *disp, Conf *conf) { char *xauthfile; - int needs_free; + bool needs_free; /* * Find the .Xauthority file. @@ -39,7 +39,7 @@ void platform_get_x11_auth(struct X11Display *disp, Conf *conf) } } -const int platform_uses_x11_unix_by_default = true; +const bool platform_uses_x11_unix_by_default = true; int platform_make_x11_server(Plug *plug, const char *progname, int mindisp, const char *screen_number_suffix, diff --git a/unix/uxagentc.c b/unix/uxagentc.c index 31829eb7..edd05d79 100644 --- a/unix/uxagentc.c +++ b/unix/uxagentc.c @@ -15,7 +15,7 @@ #include "tree234.h" #include "puttymem.h" -int agent_exists(void) +bool agent_exists(void) { const char *p = getenv("SSH_AUTH_SOCK"); if (p && *p) @@ -54,12 +54,12 @@ static int agent_connfind(void *av, void *bv) } /* - * Attempt to read from an agent socket fd. Returns 0 if the expected - * response is as yet incomplete; returns 1 if it's either complete - * (conn->retbuf non-NULL and filled with something useful) or has - * failed totally (conn->retbuf is NULL). + * Attempt to read from an agent socket fd. Returns false if the + * expected response is as yet incomplete; returns true if it's either + * complete (conn->retbuf non-NULL and filled with something useful) + * or has failed totally (conn->retbuf is NULL). */ -static int agent_try_read(agent_pending_query *conn) +static bool agent_try_read(agent_pending_query *conn) { int ret; @@ -69,7 +69,7 @@ static int agent_try_read(agent_pending_query *conn) if (conn->retbuf != conn->sizebuf) sfree(conn->retbuf); conn->retbuf = NULL; conn->retlen = 0; - return 1; + return true; } conn->retlen += ret; if (conn->retsize == 4 && conn->retlen == 4) { @@ -77,7 +77,7 @@ static int agent_try_read(agent_pending_query *conn) if (conn->retsize <= 0) { conn->retbuf = NULL; conn->retlen = 0; - return -1; /* way too large */ + return true; /* way too large */ } assert(conn->retbuf == conn->sizebuf); conn->retbuf = snewn(conn->retsize, char); @@ -85,9 +85,9 @@ static int agent_try_read(agent_pending_query *conn) } if (conn->retlen < conn->retsize) - return 0; /* more data to come */ + return false; /* more data to come */ - return 1; + return true; } void agent_cancel_query(agent_pending_query *conn) diff --git a/unix/uxcfg.c b/unix/uxcfg.c index e48a9b69..7c24603a 100644 --- a/unix/uxcfg.c +++ b/unix/uxcfg.c @@ -10,7 +10,7 @@ #include "dialog.h" #include "storage.h" -void unix_setup_config_box(struct controlbox *b, int midsession, int protocol) +void unix_setup_config_box(struct controlbox *b, bool midsession, int protocol) { struct controlset *s; union control *c; @@ -29,7 +29,7 @@ void unix_setup_config_box(struct controlbox *b, int midsession, int protocol) */ s = ctrl_getset(b, "Terminal", "printing", "Remote-controlled printing"); assert(s->ncontrols == 1 && s->ctrls[0]->generic.type == CTRL_EDITBOX); - s->ctrls[0]->editbox.has_list = 0; + s->ctrls[0]->editbox.has_list = false; /* * Unix supports a local-command proxy. This also means we must diff --git a/unix/uxcons.c b/unix/uxcons.c index e47a8003..1b5aabb3 100644 --- a/unix/uxcons.c +++ b/unix/uxcons.c @@ -21,10 +21,10 @@ #include "storage.h" #include "ssh.h" -int console_batch_mode = false; +bool console_batch_mode = false; static struct termios orig_termios_stderr; -static int stderr_is_a_tty; +static bool stderr_is_a_tty; void stderr_tty_init() { @@ -136,7 +136,7 @@ static int block_and_read(int fd, void *buf, size_t len) #ifdef EWOULDBLOCK (errno == EWOULDBLOCK) || #endif - 0)) { + false)) { fd_set rfds; FD_ZERO(&rfds); @@ -595,7 +595,7 @@ int console_get_userpass_input(prompts_t *p) return 1; /* success */ } -int is_interactive(void) +bool is_interactive(void) { return isatty(0); } diff --git a/unix/uxfdsock.c b/unix/uxfdsock.c index 41aaf232..2258e5bf 100644 --- a/unix/uxfdsock.c +++ b/unix/uxfdsock.c @@ -235,7 +235,7 @@ static void fdsocket_flush(Socket *s) /* do nothing */ } -static void fdsocket_set_frozen(Socket *s, int is_frozen) +static void fdsocket_set_frozen(Socket *s, bool is_frozen) { FdSocket *fds = container_of(s, FdSocket, sock); diff --git a/unix/uxmisc.c b/unix/uxmisc.c index cfdc5598..2170c3c4 100644 --- a/unix/uxmisc.c +++ b/unix/uxmisc.c @@ -58,12 +58,12 @@ const char *filename_to_str(const Filename *fn) return fn->path; } -int filename_equal(const Filename *f1, const Filename *f2) +bool filename_equal(const Filename *f1, const Filename *f2) { return !strcmp(f1->path, f2->path); } -int filename_is_null(const Filename *fn) +bool filename_is_null(const Filename *fn) { return !fn->path[0]; } @@ -202,7 +202,7 @@ void noncloexec(int fd) { exit(1); } } -int nonblock(int fd) { +bool nonblock(int fd) { int fdflags; fdflags = fcntl(fd, F_GETFL); @@ -217,7 +217,7 @@ int nonblock(int fd) { return fdflags & O_NONBLOCK; } -int no_nonblock(int fd) { +bool no_nonblock(int fd) { int fdflags; fdflags = fcntl(fd, F_GETFL); @@ -233,7 +233,7 @@ int no_nonblock(int fd) { return fdflags & O_NONBLOCK; } -FILE *f_open(const Filename *filename, char const *mode, int is_private) +FILE *f_open(const Filename *filename, char const *mode, bool is_private) { if (!is_private) { return fopen(filename->path, mode); @@ -330,7 +330,7 @@ char *make_dir_path(const char *path, mode_t mode) } } -int open_for_write_would_lose_data(const Filename *fn) +bool open_for_write_would_lose_data(const Filename *fn) { struct stat st; diff --git a/unix/uxnet.c b/unix/uxnet.c index 9ca98faf..512ad835 100644 --- a/unix/uxnet.c +++ b/unix/uxnet.c @@ -64,20 +64,21 @@ struct NetSocket { int s; Plug *plug; bufchain output_data; - int connected; /* irrelevant for listening sockets */ - int writable; - int frozen; /* this causes readability notifications to be ignored */ - int localhost_only; /* for listening sockets */ + bool connected; /* irrelevant for listening sockets */ + bool writable; + bool frozen; /* this causes readability notifications to be ignored */ + bool localhost_only; /* for listening sockets */ char oobdata[1]; int sending_oob; - int oobpending; /* is there OOB data available to read? */ - int oobinline; + bool oobpending; /* is there OOB data available to read? */ + bool oobinline; enum { EOF_NO, EOF_PENDING, EOF_SENT } outgoingeof; - int incomingeof; + bool incomingeof; int pending_error; /* in case send() returns error */ - int listener; - int nodelay, keepalive; /* for connect()-type sockets */ - int privport, port; /* and again */ + bool listener; + bool nodelay, keepalive; /* for connect()-type sockets */ + bool privport; + int port; /* and again */ SockAddr *addr; SockAddrStep step; /* @@ -292,7 +293,7 @@ SockAddr *sk_nonamelookup(const char *host) return ret; } -static int sk_nextaddr(SockAddr *addr, SockAddrStep *step) +static bool sk_nextaddr(SockAddr *addr, SockAddrStep *step) { #ifndef NO_IPV6 if (step->ai && step->ai->ai_next) { @@ -362,7 +363,7 @@ static SockAddr sk_extractaddr_tmp( return toret; } -int sk_addr_needs_port(SockAddr *addr) +bool sk_addr_needs_port(SockAddr *addr) { if (addr->superfamily == UNRESOLVED || addr->superfamily == UNIX) { return false; @@ -371,7 +372,7 @@ int sk_addr_needs_port(SockAddr *addr) } } -int sk_hostname_is_local(const char *name) +bool sk_hostname_is_local(const char *name) { return !strcmp(name, "localhost") || !strcmp(name, "::1") || @@ -381,7 +382,7 @@ int sk_hostname_is_local(const char *name) #define ipv4_is_loopback(addr) \ (((addr).s_addr & htonl(0xff000000)) == htonl(0x7f000000)) -static int sockaddr_is_loopback(struct sockaddr *sa) +static bool sockaddr_is_loopback(struct sockaddr *sa) { union sockaddr_union *u = (union sockaddr_union *)sa; switch (u->sa.sa_family) { @@ -398,12 +399,12 @@ static int sockaddr_is_loopback(struct sockaddr *sa) } } -int sk_address_is_local(SockAddr *addr) +bool sk_address_is_local(SockAddr *addr) { if (addr->superfamily == UNRESOLVED) - return 0; /* we don't know; assume not */ + return false; /* we don't know; assume not */ else if (addr->superfamily == UNIX) - return 1; + return true; else { #ifndef NO_IPV6 return sockaddr_is_loopback(addr->ais->ai_addr); @@ -418,7 +419,7 @@ int sk_address_is_local(SockAddr *addr) } } -int sk_address_is_special_local(SockAddr *addr) +bool sk_address_is_special_local(SockAddr *addr) { return addr->superfamily == UNIX; } @@ -502,7 +503,7 @@ static void sk_net_close(Socket *s); static int sk_net_write(Socket *s, const void *data, int len); static int sk_net_write_oob(Socket *s, const void *data, int len); static void sk_net_write_eof(Socket *s); -static void sk_net_set_frozen(Socket *s, int is_frozen); +static void sk_net_set_frozen(Socket *s, bool is_frozen); static SocketPeerInfo *sk_net_peer_info(Socket *s); static const char *sk_net_socket_error(Socket *s); @@ -531,18 +532,18 @@ static Socket *sk_net_accept(accept_ctx_t ctx, Plug *plug) ret->error = NULL; ret->plug = plug; bufchain_init(&ret->output_data); - ret->writable = 1; /* to start with */ + ret->writable = true; /* to start with */ ret->sending_oob = 0; - ret->frozen = 1; - ret->localhost_only = 0; /* unused, but best init anyway */ + ret->frozen = true; + ret->localhost_only = false; /* unused, but best init anyway */ ret->pending_error = 0; ret->oobpending = false; ret->outgoingeof = EOF_NO; ret->incomingeof = false; - ret->listener = 0; + ret->listener = false; ret->parent = ret->child = NULL; ret->addr = NULL; - ret->connected = 1; + ret->connected = true; ret->s = sockfd; @@ -551,7 +552,7 @@ static Socket *sk_net_accept(accept_ctx_t ctx, Plug *plug) return &ret->sock; } - ret->oobinline = 0; + ret->oobinline = false; uxsel_tell(ret); add234(sktree, ret); @@ -601,7 +602,7 @@ static int try_connect(NetSocket *sock) cloexec(s); if (sock->oobinline) { - int b = true; + int b = 1; if (setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (void *) &b, sizeof(b)) < 0) { err = errno; @@ -611,7 +612,7 @@ static int try_connect(NetSocket *sock) } if (sock->nodelay) { - int b = true; + int b = 1; if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (void *) &b, sizeof(b)) < 0) { err = errno; @@ -621,7 +622,7 @@ static int try_connect(NetSocket *sock) } if (sock->keepalive) { - int b = true; + int b = 1; if (setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (void *) &b, sizeof(b)) < 0) { err = errno; @@ -737,8 +738,8 @@ static int try_connect(NetSocket *sock) * If we _don't_ get EWOULDBLOCK, the connect has completed * and we should set the socket as connected and writable. */ - sock->connected = 1; - sock->writable = 1; + sock->connected = true; + sock->writable = true; } uxsel_tell(sock); @@ -758,8 +759,8 @@ static int try_connect(NetSocket *sock) return err; } -Socket *sk_new(SockAddr *addr, int port, int privport, int oobinline, - int nodelay, int keepalive, Plug *plug) +Socket *sk_new(SockAddr *addr, int port, bool privport, bool oobinline, + bool nodelay, bool keepalive, Plug *plug) { NetSocket *ret; int err; @@ -772,17 +773,17 @@ Socket *sk_new(SockAddr *addr, int port, int privport, int oobinline, ret->error = NULL; ret->plug = plug; bufchain_init(&ret->output_data); - ret->connected = 0; /* to start with */ - ret->writable = 0; /* to start with */ + ret->connected = false; /* to start with */ + ret->writable = false; /* to start with */ ret->sending_oob = 0; - ret->frozen = 0; - ret->localhost_only = 0; /* unused, but best init anyway */ + ret->frozen = false; + ret->localhost_only = false; /* unused, but best init anyway */ ret->pending_error = 0; ret->parent = ret->child = NULL; ret->oobpending = false; ret->outgoingeof = EOF_NO; ret->incomingeof = false; - ret->listener = 0; + ret->listener = false; ret->addr = addr; START_STEP(ret->addr, ret->step); ret->s = -1; @@ -804,7 +805,7 @@ Socket *sk_new(SockAddr *addr, int port, int privport, int oobinline, } Socket *sk_newlistener(const char *srcaddr, int port, Plug *plug, - int local_host_only, int orig_address_family) + bool local_host_only, int orig_address_family) { int s; #ifndef NO_IPV6 @@ -827,16 +828,16 @@ Socket *sk_newlistener(const char *srcaddr, int port, Plug *plug, ret->error = NULL; ret->plug = plug; bufchain_init(&ret->output_data); - ret->writable = 0; /* to start with */ + ret->writable = false; /* to start with */ ret->sending_oob = 0; - ret->frozen = 0; + ret->frozen = false; ret->localhost_only = local_host_only; ret->pending_error = 0; ret->parent = ret->child = NULL; ret->oobpending = false; ret->outgoingeof = EOF_NO; ret->incomingeof = false; - ret->listener = 1; + ret->listener = true; ret->addr = NULL; ret->s = -1; @@ -879,7 +880,7 @@ Socket *sk_newlistener(const char *srcaddr, int port, Plug *plug, cloexec(s); - ret->oobinline = 0; + ret->oobinline = false; if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char *)&on, sizeof(on)) < 0) { @@ -1267,7 +1268,7 @@ static void net_select_result(int fd, int event) int ret; char buf[20480]; /* nice big buffer for plenty of speed */ NetSocket *s; - u_long atmark; + bool atmark; /* Find the Socket structure */ s = find234(sktree, &fd, cmpforsearch); @@ -1359,11 +1360,14 @@ static void net_select_result(int fd, int event) * (data prior to urgent). */ if (s->oobinline && s->oobpending) { - atmark = 1; - if (ioctl(s->s, SIOCATMARK, &atmark) == 0 && atmark) - s->oobpending = false; /* clear this indicator */ + int atmark_from_ioctl; + if (ioctl(s->s, SIOCATMARK, &atmark_from_ioctl) == 0) { + atmark = atmark_from_ioctl; + if (atmark) + s->oobpending = false; /* clear this indicator */ + } } else - atmark = 1; + atmark = true; ret = recv(s->s, buf, s->oobpending ? 1 : sizeof(buf), 0); noise_ultralight(ret); @@ -1441,11 +1445,12 @@ static void net_select_result(int fd, int event) sk_addr_free(s->addr); s->addr = NULL; } - s->connected = s->writable = 1; + s->connected = true; + s->writable = true; uxsel_tell(s); } else { int bufsize_before, bufsize_after; - s->writable = 1; + s->writable = true; bufsize_before = s->sending_oob + bufchain_size(&s->output_data); try_send(s); bufsize_after = s->sending_oob + bufchain_size(&s->output_data); @@ -1471,7 +1476,7 @@ static const char *sk_net_socket_error(Socket *sock) return s->error; } -static void sk_net_set_frozen(Socket *sock, int is_frozen) +static void sk_net_set_frozen(Socket *sock, bool is_frozen) { NetSocket *s = container_of(sock, NetSocket, sock); if (s->frozen == is_frozen) @@ -1665,16 +1670,16 @@ Socket *new_unix_listener(SockAddr *listenaddr, Plug *plug) ret->error = NULL; ret->plug = plug; bufchain_init(&ret->output_data); - ret->writable = 0; /* to start with */ + ret->writable = false; /* to start with */ ret->sending_oob = 0; - ret->frozen = 0; + ret->frozen = false; ret->localhost_only = true; ret->pending_error = 0; ret->parent = ret->child = NULL; ret->oobpending = false; ret->outgoingeof = EOF_NO; ret->incomingeof = false; - ret->listener = 1; + ret->listener = true; ret->addr = listenaddr; ret->s = -1; @@ -1691,7 +1696,7 @@ Socket *new_unix_listener(SockAddr *listenaddr, Plug *plug) cloexec(s); - ret->oobinline = 0; + ret->oobinline = false; memset(&u, '\0', sizeof(u)); u.su.sun_family = AF_UNIX; diff --git a/unix/uxnoise.c b/unix/uxnoise.c index c42466f6..bcc78273 100644 --- a/unix/uxnoise.c +++ b/unix/uxnoise.c @@ -16,28 +16,28 @@ #include "ssh.h" #include "storage.h" -static int read_dev_urandom(char *buf, int len) +static bool read_dev_urandom(char *buf, int len) { int fd; int ngot, ret; fd = open("/dev/urandom", O_RDONLY); if (fd < 0) - return 0; + return false; ngot = 0; while (ngot < len) { ret = read(fd, buf+ngot, len-ngot); if (ret < 0) { close(fd); - return 0; + return false; } ngot += ret; } close(fd); - return 1; + return true; } /* @@ -52,10 +52,10 @@ void noise_get_heavy(void (*func) (void *, int)) char buf[512]; FILE *fp; int ret; - int got_dev_urandom = 0; + bool got_dev_urandom = false; if (read_dev_urandom(buf, 32)) { - got_dev_urandom = 1; + got_dev_urandom = true; func(buf, 32); } diff --git a/unix/uxpeer.c b/unix/uxpeer.c index 8aaa3579..4ad26322 100644 --- a/unix/uxpeer.c +++ b/unix/uxpeer.c @@ -16,7 +16,7 @@ #include "putty.h" -int so_peercred(int fd, int *pid, int *uid, int *gid) +bool so_peercred(int fd, int *pid, int *uid, int *gid) { #ifdef HAVE_SO_PEERCRED struct ucred cr; diff --git a/unix/uxpgnt.c b/unix/uxpgnt.c index 4cf9b0ff..42ce7ba5 100644 --- a/unix/uxpgnt.c +++ b/unix/uxpgnt.c @@ -114,7 +114,7 @@ void keylist_update(void) const char *const appname = "Pageant"; -static int time_to_die = false; +static bool time_to_die = false; /* Stub functions to permit linking against x11fwd.c. These never get * used, because in LIFE_X11 mode we connect to the X server using a @@ -122,30 +122,30 @@ static int time_to_die = false; * forwarding too. */ void chan_remotely_opened_confirmation(Channel *chan) { } void chan_remotely_opened_failure(Channel *chan, const char *err) { } -int chan_default_want_close(Channel *chan, int s, int r) { return false; } -int chan_no_exit_status(Channel *ch, int s) { return false; } -int chan_no_exit_signal(Channel *ch, ptrlen s, int c, ptrlen m) +bool chan_default_want_close(Channel *chan, bool s, bool r) { return false; } +bool chan_no_exit_status(Channel *ch, int s) { return false; } +bool chan_no_exit_signal(Channel *ch, ptrlen s, bool c, ptrlen m) { return false; } -int chan_no_exit_signal_numeric(Channel *ch, int s, int c, ptrlen m) +bool chan_no_exit_signal_numeric(Channel *ch, int s, bool c, ptrlen m) { return false; } -int chan_no_run_shell(Channel *chan) { return false; } -int chan_no_run_command(Channel *chan, ptrlen command) { return false; } -int chan_no_run_subsystem(Channel *chan, ptrlen subsys) { return false; } -int chan_no_enable_x11_forwarding( - Channel *chan, int oneshot, ptrlen authproto, ptrlen authdata, +bool chan_no_run_shell(Channel *chan) { return false; } +bool chan_no_run_command(Channel *chan, ptrlen command) { return false; } +bool chan_no_run_subsystem(Channel *chan, ptrlen subsys) { return false; } +bool chan_no_enable_x11_forwarding( + Channel *chan, bool oneshot, ptrlen authproto, ptrlen authdata, unsigned screen_number) { return false; } -int chan_no_enable_agent_forwarding(Channel *chan) { return false; } -int chan_no_allocate_pty( +bool chan_no_enable_agent_forwarding(Channel *chan) { return false; } +bool chan_no_allocate_pty( Channel *chan, ptrlen termtype, unsigned width, unsigned height, unsigned pixwidth, unsigned pixheight, struct ssh_ttymodes modes) { return false; } -int chan_no_set_env(Channel *chan, ptrlen var, ptrlen value) { return false; } -int chan_no_send_break(Channel *chan, unsigned length) { return false; } -int chan_no_send_signal(Channel *chan, ptrlen signame) { return false; } -int chan_no_change_window_size( +bool chan_no_set_env(Channel *chan, ptrlen var, ptrlen value) { return false; } +bool chan_no_send_break(Channel *chan, unsigned length) { return false; } +bool chan_no_send_signal(Channel *chan, ptrlen signame) { return false; } +bool chan_no_change_window_size( Channel *chan, unsigned width, unsigned height, unsigned pixwidth, unsigned pixheight) { return false; } -void chan_no_request_response(Channel *chan, int success) {} +void chan_no_request_response(Channel *chan, bool success) {} /* * These functions are part of the plug for our connection to the X @@ -158,7 +158,7 @@ static void x11_log(Plug *p, int type, SockAddr *addr, int port, static void x11_receive(Plug *plug, int urgent, char *data, int len) {} static void x11_sent(Plug *plug, int bufsize) {} static void x11_closing(Plug *plug, const char *error_msg, int error_code, - int calling_back) + bool calling_back) { time_to_die = true; } @@ -206,7 +206,7 @@ void pageant_print_env(int pid) } } -void pageant_fork_and_print_env(int retain_tty) +void pageant_fork_and_print_env(bool retain_tty) { pid_t pid = fork(); if (pid == -1) { @@ -279,7 +279,7 @@ struct cmdline_key_action { const char *filename; }; -int is_agent_action(keyact action) +bool is_agent_action(keyact action) { return action == KEYACT_AGENT_LOAD; } @@ -299,7 +299,7 @@ void add_keyact(keyact action, const char *filename) keyact_tail = a; } -int have_controlling_tty(void) +bool have_controlling_tty(void) { int fd = open("/dev/tty", O_RDONLY); if (fd < 0) { @@ -347,11 +347,11 @@ static char *askpass_tty(const char *prompt) static char *askpass_gui(const char *prompt) { char *passphrase; - int success; + bool success; /* in gtkask.c */ char *gtk_askpass_main(const char *display, const char *wintitle, - const char *prompt, int *success); + const char *prompt, bool *success); passphrase = gtk_askpass_main( display, "Pageant passphrase prompt", prompt, &success); @@ -395,10 +395,11 @@ static char *askpass(const char *prompt) } } -static int unix_add_keyfile(const char *filename_str) +static bool unix_add_keyfile(const char *filename_str) { Filename *filename = filename_from_str(filename_str); - int status, ret; + int status; + bool ret; char *err; ret = true; @@ -457,12 +458,12 @@ void key_list_callback(void *ctx, const char *fingerprint, struct key_find_ctx { const char *string; - int match_fp, match_comment; + bool match_fp, match_comment; struct pageant_pubkey *found; int nfound; }; -int match_fingerprint_string(const char *string, const char *fingerprint) +bool match_fingerprint_string(const char *string, const char *fingerprint) { const char *hash; @@ -503,8 +504,8 @@ struct pageant_pubkey *find_key(const char *string, char **retstr) { struct key_find_ctx actx, *ctx = &actx; struct pageant_pubkey key_in, *key_ret; - int try_file = true, try_fp = true, try_comment = true; - int file_errors = false; + bool try_file = true, try_fp = true, try_comment = true; + bool file_errors = false; /* * Trim off disambiguating prefixes telling us how to interpret @@ -512,17 +513,21 @@ struct pageant_pubkey *find_key(const char *string, char **retstr) */ if (!strncmp(string, "file:", 5)) { string += 5; - try_fp = try_comment = false; + try_fp = false; + try_comment = false; file_errors = true; /* also report failure to load the file */ } else if (!strncmp(string, "comment:", 8)) { string += 8; - try_file = try_fp = false; + try_file = false; + try_fp = false; } else if (!strncmp(string, "fp:", 3)) { string += 3; - try_file = try_comment = false; + try_file = false; + try_comment = false; } else if (!strncmp(string, "fingerprint:", 12)) { string += 12; - try_file = try_comment = false; + try_file = false; + try_comment = false; } /* @@ -633,7 +638,7 @@ void run_client(void) { const struct cmdline_key_action *act; struct pageant_pubkey *key; - int errors = false; + bool errors = false; char *retstr; if (!agent_exists()) { @@ -735,7 +740,7 @@ void run_agent(void) int fd; int i, fdcount, fdsize, fdstate; int termination_pid = -1; - int errors = false; + bool errors = false; Conf *conf; const struct cmdline_key_action *act; @@ -799,7 +804,7 @@ void run_agent(void) conn->plug.vt = &X11Connection_plugvt; s = new_connection(sk_addr_dup(disp->addr), disp->realhost, disp->port, - 0, 1, 0, 0, &conn->plug, conf); + false, true, false, false, &conn->plug, conf); if ((err = sk_socket_error(s)) != NULL) { fprintf(stderr, "pageant: unable to connect to X server: %s", err); exit(1); @@ -999,7 +1004,7 @@ void run_agent(void) int main(int argc, char **argv) { - int doing_opts = true; + bool doing_opts = true; keyact curr_keyact = KEYACT_AGENT_LOAD; const char *standalone_askpass_prompt = NULL; @@ -1121,9 +1126,9 @@ int main(int argc, char **argv) * actions of KEYACT_AGENT_* type. */ { - int has_agent_actions = false; - int has_client_actions = false; - int has_lifetime = false; + bool has_agent_actions = false; + bool has_client_actions = false; + bool has_lifetime = false; const struct cmdline_key_action *act; for (act = keyact_head; act; act = act->next) { diff --git a/unix/uxplink.c b/unix/uxplink.c index 6794eff6..35b07f92 100644 --- a/unix/uxplink.c +++ b/unix/uxplink.c @@ -38,7 +38,7 @@ void cmdline_error(const char *fmt, ...) exit(1); } -static int local_tty = false; /* do we have a local tty? */ +static bool local_tty = false; /* do we have a local tty? */ static Backend *backend; static Conf *conf; @@ -82,11 +82,11 @@ char *x_get_default(const char *key) { return NULL; /* this is a stub */ } -int term_ldisc(Terminal *term, int mode) +bool term_ldisc(Terminal *term, int mode) { return false; } -static void plink_echoedit_update(Seat *seat, int echo, int edit) +static void plink_echoedit_update(Seat *seat, bool echo, bool edit) { /* Update stdin read mode to reflect changes in line discipline. */ struct termios mode; @@ -160,7 +160,7 @@ static char *plink_get_ttymode(Seat *seat, const char *mode) #define GET_BOOL(ourname, uxname, uxmemb, transform) \ do { \ if (strcmp(mode, ourname) == 0) { \ - int b = (orig_termios.uxmemb & uxname) != 0; \ + bool b = (orig_termios.uxmemb & uxname) != 0; \ transform; \ return dupprintf("%d", b); \ } \ @@ -325,7 +325,7 @@ void cleanup_termios(void) bufchain stdout_data, stderr_data; enum { EOF_NO, EOF_PENDING, EOF_SENT } outgoingeof; -int try_output(int is_stderr) +int try_output(bool is_stderr) { bufchain *chain = (is_stderr ? &stderr_data : &stdout_data); int fd = (is_stderr ? STDERR_FILENO : STDOUT_FILENO); @@ -333,7 +333,7 @@ int try_output(int is_stderr) int sendlen, ret; if (bufchain_size(chain) > 0) { - int prev_nonblock = nonblock(fd); + bool prev_nonblock = nonblock(fd); do { bufchain_prefix(chain, &senddata, &sendlen); ret = write(fd, senddata, sendlen); @@ -354,7 +354,7 @@ int try_output(int is_stderr) return bufchain_size(&stdout_data) + bufchain_size(&stderr_data); } -static int plink_output(Seat *seat, int is_stderr, const void *data, int len) +static int plink_output(Seat *seat, bool is_stderr, const void *data, int len) { if (is_stderr) { bufchain_add(&stderr_data, data, len); @@ -366,7 +366,7 @@ static int plink_output(Seat *seat, int is_stderr, const void *data, int len) } } -static int plink_eof(Seat *seat) +static bool plink_eof(Seat *seat) { assert(outgoingeof == EOF_NO); outgoingeof = EOF_PENDING; @@ -551,21 +551,21 @@ static void version(void) void frontend_net_error_pending(void) {} -const int share_can_be_downstream = true; -const int share_can_be_upstream = true; +const bool share_can_be_downstream = true; +const bool share_can_be_upstream = true; -const int buildinfo_gtk_relevant = false; +const bool buildinfo_gtk_relevant = false; int main(int argc, char **argv) { - int sending; + bool sending; int *fdlist; int fd; int i, fdcount, fdsize, fdstate; int exitcode; - int errors; - int use_subsystem = 0; - int just_test_share_exists = false; + bool errors; + bool use_subsystem = false; + bool just_test_share_exists = false; unsigned long now; struct winsize size; const struct BackendVtable *backvt; @@ -599,7 +599,7 @@ int main(int argc, char **argv) loaded_session = false; default_protocol = conf_get_int(conf, CONF_protocol); default_port = conf_get_int(conf, CONF_port); - errors = 0; + errors = false; { /* * Override the default protocol if PLINK_PROTOCOL is set. @@ -622,16 +622,16 @@ int main(int argc, char **argv) if (ret == -2) { fprintf(stderr, "plink: option \"%s\" requires an argument\n", p); - errors = 1; + errors = true; } else if (ret == 2) { --argc, ++argv; } else if (ret == 1) { continue; } else if (!strcmp(p, "-batch")) { - console_batch_mode = 1; + console_batch_mode = true; } else if (!strcmp(p, "-s")) { /* Save status to write to conf later. */ - use_subsystem = 1; + use_subsystem = true; } else if (!strcmp(p, "-V") || !strcmp(p, "--version")) { version(); } else if (!strcmp(p, "--help")) { @@ -644,7 +644,7 @@ int main(int argc, char **argv) if (argc <= 1) { fprintf(stderr, "plink: option \"-o\" requires an argument\n"); - errors = 1; + errors = true; } else { --argc; provide_xrm_string(*++argv); @@ -684,7 +684,7 @@ int main(int argc, char **argv) break; /* done with cmdline */ } else { fprintf(stderr, "plink: unknown option \"%s\"\n", p); - errors = 1; + errors = true; } } @@ -800,7 +800,7 @@ int main(int argc, char **argv) const char *error; char *realhost; /* nodelay is only useful if stdin is a terminal device */ - int nodelay = conf_get_bool(conf, CONF_tcp_nodelay) && isatty(0); + bool nodelay = conf_get_bool(conf, CONF_tcp_nodelay) && isatty(0); /* This is a good place for a fuzzer to fork us. */ #ifdef __AFL_HAVE_MANUAL_CONTROL diff --git a/unix/uxproxy.c b/unix/uxproxy.c index c8d40d86..c1d0c3f5 100644 --- a/unix/uxproxy.c +++ b/unix/uxproxy.c @@ -15,8 +15,8 @@ #include "proxy.h" Socket *platform_new_connection(SockAddr *addr, const char *hostname, - int port, int privport, - int oobinline, int nodelay, int keepalive, + int port, bool privport, + bool oobinline, bool nodelay, bool keepalive, Plug *plug, Conf *conf) { char *cmd; diff --git a/unix/uxpterm.c b/unix/uxpterm.c index b4d66924..1be68f50 100644 --- a/unix/uxpterm.c +++ b/unix/uxpterm.c @@ -8,10 +8,11 @@ #include "putty.h" const char *const appname = "pterm"; -const int use_event_log = 0; /* pterm doesn't need it */ -const int new_session = 0, saved_sessions = 0; /* or these */ -const int dup_check_launchable = 0; /* no need to check host name in conf */ -const int use_pty_argv = true; +const bool use_event_log = false; /* pterm doesn't need it */ +const bool new_session = false, saved_sessions = false; /* or these */ +const bool dup_check_launchable = false; /* no need to check host name + * in conf */ +const bool use_pty_argv = true; const struct BackendVtable *select_backend(Conf *conf) { @@ -40,7 +41,7 @@ char *make_default_wintitle(char *hostname) return dupstr("pterm"); } -void setup(int single) +void setup(bool single) { extern void pty_pre_init(void); /* declared in pty.c */ diff --git a/unix/uxpty.c b/unix/uxpty.c index e767aeb6..8dd82d42 100644 --- a/unix/uxpty.c +++ b/unix/uxpty.c @@ -87,10 +87,10 @@ struct Pty { char name[FILENAME_MAX]; pid_t child_pid; int term_width, term_height; - int child_dead, finished; + bool child_dead, finished; int exit_code; bufchain output_data; - int pending_eof; + bool pending_eof; Backend backend; }; @@ -178,7 +178,7 @@ static Pty *single_pty = NULL; #ifndef OMIT_UTMP static pid_t pty_utmp_helper_pid = -1; static int pty_utmp_helper_pipe = -1; -static int pty_stamped_utmp; +static bool pty_stamped_utmp; static struct utmpx utmp_entry; #endif @@ -246,7 +246,7 @@ static void setup_utmp(char *ttyname, char *location) } #endif - pty_stamped_utmp = 1; + pty_stamped_utmp = true; } @@ -273,7 +273,7 @@ static void cleanup_utmp(void) pututxline(&utmp_entry); endutxent(); - pty_stamped_utmp = 0; /* ensure we never double-cleanup */ + pty_stamped_utmp = false; /* ensure we never double-cleanup */ } #endif @@ -285,7 +285,7 @@ static void sigchld_handler(int signum) static void pty_setup_sigchld_handler(void) { - static int setup = false; + static bool setup = false; if (!setup) { putty_signal(SIGCHLD, sigchld_handler); setup = true; @@ -597,7 +597,7 @@ static void pty_real_select_result(Pty *pty, int fd, int event, int status) { char buf[4096]; int ret; - int finished = false; + bool finished = false; if (event < 0) { /* @@ -629,7 +629,7 @@ static void pty_real_select_result(Pty *pty, int fd, int event, int status) } } else { if (event == 1) { - int is_stdout = (fd == pty->master_o); + bool is_stdout = (fd == pty->master_o); ret = read(fd, buf, sizeof(buf)); @@ -844,12 +844,12 @@ static void copy_ttymodes_into_termios( */ Backend *pty_backend_create( Seat *seat, LogContext *logctx, Conf *conf, char **argv, const char *cmd, - struct ssh_ttymodes ttymodes, int pipes_instead) + struct ssh_ttymodes ttymodes, bool pipes_instead) { int slavefd; pid_t pid, pgrp; #ifndef NOT_X_WINDOWS /* for Mac OS X native compilation */ - int got_windowid; + bool got_windowid; long windowid; #endif Pty *pty; @@ -987,7 +987,7 @@ Backend *pty_backend_create( char *e = *ep; if (!strncmp(e, pty_osx_envrestore_prefix, plen)) { - int unset = (e[plen] == 'u'); + bool unset = (e[plen] == 'u'); char *pname = dupprintf("%.*s", (int)strcspn(e, "="), e); char *name = pname + plen + 1; char *value = e + strcspn(e, "="); @@ -1129,7 +1129,7 @@ Backend *pty_backend_create( putty_signal(SIGINT, SIG_DFL); putty_signal(SIGQUIT, SIG_DFL); putty_signal(SIGPIPE, SIG_DFL); - block_signal(SIGPIPE, 0); + block_signal(SIGPIPE, false); if (argv || cmd) { /* * If we were given a separated argument list, try to exec @@ -1237,7 +1237,7 @@ Backend *pty_backend_create( static const char *pty_init(Seat *seat, Backend **backend_handle, LogContext *logctx, Conf *conf, const char *host, int port, - char **realhost, int nodelay, int keepalive) + char **realhost, bool nodelay, bool keepalive) { const char *cmd = NULL; struct ssh_ttymodes modes; @@ -1470,16 +1470,16 @@ static const SessionSpecial *pty_get_specials(Backend *be) return NULL; } -static int pty_connected(Backend *be) +static bool pty_connected(Backend *be) { /* Pty *pty = container_of(be, Pty, backend); */ return true; } -static int pty_sendok(Backend *be) +static bool pty_sendok(Backend *be) { /* Pty *pty = container_of(be, Pty, backend); */ - return 1; + return true; } static void pty_unthrottle(Backend *be, int backlog) @@ -1488,10 +1488,10 @@ static void pty_unthrottle(Backend *be, int backlog) /* do nothing */ } -static int pty_ldisc(Backend *be, int option) +static bool pty_ldisc(Backend *be, int option) { /* Pty *pty = container_of(be, Pty, backend); */ - return 0; /* neither editing nor echoing */ + return false; /* neither editing nor echoing */ } static void pty_provide_ldisc(Backend *be, Ldisc *ldisc) diff --git a/unix/uxputty.c b/unix/uxputty.c index a583f878..86ae8278 100644 --- a/unix/uxputty.c +++ b/unix/uxputty.c @@ -20,7 +20,7 @@ /* * Stubs to avoid uxpty.c needing to be linked in. */ -const int use_pty_argv = false; +const bool use_pty_argv = false; char **pty_argv; /* never used */ char *pty_osx_envrestore_prefix; @@ -52,8 +52,8 @@ void initial_config_box(Conf *conf, post_dialog_fn_t after, void *afterctx) sfree(title); } -const int use_event_log = 1, new_session = 1, saved_sessions = 1; -const int dup_check_launchable = 1; +const bool use_event_log = true, new_session = true, saved_sessions = true; +const bool dup_check_launchable = true; char *make_default_wintitle(char *hostname) { @@ -73,10 +73,10 @@ char *platform_get_x_display(void) { return dupstr(display); } -const int share_can_be_downstream = true; -const int share_can_be_upstream = true; +const bool share_can_be_downstream = true; +const bool share_can_be_upstream = true; -void setup(int single) +void setup(bool single) { sk_init(); flags = FLAG_VERBOSE | FLAG_INTERACTIVE; diff --git a/unix/uxser.c b/unix/uxser.c index 5be7cdf8..ec287be7 100644 --- a/unix/uxser.c +++ b/unix/uxser.c @@ -22,7 +22,7 @@ struct Serial { Seat *seat; LogContext *logctx; int fd; - int finished; + bool finished; int inbufsize; bufchain output_data; Backend backend; @@ -282,7 +282,7 @@ static const char *serial_configure(Serial *serial, Conf *conf) static const char *serial_init(Seat *seat, Backend **backend_handle, LogContext *logctx, Conf *conf, const char *host, int port, char **realhost, - int nodelay, int keepalive) + bool nodelay, bool keepalive) { Serial *serial; const char *err; @@ -361,7 +361,7 @@ static void serial_select_result(int fd, int event) Serial *serial; char buf[4096]; int ret; - int finished = false; + bool finished = false; serial = find234(serial_by_fd, &fd, serial_find_by_fd); @@ -509,14 +509,14 @@ static const SessionSpecial *serial_get_specials(Backend *be) return specials; } -static int serial_connected(Backend *be) +static bool serial_connected(Backend *be) { - return 1; /* always connected */ + return true; /* always connected */ } -static int serial_sendok(Backend *be) +static bool serial_sendok(Backend *be) { - return 1; + return true; } static void serial_unthrottle(Backend *be, int backlog) @@ -526,12 +526,12 @@ static void serial_unthrottle(Backend *be, int backlog) serial_uxsel_setup(serial); } -static int serial_ldisc(Backend *be, int option) +static bool serial_ldisc(Backend *be, int option) { /* * Local editing and local echo are off by default. */ - return 0; + return false; } static void serial_provide_ldisc(Backend *be, Ldisc *ldisc) diff --git a/unix/uxserver.c b/unix/uxserver.c index 4c532212..7b9ab0f0 100644 --- a/unix/uxserver.c +++ b/unix/uxserver.c @@ -112,7 +112,7 @@ void timer_change_notify(unsigned long next) char *platform_get_x_display(void) { return NULL; } -static int verbose; +static bool verbose; static void log_to_stderr(const char *msg) { @@ -176,7 +176,7 @@ unsigned auth_methods(AuthPolicy *ap) return (AUTHMETHOD_PUBLICKEY | AUTHMETHOD_PASSWORD | AUTHMETHOD_KBDINT | AUTHMETHOD_TIS | AUTHMETHOD_CRYPTOCARD); } -int auth_none(AuthPolicy *ap, ptrlen username) +bool auth_none(AuthPolicy *ap, ptrlen username) { return false; } @@ -211,7 +211,7 @@ int auth_password(AuthPolicy *ap, ptrlen username, ptrlen password, return 2; } } -int auth_publickey(AuthPolicy *ap, ptrlen username, ptrlen public_blob) +bool auth_publickey(AuthPolicy *ap, ptrlen username, ptrlen public_blob) { struct AuthPolicy_ssh2_pubkey *iter; for (iter = ap->ssh2keys; iter; iter = iter->next) { @@ -285,11 +285,11 @@ char *auth_ssh1int_challenge(AuthPolicy *ap, unsigned method, ptrlen username) return dupprintf("This is a dummy %s challenge!\n", (method == AUTHMETHOD_TIS ? "TIS" : "CryptoCard")); } -int auth_ssh1int_response(AuthPolicy *ap, ptrlen response) +bool auth_ssh1int_response(AuthPolicy *ap, ptrlen response) { return ptrlen_eq_string(response, "otter"); } -int auth_successful(AuthPolicy *ap, ptrlen username, unsigned method) +bool auth_successful(AuthPolicy *ap, ptrlen username, unsigned method) { return true; } @@ -324,17 +324,17 @@ static void show_version_and_exit(void) exit(0); } -const int buildinfo_gtk_relevant = false; +const bool buildinfo_gtk_relevant = false; -static int finished = false; +static bool finished = false; void server_instance_terminated(void) { /* FIXME: change policy here if we're running in a listening loop */ finished = true; } -static int longoptarg(const char *arg, const char *expected, - const char **val, int *argcp, char ***argvp) +static bool longoptarg(const char *arg, const char *expected, + const char **val, int *argcp, char ***argvp) { int len = strlen(expected); if (memcmp(arg, expected, len)) diff --git a/unix/uxsftp.c b/unix/uxsftp.c index 62c9bce6..f91d3094 100644 --- a/unix/uxsftp.c +++ b/unix/uxsftp.c @@ -37,7 +37,7 @@ void platform_get_x11_auth(struct X11Display *display, Conf *conf) { /* Do nothing, therefore no auth. */ } -const int platform_uses_x11_unix_by_default = true; +const bool platform_uses_x11_unix_by_default = true; /* * Default settings that are specific to PSFTP. @@ -346,7 +346,7 @@ void close_directory(DirHandle *dir) sfree(dir); } -int test_wildcard(const char *name, int cmdline) +int test_wildcard(const char *name, bool cmdline) { struct stat statbuf; @@ -403,7 +403,7 @@ void finish_wildcard_matching(WildcardMatcher *dir) { sfree(dir); } -char *stripslashes(const char *str, int local) +char *stripslashes(const char *str, bool local) { char *p; @@ -417,7 +417,7 @@ char *stripslashes(const char *str, int local) return (char *)str; } -int vet_filename(const char *name) +bool vet_filename(const char *name) { if (strchr(name, '/')) return false; @@ -428,7 +428,7 @@ int vet_filename(const char *name) return true; } -int create_directory(const char *name) +bool create_directory(const char *name) { return mkdir(name, 0777) == 0; } @@ -442,14 +442,14 @@ char *dir_file_cat(const char *dir, const char *file) * Do a select() between all currently active network fds and * optionally stdin. */ -static int ssh_sftp_do_select(int include_stdin, int no_fds_ok) +static int ssh_sftp_do_select(bool include_stdin, bool no_fds_ok) { fd_set rset, wset, xset; int i, fdcount, fdsize, *fdlist; int fd, fdstate, rwx, ret, maxfd; unsigned long now = GETTICKCOUNT(); unsigned long next; - int done_something = false; + bool done_something = false; fdlist = NULL; fdcount = fdsize = 0; @@ -566,7 +566,7 @@ int ssh_sftp_loop_iteration(void) /* * Read a PSFTP command line from stdin. */ -char *ssh_sftp_get_cmdline(const char *prompt, int no_fds_ok) +char *ssh_sftp_get_cmdline(const char *prompt, bool no_fds_ok) { char *buf; int buflen, bufsize, ret; @@ -613,7 +613,7 @@ void frontend_net_error_pending(void) {} void platform_psftp_pre_conn_setup(void) {} -const int buildinfo_gtk_relevant = false; +const bool buildinfo_gtk_relevant = false; /* * Main program: do platform-specific initialisation and then call diff --git a/unix/uxsftpserver.c b/unix/uxsftpserver.c index 7cfee950..81214c4c 100644 --- a/unix/uxsftpserver.c +++ b/unix/uxsftpserver.c @@ -27,7 +27,7 @@ typedef struct UnixSftpServer UnixSftpServer; struct UnixSftpServer { unsigned *fdseqs; - int *fdsopen; + bool *fdsopen; int fdsize; tree234 *dirhandles; @@ -101,7 +101,7 @@ static void uss_return_handle_raw( fxp_reply_handle(reply, make_ptrlen(handlebuf, 8)); } -static int uss_decode_handle( +static bool uss_decode_handle( UnixSftpServer *uss, ptrlen handle, int *index, unsigned *seq) { unsigned char handlebuf[8]; @@ -123,7 +123,7 @@ static void uss_return_new_handle( int old_size = uss->fdsize; uss->fdsize = fd * 5 / 4 + 32; uss->fdseqs = sresize(uss->fdseqs, uss->fdsize, unsigned); - uss->fdsopen = sresize(uss->fdsopen, uss->fdsize, int); + uss->fdsopen = sresize(uss->fdsopen, uss->fdsize, bool); while (old_size < uss->fdsize) { uss->fdseqs[old_size] = 0; uss->fdsopen[old_size] = false; @@ -382,7 +382,7 @@ static void uss_reply_struct_stat(SftpReplyBuilder *reply, } static void uss_stat(SftpServer *srv, SftpReplyBuilder *reply, - ptrlen path, int follow_symlinks) + ptrlen path, bool follow_symlinks) { UnixSftpServer *uss = container_of(srv, UnixSftpServer, srv); struct stat st; @@ -450,7 +450,7 @@ static void uss_setstat(SftpServer *srv, SftpReplyBuilder *reply, UnixSftpServer *uss = container_of(srv, UnixSftpServer, srv); char *pathstr = mkstr(path); - int success = true; + bool success = true; SETSTAT_GUTS(PATH_PREFIX, pathstr, attrs, success); free(pathstr); @@ -470,7 +470,7 @@ static void uss_fsetstat(SftpServer *srv, SftpReplyBuilder *reply, if ((fd = uss_lookup_fd(uss, reply, handle)) < 0) return; - int success = true; + bool success = true; SETSTAT_GUTS(FD_PREFIX, fd, attrs, success); if (!success) { @@ -504,7 +504,7 @@ static void uss_read(SftpServer *srv, SftpReplyBuilder *reply, int status = lseek(fd, offset, SEEK_SET); if (status >= 0 || errno == ESPIPE) { - int seekable = (status >= 0); + bool seekable = (status >= 0); while (length > 0) { status = read(fd, p, length); if (status <= 0) @@ -573,7 +573,7 @@ static void uss_write(SftpServer *srv, SftpReplyBuilder *reply, } static void uss_readdir(SftpServer *srv, SftpReplyBuilder *reply, - ptrlen handle, int max_entries, int omit_longname) + ptrlen handle, int max_entries, bool omit_longname) { UnixSftpServer *uss = container_of(srv, UnixSftpServer, srv); struct dirent *de; diff --git a/unix/uxshare.c b/unix/uxshare.c index 2b96f7d8..a7d7fc12 100644 --- a/unix/uxshare.c +++ b/unix/uxshare.c @@ -250,7 +250,7 @@ static char *make_dirname(const char *pi_name, char **logtext) int platform_ssh_share(const char *pi_name, Conf *conf, Plug *downplug, Plug *upplug, Socket **sock, char **logtext, char **ds_err, char **us_err, - int can_upstream, int can_downstream) + bool can_upstream, bool can_downstream) { char *dirname, *lockname, *sockname, *err; int lockfd; @@ -302,7 +302,8 @@ int platform_ssh_share(const char *pi_name, Conf *conf, if (can_downstream) { retsock = new_connection(unix_sock_addr(sockname), - "", 0, 0, 1, 0, 0, downplug, conf); + "", 0, false, true, false, false, + downplug, conf); if (sk_socket_error(retsock) == NULL) { sfree(*logtext); *logtext = sockname; diff --git a/unix/uxsignal.c b/unix/uxsignal.c index e21e0e80..8edbfacd 100644 --- a/unix/uxsignal.c +++ b/unix/uxsignal.c @@ -2,6 +2,8 @@ #include #include +#include "defs.h" + /* * Calling signal() is non-portable, as it varies in meaning * between platforms and depending on feature macros, and has @@ -25,7 +27,7 @@ void (*putty_signal(int sig, void (*func)(int)))(int) { return old.sa_handler; } -void block_signal(int sig, int block_it) +void block_signal(int sig, bool block_it) { sigset_t ss; diff --git a/unix/uxstore.c b/unix/uxstore.c index de1680f4..0d0c582e 100644 --- a/unix/uxstore.c +++ b/unix/uxstore.c @@ -678,8 +678,8 @@ int verify_host_key(const char *hostname, int port, return ret; } -int have_ssh_host_key(const char *hostname, int port, - const char *keytype) +bool have_ssh_host_key(const char *hostname, int port, + const char *keytype) { /* * If we have a host key, verify_host_key will return 0 or 2. diff --git a/unix/uxucs.c b/unix/uxucs.c index 92961eaa..3a34a969 100644 --- a/unix/uxucs.c +++ b/unix/uxucs.c @@ -16,9 +16,9 @@ * Unix Unicode-handling routines. */ -int is_dbcs_leadbyte(int codepage, char byte) +bool is_dbcs_leadbyte(int codepage, char byte) { - return 0; /* we don't do DBCS */ + return false; /* we don't do DBCS */ } int mb_to_wc(int codepage, int flags, const char *mbstr, int mblen, @@ -98,10 +98,11 @@ int wc_to_mb(int codepage, int flags, const wchar_t *wcstr, int wclen, /* * Return value is true if pterm is to run in direct-to-font mode. */ -int init_ucs(struct unicode_data *ucsdata, char *linecharset, - int utf8_override, int font_charset, int vtmode) +bool init_ucs(struct unicode_data *ucsdata, char *linecharset, + bool utf8_override, int font_charset, int vtmode) { - int i, ret = 0; + int i; + bool ret = false; /* * In the platform-independent parts of the code, font_codepage @@ -145,7 +146,7 @@ int init_ucs(struct unicode_data *ucsdata, char *linecharset, ucsdata->line_codepage = font_charset; if (ucsdata->line_codepage == CS_NONE) - ret = 1; + ret = true; /* * Set up unitab_line, by translating each individual character diff --git a/wcwidth.c b/wcwidth.c index 25372a79..a6596aae 100644 --- a/wcwidth.c +++ b/wcwidth.c @@ -69,12 +69,12 @@ struct interval { }; /* auxiliary function for binary search in interval table */ -static int bisearch(unsigned int ucs, const struct interval *table, int max) { +static bool bisearch(unsigned int ucs, const struct interval *table, int max) { int min = 0; int mid; if (ucs < table[0].first || ucs > table[max].last) - return 0; + return false; while (max >= min) { mid = (min + max) / 2; if (ucs > table[mid].last) @@ -82,10 +82,10 @@ static int bisearch(unsigned int ucs, const struct interval *table, int max) { else if (ucs < table[mid].first) max = mid - 1; else - return 1; + return true; } - return 0; + return false; } diff --git a/wildcard.c b/wildcard.c index f480a19a..9c560d0d 100644 --- a/wildcard.c +++ b/wildcard.c @@ -131,14 +131,14 @@ static int wc_match_fragment(const char **fragment, const char **target, */ f++; } else if (*f == '[') { - int invert = 0; - int matched = 0; + bool invert = false; + bool matched = false; /* * Open bracket introduces a character class. */ f++; if (*f == '^') { - invert = 1; + invert = true; f++; } while (*f != ']') { @@ -162,7 +162,7 @@ static int wc_match_fragment(const char **fragment, const char **target, int t = lower; lower = upper; upper = t; } if (ourchr >= lower && ourchr <= upper) - matched = 1; + matched = true; } else { matched |= (*t == *f++); } @@ -315,11 +315,11 @@ int wc_match_pl(const char *wildcard, ptrlen target) * the original wildcard. You can also pass NULL as the output * buffer if you're only interested in the return value. * - * Returns 1 on success, or 0 if a wildcard character was + * Returns true on success, or false if a wildcard character was * encountered. In the latter case the output string MAY not be * zero-terminated and you should not use it for anything! */ -int wc_unescape(char *output, const char *wildcard) +bool wc_unescape(char *output, const char *wildcard) { while (*wildcard) { if (*wildcard == '\\') { @@ -332,7 +332,7 @@ int wc_unescape(char *output, const char *wildcard) } } else if (*wildcard == '*' || *wildcard == '?' || *wildcard == '[' || *wildcard == ']') { - return 0; /* it's a wildcard! */ + return false; /* it's a wildcard! */ } else { if (output) *output++ = *wildcard; @@ -341,7 +341,7 @@ int wc_unescape(char *output, const char *wildcard) } if (output) *output = '\0'; - return 1; /* it's clean */ + return true; /* it's clean */ } #ifdef TESTMODE diff --git a/windows/sizetip.c b/windows/sizetip.c index a0fd415f..e91c5b90 100644 --- a/windows/sizetip.c +++ b/windows/sizetip.c @@ -91,7 +91,7 @@ static LRESULT CALLBACK SizeTipWndProc(HWND hWnd, UINT nMsg, } static HWND tip_wnd = NULL; -static int tip_enabled = 0; +static bool tip_enabled = false; void UpdateSizeTip(HWND src, int cx, int cy) { @@ -183,7 +183,7 @@ void UpdateSizeTip(HWND src, int cx, int cy) } } -void EnableSizeTip(int bEnable) +void EnableSizeTip(bool bEnable) { if (tip_wnd && !bEnable) { DestroyWindow(tip_wnd); diff --git a/windows/wincapi.c b/windows/wincapi.c index fbaf58e2..5ff7cdfa 100644 --- a/windows/wincapi.c +++ b/windows/wincapi.c @@ -9,10 +9,10 @@ #define WINCAPI_GLOBAL #include "wincapi.h" -int got_crypt(void) +bool got_crypt(void) { - static int attempted = false; - static int successful; + static bool attempted = false; + static bool successful; static HMODULE crypt; if (!attempted) { diff --git a/windows/wincapi.h b/windows/wincapi.h index 06ee2d36..f327be27 100644 --- a/windows/wincapi.h +++ b/windows/wincapi.h @@ -13,6 +13,6 @@ DECL_WINDOWS_FUNCTION(WINCAPI_GLOBAL, BOOL, CryptProtectMemory, (LPVOID,DWORD,DWORD)); -int got_crypt(void); +bool got_crypt(void); #endif diff --git a/windows/wincfg.c b/windows/wincfg.c index ec9b7e3d..493e0006 100644 --- a/windows/wincfg.c +++ b/windows/wincfg.c @@ -40,8 +40,8 @@ static void variable_pitch_handler(union control *ctrl, dlgparam *dlg, } } -void win_setup_config_box(struct controlbox *b, HWND *hwndp, int has_help, - int midsession, int protocol) +void win_setup_config_box(struct controlbox *b, HWND *hwndp, bool has_help, + bool midsession, int protocol) { struct controlset *s; union control *c; diff --git a/windows/wincons.c b/windows/wincons.c index b01b1637..48dd3c2e 100644 --- a/windows/wincons.c +++ b/windows/wincons.c @@ -11,7 +11,7 @@ #include "storage.h" #include "ssh.h" -int console_batch_mode = false; +bool console_batch_mode = false; /* * Clean up and exit. @@ -481,14 +481,11 @@ int console_get_userpass_input(prompts_t *p) len = 0; while (1) { DWORD ret = 0; - BOOL r; prompt_ensure_result_size(pr, len * 5 / 4 + 512); - r = ReadFile(hin, pr->result + len, pr->resultsize - len - 1, - &ret, NULL); - - if (!r || ret == 0) { + if (!ReadFile(hin, pr->result + len, pr->resultsize - len - 1, + &ret, NULL) || ret == 0) { len = -1; break; } diff --git a/windows/winctrls.c b/windows/winctrls.c index 2a3a093f..99119cc9 100644 --- a/windows/winctrls.c +++ b/windows/winctrls.c @@ -165,7 +165,7 @@ void endbox(struct ctlpos *cp) /* * A static line, followed by a full-width edit box. */ -void editboxfw(struct ctlpos *cp, int password, char *text, +void editboxfw(struct ctlpos *cp, bool password, char *text, int staticid, int editid) { RECT r; @@ -534,7 +534,7 @@ void staticbtn(struct ctlpos *cp, char *stext, int sid, /* * A simple push button. */ -void button(struct ctlpos *cp, char *btext, int bid, int defbtn) +void button(struct ctlpos *cp, char *btext, int bid, bool defbtn) { RECT r; @@ -769,7 +769,7 @@ void bigeditctrl(struct ctlpos *cp, char *stext, * A list box with a static labelling it. */ void listbox(struct ctlpos *cp, char *stext, - int sid, int lid, int lines, int multi) + int sid, int lid, int lines, bool multi) { RECT r; @@ -994,7 +994,7 @@ static void pl_moveitem(HWND hwnd, int listid, int src, int dst) sfree (txt); } -int pl_itemfrompt(HWND hwnd, POINT cursor, BOOL scroll) +int pl_itemfrompt(HWND hwnd, POINT cursor, bool scroll) { int ret; POINT uppoint, downpoint; @@ -1041,7 +1041,7 @@ int pl_itemfrompt(HWND hwnd, POINT cursor, BOOL scroll) */ int handle_prefslist(struct prefslist *hdl, int *array, int maxmemb, - int is_dlmsg, HWND hwnd, + bool is_dlmsg, HWND hwnd, WPARAM wParam, LPARAM lParam) { int i; @@ -1063,7 +1063,7 @@ int handle_prefslist(struct prefslist *hdl, LB_ADDSTRING, 0, (LPARAM) ""); hdl->srcitem = p_LBItemFromPt(dlm->hWnd, dlm->ptCursor, true); - hdl->dragging = 0; + hdl->dragging = false; /* XXX hack Q183115 */ SetWindowLongPtr(hwnd, DWLP_MSGRESULT, true); ret |= 1; break; @@ -1071,10 +1071,10 @@ int handle_prefslist(struct prefslist *hdl, p_DrawInsert(hwnd, dlm->hWnd, -1); /* Clear arrow */ SendDlgItemMessage(hwnd, hdl->listid, LB_DELETESTRING, hdl->dummyitem, 0); - hdl->dragging = 0; + hdl->dragging = false; ret |= 1; break; case DL_DRAGGING: - hdl->dragging = 1; + hdl->dragging = true; dest = pl_itemfrompt(dlm->hWnd, dlm->ptCursor, true); if (dest > hdl->dummyitem) dest = hdl->dummyitem; p_DrawInsert (hwnd, dlm->hWnd, dest); @@ -1092,7 +1092,7 @@ int handle_prefslist(struct prefslist *hdl, SendDlgItemMessage(hwnd, hdl->listid, LB_DELETESTRING, hdl->dummyitem, 0); if (hdl->dragging) { - hdl->dragging = 0; + hdl->dragging = false; if (dest >= 0) { /* Correct for "missing" item. */ if (dest > hdl->srcitem) dest--; @@ -1654,7 +1654,7 @@ void winctrl_layout(struct dlgparam *dp, struct winctrls *wc, shortcuts[nshortcuts++] = ctrl->fontselect.shortcut; statictext(&pos, escaped, 1, base_id); staticbtn(&pos, "", base_id+1, "Change...", base_id+2); - data = fontspec_new("", 0, 0, 0); + data = fontspec_new("", false, 0, 0); sfree(escaped); break; default: @@ -1710,7 +1710,7 @@ void winctrl_layout(struct dlgparam *dp, struct winctrls *wc, } static void winctrl_set_focus(union control *ctrl, struct dlgparam *dp, - int has_focus) + bool has_focus) { if (has_focus) { if (dp->focused) @@ -1731,12 +1731,13 @@ union control *dlg_last_focused(union control *ctrl, dlgparam *dp) * The dialog-box procedure calls this function to handle Windows * messages on a control we manage. */ -int winctrl_handle_command(struct dlgparam *dp, UINT msg, - WPARAM wParam, LPARAM lParam) +bool winctrl_handle_command(struct dlgparam *dp, UINT msg, + WPARAM wParam, LPARAM lParam) { struct winctrl *c; union control *ctrl; - int i, id, ret; + int i, id; + bool ret; static UINT draglistmsg = WM_NULL; /* @@ -1747,7 +1748,7 @@ int winctrl_handle_command(struct dlgparam *dp, UINT msg, draglistmsg = RegisterWindowMessage (DRAGLISTMSGSTRING); if (msg != draglistmsg && msg != WM_COMMAND && msg != WM_DRAWITEM) - return 0; + return false; /* * Look up the control ID in our data. @@ -1759,7 +1760,7 @@ int winctrl_handle_command(struct dlgparam *dp, UINT msg, break; } if (!c) - return 0; /* we have nothing to do */ + return false; /* we have nothing to do */ if (msg == WM_DRAWITEM) { /* @@ -1787,7 +1788,7 @@ int winctrl_handle_command(struct dlgparam *dp, UINT msg, id = LOWORD(wParam) - c->base_id; if (!ctrl || !ctrl->generic.handler) - return 0; /* nothing we can do here */ + return false; /* nothing we can do here */ /* * From here on we do not issue `return' statements until the @@ -1796,7 +1797,7 @@ int winctrl_handle_command(struct dlgparam *dp, UINT msg, * to reach the end of this switch statement so that the * subsequent code can test dp->coloursel_wanted(). */ - ret = 0; + ret = false; dp->coloursel_wanted = false; /* @@ -2021,7 +2022,7 @@ int winctrl_handle_command(struct dlgparam *dp, UINT msg, * This function can be called to produce context help on a * control. Returns true if it has actually launched some help. */ -int winctrl_context_help(struct dlgparam *dp, HWND hwnd, int id) +bool winctrl_context_help(struct dlgparam *dp, HWND hwnd, int id) { int i; struct winctrl *c; @@ -2036,17 +2037,17 @@ int winctrl_context_help(struct dlgparam *dp, HWND hwnd, int id) break; } if (!c) - return 0; /* we have nothing to do */ + return false; /* we have nothing to do */ /* * This is the Windows front end, so we're allowed to assume * `helpctx.p' is a context string. */ if (!c->ctrl || !c->ctrl->generic.helpctx.p) - return 0; /* no help available for this ctrl */ + return false; /* no help available for this ctrl */ launch_help(hwnd, c->ctrl->generic.helpctx.p); - return 1; + return true; } /* @@ -2088,14 +2089,14 @@ int dlg_radiobutton_get(union control *ctrl, dlgparam *dp) return 0; } -void dlg_checkbox_set(union control *ctrl, dlgparam *dp, int checked) +void dlg_checkbox_set(union control *ctrl, dlgparam *dp, bool checked) { struct winctrl *c = dlg_findbyctrl(dp, ctrl); assert(c && c->ctrl->generic.type == CTRL_CHECKBOX); - CheckDlgButton(dp->hwnd, c->base_id, (checked != 0)); + CheckDlgButton(dp->hwnd, c->base_id, checked); } -int dlg_checkbox_get(union control *ctrl, dlgparam *dp) +bool dlg_checkbox_get(union control *ctrl, dlgparam *dp) { struct winctrl *c = dlg_findbyctrl(dp, ctrl); assert(c && c->ctrl->generic.type == CTRL_CHECKBOX); @@ -2210,7 +2211,7 @@ int dlg_listbox_index(union control *ctrl, dlgparam *dp) return ret; } -int dlg_listbox_issel(union control *ctrl, dlgparam *dp, int index) +bool dlg_listbox_issel(union control *ctrl, dlgparam *dp, int index) { struct winctrl *c = dlg_findbyctrl(dp, ctrl); assert(c && c->ctrl->generic.type == CTRL_LISTBOX && @@ -2447,16 +2448,16 @@ void dlg_coloursel_start(union control *ctrl, dlgparam *dp, int r, int g, int b) dp->coloursel_result.b = b; } -int dlg_coloursel_results(union control *ctrl, dlgparam *dp, - int *r, int *g, int *b) +bool dlg_coloursel_results(union control *ctrl, dlgparam *dp, + int *r, int *g, int *b) { if (dp->coloursel_result.ok) { *r = dp->coloursel_result.r; *g = dp->coloursel_result.g; *b = dp->coloursel_result.b; - return 1; + return true; } else - return 0; + return false; } void dlg_auto_set_fixed_pitch_flag(dlgparam *dp) @@ -2467,7 +2468,7 @@ void dlg_auto_set_fixed_pitch_flag(dlgparam *dp) HFONT hfont; HDC hdc; TEXTMETRIC tm; - int is_var; + bool is_var; /* * Attempt to load the current font, and see if it's @@ -2502,12 +2503,12 @@ void dlg_auto_set_fixed_pitch_flag(dlgparam *dp) dp->fixed_pitch_fonts = false; } -int dlg_get_fixed_pitch_flag(dlgparam *dp) +bool dlg_get_fixed_pitch_flag(dlgparam *dp) { return dp->fixed_pitch_fonts; } -void dlg_set_fixed_pitch_flag(dlgparam *dp, int flag) +void dlg_set_fixed_pitch_flag(dlgparam *dp, bool flag) { dp->fixed_pitch_fonts = flag; } diff --git a/windows/windefs.c b/windows/windefs.c index b210cde0..308c29eb 100644 --- a/windows/windefs.c +++ b/windows/windefs.c @@ -9,9 +9,9 @@ FontSpec *platform_default_fontspec(const char *name) { if (!strcmp(name, "Font")) - return fontspec_new("Courier New", 0, 10, ANSI_CHARSET); + return fontspec_new("Courier New", false, 10, ANSI_CHARSET); else - return fontspec_new("", 0, 0, 0); + return fontspec_new("", false, 0, 0); } Filename *platform_default_filename(const char *name) diff --git a/windows/windlg.c b/windows/windlg.c index d20cd805..4019b9a3 100644 --- a/windows/windlg.c +++ b/windows/windlg.c @@ -55,20 +55,20 @@ extern Conf *conf; /* defined in window.c */ void force_normal(HWND hwnd) { - static int recurse = 0; + static bool recurse = false; WINDOWPLACEMENT wp; if (recurse) return; - recurse = 1; + recurse = true; wp.length = sizeof(wp); if (GetWindowPlacement(hwnd, &wp) && wp.showCmd == SW_SHOWMAXIMIZED) { wp.showCmd = SW_SHOWNORMAL; SetWindowPlacement(hwnd, &wp); } - recurse = 0; + recurse = false; } static char *getevent(int i) @@ -693,9 +693,9 @@ void defuse_showwindow(void) } } -int do_config(void) +bool do_config(void) { - int ret; + bool ret; ctrlbox = ctrl_new_box(); setup_config_box(ctrlbox, false, 0, 0); @@ -723,10 +723,11 @@ int do_config(void) return ret; } -int do_reconfig(HWND hwnd, int protcfginfo) +bool do_reconfig(HWND hwnd, int protcfginfo) { Conf *backup_conf; - int ret, protocol; + bool ret; + int protocol; backup_conf = conf_copy(conf); diff --git a/windows/window.c b/windows/window.c index e4bcbf43..31b1cbe5 100644 --- a/windows/window.c +++ b/windows/window.c @@ -102,24 +102,25 @@ static void set_input_locale(HKL); static void update_savedsess_menu(void); static void init_winfuncs(void); -static int is_full_screen(void); +static bool is_full_screen(void); static void make_full_screen(void); static void clear_full_screen(void); static void flip_full_screen(void); -static void process_clipdata(HGLOBAL clipdata, int unicode); +static void process_clipdata(HGLOBAL clipdata, bool unicode); static void setup_clipboards(Terminal *, Conf *); /* Window layout information */ static void reset_window(int); static int extra_width, extra_height; -static int font_width, font_height, font_dualwidth, font_varpitch; +static int font_width, font_height; +static bool font_dualwidth, font_varpitch; static int offset_width, offset_height; -static int was_zoomed = 0; +static bool was_zoomed = false; static int prev_rows, prev_cols; static void flash_window(int mode); static void sys_cursor_update(void); -static int get_fullscreen_rect(RECT * ss); +static bool get_fullscreen_rect(RECT * ss); static int caret_x = -1, caret_y = -1; @@ -129,8 +130,8 @@ static Ldisc *ldisc; static Backend *backend; static struct unicode_data ucsdata; -static int session_closed; -static int reconfiguring = false; +static bool session_closed; +static bool reconfiguring = false; static const SessionSpecial *specials = NULL; static HMENU specials_menu = NULL; @@ -183,11 +184,11 @@ struct agent_callback { #define FONT_SHIFT 5 static HFONT fonts[FONT_MAXNO]; static LOGFONT lfont; -static int fontflag[FONT_MAXNO]; +static bool fontflag[FONT_MAXNO]; static enum { BOLD_NONE, BOLD_SHADOW, BOLD_FONT } bold_font_mode; -static int bold_colours; +static bool bold_colours; static enum { UND_LINE, UND_FONT } und_mode; @@ -210,7 +211,7 @@ static int dbltime, lasttime, lastact; static Mouse_Button lastbtn; /* this allows xterm-style mouse handling. */ -static int send_raw_mouse = 0; +static bool send_raw_mouse = false; static int wheel_accumulator = 0; static BusyStatus busy_status = BUSY_NOT; @@ -227,7 +228,7 @@ static UINT wm_mousewheel = WM_MOUSEWHEEL; (((wch) >= 0x180B && (wch) <= 0x180D) || /* MONGOLIAN FREE VARIATION SELECTOR */ \ ((wch) >= 0xFE00 && (wch) <= 0xFE0F)) /* VARIATION SELECTOR 1-16 */ -static int wintw_setup_draw_ctx(TermWin *); +static bool wintw_setup_draw_ctx(TermWin *); static void wintw_draw_text(TermWin *, int x, int y, wchar_t *text, int len, unsigned long attrs, int lattrs, truecolour tc); static void wintw_draw_cursor(TermWin *, int x, int y, wchar_t *text, int len, @@ -235,29 +236,29 @@ static void wintw_draw_cursor(TermWin *, int x, int y, wchar_t *text, int len, static int wintw_char_width(TermWin *, int uc); static void wintw_free_draw_ctx(TermWin *); static void wintw_set_cursor_pos(TermWin *, int x, int y); -static void wintw_set_raw_mouse_mode(TermWin *, int enable); +static void wintw_set_raw_mouse_mode(TermWin *, bool enable); static void wintw_set_scrollbar(TermWin *, int total, int start, int page); static void wintw_bell(TermWin *, int mode); static void wintw_clip_write( TermWin *, int clipboard, wchar_t *text, int *attrs, - truecolour *colours, int len, int must_deselect); + truecolour *colours, int len, bool must_deselect); static void wintw_clip_request_paste(TermWin *, int clipboard); static void wintw_refresh(TermWin *); static void wintw_request_resize(TermWin *, int w, int h); static void wintw_set_title(TermWin *, const char *title); static void wintw_set_icon_title(TermWin *, const char *icontitle); -static void wintw_set_minimised(TermWin *, int minimised); -static int wintw_is_minimised(TermWin *); -static void wintw_set_maximised(TermWin *, int maximised); +static void wintw_set_minimised(TermWin *, bool minimised); +static bool wintw_is_minimised(TermWin *); +static void wintw_set_maximised(TermWin *, bool maximised); static void wintw_move(TermWin *, int x, int y); -static void wintw_set_zorder(TermWin *, int top); -static int wintw_palette_get(TermWin *, int n, int *r, int *g, int *b); +static void wintw_set_zorder(TermWin *, bool top); +static bool wintw_palette_get(TermWin *, int n, int *r, int *g, int *b); static void wintw_palette_set(TermWin *, int n, int r, int g, int b); static void wintw_palette_reset(TermWin *); static void wintw_get_pos(TermWin *, int *x, int *y); static void wintw_get_pixels(TermWin *, int *x, int *y); -static const char *wintw_get_title(TermWin *, int icon); -static int wintw_is_utf8(TermWin *); +static const char *wintw_get_title(TermWin *, bool icon); +static bool wintw_is_utf8(TermWin *); static const TermWinVtable windows_termwin_vt = { wintw_setup_draw_ctx, @@ -292,20 +293,20 @@ static const TermWinVtable windows_termwin_vt = { static TermWin wintw[1]; static HDC wintw_hdc; -const int share_can_be_downstream = true; -const int share_can_be_upstream = true; +const bool share_can_be_downstream = true; +const bool share_can_be_upstream = true; -static int is_utf8(void) +static bool is_utf8(void) { return ucsdata.line_codepage == CP_UTF8; } -static int wintw_is_utf8(TermWin *tw) +static bool wintw_is_utf8(TermWin *tw) { return is_utf8(); } -static int win_seat_is_utf8(Seat *seat) +static bool win_seat_is_utf8(Seat *seat) { return is_utf8(); } @@ -315,14 +316,14 @@ char *win_seat_get_ttymode(Seat *seat, const char *mode) return term_get_ttymode(term, mode); } -int win_seat_get_window_pixel_size(Seat *seat, int *x, int *y) +bool win_seat_get_window_pixel_size(Seat *seat, int *x, int *y) { win_get_pixels(wintw, x, y); return true; } -static int win_seat_output(Seat *seat, int is_stderr, const void *, int); -static int win_seat_eof(Seat *seat); +static int win_seat_output(Seat *seat, bool is_stderr, const void *, int); +static bool win_seat_eof(Seat *seat); static int win_seat_get_userpass_input( Seat *seat, prompts_t *p, bufchain *input); static void win_seat_notify_remote_exit(Seat *seat); @@ -511,7 +512,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) */ { char *p; - int special_launchable_argument = false; + bool special_launchable_argument = false; default_protocol = be_default_protocol; /* Find the appropriate default port. */ @@ -1006,7 +1007,7 @@ void cleanup_exit(int code) /* * Set up, or shut down, an AsyncSelect. Called from winnet.c. */ -char *do_select(SOCKET skt, int startup) +char *do_select(SOCKET skt, bool startup) { int msg, events; if (startup) { @@ -1122,8 +1123,8 @@ static void win_seat_update_specials_menu(Seat *seat) static void update_mouse_pointer(void) { LPTSTR curstype = NULL; - int force_visible = false; - static int forced_visible = false; + bool force_visible = false; + static bool forced_visible = false; switch (busy_status) { case BUSY_NOT: if (send_raw_mouse) @@ -1166,7 +1167,7 @@ static void win_seat_set_busy_status(Seat *seat, BusyStatus status) /* * set or clear the "raw mouse message" mode */ -static void wintw_set_raw_mouse_mode(TermWin *tw, int activate) +static void wintw_set_raw_mouse_mode(TermWin *tw, bool activate) { activate = activate && !conf_get_bool(conf, CONF_no_mouse_rep); send_raw_mouse = activate; @@ -1343,7 +1344,7 @@ static void init_palette(void) */ static void exact_textout(HDC hdc, int x, int y, CONST RECT *lprc, unsigned short *lpString, UINT cbCount, - CONST INT *lpDx, int opaque) + CONST INT *lpDx, bool opaque) { #ifdef __LCC__ /* @@ -1385,15 +1386,16 @@ static void exact_textout(HDC hdc, int x, int y, CONST RECT *lprc, */ static void general_textout(HDC hdc, int x, int y, CONST RECT *lprc, unsigned short *lpString, UINT cbCount, - CONST INT *lpDx, int opaque) + CONST INT *lpDx, bool opaque) { int i, j, xp, xn; - int bkmode = 0, got_bkmode = false; + int bkmode = 0; + bool got_bkmode = false; xp = xn = x; for (i = 0; i < (int)cbCount ;) { - int rtl = is_rtl(lpString[i]); + bool rtl = is_rtl(lpString[i]); xn += lpDx[i]; @@ -1592,7 +1594,8 @@ static void init_fonts(int pick_width, int pick_height) { HDC und_dc; HBITMAP und_bm, und_oldbm; - int i, gotit; + int i; + bool gotit; COLORREF c; und_dc = CreateCompatibleDC(hdc); @@ -1653,7 +1656,9 @@ static void init_fonts(int pick_width, int pick_height) DeleteObject(fonts[FONT_BOLD]); fonts[FONT_BOLD] = 0; } - fontflag[0] = fontflag[1] = fontflag[2] = 1; + fontflag[0] = true; + fontflag[1] = true; + fontflag[2] = true; init_ucs(conf, &ucsdata); } @@ -1662,7 +1667,8 @@ static void another_font(int fontno) { int basefont; int fw_dontcare, fw_bold, quality; - int c, u, w, x; + int c, w, x; + bool u; char *s; FontSpec *font; @@ -1708,7 +1714,7 @@ static void another_font(int fontno) CLIP_DEFAULT_PRECIS, FONT_QUALITY(quality), DEFAULT_PITCH | FF_DONTCARE, s); - fontflag[fontno] = 1; + fontflag[fontno] = true; } static void deinit_fonts(void) @@ -1718,7 +1724,7 @@ static void deinit_fonts(void) if (fonts[i]) DeleteObject(fonts[i]); fonts[i] = 0; - fontflag[i] = 0; + fontflag[i] = false; } } @@ -1998,7 +2004,8 @@ static void set_input_locale(HKL kl) kbd_codepage = atoi(lbuf); } -static void click(Mouse_Button b, int x, int y, int shift, int ctrl, int alt) +static void click(Mouse_Button b, int x, int y, + bool shift, bool ctrl, bool alt) { int thistime = GetMessageTime(); @@ -2041,13 +2048,13 @@ static Mouse_Button translate_button(Mouse_Button button) return 0; /* shouldn't happen */ } -static void show_mouseptr(int show) +static void show_mouseptr(bool show) { /* NB that the counter in ShowCursor() is also frobbed by * update_mouse_pointer() */ - static int cursor_visible = 1; + static bool cursor_visible = true; if (!conf_get_bool(conf, CONF_hide_mouseptr)) - show = 1; /* override if this feature disabled */ + show = true; /* override if this feature disabled */ if (cursor_visible && !show) ShowCursor(false); else if (!cursor_visible && show) @@ -2055,7 +2062,7 @@ static void show_mouseptr(int show) cursor_visible = show; } -static int is_alt_pressed(void) +static bool is_alt_pressed(void) { BYTE keystate[256]; int r = GetKeyboardState(keystate); @@ -2068,7 +2075,7 @@ static int is_alt_pressed(void) return false; } -static int resizing; +static bool resizing; static void win_seat_notify_remote_exit(Seat *seat) { @@ -2143,10 +2150,10 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { HDC hdc; - static int ignore_clip = false; - static int need_backend_resize = false; - static int fullscr_on_max = false; - static int processed_resize = false; + static bool ignore_clip = false; + static bool need_backend_resize = false; + static bool fullscr_on_max = false; + static bool processed_resize = false; static UINT last_mousemove = 0; int resize_action; @@ -2167,7 +2174,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, case WM_CLOSE: { char *str; - show_mouseptr(1); + show_mouseptr(true); str = dupprintf("%s Exit Confirmation", appname); if (session_closed || !conf_get_bool(conf, CONF_warn_on_close) || MessageBox(hwnd, @@ -2179,7 +2186,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, } return 0; case WM_DESTROY: - show_mouseptr(1); + show_mouseptr(true); PostQuitMessage(0); return 0; case WM_INITMENUPOPUP: @@ -2205,7 +2212,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, char b[2048]; char *cl; const char *argprefix; - BOOL inherit_handles; + bool inherit_handles; STARTUPINFO si; PROCESS_INFORMATION pi; HANDLE filemap = NULL; @@ -2295,7 +2302,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, { Conf *prev_conf; int init_lvl = 1; - int reconfig_result; + bool reconfig_result; if (reconfiguring) break; @@ -2506,7 +2513,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, * We get this if the System menu has been activated * using the mouse. */ - show_mouseptr(1); + show_mouseptr(true); break; case SC_KEYMENU: /* @@ -2517,7 +2524,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, * the menu up_ rather than just sitting there in * `ready to appear' state. */ - show_mouseptr(1); /* make sure pointer is visible */ + show_mouseptr(true); /* make sure pointer is visible */ if( lParam == 0 ) PostMessage(hwnd, WM_CHAR, ' ', 0); break; @@ -2560,7 +2567,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, (conf_get_int(conf, CONF_mouse_is_xterm) == 2))) { POINT cursorpos; - show_mouseptr(1); /* make sure pointer is visible */ + show_mouseptr(true); /* make sure pointer is visible */ GetCursorPos(&cursorpos); TrackPopupMenu(popup_menus[CTXMENU].menu, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RIGHTBUTTON, @@ -2569,43 +2576,45 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, break; } { - int button, press; + int button; + bool press; switch (message) { case WM_LBUTTONDOWN: button = MBT_LEFT; wParam |= MK_LBUTTON; - press = 1; + press = true; break; case WM_MBUTTONDOWN: button = MBT_MIDDLE; wParam |= MK_MBUTTON; - press = 1; + press = true; break; case WM_RBUTTONDOWN: button = MBT_RIGHT; wParam |= MK_RBUTTON; - press = 1; + press = true; break; case WM_LBUTTONUP: button = MBT_LEFT; wParam &= ~MK_LBUTTON; - press = 0; + press = false; break; case WM_MBUTTONUP: button = MBT_MIDDLE; wParam &= ~MK_MBUTTON; - press = 0; + press = false; break; case WM_RBUTTONUP: button = MBT_RIGHT; wParam &= ~MK_RBUTTON; - press = 0; + press = false; break; - default: - button = press = 0; /* shouldn't happen */ + default: /* shouldn't happen */ + button = 0; + press = false; } - show_mouseptr(1); + show_mouseptr(true); /* * Special case: in full-screen mode, if the left * button is clicked in the very top left corner of the @@ -2613,7 +2622,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, * selection. */ { - char mouse_on_hotspot = 0; + bool mouse_on_hotspot = false; POINT pt; GetCursorPos(&pt); @@ -2630,13 +2639,13 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, if (mi.rcMonitor.left == pt.x && mi.rcMonitor.top == pt.y) { - mouse_on_hotspot = 1; + mouse_on_hotspot = true; } } } #else if (pt.x == 0 && pt.y == 0) { - mouse_on_hotspot = 1; + mouse_on_hotspot = true; } #endif if (is_full_screen() && press && @@ -2674,7 +2683,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, static LPARAM lp = 0; if (wParam != wp || lParam != lp || last_mousemove != WM_MOUSEMOVE) { - show_mouseptr(1); + show_mouseptr(true); wp = wParam; lp = lParam; last_mousemove = WM_MOUSEMOVE; } @@ -2706,7 +2715,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, static LPARAM lp = 0; if (wParam != wp || lParam != lp || last_mousemove != WM_NCMOUSEMOVE) { - show_mouseptr(1); + show_mouseptr(true); wp = wParam; lp = lParam; last_mousemove = WM_NCMOUSEMOVE; } @@ -2846,7 +2855,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, term_update(term); break; case WM_KILLFOCUS: - show_mouseptr(1); + show_mouseptr(true); term_set_focus(term, false); DestroyCaret(); caret_x = caret_y = -1; /* ensure caret is replaced next time */ @@ -2856,12 +2865,12 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, #ifdef RDB_DEBUG_PATCH debug((27, "WM_ENTERSIZEMOVE")); #endif - EnableSizeTip(1); + EnableSizeTip(true); resizing = true; need_backend_resize = false; break; case WM_EXITSIZEMOVE: - EnableSizeTip(0); + EnableSizeTip(false); resizing = false; #ifdef RDB_DEBUG_PATCH debug((27, "WM_EXITSIZEMOVE")); @@ -3031,7 +3040,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, height = HIWORD(lParam); if (wParam == SIZE_MAXIMIZED && !was_zoomed) { - was_zoomed = 1; + was_zoomed = true; prev_rows = term->rows; prev_cols = term->cols; if (resize_action == RESIZE_TERM) { @@ -3058,7 +3067,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, } reset_window(0); } else if (wParam == SIZE_RESTORED && was_zoomed) { - was_zoomed = 0; + was_zoomed = false; if (resize_action == RESIZE_TERM) { w = (width-window_border*2) / font_width; if (w < 1) w = 1; @@ -3205,8 +3214,8 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, */ term_seen_key_event(term); if (ldisc) - ldisc_send(ldisc, buf, len, 1); - show_mouseptr(0); + ldisc_send(ldisc, buf, len, true); + show_mouseptr(false); } } } @@ -3258,12 +3267,13 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, if (IS_HIGH_SURROGATE(hs) && i+2 < n) { WCHAR ls = *(unsigned short *)(buff+i+2); if (IS_LOW_SURROGATE(ls)) { - luni_send(ldisc, (unsigned short *)(buff+i), 2, 1); + luni_send(ldisc, (unsigned short *)(buff+i), + 2, true); i += 2; continue; } } - luni_send(ldisc, (unsigned short *)(buff+i), 1, 1); + luni_send(ldisc, (unsigned short *)(buff+i), 1, true); } } free(buff); @@ -3280,12 +3290,12 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, buf[0] = wParam >> 8; term_seen_key_event(term); if (ldisc) - lpage_send(ldisc, kbd_codepage, buf, 2, 1); + lpage_send(ldisc, kbd_codepage, buf, 2, true); } else { char c = (unsigned char) wParam; term_seen_key_event(term); if (ldisc) - lpage_send(ldisc, kbd_codepage, &c, 1, 1); + lpage_send(ldisc, kbd_codepage, &c, 1, true); } return (0); case WM_CHAR: @@ -3307,10 +3317,10 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, pair[0] = pending_surrogate; pair[1] = c; term_seen_key_event(term); - luni_send(ldisc, pair, 2, 1); + luni_send(ldisc, pair, 2, true); } else if (!IS_SURROGATE(c)) { term_seen_key_event(term); - luni_send(ldisc, &c, 1, 1); + luni_send(ldisc, &c, 1, true); } } return 0; @@ -3336,7 +3346,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, return 0; default: if (message == wm_mousewheel || message == WM_MOUSEWHEEL) { - int shift_pressed=0, control_pressed=0; + bool shift_pressed = false, control_pressed = false; if (message == WM_MOUSEWHEEL) { wheel_accumulator += (short)HIWORD(wParam); @@ -3465,12 +3475,13 @@ static void do_text_internal( COLORREF fg, bg, t; int nfg, nbg, nfont; RECT line_box; - int force_manual_underline = 0; + bool force_manual_underline = false; int fnt_width, char_width; int text_adjust = 0; int xoffset = 0; - int maxlen, remaining, opaque; - int is_cursor = false; + int maxlen, remaining; + bool opaque; + bool is_cursor = false; static int *lpDx = NULL; static int lpDx_len = 0; int *lpDx_maybe; @@ -3540,7 +3551,7 @@ static void do_text_internal( text[0] = ucsdata.unitab_xterm['q']; if (attr & ATTR_UNDER) { attr &= ~ATTR_UNDER; - force_manual_underline = 1; + force_manual_underline = true; } } #endif @@ -3566,7 +3577,7 @@ static void do_text_internal( another_font(nfont); if (!fonts[nfont]) { if (nfont & FONT_UNDERLINE) - force_manual_underline = 1; + force_manual_underline = true; /* Don't do the same for manual bold, it could be bad news. */ nfont &= ~(FONT_BOLD | FONT_UNDERLINE); @@ -4056,7 +4067,8 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, unsigned char *output) { BYTE keystate[256]; - int scan, left_alt = 0, key_down, shift_state; + int scan, shift_state; + bool left_alt = false, key_down; int r, i, code; unsigned char *p = output; static int alt_sum = 0; @@ -4178,7 +4190,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, return 0; if ((HIWORD(lParam) & KF_ALTDOWN) && (keystate[VK_RMENU] & 0x80) == 0) - left_alt = 1; + left_alt = true; key_down = ((HIWORD(lParam) & KF_UP) == 0); @@ -4188,7 +4200,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, keystate[VK_MENU] = 0; else { keystate[VK_RMENU] = 0x80; - left_alt = 0; + left_alt = false; } } @@ -4373,7 +4385,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, } /* Control-Numlock for app-keypad mode switch */ if (wParam == VK_PAUSE && shift_state == 2) { - term->app_keypad_keys ^= 1; + term->app_keypad_keys = !term->app_keypad_keys; return 0; } @@ -4782,7 +4794,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, /* Okay we've done everything interesting; let windows deal with * the boring stuff */ { - BOOL capsOn=0; + bool capsOn = false; /* helg: clear CAPS LOCK state if caps lock switches to cyrillic */ if(keystate[VK_CAPITAL] != 0 && @@ -4862,7 +4874,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, keybuf = nc; term_seen_key_event(term); if (ldisc) - luni_send(ldisc, &keybuf, 1, 1); + luni_send(ldisc, &keybuf, 1, true); continue; } @@ -4874,7 +4886,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, keybuf = alt_sum; term_seen_key_event(term); if (ldisc) - luni_send(ldisc, &keybuf, 1, 1); + luni_send(ldisc, &keybuf, 1, true); } else { char ch = (char) alt_sum; /* @@ -4888,13 +4900,13 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, */ term_seen_key_event(term); if (ldisc) - ldisc_send(ldisc, &ch, 1, 1); + ldisc_send(ldisc, &ch, 1, true); } alt_sum = 0; } else { term_seen_key_event(term); if (ldisc) - luni_send(ldisc, &wch, 1, 1); + luni_send(ldisc, &wch, 1, true); } } else { if(capsOn && wch < 0x80) { @@ -4903,17 +4915,19 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, cbuf[1] = xlat_uskbd2cyrllic(wch); term_seen_key_event(term); if (ldisc) - luni_send(ldisc, cbuf+!left_alt, 1+!!left_alt, 1); + luni_send(ldisc, cbuf+!left_alt, 1+!!left_alt, + true); } else { WCHAR cbuf[2]; cbuf[0] = '\033'; cbuf[1] = wch; term_seen_key_event(term); if (ldisc) - luni_send(ldisc, cbuf +!left_alt, 1+!!left_alt, 1); + luni_send(ldisc, cbuf +!left_alt, 1+!!left_alt, + true); } } - show_mouseptr(0); + show_mouseptr(false); } /* This is so the ALT-Numpad and dead keys work correctly. */ @@ -4978,7 +4992,7 @@ static void wintw_set_scrollbar(TermWin *tw, int total, int start, int page) SetScrollInfo(hwnd, SB_VERT, &si, true); } -static int wintw_setup_draw_ctx(TermWin *tw) +static bool wintw_setup_draw_ctx(TermWin *tw) { assert(!wintw_hdc); wintw_hdc = make_hdc(); @@ -5004,7 +5018,7 @@ static void real_palette_set(int n, int r, int g, int b) } } -static int wintw_palette_get(TermWin *tw, int n, int *r, int *g, int *b) +static bool wintw_palette_get(TermWin *tw, int n, int *r, int *g, int *b) { if (n < 0 || n >= NALLCOLOURS) return false; @@ -5064,7 +5078,7 @@ static void wintw_palette_reset(TermWin *tw) } } -void write_aclip(int clipboard, char *data, int len, int must_deselect) +void write_aclip(int clipboard, char *data, int len, bool must_deselect) { HGLOBAL clipdata; void *lock; @@ -5113,7 +5127,7 @@ int cmpCOLORREF(void *va, void *vb) */ static void wintw_clip_write( TermWin *tw, int clipboard, wchar_t *data, int *attr, - truecolour *truecolour, int len, int must_deselect) + truecolour *truecolour, int len, bool must_deselect) { HGLOBAL clipdata, clipdata2, clipdata3; int len2; @@ -5536,9 +5550,11 @@ static DWORD WINAPI clipboard_read_threadfunc(void *param) if (OpenClipboard(NULL)) { if ((clipdata = GetClipboardData(CF_UNICODETEXT))) { - SendMessage(hwnd, WM_GOT_CLIPDATA, (WPARAM)1, (LPARAM)clipdata); + SendMessage(hwnd, WM_GOT_CLIPDATA, + (WPARAM)true, (LPARAM)clipdata); } else if ((clipdata = GetClipboardData(CF_TEXT))) { - SendMessage(hwnd, WM_GOT_CLIPDATA, (WPARAM)0, (LPARAM)clipdata); + SendMessage(hwnd, WM_GOT_CLIPDATA, + (WPARAM)false, (LPARAM)clipdata); } CloseClipboard(); } @@ -5546,7 +5562,7 @@ static DWORD WINAPI clipboard_read_threadfunc(void *param) return 0; } -static void process_clipdata(HGLOBAL clipdata, int unicode) +static void process_clipdata(HGLOBAL clipdata, bool unicode) { wchar_t *clipboard_contents = NULL; size_t clipboard_length = 0; @@ -5641,7 +5657,7 @@ void nonfatal(const char *fmt, ...) sfree(stuff); } -static BOOL flash_window_ex(DWORD dwFlags, UINT uCount, DWORD dwTimeout) +static bool flash_window_ex(DWORD dwFlags, UINT uCount, DWORD dwTimeout) { if (p_FlashWindowEx) { FLASHWINFO fi; @@ -5658,7 +5674,7 @@ static BOOL flash_window_ex(DWORD dwFlags, UINT uCount, DWORD dwTimeout) static void flash_window(int mode); static long next_flash; -static int flashing = 0; +static bool flashing = false; /* * Timer for platforms where we must maintain window flashing manually @@ -5681,7 +5697,7 @@ static void flash_window(int mode) if ((mode == 0) || (beep_ind == B_IND_DISABLED)) { /* stop */ if (flashing) { - flashing = 0; + flashing = false; if (p_FlashWindowEx) flash_window_ex(FLASHW_STOP, 0, 0); else @@ -5691,7 +5707,7 @@ static void flash_window(int mode) } else if (mode == 2) { /* start */ if (!flashing) { - flashing = 1; + flashing = true; if (p_FlashWindowEx) { /* For so-called "steady" mode, we use uCount=2, which * seems to be the traditional number of flashes used @@ -5783,7 +5799,7 @@ static void wintw_bell(TermWin *tw, int mode) * Minimise or restore the window in response to a server-side * request. */ -static void wintw_set_minimised(TermWin *tw, int minimised) +static void wintw_set_minimised(TermWin *tw, bool minimised) { if (IsIconic(hwnd)) { if (!minimised) @@ -5812,7 +5828,7 @@ static void wintw_move(TermWin *tw, int x, int y) * Move the window to the top or bottom of the z-order in response * to a server-side request. */ -static void wintw_set_zorder(TermWin *tw, int top) +static void wintw_set_zorder(TermWin *tw, bool top) { if (conf_get_bool(conf, CONF_alwaysontop)) return; /* ignore */ @@ -5832,7 +5848,7 @@ static void wintw_refresh(TermWin *tw) * Maximise or restore the window in response to a server-side * request. */ -static void wintw_set_maximised(TermWin *tw, int maximised) +static void wintw_set_maximised(TermWin *tw, bool maximised) { if (IsZoomed(hwnd)) { if (!maximised) @@ -5846,7 +5862,7 @@ static void wintw_set_maximised(TermWin *tw, int maximised) /* * Report whether the window is iconic, for terminal reports. */ -static int wintw_is_minimised(TermWin *tw) +static bool wintw_is_minimised(TermWin *tw) { return IsIconic(hwnd); } @@ -5876,7 +5892,7 @@ static void wintw_get_pixels(TermWin *tw, int *x, int *y) /* * Return the window or icon title. */ -static const char *wintw_get_title(TermWin *tw, int icon) +static const char *wintw_get_title(TermWin *tw, bool icon) { return icon ? icon_name : window_name; } @@ -5884,7 +5900,7 @@ static const char *wintw_get_title(TermWin *tw, int icon) /* * See if we're in full-screen mode. */ -static int is_full_screen() +static bool is_full_screen() { if (!IsZoomed(hwnd)) return false; @@ -5896,7 +5912,7 @@ static int is_full_screen() /* Get the rect/size of a full screen window using the nearest available * monitor in multimon systems; default to something sensible if only * one monitor is present. */ -static int get_fullscreen_rect(RECT * ss) +static bool get_fullscreen_rect(RECT * ss) { #if defined(MONITOR_DEFAULTTONEAREST) && !defined(NO_MULTIMON) HMONITOR mon; @@ -6009,13 +6025,13 @@ static void flip_full_screen() } } -static int win_seat_output(Seat *seat, int is_stderr, +static int win_seat_output(Seat *seat, bool is_stderr, const void *data, int len) { return term_data(term, is_stderr, data, len); } -static int win_seat_eof(Seat *seat) +static bool win_seat_eof(Seat *seat) { return true; /* do respond to incoming EOF with outgoing */ } diff --git a/windows/winhandl.c b/windows/winhandl.c index 88c375cd..2a59885b 100644 --- a/windows/winhandl.c +++ b/windows/winhandl.c @@ -58,10 +58,10 @@ struct handle_generic { HANDLE h; /* the handle itself */ HANDLE ev_to_main; /* event used to signal main thread */ HANDLE ev_from_main; /* event used to signal back to us */ - int moribund; /* are we going to kill this soon? */ - int done; /* request subthread to terminate */ - int defunct; /* has the subthread already gone? */ - int busy; /* operation currently in progress? */ + bool moribund; /* are we going to kill this soon? */ + bool done; /* request subthread to terminate */ + bool defunct; /* has the subthread already gone? */ + bool busy; /* operation currently in progress? */ void *privdata; /* for client to remember who they are */ }; @@ -81,10 +81,10 @@ struct handle_input { HANDLE h; /* the handle itself */ HANDLE ev_to_main; /* event used to signal main thread */ HANDLE ev_from_main; /* event used to signal back to us */ - int moribund; /* are we going to kill this soon? */ - int done; /* request subthread to terminate */ - int defunct; /* has the subthread already gone? */ - int busy; /* operation currently in progress? */ + bool moribund; /* are we going to kill this soon? */ + bool done; /* request subthread to terminate */ + bool defunct; /* has the subthread already gone? */ + bool busy; /* operation currently in progress? */ void *privdata; /* for client to remember who they are */ /* @@ -115,7 +115,8 @@ static DWORD WINAPI handle_input_threadfunc(void *param) struct handle_input *ctx = (struct handle_input *) param; OVERLAPPED ovl, *povl; HANDLE oev; - int readret, readlen, finished; + bool readret, finished; + int readlen; if (ctx->flags & HANDLE_FLAG_OVERLAPPED) { povl = &ovl; @@ -241,10 +242,10 @@ struct handle_output { HANDLE h; /* the handle itself */ HANDLE ev_to_main; /* event used to signal main thread */ HANDLE ev_from_main; /* event used to signal back to us */ - int moribund; /* are we going to kill this soon? */ - int done; /* request subthread to terminate */ - int defunct; /* has the subthread already gone? */ - int busy; /* operation currently in progress? */ + bool moribund; /* are we going to kill this soon? */ + bool done; /* request subthread to terminate */ + bool defunct; /* has the subthread already gone? */ + bool busy; /* operation currently in progress? */ void *privdata; /* for client to remember who they are */ /* @@ -284,7 +285,7 @@ static DWORD WINAPI handle_output_threadfunc(void *param) struct handle_output *ctx = (struct handle_output *) param; OVERLAPPED ovl, *povl; HANDLE oev; - int writeret; + bool writeret; if (ctx->flags & HANDLE_FLAG_OVERLAPPED) { povl = &ovl; @@ -377,10 +378,10 @@ struct handle_foreign { HANDLE h; /* the handle itself */ HANDLE ev_to_main; /* event used to signal main thread */ HANDLE ev_from_main; /* event used to signal back to us */ - int moribund; /* are we going to kill this soon? */ - int done; /* request subthread to terminate */ - int defunct; /* has the subthread already gone? */ - int busy; /* operation currently in progress? */ + bool moribund; /* are we going to kill this soon? */ + bool done; /* request subthread to terminate */ + bool defunct; /* has the subthread already gone? */ + bool busy; /* operation currently in progress? */ void *privdata; /* for client to remember who they are */ /* diff --git a/windows/winhelp.c b/windows/winhelp.c index 03444236..53e8dc1e 100644 --- a/windows/winhelp.c +++ b/windows/winhelp.c @@ -15,9 +15,9 @@ #include #endif /* NO_HTMLHELP */ -static int requested_help; +static bool requested_help; static char *help_path; -static int help_has_contents; +static bool help_has_contents; #ifndef NO_HTMLHELP DECL_WINDOWS_FUNCTION(static, HWND, HtmlHelpA, (HWND, LPCSTR, UINT, DWORD_PTR)); static char *chm_path; @@ -74,7 +74,7 @@ void shutdown_help(void) * call HH_UNINITIALIZE.) */ } -int has_help(void) +bool has_help(void) { /* * FIXME: it would be nice here to disregard help_path on diff --git a/windows/winhsock.c b/windows/winhsock.c index fdc225b4..71f2c188 100644 --- a/windows/winhsock.c +++ b/windows/winhsock.c @@ -36,7 +36,7 @@ typedef struct HandleSocket { /* Data received from stderr_H, if we have one. */ bufchain stderrdata; - int defer_close, deferred_close; /* in case of re-entrance */ + bool defer_close, deferred_close; /* in case of re-entrance */ char *error; @@ -209,7 +209,7 @@ static void handle_socket_unfreeze(void *hsv) } } -static void sk_handle_set_frozen(Socket *s, int is_frozen) +static void sk_handle_set_frozen(Socket *s, bool is_frozen) { HandleSocket *hs = container_of(s, HandleSocket, sock); @@ -324,7 +324,7 @@ static const SocketVtable HandleSocket_sockvt = { }; Socket *make_handle_socket(HANDLE send_H, HANDLE recv_H, HANDLE stderr_H, - Plug *plug, int overlapped) + Plug *plug, bool overlapped) { HandleSocket *hs; int flags = (overlapped ? HANDLE_FLAG_OVERLAPPED : 0); diff --git a/windows/winjump.c b/windows/winjump.c index dccdb93d..745984ca 100644 --- a/windows/winjump.c +++ b/windows/winjump.c @@ -492,7 +492,7 @@ static void update_jumplist_from_registry(void) IObjectArray *array = NULL; IShellLink *link = NULL; IObjectArray *pRemoved = NULL; - int need_abort = false; + bool need_abort = false; /* * Create an ICustomDestinationList: the top-level object which @@ -538,7 +538,7 @@ static void update_jumplist_from_registry(void) link = make_shell_link(NULL, piterator); if (link) { UINT i; - int found; + bool found; /* * Check that the link isn't in the user-removed list. @@ -715,7 +715,7 @@ void remove_session_from_jumplist(const char * const sessionname) /* Set Explicit App User Model Id to fix removable media error with jump lists */ -BOOL set_explicit_app_user_model_id() +bool set_explicit_app_user_model_id() { DECL_WINDOWS_FUNCTION(static, HRESULT, SetCurrentProcessExplicitAppUserModelID, (PCWSTR)); diff --git a/windows/winmisc.c b/windows/winmisc.c index 6bdbedee..bf60d4a5 100644 --- a/windows/winmisc.c +++ b/windows/winmisc.c @@ -35,12 +35,12 @@ const char *filename_to_str(const Filename *fn) return fn->path; } -int filename_equal(const Filename *f1, const Filename *f2) +bool filename_equal(const Filename *f1, const Filename *f2) { return !strcmp(f1->path, f2->path); } -int filename_is_null(const Filename *fn) +bool filename_is_null(const Filename *fn) { return !*fn->path; } @@ -81,12 +81,12 @@ char *get_username(void) { DWORD namelen; char *user; - int got_username = false; + bool got_username = false; DECL_WINDOWS_FUNCTION(static, BOOLEAN, GetUserNameExA, (EXTENDED_NAME_FORMAT, LPSTR, PULONG)); { - static int tried_usernameex = false; + static bool tried_usernameex = false; if (!tried_usernameex) { /* Not available on Win9x, so load dynamically */ HMODULE secur32 = load_system32_dll("secur32.dll"); @@ -125,7 +125,7 @@ char *get_username(void) if (!got_username) { /* Fall back to local user name */ namelen = 0; - if (GetUserName(NULL, &namelen) == false) { + if (!GetUserName(NULL, &namelen)) { /* * Apparently this doesn't work at least on Windows XP SP2. * Thus assume a maximum of 256. It will fail again if it @@ -559,8 +559,7 @@ void *minefield_c_realloc(void *p, size_t size) #endif /* MINEFIELD */ -FontSpec *fontspec_new(const char *name, - int bold, int height, int charset) +FontSpec *fontspec_new(const char *name, bool bold, int height, int charset) { FontSpec *f = snew(FontSpec); f->name = dupstr(name); @@ -594,7 +593,7 @@ FontSpec *fontspec_deserialise(BinarySource *src) return fontspec_new(name, isbold, height, charset); } -int open_for_write_would_lose_data(const Filename *fn) +bool open_for_write_would_lose_data(const Filename *fn) { WIN32_FILE_ATTRIBUTE_DATA attrs; if (!GetFileAttributesEx(fn->path, GetFileExInfoStandard, &attrs)) { diff --git a/windows/winnet.c b/windows/winnet.c index 44092bbb..2e6b0f03 100644 --- a/windows/winnet.c +++ b/windows/winnet.c @@ -53,20 +53,20 @@ struct NetSocket { SOCKET s; Plug *plug; bufchain output_data; - int connected; - int writable; - int frozen; /* this causes readability notifications to be ignored */ - int frozen_readable; /* this means we missed at least one readability - * notification while we were frozen */ - int localhost_only; /* for listening sockets */ + bool connected; + bool writable; + bool frozen; /* this causes readability notifications to be ignored */ + bool frozen_readable; /* this means we missed at least one readability + * notification while we were frozen */ + bool localhost_only; /* for listening sockets */ char oobdata[1]; int sending_oob; - int oobinline, nodelay, keepalive, privport; + bool oobinline, nodelay, keepalive, privport; enum { EOF_NO, EOF_PENDING, EOF_SENT } outgoingeof; SockAddr *addr; SockAddrStep step; int port; - int pending_error; /* in case send() returns error */ + int pending_error; /* in case send() returns error */ /* * We sometimes need pairs of Socket structures to be linked: * if we are listening on the same IPv6 and v4 port, for @@ -81,9 +81,9 @@ struct NetSocket { struct SockAddr { int refcount; char *error; - int resolved; - int namedpipe; /* indicates that this SockAddr is phony, holding a Windows - * named pipe pathname instead of a network address */ + bool resolved; + bool namedpipe; /* indicates that this SockAddr is phony, holding a Windows + * named pipe pathname instead of a network address */ #ifndef NO_IPV6 struct addrinfo *ais; /* Addresses IPv6 style. */ #endif @@ -206,7 +206,7 @@ static HMODULE winsock2_module = NULL; static HMODULE wship6_module = NULL; #endif -int sk_startup(int hi, int lo) +bool sk_startup(int hi, int lo) { WORD winsock_ver; @@ -657,7 +657,7 @@ SockAddr *sk_namedpipe_addr(const char *pipename) return ret; } -int sk_nextaddr(SockAddr *addr, SockAddrStep *step) +bool sk_nextaddr(SockAddr *addr, SockAddrStep *step) { #ifndef NO_IPV6 if (step->ai) { @@ -739,12 +739,12 @@ static SockAddr sk_extractaddr_tmp( return toret; } -int sk_addr_needs_port(SockAddr *addr) +bool sk_addr_needs_port(SockAddr *addr) { - return addr->namedpipe ? false : true; + return !addr->namedpipe; } -int sk_hostname_is_local(const char *name) +bool sk_hostname_is_local(const char *name) { return !strcmp(name, "localhost") || !strcmp(name, "::1") || @@ -754,10 +754,10 @@ int sk_hostname_is_local(const char *name) static INTERFACE_INFO local_interfaces[16]; static int n_local_interfaces; /* 0=not yet, -1=failed, >0=number */ -static int ipv4_is_local_addr(struct in_addr addr) +static bool ipv4_is_local_addr(struct in_addr addr) { if (ipv4_is_loopback(addr)) - return 1; /* loopback addresses are local */ + return true; /* loopback addresses are local */ if (!n_local_interfaces) { SOCKET s = p_socket(AF_INET, SOCK_DGRAM, 0); DWORD retbytes; @@ -778,13 +778,13 @@ static int ipv4_is_local_addr(struct in_addr addr) SOCKADDR_IN *address = (SOCKADDR_IN *)&local_interfaces[i].iiAddress; if (address->sin_addr.s_addr == addr.s_addr) - return 1; /* this address is local */ + return true; /* this address is local */ } } - return 0; /* this address is not local */ + return false; /* this address is not local */ } -int sk_address_is_local(SockAddr *addr) +bool sk_address_is_local(SockAddr *addr) { SockAddrStep step; int family; @@ -811,13 +811,13 @@ int sk_address_is_local(SockAddr *addr) } } else { assert(family == AF_UNSPEC); - return 0; /* we don't know; assume not */ + return false; /* we don't know; assume not */ } } -int sk_address_is_special_local(SockAddr *addr) +bool sk_address_is_special_local(SockAddr *addr) { - return 0; /* no Unix-domain socket analogue here */ + return false; /* no Unix-domain socket analogue here */ } int sk_addrtype(SockAddr *addr) @@ -902,11 +902,11 @@ static void sk_net_close(Socket *s); static int sk_net_write(Socket *s, const void *data, int len); static int sk_net_write_oob(Socket *s, const void *data, int len); static void sk_net_write_eof(Socket *s); -static void sk_net_set_frozen(Socket *s, int is_frozen); +static void sk_net_set_frozen(Socket *s, bool is_frozen); static const char *sk_net_socket_error(Socket *s); static SocketPeerInfo *sk_net_peer_info(Socket *s); -extern char *do_select(SOCKET skt, int startup); +extern char *do_select(SOCKET skt, bool startup); static const SocketVtable NetSocket_sockvt = { sk_net_plug, @@ -934,12 +934,12 @@ static Socket *sk_net_accept(accept_ctx_t ctx, Plug *plug) ret->error = NULL; ret->plug = plug; bufchain_init(&ret->output_data); - ret->writable = 1; /* to start with */ + ret->writable = true; /* to start with */ ret->sending_oob = 0; ret->outgoingeof = EOF_NO; - ret->frozen = 1; - ret->frozen_readable = 0; - ret->localhost_only = 0; /* unused, but best init anyway */ + ret->frozen = true; + ret->frozen_readable = false; + ret->localhost_only = false; /* unused, but best init anyway */ ret->pending_error = 0; ret->parent = ret->child = NULL; ret->addr = NULL; @@ -952,11 +952,11 @@ static Socket *sk_net_accept(accept_ctx_t ctx, Plug *plug) return &ret->sock; } - ret->oobinline = 0; + ret->oobinline = false; /* Set up a select mechanism. This could be an AsyncSelect on a * window, or an EventSelect on an event object. */ - errstr = do_select(ret->s, 1); + errstr = do_select(ret->s, true); if (errstr) { ret->error = errstr; return &ret->sock; @@ -980,7 +980,7 @@ static DWORD try_connect(NetSocket *sock) int family; if (sock->s != INVALID_SOCKET) { - do_select(sock->s, 0); + do_select(sock->s, false); p_closesocket(sock->s); } @@ -1112,7 +1112,7 @@ static DWORD try_connect(NetSocket *sock) /* Set up a select mechanism. This could be an AsyncSelect on a * window, or an EventSelect on an event object. */ - errstr = do_select(s, 1); + errstr = do_select(s, true); if (errstr) { sock->error = errstr; err = 1; @@ -1145,7 +1145,7 @@ static DWORD try_connect(NetSocket *sock) * If we _don't_ get EWOULDBLOCK, the connect has completed * and we should set the socket as writable. */ - sock->writable = 1; + sock->writable = true; } err = 0; @@ -1165,8 +1165,8 @@ static DWORD try_connect(NetSocket *sock) return err; } -Socket *sk_new(SockAddr *addr, int port, int privport, int oobinline, - int nodelay, int keepalive, Plug *plug) +Socket *sk_new(SockAddr *addr, int port, bool privport, bool oobinline, + bool nodelay, bool keepalive, Plug *plug) { NetSocket *ret; DWORD err; @@ -1179,13 +1179,13 @@ Socket *sk_new(SockAddr *addr, int port, int privport, int oobinline, ret->error = NULL; ret->plug = plug; bufchain_init(&ret->output_data); - ret->connected = 0; /* to start with */ - ret->writable = 0; /* to start with */ + ret->connected = false; /* to start with */ + ret->writable = false; /* to start with */ ret->sending_oob = 0; ret->outgoingeof = EOF_NO; - ret->frozen = 0; - ret->frozen_readable = 0; - ret->localhost_only = 0; /* unused, but best init anyway */ + ret->frozen = false; + ret->frozen_readable = false; + ret->localhost_only = false; /* unused, but best init anyway */ ret->pending_error = 0; ret->parent = ret->child = NULL; ret->oobinline = oobinline; @@ -1206,7 +1206,7 @@ Socket *sk_new(SockAddr *addr, int port, int privport, int oobinline, } Socket *sk_newlistener(const char *srcaddr, int port, Plug *plug, - int local_host_only, int orig_address_family) + bool local_host_only, int orig_address_family) { SOCKET s; #ifndef NO_IPV6 @@ -1230,11 +1230,11 @@ Socket *sk_newlistener(const char *srcaddr, int port, Plug *plug, ret->error = NULL; ret->plug = plug; bufchain_init(&ret->output_data); - ret->writable = 0; /* to start with */ + ret->writable = false; /* to start with */ ret->sending_oob = 0; ret->outgoingeof = EOF_NO; - ret->frozen = 0; - ret->frozen_readable = 0; + ret->frozen = false; + ret->frozen_readable = false; ret->localhost_only = local_host_only; ret->pending_error = 0; ret->parent = ret->child = NULL; @@ -1273,7 +1273,7 @@ Socket *sk_newlistener(const char *srcaddr, int port, Plug *plug, SetHandleInformation((HANDLE)s, HANDLE_FLAG_INHERIT, 0); - ret->oobinline = 0; + ret->oobinline = false; p_setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char *)&on, sizeof(on)); @@ -1308,7 +1308,7 @@ Socket *sk_newlistener(const char *srcaddr, int port, Plug *plug, } else #endif { - int got_addr = 0; + bool got_addr = false; a.sin_family = AF_INET; /* @@ -1320,7 +1320,7 @@ Socket *sk_newlistener(const char *srcaddr, int port, Plug *plug, if (a.sin_addr.s_addr != INADDR_NONE) { /* Override localhost_only with specified listen addr. */ ret->localhost_only = ipv4_is_loopback(a.sin_addr); - got_addr = 1; + got_addr = true; } } @@ -1366,7 +1366,7 @@ Socket *sk_newlistener(const char *srcaddr, int port, Plug *plug, /* Set up a select mechanism. This could be an AsyncSelect on a * window, or an EventSelect on an event object. */ - errstr = do_select(s, 1); + errstr = do_select(s, true); if (errstr) { p_closesocket(s); ret->error = errstr; @@ -1401,14 +1401,13 @@ Socket *sk_newlistener(const char *srcaddr, int port, Plug *plug, static void sk_net_close(Socket *sock) { - extern char *do_select(SOCKET skt, int startup); NetSocket *s = container_of(sock, NetSocket, sock); if (s->child) sk_net_close(&s->child->sock); del234(sktree, s); - do_select(s->s, 0); + do_select(s->s, false); p_closesocket(s->s); if (s->addr) sk_addr_free(s->addr); @@ -1578,7 +1577,7 @@ void select_result(WPARAM wParam, LPARAM lParam) DWORD err; char buf[20480]; /* nice big buffer for plenty of speed */ NetSocket *s; - u_long atmark; + bool atmark; /* wParam is the socket itself */ @@ -1612,7 +1611,8 @@ void select_result(WPARAM wParam, LPARAM lParam) switch (WSAGETSELECTEVENT(lParam)) { case FD_CONNECT: - s->connected = s->writable = 1; + s->connected = true; + s->writable = true; /* * Once a socket is connected, we can stop falling * back through the candidate addresses to connect @@ -1626,7 +1626,7 @@ void select_result(WPARAM wParam, LPARAM lParam) case FD_READ: /* In the case the socket is still frozen, we don't even bother */ if (s->frozen) { - s->frozen_readable = 1; + s->frozen_readable = true; break; } @@ -1637,8 +1637,8 @@ void select_result(WPARAM wParam, LPARAM lParam) * (data prior to urgent). */ if (s->oobinline) { - atmark = 1; - p_ioctlsocket(s->s, SIOCATMARK, &atmark); + u_long atmark_from_ioctl = 1; + p_ioctlsocket(s->s, SIOCATMARK, &atmark_from_ioctl); /* * Avoid checking the return value from ioctlsocket(), * on the grounds that some WinSock wrappers don't @@ -1646,8 +1646,9 @@ void select_result(WPARAM wParam, LPARAM lParam) * which is equivalent to `no OOB pending', so the * effect will be to non-OOB-ify any OOB data. */ + atmark = atmark_from_ioctl; } else - atmark = 1; + atmark = true; ret = p_recv(s->s, buf, sizeof(buf), 0); noise_ultralight(ret); @@ -1684,7 +1685,7 @@ void select_result(WPARAM wParam, LPARAM lParam) case FD_WRITE: { int bufsize_before, bufsize_after; - s->writable = 1; + s->writable = true; bufsize_before = s->sending_oob + bufchain_size(&s->output_data); try_send(s); bufsize_after = s->sending_oob + bufchain_size(&s->output_data); @@ -1812,20 +1813,20 @@ static SocketPeerInfo *sk_net_peer_info(Socket *sock) return pi; } -static void sk_net_set_frozen(Socket *sock, int is_frozen) +static void sk_net_set_frozen(Socket *sock, bool is_frozen) { NetSocket *s = container_of(sock, NetSocket, sock); if (s->frozen == is_frozen) return; s->frozen = is_frozen; if (!is_frozen) { - do_select(s->s, 1); + do_select(s->s, true); if (s->frozen_readable) { char c; p_recv(s->s, &c, 1, MSG_PEEK); } } - s->frozen_readable = 0; + s->frozen_readable = false; } void socket_reselect_all(void) @@ -1835,7 +1836,7 @@ void socket_reselect_all(void) for (i = 0; (s = index234(sktree, i)) != NULL; i++) { if (!s->frozen) - do_select(s->s, 1); + do_select(s->s, true); } } @@ -1856,14 +1857,14 @@ SOCKET next_socket(int *state) return s ? s->s : INVALID_SOCKET; } -extern int socket_writable(SOCKET skt) +extern bool socket_writable(SOCKET skt) { NetSocket *s = find234(sktree, (void *)skt, cmpforsearch); if (s) return bufchain_size(&s->output_data) > 0; else - return 0; + return false; } int net_service_lookup(char *service) diff --git a/windows/winnoise.c b/windows/winnoise.c index b2305d26..39c2049a 100644 --- a/windows/winnoise.c +++ b/windows/winnoise.c @@ -19,9 +19,9 @@ DECL_WINDOWS_FUNCTION(static, BOOL, CryptReleaseContext, (HCRYPTPROV, DWORD)); static HMODULE wincrypt_module = NULL; -int win_read_random(void *buf, unsigned wanted) +bool win_read_random(void *buf, unsigned wanted) { - int toret = false; + bool toret = false; HCRYPTPROV crypt_provider; if (!wincrypt_module) { diff --git a/windows/winnpc.c b/windows/winnpc.c index f5bffbf7..31906e0d 100644 --- a/windows/winnpc.c +++ b/windows/winnpc.c @@ -16,7 +16,7 @@ #include "winsecur.h" Socket *make_handle_socket(HANDLE send_H, HANDLE recv_H, HANDLE stderr_H, - Plug *plug, int overlapped); + Plug *plug, bool overlapped); Socket *new_named_pipe_client(const char *pipename, Plug *plug) { diff --git a/windows/winnps.c b/windows/winnps.c index 5ea141fa..d355a90a 100644 --- a/windows/winnps.c +++ b/windows/winnps.c @@ -16,7 +16,7 @@ #include "winsecur.h" Socket *make_handle_socket(HANDLE send_H, HANDLE recv_H, HANDLE stderr_H, - Plug *plug, int overlapped); + Plug *plug, bool overlapped); typedef struct NamedPipeServerSocket { /* Parameters for (repeated) creation of named pipe objects */ @@ -73,7 +73,7 @@ static SocketPeerInfo *sk_namedpipeserver_peer_info(Socket *s) return NULL; } -static int create_named_pipe(NamedPipeServerSocket *ps, int first_instance) +static bool create_named_pipe(NamedPipeServerSocket *ps, bool first_instance) { SECURITY_ATTRIBUTES sa; @@ -127,7 +127,7 @@ static Socket *named_pipe_accept(accept_ctx_t ctx, Plug *plug) SockAddr *sk_namedpipe_addr(const char *pipename); static void named_pipe_accept_loop(NamedPipeServerSocket *ps, - int got_one_already) + bool got_one_already) { while (1) { int error; diff --git a/windows/winpgen.c b/windows/winpgen.c index 0c90838e..6d5c244b 100644 --- a/windows/winpgen.c +++ b/windows/winpgen.c @@ -71,7 +71,7 @@ void queue_idempotent_callback(IdempotentCallback *ic) { assert(0); } struct progress { int nphases; struct { - int exponential; + bool exponential; unsigned startpoint, total; unsigned param, current, n; /* if exponential */ unsigned mult; /* if linear */ @@ -93,11 +93,11 @@ static void progress_update(void *param, int action, int phase, int iprogress) p->nphases = 0; break; case PROGFN_LIN_PHASE: - p->phases[phase-1].exponential = 0; + p->phases[phase-1].exponential = false; p->phases[phase-1].mult = p->phases[phase].total / progress; break; case PROGFN_EXP_PHASE: - p->phases[phase-1].exponential = 1; + p->phases[phase-1].exponential = true; p->phases[phase-1].param = 0x10000 + progress; p->phases[phase-1].current = p->phases[phase-1].total; p->phases[phase-1].n = 0; @@ -212,8 +212,8 @@ static INT_PTR CALLBACK PassphraseProc(HWND hwnd, UINT msg, * Prompt for a key file. Assumes the filename buffer is of size * FILENAME_MAX. */ -static int prompt_keyfile(HWND hwnd, char *dlgtitle, - char *filename, int save, int ppk) +static bool prompt_keyfile(HWND hwnd, char *dlgtitle, + char *filename, bool save, bool ppk) { OPENFILENAME of; memset(&of, 0, sizeof(of)); @@ -379,12 +379,12 @@ static DWORD WINAPI generate_key_thread(void *param) } struct MainDlgState { - int collecting_entropy; - int generation_thread_exists; - int key_exists; + bool collecting_entropy; + bool generation_thread_exists; + bool key_exists; int entropy_got, entropy_required, entropy_size; int key_bits, curve_bits; - int ssh2; + bool ssh2; keytype keytype; char **commentptr; /* points to key.comment or ssh2key.comment */ struct ssh2_userkey ssh2key; @@ -397,7 +397,7 @@ struct MainDlgState { HMENU filemenu, keymenu, cvtmenu; }; -static void hidemany(HWND hwnd, const int *ids, int hideit) +static void hidemany(HWND hwnd, const int *ids, bool hideit) { while (*ids) { ShowWindow(GetDlgItem(hwnd, *ids++), (hideit ? SW_HIDE : SW_SHOW)); @@ -642,10 +642,10 @@ void ui_set_key_type(HWND hwnd, struct MainDlgState *state, int button) } void load_key_file(HWND hwnd, struct MainDlgState *state, - Filename *filename, int was_import_cmd) + Filename *filename, bool was_import_cmd) { char *passphrase; - int needs_pass; + bool needs_pass; int type, realtype; int ret; const char *errmsg = NULL; @@ -1029,7 +1029,7 @@ static INT_PTR CALLBACK MainDlgProc(HWND hwnd, UINT msg, */ if (cmdline_keyfile) { Filename *fn = filename_from_str(cmdline_keyfile); - load_key_file(hwnd, state, fn, 0); + load_key_file(hwnd, state, fn, false); filename_free(fn); } @@ -1280,7 +1280,7 @@ static INT_PTR CALLBACK MainDlgProc(HWND hwnd, UINT msg, } } if (prompt_keyfile(hwnd, "Save private key as:", - filename, 1, (type == realtype))) { + filename, true, (type == realtype))) { int ret; FILE *fp = fopen(filename, "r"); if (fp) { @@ -1334,7 +1334,7 @@ static INT_PTR CALLBACK MainDlgProc(HWND hwnd, UINT msg, if (state->key_exists) { char filename[FILENAME_MAX]; if (prompt_keyfile(hwnd, "Save public key as:", - filename, 1, 0)) { + filename, true, false)) { int ret; FILE *fp = fopen(filename, "r"); if (fp) { @@ -1380,8 +1380,8 @@ static INT_PTR CALLBACK MainDlgProc(HWND hwnd, UINT msg, (struct MainDlgState *) GetWindowLongPtr(hwnd, GWLP_USERDATA); if (!state->generation_thread_exists) { char filename[FILENAME_MAX]; - if (prompt_keyfile(hwnd, "Load private key:", - filename, 0, LOWORD(wParam)==IDC_LOAD)) { + if (prompt_keyfile(hwnd, "Load private key:", filename, false, + LOWORD(wParam) == IDC_LOAD)) { Filename *fn = filename_from_str(filename); load_key_file(hwnd, state, fn, LOWORD(wParam) != IDC_LOAD); filename_free(fn); diff --git a/windows/winpgnt.c b/windows/winpgnt.c index bae72174..ff105588 100644 --- a/windows/winpgnt.c +++ b/windows/winpgnt.c @@ -55,10 +55,10 @@ extern const char ver[]; static HWND keylist; static HWND aboutbox; static HMENU systray_menu, session_menu; -static int already_running; +static bool already_running; static char *putty_path; -static int restrict_putty_acl = false; +static bool restrict_putty_acl = false; /* CWD for "add key" file requester. */ static filereq *keypath = NULL; @@ -116,7 +116,7 @@ static void unmungestr(char *in, char *out, int outlen) /* Stubs needed to link against misc.c */ void queue_idempotent_callback(IdempotentCallback *ic) { assert(0); } -static int has_security; +static bool has_security; struct PassphraseProcStruct { char **passphrase; @@ -783,7 +783,7 @@ PSID get_default_sid(void) struct PageantReply { char *buf; size_t size, len; - int overflowed; + bool overflowed; BinarySink_IMPLEMENTATION; }; @@ -969,7 +969,7 @@ static char *answer_filemapping_message(const char *mapname) static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { - static int menuinprogress; + static bool menuinprogress; static UINT msgTaskbarCreated = 0; switch (message) { @@ -1000,14 +1000,14 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, break; case WM_SYSTRAY2: if (!menuinprogress) { - menuinprogress = 1; + menuinprogress = true; update_sessions(); SetForegroundWindow(hwnd); TrackPopupMenu(systray_menu, TPM_RIGHTALIGN | TPM_BOTTOMALIGN | TPM_RIGHTBUTTON, wParam, lParam, 0, hwnd, NULL); - menuinprogress = 0; + menuinprogress = false; } break; case WM_COMMAND: @@ -1169,7 +1169,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) WNDCLASS wndclass; MSG msg; const char *command = NULL; - int added_keys = 0; + bool added_keys = false; int argc, i; char **argv, **argstart; diff --git a/windows/winpgntc.c b/windows/winpgntc.c index d079c9b9..470fa847 100644 --- a/windows/winpgntc.c +++ b/windows/winpgntc.c @@ -15,7 +15,7 @@ #define AGENT_COPYDATA_ID 0x804e50ba /* random goop */ -int agent_exists(void) +bool agent_exists(void) { HWND hwnd; hwnd = FindWindow("Pageant", "Pageant"); diff --git a/windows/winplink.c b/windows/winplink.c index 14bb7498..493db000 100644 --- a/windows/winplink.c +++ b/windows/winplink.c @@ -40,11 +40,11 @@ WSAEVENT netevent; static Backend *backend; static Conf *conf; -int term_ldisc(Terminal *term, int mode) +bool term_ldisc(Terminal *term, int mode) { return false; } -static void plink_echoedit_update(Seat *seat, int echo, int edit) +static void plink_echoedit_update(Seat *seat, bool echo, bool edit) { /* Update stdin read mode to reflect changes in line discipline. */ DWORD mode; @@ -61,7 +61,7 @@ static void plink_echoedit_update(Seat *seat, int echo, int edit) SetConsoleMode(inhandle, mode); } -static int plink_output(Seat *seat, int is_stderr, const void *data, int len) +static int plink_output(Seat *seat, bool is_stderr, const void *data, int len) { if (is_stderr) { handle_write(stderr_handle, data, len); @@ -72,7 +72,7 @@ static int plink_output(Seat *seat, int is_stderr, const void *data, int len) return handle_backlog(stdout_handle) + handle_backlog(stderr_handle); } -static int plink_eof(Seat *seat) +static bool plink_eof(Seat *seat) { handle_write_eof(stdout_handle); return false; /* do not respond to incoming EOF with outgoing */ @@ -185,7 +185,7 @@ static void version(void) exit(0); } -char *do_select(SOCKET skt, int startup) +char *do_select(SOCKET skt, bool startup) { int events; if (startup) { @@ -254,18 +254,18 @@ void stdouterr_sent(struct handle *h, int new_backlog) } } -const int share_can_be_downstream = true; -const int share_can_be_upstream = true; +const bool share_can_be_downstream = true; +const bool share_can_be_upstream = true; int main(int argc, char **argv) { - int sending; + bool sending; SOCKET *sklist; int skcount, sksize; int exitcode; - int errors; - int use_subsystem = 0; - int just_test_share_exists = false; + bool errors; + bool use_subsystem = false; + bool just_test_share_exists = false; unsigned long now, next, then; const struct BackendVtable *vt; @@ -295,7 +295,7 @@ int main(int argc, char **argv) loaded_session = false; default_protocol = conf_get_int(conf, CONF_protocol); default_port = conf_get_int(conf, CONF_port); - errors = 0; + errors = false; { /* * Override the default protocol if PLINK_PROTOCOL is set. @@ -318,16 +318,16 @@ int main(int argc, char **argv) if (ret == -2) { fprintf(stderr, "plink: option \"%s\" requires an argument\n", p); - errors = 1; + errors = true; } else if (ret == 2) { --argc, ++argv; } else if (ret == 1) { continue; } else if (!strcmp(p, "-batch")) { - console_batch_mode = 1; + console_batch_mode = true; } else if (!strcmp(p, "-s")) { /* Save status to write to conf later. */ - use_subsystem = 1; + use_subsystem = true; } else if (!strcmp(p, "-V") || !strcmp(p, "--version")) { version(); } else if (!strcmp(p, "--help")) { @@ -367,7 +367,7 @@ int main(int argc, char **argv) break; /* done with cmdline */ } else { fprintf(stderr, "plink: unknown option \"%s\"\n", p); - errors = 1; + errors = true; } } @@ -451,7 +451,7 @@ int main(int argc, char **argv) const char *error; char *realhost; /* nodelay is only useful if stdin is a character device (console) */ - int nodelay = conf_get_bool(conf, CONF_tcp_nodelay) && + bool nodelay = conf_get_bool(conf, CONF_tcp_nodelay) && (GetFileType(GetStdHandle(STD_INPUT_HANDLE)) == FILE_TYPE_CHAR); error = backend_init(vt, plink_seat, &backend, logctx, conf, diff --git a/windows/winprint.c b/windows/winprint.c index cb9184ba..b8b24512 100644 --- a/windows/winprint.c +++ b/windows/winprint.c @@ -32,7 +32,7 @@ DECL_WINDOWS_FUNCTION(static, BOOL, WritePrinter, static void init_winfuncs(void) { - static int initialised = false; + static bool initialised = false; if (initialised) return; { @@ -56,8 +56,8 @@ static void init_winfuncs(void) initialised = true; } -static int printer_add_enum(int param, DWORD level, char **buffer, - int offset, int *nprinters_ptr) +static bool printer_add_enum(int param, DWORD level, char **buffer, + int offset, int *nprinters_ptr) { DWORD needed = 0, nprinters = 0; @@ -169,7 +169,7 @@ printer_job *printer_start_job(char *printer) { printer_job *ret = snew(printer_job); DOC_INFO_1 docinfo; - int jobstarted = 0, pagestarted = 0; + bool jobstarted = false, pagestarted = false; init_winfuncs(); @@ -183,11 +183,11 @@ printer_job *printer_start_job(char *printer) if (!p_StartDocPrinter(ret->hprinter, 1, (LPBYTE)&docinfo)) goto error; - jobstarted = 1; + jobstarted = true; if (!p_StartPagePrinter(ret->hprinter)) goto error; - pagestarted = 1; + pagestarted = true; return ret; diff --git a/windows/winproxy.c b/windows/winproxy.c index c83e2b4f..73b77d42 100644 --- a/windows/winproxy.c +++ b/windows/winproxy.c @@ -13,11 +13,11 @@ #include "proxy.h" Socket *make_handle_socket(HANDLE send_H, HANDLE recv_H, HANDLE stderr_H, - Plug *plug, int overlapped); + Plug *plug, bool overlapped); Socket *platform_new_connection(SockAddr *addr, const char *hostname, - int port, int privport, - int oobinline, int nodelay, int keepalive, + int port, bool privport, + bool oobinline, bool nodelay, bool keepalive, Plug *plug, Conf *conf) { char *cmd; diff --git a/windows/winsecur.c b/windows/winsecur.c index 656c327a..3096d26e 100644 --- a/windows/winsecur.c +++ b/windows/winsecur.c @@ -16,10 +16,10 @@ static PSID worldsid, networksid, usersid; -int got_advapi(void) +bool got_advapi(void) { - static int attempted = false; - static int successful; + static bool attempted = false; + static bool successful; static HMODULE advapi; if (!attempted) { @@ -92,7 +92,7 @@ PSID get_user_sid(void) return ret; } -int getsids(char **error) +bool getsids(char **error) { #ifdef __clang__ #pragma clang diagnostic push @@ -104,7 +104,7 @@ int getsids(char **error) #pragma clang diagnostic pop #endif - int ret = false; + bool ret = false; *error = NULL; @@ -142,14 +142,14 @@ int getsids(char **error) } -int make_private_security_descriptor(DWORD permissions, - PSECURITY_DESCRIPTOR *psd, - PACL *acl, - char **error) +bool make_private_security_descriptor(DWORD permissions, + PSECURITY_DESCRIPTOR *psd, + PACL *acl, + char **error) { EXPLICIT_ACCESS ea[3]; int acl_err; - int ret = false; + bool ret = false; *psd = NULL; @@ -228,11 +228,11 @@ int make_private_security_descriptor(DWORD permissions, return ret; } -static int really_restrict_process_acl(char **error) +static bool really_restrict_process_acl(char **error) { EXPLICIT_ACCESS ea[2]; int acl_err; - int ret=false; + bool ret = false; PACL acl = NULL; static const DWORD nastyace=WRITE_DAC | WRITE_OWNER | @@ -312,7 +312,7 @@ static int really_restrict_process_acl(char **error) void restrict_process_acl(void) { char *error = NULL; - int ret; + bool ret; #if !defined NO_SECURITY ret = really_restrict_process_acl(&error); diff --git a/windows/winsecur.h b/windows/winsecur.h index dd4da9ee..50c696db 100644 --- a/windows/winsecur.h +++ b/windows/winsecur.h @@ -33,7 +33,7 @@ DECL_WINDOWS_FUNCTION(WINSECUR_GLOBAL, DWORD, SetSecurityInfo, PSID, PSID, PACL, PACL)); DECL_WINDOWS_FUNCTION(WINSECUR_GLOBAL, DWORD, SetEntriesInAclA, (ULONG, PEXPLICIT_ACCESS, PACL, PACL *)); -int got_advapi(void); +bool got_advapi(void); /* * Find the SID describing the current user. The return value (if not @@ -51,9 +51,7 @@ PSID get_user_sid(void); * freed later using LocalFree). If it returns false, then instead * 'error' has been filled with a dynamically allocated error message. */ -int make_private_security_descriptor(DWORD permissions, - PSECURITY_DESCRIPTOR *psd, - PACL *acl, - char **error); +bool make_private_security_descriptor( + DWORD permissions, PSECURITY_DESCRIPTOR *psd, PACL *acl, char **error); #endif diff --git a/windows/winser.c b/windows/winser.c index d848c20c..24c8902b 100644 --- a/windows/winser.c +++ b/windows/winser.c @@ -18,7 +18,7 @@ struct Serial { LogContext *logctx; int bufsize; long clearbreak_time; - int break_in_progress; + bool break_in_progress; Backend backend; }; @@ -193,7 +193,7 @@ static const char *serial_configure(Serial *serial, HANDLE serport, Conf *conf) static const char *serial_init(Seat *seat, Backend **backend_handle, LogContext *logctx, Conf *conf, const char *host, int port, - char **realhost, int nodelay, int keepalive) + char **realhost, bool nodelay, bool keepalive) { Serial *serial; HANDLE serport; @@ -375,14 +375,14 @@ static const SessionSpecial *serial_get_specials(Backend *be) return specials; } -static int serial_connected(Backend *be) +static bool serial_connected(Backend *be) { - return 1; /* always connected */ + return true; /* always connected */ } -static int serial_sendok(Backend *be) +static bool serial_sendok(Backend *be) { - return 1; + return true; } static void serial_unthrottle(Backend *be, int backlog) @@ -392,12 +392,12 @@ static void serial_unthrottle(Backend *be, int backlog) handle_unthrottle(serial->in, backlog); } -static int serial_ldisc(Backend *be, int option) +static bool serial_ldisc(Backend *be, int option) { /* * Local editing and local echo are off by default. */ - return 0; + return false; } static void serial_provide_ldisc(Backend *be, Ldisc *ldisc) diff --git a/windows/winsftp.c b/windows/winsftp.c index c85c6c8f..7d0adde5 100644 --- a/windows/winsftp.c +++ b/windows/winsftp.c @@ -25,7 +25,7 @@ void platform_get_x11_auth(struct X11Display *display, Conf *conf) { /* Do nothing, therefore no auth. */ } -const int platform_uses_x11_unix_by_default = true; +const bool platform_uses_x11_unix_by_default = true; /* ---------------------------------------------------------------------- * File access abstraction. @@ -131,10 +131,8 @@ RFile *open_existing_file(const char *name, uint64_t *size, int read_from_file(RFile *f, void *buffer, int length) { - int ret; DWORD read; - ret = ReadFile(f->h, buffer, length, &read, NULL); - if (!ret) + if (!ReadFile(f->h, buffer, length, &read, NULL)) return -1; /* error */ else return read; @@ -190,10 +188,8 @@ WFile *open_existing_wfile(const char *name, uint64_t *size) int write_to_file(WFile *f, void *buffer, int length) { - int ret; DWORD written; - ret = WriteFile(f->h, buffer, length, &written, NULL); - if (!ret) + if (!WriteFile(f->h, buffer, length, &written, NULL)) return -1; /* error */ else return written; @@ -296,8 +292,7 @@ char *read_filename(DirHandle *dir) if (!dir->name) { WIN32_FIND_DATA fdat; - int ok = FindNextFile(dir->h, &fdat); - if (!ok) + if (!FindNextFile(dir->h, &fdat)) return NULL; else dir->name = dupstr(fdat.cFileName); @@ -329,7 +324,7 @@ void close_directory(DirHandle *dir) sfree(dir); } -int test_wildcard(const char *name, int cmdline) +int test_wildcard(const char *name, bool cmdline) { HANDLE fh; WIN32_FIND_DATA fdat; @@ -353,7 +348,7 @@ struct WildcardMatcher { char *srcpath; }; -char *stripslashes(const char *str, int local) +char *stripslashes(const char *str, bool local) { char *p; @@ -391,7 +386,7 @@ WildcardMatcher *begin_wildcard_matching(const char *name) ret = snew(WildcardMatcher); ret->h = h; ret->srcpath = dupstr(name); - last = stripslashes(ret->srcpath, 1); + last = stripslashes(ret->srcpath, true); *last = '\0'; if (fdat.cFileName[0] == '.' && (fdat.cFileName[1] == '\0' || @@ -407,9 +402,8 @@ char *wildcard_get_filename(WildcardMatcher *dir) { while (!dir->name) { WIN32_FIND_DATA fdat; - int ok = FindNextFile(dir->h, &fdat); - if (!ok) + if (!FindNextFile(dir->h, &fdat)) return NULL; if (fdat.cFileName[0] == '.' && @@ -437,7 +431,7 @@ void finish_wildcard_matching(WildcardMatcher *dir) sfree(dir); } -int vet_filename(const char *name) +bool vet_filename(const char *name) { if (strchr(name, '/') || strchr(name, '\\') || strchr(name, ':')) return false; @@ -448,7 +442,7 @@ int vet_filename(const char *name) return true; } -int create_directory(const char *name) +bool create_directory(const char *name) { return CreateDirectory(name, NULL) != 0; } @@ -467,7 +461,7 @@ char *dir_file_cat(const char *dir, const char *file) */ static SOCKET sftp_ssh_socket = INVALID_SOCKET; static HANDLE netevent = INVALID_HANDLE_VALUE; -char *do_select(SOCKET skt, int startup) +char *do_select(SOCKET skt, bool startup) { int events; if (startup) @@ -702,7 +696,7 @@ static DWORD WINAPI command_read_thread(void *param) return 0; } -char *ssh_sftp_get_cmdline(const char *prompt, int no_fds_ok) +char *ssh_sftp_get_cmdline(const char *prompt, bool no_fds_ok) { int ret; struct command_read_ctx actx, *ctx = &actx; diff --git a/windows/winshare.c b/windows/winshare.c index 864dd9c6..5d98cc17 100644 --- a/windows/winshare.c +++ b/windows/winshare.c @@ -121,7 +121,7 @@ Socket *new_named_pipe_listener(const char *pipename, Plug *plug); int platform_ssh_share(const char *pi_name, Conf *conf, Plug *downplug, Plug *upplug, Socket **sock, char **logtext, char **ds_err, char **us_err, - int can_upstream, int can_downstream) + bool can_upstream, bool can_downstream) { char *name, *mutexname, *pipename; HANDLE mutex; diff --git a/windows/winstore.c b/windows/winstore.c index 52f9b337..5c9d1704 100644 --- a/windows/winstore.c +++ b/windows/winstore.c @@ -24,14 +24,14 @@ static const char *const puttystr = PUTTY_REG_POS "\\Sessions"; static const char hex[16] = "0123456789ABCDEF"; -static int tried_shgetfolderpath = false; +static bool tried_shgetfolderpath = false; static HMODULE shell32_module = NULL; DECL_WINDOWS_FUNCTION(static, HRESULT, SHGetFolderPathA, (HWND, int, HANDLE, DWORD, LPSTR)); static void mungestr(const char *in, char *out) { - int candot = 0; + bool candot = false; while (*in) { if (*in == ' ' || *in == '\\' || *in == '*' || *in == '?' || @@ -43,7 +43,7 @@ static void mungestr(const char *in, char *out) } else *out++ = *in; in++; - candot = 1; + candot = true; } *out = '\0'; return; @@ -470,7 +470,7 @@ int verify_host_key(const char *hostname, int port, return 0; /* key matched OK in registry */ } -int have_ssh_host_key(const char *hostname, int port, +bool have_ssh_host_key(const char *hostname, int port, const char *keytype) { /* @@ -503,7 +503,7 @@ void store_host_key(const char *hostname, int port, * Open (or delete) the random seed file. */ enum { DEL, OPEN_R, OPEN_W }; -static int try_random_seed(char const *path, int action, HANDLE *ret) +static bool try_random_seed(char const *path, int action, HANDLE *ret) { if (action == DEL) { if (!DeleteFile(path) && GetLastError() != ERROR_FILE_NOT_FOUND) { diff --git a/windows/winstuff.h b/windows/winstuff.h index d71663c3..bbba4c3b 100644 --- a/windows/winstuff.h +++ b/windows/winstuff.h @@ -44,12 +44,12 @@ struct Filename { struct FontSpec { char *name; - int isbold; + bool isbold; int height; int charset; }; -struct FontSpec *fontspec_new(const char *name, - int bold, int height, int charset); +struct FontSpec *fontspec_new( + const char *name, bool bold, int height, int charset); #ifndef CLEARTYPE_QUALITY #define CLEARTYPE_QUALITY 5 @@ -228,7 +228,7 @@ GLOBAL HINSTANCE hinst; */ void init_help(void); void shutdown_help(void); -int has_help(void); +bool has_help(void); void launch_help(HWND hwnd, const char *topic); void quit_help(HWND hwnd); @@ -259,7 +259,7 @@ int win_seat_confirm_weak_cached_hostkey( * which takes the data string in the system code page instead of * Unicode. */ -void write_aclip(int clipboard, char *, int, int); +void write_aclip(int clipboard, char *, int, bool); #define WM_NETEVENT (WM_APP + 5) @@ -331,7 +331,7 @@ DECL_WINDOWS_FUNCTION(GLOBAL, int, select, fd_set FAR *, const struct timeval FAR *)); #endif -extern int socket_writable(SOCKET skt); +extern bool socket_writable(SOCKET skt); extern void socket_reselect_all(void); @@ -354,7 +354,7 @@ void init_common_controls(void); /* also does some DLL-loading */ * Exports from winutils.c. */ typedef struct filereq_tag filereq; /* cwd for file requester */ -BOOL request_file(filereq *state, OPENFILENAME *of, int preserve, int save); +bool request_file(filereq *state, OPENFILENAME *of, bool preserve, bool save); filereq *filereq_new(void); void filereq_free(filereq *state); int message_box(LPCTSTR text, LPCTSTR caption, DWORD style, DWORD helpctxid); @@ -369,7 +369,7 @@ struct prefslist { int listid, upbid, dnbid; int srcitem; int dummyitem; - int dragging; + bool dragging; }; /* @@ -384,13 +384,17 @@ struct dlgparam { char *errtitle; /* title of error sub-messageboxes */ void *data; /* data to pass in refresh events */ union control *focused, *lastfocused; /* which ctrl has focus now/before */ - char shortcuts[128]; /* track which shortcuts in use */ - int coloursel_wanted; /* has an event handler asked for + bool shortcuts[128]; /* track which shortcuts in use */ + bool coloursel_wanted; /* has an event handler asked for * a colour selector? */ - struct { unsigned char r, g, b, ok; } coloursel_result; /* 0-255 */ + struct { + unsigned char r, g, b; /* 0-255 */ + bool ok; + } coloursel_result; tree234 *privdata; /* stores per-control private data */ - int ended, endresult; /* has the dialog been ended? */ - int fixed_pitch_fonts; /* are we constrained to fixed fonts? */ + bool ended; /* has the dialog been ended? */ + int endresult; /* and if so, what was the result? */ + bool fixed_pitch_fonts; /* are we constrained to fixed fonts? */ }; /* @@ -403,7 +407,7 @@ HWND doctl(struct ctlpos *cp, RECT r, void bartitle(struct ctlpos *cp, char *name, int id); void beginbox(struct ctlpos *cp, char *name, int idbox); void endbox(struct ctlpos *cp); -void editboxfw(struct ctlpos *cp, int password, char *text, +void editboxfw(struct ctlpos *cp, bool password, char *text, int staticid, int editid); void radioline(struct ctlpos *cp, char *text, int id, int nacross, ...); void bareradioline(struct ctlpos *cp, int nacross, ...); @@ -440,7 +444,7 @@ void prefslist(struct prefslist *hdl, struct ctlpos *cp, int lines, char *stext, int sid, int listid, int upbid, int dnbid); int handle_prefslist(struct prefslist *hdl, int *array, int maxmemb, - int is_dlmsg, HWND hwnd, + bool is_dlmsg, HWND hwnd, WPARAM wParam, LPARAM lParam); void progressbar(struct ctlpos *cp, int id); void fwdsetter(struct ctlpos *cp, int listid, char *stext, int sid, @@ -450,8 +454,8 @@ void fwdsetter(struct ctlpos *cp, int listid, char *stext, int sid, char *r1text, int r1id, char *r2text, int r2id); void dlg_auto_set_fixed_pitch_flag(dlgparam *dlg); -int dlg_get_fixed_pitch_flag(dlgparam *dlg); -void dlg_set_fixed_pitch_flag(dlgparam *dlg, int flag); +bool dlg_get_fixed_pitch_flag(dlgparam *dlg); +void dlg_set_fixed_pitch_flag(dlgparam *dlg, bool flag); #define MAX_SHORTCUTS_PER_CTRL 16 @@ -503,10 +507,10 @@ struct winctrl *winctrl_findbyid(struct winctrls *, int); struct winctrl *winctrl_findbyindex(struct winctrls *, int); void winctrl_layout(struct dlgparam *dp, struct winctrls *wc, struct ctlpos *cp, struct controlset *s, int *id); -int winctrl_handle_command(struct dlgparam *dp, UINT msg, - WPARAM wParam, LPARAM lParam); +bool winctrl_handle_command(struct dlgparam *dp, UINT msg, + WPARAM wParam, LPARAM lParam); void winctrl_rem_shortcuts(struct dlgparam *dp, struct winctrl *c); -int winctrl_context_help(struct dlgparam *dp, HWND hwnd, int id); +bool winctrl_context_help(struct dlgparam *dp, HWND hwnd, int id); void dp_init(struct dlgparam *dp); void dp_add_tree(struct dlgparam *dp, struct winctrls *tree); @@ -515,15 +519,15 @@ void dp_cleanup(struct dlgparam *dp); /* * Exports from wincfg.c. */ -void win_setup_config_box(struct controlbox *b, HWND *hwndp, int has_help, - int midsession, int protocol); +void win_setup_config_box(struct controlbox *b, HWND *hwndp, bool has_help, + bool midsession, int protocol); /* * Exports from windlg.c. */ void defuse_showwindow(void); -int do_config(void); -int do_reconfig(HWND, int); +bool do_config(void); +bool do_reconfig(HWND, int); void showeventlog(HWND); void showabout(HWND); void force_normal(HWND hwnd); @@ -539,7 +543,7 @@ void dll_hijacking_protection(void); HMODULE load_system32_dll(const char *libname); const char *win_strerror(int error); void restrict_process_acl(void); -GLOBAL int restricted_acl; +GLOBAL bool restricted_acl; /* A few pieces of up-to-date Windows API definition needed for older * compilers. */ @@ -561,7 +565,7 @@ DECLSPEC_IMPORT DLL_DIRECTORY_COOKIE WINAPI AddDllDirectory (PCWSTR NewDirectory * Exports from sizetip.c. */ void UpdateSizeTip(HWND src, int cx, int cy); -void EnableSizeTip(int bEnable); +void EnableSizeTip(bool bEnable); /* * Exports from unicode.c. @@ -617,12 +621,12 @@ extern const struct BackendVtable serial_backend; void add_session_to_jumplist(const char * const sessionname); void remove_session_from_jumplist(const char * const sessionname); void clear_jumplist(void); -BOOL set_explicit_app_user_model_id(); +bool set_explicit_app_user_model_id(); /* * Exports from winnoise.c. */ -int win_read_random(void *buf, unsigned wanted); /* returns true on success */ +bool win_read_random(void *buf, unsigned wanted); /* returns true on success */ /* * Extra functions in winstore.c over and above the interface in diff --git a/windows/winucs.c b/windows/winucs.c index f40444c9..7195081a 100644 --- a/windows/winucs.c +++ b/windows/winucs.c @@ -440,7 +440,7 @@ static void link_font(WCHAR * line_tbl, WCHAR * font_tbl, WCHAR attr); void init_ucs(Conf *conf, struct unicode_data *ucsdata) { int i, j; - int used_dtf = 0; + bool used_dtf = false; int vtmode; /* Decide on the Line and Font codepages */ @@ -449,13 +449,13 @@ void init_ucs(Conf *conf, struct unicode_data *ucsdata) if (ucsdata->font_codepage <= 0) { ucsdata->font_codepage=0; - ucsdata->dbcs_screenfont=0; + ucsdata->dbcs_screenfont=false; } vtmode = conf_get_int(conf, CONF_vtmode); if (vtmode == VT_OEMONLY) { ucsdata->font_codepage = 437; - ucsdata->dbcs_screenfont = 0; + ucsdata->dbcs_screenfont = false; if (ucsdata->line_codepage <= 0) ucsdata->line_codepage = GetACP(); } else if (ucsdata->line_codepage <= 0) @@ -493,7 +493,7 @@ void init_ucs(Conf *conf, struct unicode_data *ucsdata) vtmode == VT_POORMAN || ucsdata->font_codepage==0)) { /* For DBCS and POOR fonts force direct to font */ - used_dtf = 1; + used_dtf = true; for (i = 0; i < 32; i++) ucsdata->unitab_line[i] = (WCHAR) i; for (i = 32; i < 256; i++) @@ -1201,7 +1201,7 @@ int mb_to_wc(int codepage, int flags, const char *mbstr, int mblen, return MultiByteToWideChar(codepage, flags, mbstr, mblen, wcstr, wclen); } -int is_dbcs_leadbyte(int codepage, char byte) +bool is_dbcs_leadbyte(int codepage, char byte) { return IsDBCSLeadByteEx(codepage, byte); } diff --git a/windows/winutils.c b/windows/winutils.c index 58614966..5edde65b 100644 --- a/windows/winutils.c +++ b/windows/winutils.c @@ -34,17 +34,17 @@ struct filereq_tag { * save==1 -> GetSaveFileName; save==0 -> GetOpenFileName * `state' is optional. */ -BOOL request_file(filereq *state, OPENFILENAME *of, int preserve, int save) +bool request_file(filereq *state, OPENFILENAME *of, bool preserve, bool save) { TCHAR cwd[MAX_PATH]; /* process CWD */ - BOOL ret; + bool ret; /* Get process CWD */ if (preserve) { DWORD r = GetCurrentDirectory(lenof(cwd), cwd); if (r == 0 || r >= lenof(cwd)) /* Didn't work, oh well. Stop trying to be clever. */ - preserve = 0; + preserve = false; } /* Open the file requester, maybe setting lpstrInitialDir */ @@ -321,7 +321,7 @@ void split_into_argv(char *cmdline, int *argc, char ***argv, p = cmdline; q = outputline; outputargc = 0; while (*p) { - int quote; + bool quote; /* Skip whitespace searching for start of argument. */ while (*p && isspace(*p)) p++; @@ -331,7 +331,7 @@ void split_into_argv(char *cmdline, int *argc, char ***argv, outputargv[outputargc] = q; outputargstart[outputargc] = p; outputargc++; - quote = 0; + quote = false; /* Copy data into the argument until it's finished. */ while (*p) { diff --git a/windows/winx11.c b/windows/winx11.c index eb15b39a..e85fe4fb 100644 --- a/windows/winx11.c +++ b/windows/winx11.c @@ -16,4 +16,4 @@ void platform_get_x11_auth(struct X11Display *disp, Conf *conf) x11_get_auth_from_authfile(disp, xauthpath); } -const int platform_uses_x11_unix_by_default = false; +const bool platform_uses_x11_unix_by_default = false; diff --git a/x11fwd.c b/x11fwd.c index 4f1bb45c..b0bfa3c1 100644 --- a/x11fwd.c +++ b/x11fwd.c @@ -34,9 +34,9 @@ typedef struct X11Connection { char *auth_protocol; unsigned char *auth_data; int data_read, auth_plen, auth_psize, auth_dlen, auth_dsize; - int verified; - int input_wanted; - int no_data_sent_to_x_client; + bool verified; + bool input_wanted; + bool no_data_sent_to_x_client; char *peer_addr; int peer_port; SshChannel *c; /* channel structure held by SSH backend */ @@ -302,7 +302,8 @@ struct X11Display *x11_setup_display(const char *display, Conf *conf, if (!err) { /* Create trial connection to see if there is a useful Unix-domain * socket */ - Socket *s = sk_new(sk_addr_dup(ux), 0, 0, 0, 0, 0, nullplug); + Socket *s = sk_new(sk_addr_dup(ux), 0, false, false, + false, false, nullplug); err = sk_socket_error(s); sk_close(s); } @@ -469,7 +470,7 @@ void x11_get_auth_from_authfile(struct X11Display *disp, ptrlen addr, protoname, data; char *displaynum_string; int displaynum; - int ideal_match = false; + bool ideal_match = false; char *ourhostname; /* A maximally sized (wildly implausible) .Xauthority record @@ -502,7 +503,7 @@ void x11_get_auth_from_authfile(struct X11Display *disp, * that is; so if we can't find a Unix-domain-socket entry we'll * fall back to an IP-based entry if we can find one. */ - int localhost = !disp->unixdomain && sk_address_is_local(disp->addr); + bool localhost = !disp->unixdomain && sk_address_is_local(disp->addr); authfp = fopen(authfilename, "rb"); if (!authfp) @@ -527,7 +528,7 @@ void x11_get_auth_from_authfile(struct X11Display *disp, BinarySource_BARE_INIT(src, buf, size); while (!ideal_match) { - int match = false; + bool match = false; if (src->pos >= MAX_RECORD_SIZE) { size -= src->pos; @@ -617,10 +618,12 @@ void x11_get_auth_from_authfile(struct X11Display *disp, break; case 256: /* Unix-domain / localhost */ if ((disp->unixdomain || localhost) - && ourhostname && ptrlen_eq_string(addr, ourhostname)) + && ourhostname && ptrlen_eq_string(addr, ourhostname)) { /* A matching Unix-domain socket is always the best * match. */ - match = ideal_match = true; + match = true; + ideal_match = true; + } break; } @@ -683,7 +686,7 @@ static void x11_send_init_error(struct X11Connection *conn, const char *err_message); static void x11_closing(Plug *plug, const char *error_msg, int error_code, - int calling_back) + bool calling_back) { struct X11Connection *xconn = container_of( plug, struct X11Connection, plug); @@ -759,9 +762,9 @@ static const PlugVtable X11Connection_plugvt = { }; static void x11_chan_free(Channel *chan); -static int x11_send(Channel *chan, int is_stderr, const void *vdata, int len); +static int x11_send(Channel *chan, bool is_stderr, const void *vdata, int len); static void x11_send_eof(Channel *chan); -static void x11_set_input_wanted(Channel *chan, int wanted); +static void x11_set_input_wanted(Channel *chan, bool wanted); static char *x11_log_close_msg(Channel *chan); static const struct ChannelVtable X11Connection_channelvt = { @@ -795,7 +798,7 @@ static const struct ChannelVtable X11Connection_channelvt = { */ Channel *x11_new_channel(tree234 *authtree, SshChannel *c, const char *peeraddr, int peerport, - int connection_sharing_possible) + bool connection_sharing_possible) { struct X11Connection *xconn; @@ -809,7 +812,7 @@ Channel *x11_new_channel(tree234 *authtree, SshChannel *c, (connection_sharing_possible ? 128 : 0); xconn->auth_protocol = NULL; xconn->authtree = authtree; - xconn->verified = 0; + xconn->verified = false; xconn->data_read = 0; xconn->input_wanted = true; xconn->no_data_sent_to_x_client = true; @@ -852,7 +855,7 @@ static void x11_chan_free(Channel *chan) sfree(xconn); } -static void x11_set_input_wanted(Channel *chan, int wanted) +static void x11_set_input_wanted(Channel *chan, bool wanted) { assert(chan->vt == &X11Connection_channelvt); X11Connection *xconn = container_of(chan, X11Connection, chan); @@ -887,7 +890,7 @@ static void x11_send_init_error(struct X11Connection *xconn, sfree(full_message); } -static int x11_parse_ip(const char *addr_string, unsigned long *ip) +static bool x11_parse_ip(const char *addr_string, unsigned long *ip) { /* @@ -907,7 +910,7 @@ static int x11_parse_ip(const char *addr_string, unsigned long *ip) /* * Called to send data down the raw connection. */ -static int x11_send(Channel *chan, int is_stderr, const void *vdata, int len) +static int x11_send(Channel *chan, bool is_stderr, const void *vdata, int len) { assert(chan->vt == &X11Connection_channelvt); X11Connection *xconn = container_of(chan, X11Connection, chan); @@ -1010,7 +1013,7 @@ static int x11_send(Channel *chan, int is_stderr, const void *vdata, int len) xconn->disp = auth_matched->disp; xconn->s = new_connection(sk_addr_dup(xconn->disp->addr), xconn->disp->realhost, xconn->disp->port, - 0, 1, 0, 0, &xconn->plug, + false, true, false, false, &xconn->plug, sshfwd_get_conf(xconn->c)); if ((err = sk_socket_error(xconn->s)) != NULL) { char *err_message = dupprintf("unable to connect to" @@ -1051,7 +1054,7 @@ static int x11_send(Channel *chan, int is_stderr, const void *vdata, int len) /* * Now we're done. */ - xconn->verified = 1; + xconn->verified = true; } /* From f9cb4eb568ac5527a47dc01bf364f0a963b4dc04 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Fri, 26 Oct 2018 23:08:50 +0100 Subject: [PATCH 590/607] Make a few small helper functions inline. Notably toint(), which ought to compile down to the identity function in any case so you don't really want to put in a pointless call overhead, and make_ptrlen() (and a couple of its wrappers) which is standing in for what ought to be a struct-literal syntax. --- misc.c | 41 ----------------------------------------- misc.h | 46 ++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 42 insertions(+), 45 deletions(-) diff --git a/misc.c b/misc.c index c11b2621..25ed8636 100644 --- a/misc.c +++ b/misc.c @@ -349,29 +349,6 @@ void burnstr(char *string) /* sfree(str), only clear it first */ } } -int toint(unsigned u) -{ - /* - * Convert an unsigned to an int, without running into the - * undefined behaviour which happens by the strict C standard if - * the value overflows. You'd hope that sensible compilers would - * do the sensible thing in response to a cast, but actually I - * don't trust modern compilers not to do silly things like - * assuming that _obviously_ you wouldn't have caused an overflow - * and so they can elide an 'if (i < 0)' test immediately after - * the cast. - * - * Sensible compilers ought of course to optimise this entire - * function into 'just return the input value'! - */ - if (u <= (unsigned)INT_MAX) - return (int)u; - else if (u >= (unsigned)INT_MIN) /* wrap in cast _to_ unsigned is OK */ - return INT_MIN + (int)(u - (unsigned)INT_MIN); - else - return INT_MIN; /* fallback; should never occur on binary machines */ -} - int string_length_for_printf(size_t s) { /* Truncate absurdly long strings (should one show up) to fit @@ -1235,24 +1212,6 @@ int nullstrcmp(const char *a, const char *b) return strcmp(a, b); } -ptrlen make_ptrlen(const void *ptr, size_t len) -{ - ptrlen pl; - pl.ptr = ptr; - pl.len = len; - return pl; -} - -ptrlen ptrlen_from_asciz(const char *str) -{ - return make_ptrlen(str, strlen(str)); -} - -ptrlen ptrlen_from_strbuf(strbuf *sb) -{ - return make_ptrlen(sb->u, sb->len); -} - bool ptrlen_eq_string(ptrlen pl, const char *str) { size_t len = strlen(str); diff --git a/misc.h b/misc.h index 5d493c48..2302fbbc 100644 --- a/misc.h +++ b/misc.h @@ -12,6 +12,7 @@ #include /* for FILE * */ #include /* for va_list */ #include /* for struct tm */ +#include /* for INT_MAX/MIN */ unsigned long parse_blocksize(const char *bs); char ctrlparse(char *s, char **next); @@ -57,7 +58,29 @@ void strbuf_finalise_agent_query(strbuf *buf); wchar_t *dup_mb_to_wc_c(int codepage, int flags, const char *string, int len); wchar_t *dup_mb_to_wc(int codepage, int flags, const char *string); -int toint(unsigned); +static inline int toint(unsigned u) +{ + /* + * Convert an unsigned to an int, without running into the + * undefined behaviour which happens by the strict C standard if + * the value overflows. You'd hope that sensible compilers would + * do the sensible thing in response to a cast, but actually I + * don't trust modern compilers not to do silly things like + * assuming that _obviously_ you wouldn't have caused an overflow + * and so they can elide an 'if (i < 0)' test immediately after + * the cast. + * + * Sensible compilers ought of course to optimise this entire + * function into 'just return the input value', and since it's + * also declared inline, elide it completely in their output. + */ + if (u <= (unsigned)INT_MAX) + return (int)u; + else if (u >= (unsigned)INT_MIN) /* wrap in cast _to_ unsigned is OK */ + return INT_MIN + (int)(u - (unsigned)INT_MIN); + else + return INT_MIN; /* fallback; should never occur on binary machines */ +} char *fgetline(FILE *fp); char *chomp(char *str); @@ -96,9 +119,24 @@ struct tm ltime(void); */ int nullstrcmp(const char *a, const char *b); -ptrlen make_ptrlen(const void *ptr, size_t len); -ptrlen ptrlen_from_asciz(const char *str); -ptrlen ptrlen_from_strbuf(strbuf *sb); +static inline ptrlen make_ptrlen(const void *ptr, size_t len) +{ + ptrlen pl; + pl.ptr = ptr; + pl.len = len; + return pl; +} + +static inline ptrlen ptrlen_from_asciz(const char *str) +{ + return make_ptrlen(str, strlen(str)); +} + +static inline ptrlen ptrlen_from_strbuf(strbuf *sb) +{ + return make_ptrlen(sb->u, sb->len); +} + bool ptrlen_eq_string(ptrlen pl, const char *str); bool ptrlen_eq_ptrlen(ptrlen pl1, ptrlen pl2); bool ptrlen_startswith(ptrlen whole, ptrlen prefix, ptrlen *tail); From 3933a27d932fd8ec4aa416d43a2ab8c69a8e7f52 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 3 Nov 2018 08:17:44 +0000 Subject: [PATCH 591/607] Make send_raw_mouse a field of GtkFrontend. I came across this unexplained static variable in my boolification trawl. It seems clearly unintentional that it has only one instance instead of one per terminal window - the code in question closely resembles the Windows front end, and I think this must just be a variable that I never swept up into 'inst' in the very early days when I was making gtkwin.c out of a cloned-and-hacked window.c in the first place. These days it's even a bug, now that the OS X port actually does run multiple terminal windows in the same process: if one goes into mouse reporting mode, I'm pretty sure this would have done confusing things to the effects of mouse actions in the other. --- unix/gtkwin.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/unix/gtkwin.c b/unix/gtkwin.c index 67068f06..c4269dd5 100644 --- a/unix/gtkwin.c +++ b/unix/gtkwin.c @@ -181,6 +181,7 @@ struct GtkFrontend { #ifdef OSX_META_KEY_CONFIG int system_mod_mask; #endif + bool send_raw_mouse; unifont_drawctx uctx; Seat seat; @@ -205,8 +206,6 @@ static void cache_conf_values(GtkFrontend *inst) #endif } -static bool send_raw_mouse; - static void start_backend(GtkFrontend *inst); static void exit_callback(void *vinst); static void destroy_inst_connection(GtkFrontend *inst); @@ -665,7 +664,7 @@ static void update_mouseptr(GtkFrontend *inst) if (!inst->mouseptr_visible) { gdk_window_set_cursor(gtk_widget_get_window(inst->area), inst->blankcursor); - } else if (send_raw_mouse) { + } else if (inst->send_raw_mouse) { gdk_window_set_cursor(gtk_widget_get_window(inst->area), inst->rawcursor); } else { @@ -2259,9 +2258,9 @@ gboolean scroll_internal(GtkFrontend *inst, gdouble delta, guint state, x = (ex - inst->window_border) / inst->font_width; y = (ey - inst->window_border) / inst->font_height; - raw_mouse_mode = - send_raw_mouse && !(shift && conf_get_bool(inst->conf, - CONF_mouse_override)); + raw_mouse_mode = (inst->send_raw_mouse && + !(shift && conf_get_bool(inst->conf, + CONF_mouse_override))); inst->cumulative_scroll += delta * SCROLL_INCREMENT_LINES; @@ -2311,9 +2310,9 @@ static gboolean button_internal(GtkFrontend *inst, GdkEventButton *event) ctrl = event->state & GDK_CONTROL_MASK; alt = event->state & inst->meta_mod_mask; - raw_mouse_mode = - send_raw_mouse && !(shift && conf_get_bool(inst->conf, - CONF_mouse_override)); + raw_mouse_mode = (inst->send_raw_mouse && + !(shift && conf_get_bool(inst->conf, + CONF_mouse_override))); if (!raw_mouse_mode) { if (event->button == 4 && event->type == GDK_BUTTON_PRESS) { @@ -2607,7 +2606,7 @@ static void gtkwin_set_raw_mouse_mode(TermWin *tw, bool activate) { GtkFrontend *inst = container_of(tw, GtkFrontend, termwin); activate = activate && !conf_get_bool(inst->conf, CONF_no_mouse_rep); - send_raw_mouse = activate; + inst->send_raw_mouse = activate; update_mouseptr(inst); } From 650bfbb084f64a3d5e0dd87626eb7074dff536ec Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 3 Nov 2018 08:28:35 +0000 Subject: [PATCH 592/607] Nitpick: fix missing 'void' in one declaration. Jumped out at me in my trawl of the whole code base: set_explicit_app_user_model_id is declared and defined as () rather than (void), but this isn't C++. --- windows/winjump.c | 2 +- windows/winstuff.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/windows/winjump.c b/windows/winjump.c index 745984ca..d33b5ce0 100644 --- a/windows/winjump.c +++ b/windows/winjump.c @@ -715,7 +715,7 @@ void remove_session_from_jumplist(const char * const sessionname) /* Set Explicit App User Model Id to fix removable media error with jump lists */ -bool set_explicit_app_user_model_id() +bool set_explicit_app_user_model_id(void) { DECL_WINDOWS_FUNCTION(static, HRESULT, SetCurrentProcessExplicitAppUserModelID, (PCWSTR)); diff --git a/windows/winstuff.h b/windows/winstuff.h index bbba4c3b..c5d0ba24 100644 --- a/windows/winstuff.h +++ b/windows/winstuff.h @@ -621,7 +621,7 @@ extern const struct BackendVtable serial_backend; void add_session_to_jumplist(const char * const sessionname); void remove_session_from_jumplist(const char * const sessionname); void clear_jumplist(void); -bool set_explicit_app_user_model_id(); +bool set_explicit_app_user_model_id(void); /* * Exports from winnoise.c. From 9248f5c994ae84daeeb5c1dc25d55c8c290581de Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 3 Nov 2018 08:32:25 +0000 Subject: [PATCH 593/607] winnet.c: remove duplicated errstring system. There's one of these centralised in win_strerror() in winmisc.c, and it doesn't seem worth keeping an earlier iteration of the same idea entirely separate in winsock_error_string. This removal means that non-network-specific error codes received in a network context will no longer have "Network error:" prefixed to them. But I think that's OK, because it seems unlikely to be critically important that such an error was received from a network function - if anything like that comes up then it's probably some kind of systemwide chaos. --- windows/winnet.c | 71 ++---------------------------------------------- 1 file changed, 2 insertions(+), 69 deletions(-) diff --git a/windows/winnet.c b/windows/winnet.c index 2e6b0f03..f26343be 100644 --- a/windows/winnet.c +++ b/windows/winnet.c @@ -351,34 +351,8 @@ void sk_cleanup(void) #endif } -struct errstring { - int error; - char *text; -}; - -static int errstring_find(void *av, void *bv) -{ - int *a = (int *)av; - struct errstring *b = (struct errstring *)bv; - if (*a < b->error) - return -1; - if (*a > b->error) - return +1; - return 0; -} -static int errstring_compare(void *av, void *bv) -{ - struct errstring *a = (struct errstring *)av; - return errstring_find(&a->error, bv); -} - -static tree234 *errstrings = NULL; - const char *winsock_error_string(int error) { - const char prefix[] = "Network error: "; - struct errstring *es; - /* * Error codes we know about and have historically had reasonably * sensible error messages for. @@ -458,50 +432,9 @@ const char *winsock_error_string(int error) } /* - * Generic code to handle any other error. - * - * Slightly nasty hack here: we want to return a static string - * which the caller will never have to worry about freeing, but on - * the other hand if we call FormatMessage to get it then it will - * want to either allocate a buffer or write into one we own. - * - * So what we do is to maintain a tree234 of error strings we've - * already used. New ones are allocated from the heap, but then - * put in this tree and kept forever. + * Handle any other error code by delegating to win_strerror. */ - - if (!errstrings) - errstrings = newtree234(errstring_compare); - - es = find234(errstrings, &error, errstring_find); - - if (!es) { - int bufsize, bufused; - - es = snew(struct errstring); - es->error = error; - /* maximum size for FormatMessage is 64K */ - bufsize = 65535 + sizeof(prefix); - es->text = snewn(bufsize, char); - strcpy(es->text, prefix); - bufused = strlen(es->text); - if (!FormatMessage((FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS), NULL, error, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - es->text + bufused, bufsize - bufused, NULL)) { - sprintf(es->text + bufused, - "Windows error code %d (and FormatMessage returned %u)", - error, (unsigned int)GetLastError()); - } else { - int len = strlen(es->text); - if (len > 0 && es->text[len-1] == '\n') - es->text[len-1] = '\0'; - } - es->text = sresize(es->text, strlen(es->text) + 1, char); - add234(errstrings, es); - } - - return es->text; + return win_strerror(error); } SockAddr *sk_namelookup(const char *host, char **canonicalname, From c089827ea0eda423fc7fbd98519f02185db89e99 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 3 Nov 2018 08:58:41 +0000 Subject: [PATCH 594/607] Rework mungestr() and unmungestr(). For a start, they now have different names on Windows and Unix, reflecting their different roles: on Windows they apply escaping to any string that's going to be used as a registry key (be it a session name, or a host name for host key storage), whereas on Unix they're for constructing saved-session file names in particular (and also handle the special case of filling in "Default Settings" for NULL). Also, they now produce output by writing to a strbuf, which simplifies a lot of the call sites. In particular, the strbuf output idiom is passed on to enum_settings_next, which is especially nice because its only actual caller was doing an ad-hoc realloc loop that I can now get rid of completely. Thirdly, on Windows they're centralised into winmisc.c instead of living in winstore.c, because that way Pageant can use the unescape function too. (It was spotting the duplication there that made me think of doing this in the first place, but once I'd started, I had to keep unravelling the thread...) --- settings.c | 26 +++----- storage.h | 2 +- unix/uxstore.c | 46 +++++--------- windows/winmisc.c | 38 ++++++++++++ windows/winpgnt.c | 36 +++-------- windows/winstore.c | 146 ++++++++++++++++----------------------------- windows/winstuff.h | 2 + 7 files changed, 123 insertions(+), 173 deletions(-) diff --git a/settings.c b/settings.c index 1e945173..5c3f534a 100644 --- a/settings.c +++ b/settings.c @@ -1268,32 +1268,20 @@ static int sessioncmp(const void *av, const void *bv) void get_sesslist(struct sesslist *list, bool allocate) { - char otherbuf[2048]; - int buflen, bufsize, i; - char *p, *ret; + int i; + char *p; settings_e *handle; if (allocate) { + strbuf *sb = strbuf_new(); - buflen = bufsize = 0; - list->buffer = NULL; if ((handle = enum_settings_start()) != NULL) { - do { - ret = enum_settings_next(handle, otherbuf, sizeof(otherbuf)); - if (ret) { - int len = strlen(otherbuf) + 1; - if (bufsize < buflen + len) { - bufsize = buflen + len + 2048; - list->buffer = sresize(list->buffer, bufsize, char); - } - strcpy(list->buffer + buflen, otherbuf); - buflen += strlen(list->buffer + buflen) + 1; - } - } while (ret); + while (enum_settings_next(handle, sb)) + put_byte(sb, '\0'); enum_settings_finish(handle); } - list->buffer = sresize(list->buffer, buflen + 1, char); - list->buffer[buflen] = '\0'; + put_byte(sb, '\0'); + list->buffer = strbuf_to_str(sb); /* * Now set up the list of sessions. Note that "Default diff --git a/storage.h b/storage.h index 6186e91d..41e4b5c9 100644 --- a/storage.h +++ b/storage.h @@ -69,7 +69,7 @@ void del_settings(const char *sessionname); * Enumerate all saved sessions. */ settings_e *enum_settings_start(void); -char *enum_settings_next(settings_e *handle, char *buffer, int buflen); +bool enum_settings_next(settings_e *handle, strbuf *out); void enum_settings_finish(settings_e *handle); /* ---------------------------------------------------------------------- diff --git a/unix/uxstore.c b/unix/uxstore.c index 0d0c582e..409a5787 100644 --- a/unix/uxstore.c +++ b/unix/uxstore.c @@ -33,15 +33,11 @@ enum { static const char hex[16] = "0123456789ABCDEF"; -static char *mungestr(const char *in) +static void make_session_filename(const char *in, strbuf *out) { - char *out, *ret; - if (!in || !*in) in = "Default Settings"; - ret = out = snewn(3*strlen(in)+1, char); - while (*in) { /* * There are remarkably few punctuation characters that @@ -54,21 +50,17 @@ static char *mungestr(const char *in) !(*in >= '0' && *in <= '9') && !(*in >= 'A' && *in <= 'Z') && !(*in >= 'a' && *in <= 'z')) { - *out++ = '%'; - *out++ = hex[((unsigned char) *in) >> 4]; - *out++ = hex[((unsigned char) *in) & 15]; + put_byte(out, '%'); + put_byte(out, hex[((unsigned char) *in) >> 4]); + put_byte(out, hex[((unsigned char) *in) & 15]); } else - *out++ = *in; + put_byte(out, *in); in++; } - *out = '\0'; - return ret; } -static char *unmungestr(const char *in) +static void decode_session_filename(const char *in, strbuf *out) { - char *out, *ret; - out = ret = snewn(strlen(in)+1, char); while (*in) { if (*in == '%' && in[1] && in[2]) { int i, j; @@ -78,14 +70,12 @@ static char *unmungestr(const char *in) j = in[2] - '0'; j -= (j > 9 ? 7 : 0); - *out++ = (i << 4) + j; + put_byte(out, (i << 4) + j); in += 3; } else { - *out++ = *in++; + put_byte(out, *in++); } } - *out = '\0'; - return ret; } static char *make_filename(int index, const char *subname) @@ -181,12 +171,12 @@ static char *make_filename(int index, const char *subname) return ret; } if (index == INDEX_SESSION) { - char *munged = mungestr(subname); + strbuf *sb = strbuf_new(); tmp = make_filename(INDEX_SESSIONDIR, NULL); - ret = dupprintf("%s/%s", tmp, munged); + strbuf_catf(sb, "%s/", tmp); sfree(tmp); - sfree(munged); - return ret; + make_session_filename(subname, sb); + return strbuf_to_str(sb); } if (index == INDEX_HOSTKEYS) { env = getenv("PUTTYSSHHOSTKEYS"); @@ -554,13 +544,12 @@ settings_e *enum_settings_start(void) return toret; } -char *enum_settings_next(settings_e *handle, char *buffer, int buflen) +bool enum_settings_next(settings_e *handle, strbuf *out) { struct dirent *de; struct stat st; char *fullpath; int maxlen, thislen, len; - char *unmunged; if (!handle->dp) return NULL; @@ -581,16 +570,13 @@ char *enum_settings_next(settings_e *handle, char *buffer, int buflen) if (stat(fullpath, &st) < 0 || !S_ISREG(st.st_mode)) continue; /* try another one */ - unmunged = unmungestr(de->d_name); - strncpy(buffer, unmunged, buflen); - buffer[buflen-1] = '\0'; - sfree(unmunged); + decode_session_filename(de->d_name, out); sfree(fullpath); - return buffer; + return true; } sfree(fullpath); - return NULL; + return false; } void enum_settings_finish(settings_e *handle) diff --git a/windows/winmisc.c b/windows/winmisc.c index bf60d4a5..86f413e8 100644 --- a/windows/winmisc.c +++ b/windows/winmisc.c @@ -625,3 +625,41 @@ bool open_for_write_would_lose_data(const Filename *fn) } return true; } + +void escape_registry_key(const char *in, strbuf *out) +{ + bool candot = false; + static const char hex[16] = "0123456789ABCDEF"; + + while (*in) { + if (*in == ' ' || *in == '\\' || *in == '*' || *in == '?' || + *in == '%' || *in < ' ' || *in > '~' || (*in == '.' + && !candot)) { + put_byte(out, '%'); + put_byte(out, hex[((unsigned char) *in) >> 4]); + put_byte(out, hex[((unsigned char) *in) & 15]); + } else + put_byte(out, *in); + in++; + candot = true; + } +} + +void unescape_registry_key(const char *in, strbuf *out) +{ + while (*in) { + if (*in == '%' && in[1] && in[2]) { + int i, j; + + i = in[1] - '0'; + i -= (i > 9 ? 7 : 0); + j = in[2] - '0'; + j -= (j > 9 ? 7 : 0); + + put_byte(out, (i << 4) + j); + in += 3; + } else { + put_byte(out, *in++); + } + } +} diff --git a/windows/winpgnt.c b/windows/winpgnt.c index ff105588..f8320f4a 100644 --- a/windows/winpgnt.c +++ b/windows/winpgnt.c @@ -87,32 +87,6 @@ void modalfatalbox(const char *fmt, ...) exit(1); } -/* Un-munge session names out of the registry. */ -static void unmungestr(char *in, char *out, int outlen) -{ - while (*in) { - if (*in == '%' && in[1] && in[2]) { - int i, j; - - i = in[1] - '0'; - i -= (i > 9 ? 7 : 0); - j = in[2] - '0'; - j -= (j > 9 ? 7 : 0); - - *out++ = (i << 4) + j; - if (!--outlen) - return; - in += 3; - } else { - *out++ = *in++; - if (!--outlen) - return; - } - } - *out = '\0'; - return; -} - /* Stubs needed to link against misc.c */ void queue_idempotent_callback(IdempotentCallback *ic) { assert(0); } @@ -687,6 +661,7 @@ static void update_sessions(void) HKEY hkey; TCHAR buf[MAX_PATH + 1]; MENUITEMINFO mii; + strbuf *sb; int index_key, index_menu; @@ -704,22 +679,25 @@ static void update_sessions(void) index_key = 0; index_menu = 0; + sb = strbuf_new(); while(ERROR_SUCCESS == RegEnumKey(hkey, index_key, buf, MAX_PATH)) { - TCHAR session_name[MAX_PATH + 1]; - unmungestr(buf, session_name, MAX_PATH); if(strcmp(buf, PUTTY_DEFAULT) != 0) { + sb->len = 0; + unescape_registry_key(buf, sb); + memset(&mii, 0, sizeof(mii)); mii.cbSize = sizeof(mii); mii.fMask = MIIM_TYPE | MIIM_STATE | MIIM_ID; mii.fType = MFT_STRING; mii.fState = MFS_ENABLED; mii.wID = (index_menu * 16) + IDM_SESSIONS_BASE; - mii.dwTypeData = session_name; + mii.dwTypeData = sb->s; InsertMenuItem(session_menu, index_menu, true, &mii); index_menu++; } index_key++; } + strbuf_free(sb); RegCloseKey(hkey); diff --git a/windows/winstore.c b/windows/winstore.c index 5c9d1704..3b80e147 100644 --- a/windows/winstore.c +++ b/windows/winstore.c @@ -22,58 +22,11 @@ static const char *const reg_jumplist_key = PUTTY_REG_POS "\\Jumplist"; static const char *const reg_jumplist_value = "Recent sessions"; static const char *const puttystr = PUTTY_REG_POS "\\Sessions"; -static const char hex[16] = "0123456789ABCDEF"; - static bool tried_shgetfolderpath = false; static HMODULE shell32_module = NULL; DECL_WINDOWS_FUNCTION(static, HRESULT, SHGetFolderPathA, (HWND, int, HANDLE, DWORD, LPSTR)); -static void mungestr(const char *in, char *out) -{ - bool candot = false; - - while (*in) { - if (*in == ' ' || *in == '\\' || *in == '*' || *in == '?' || - *in == '%' || *in < ' ' || *in > '~' || (*in == '.' - && !candot)) { - *out++ = '%'; - *out++ = hex[((unsigned char) *in) >> 4]; - *out++ = hex[((unsigned char) *in) & 15]; - } else - *out++ = *in; - in++; - candot = true; - } - *out = '\0'; - return; -} - -static void unmungestr(const char *in, char *out, int outlen) -{ - while (*in) { - if (*in == '%' && in[1] && in[2]) { - int i, j; - - i = in[1] - '0'; - i -= (i > 9 ? 7 : 0); - j = in[2] - '0'; - j -= (j > 9 ? 7 : 0); - - *out++ = (i << 4) + j; - if (!--outlen) - return; - in += 3; - } else { - *out++ = *in++; - if (!--outlen) - return; - } - } - *out = '\0'; - return; -} - struct settings_w { HKEY sesskey; }; @@ -82,32 +35,32 @@ settings_w *open_settings_w(const char *sessionname, char **errmsg) { HKEY subkey1, sesskey; int ret; - char *p; + strbuf *sb; *errmsg = NULL; if (!sessionname || !*sessionname) sessionname = "Default Settings"; - p = snewn(3 * strlen(sessionname) + 1, char); - mungestr(sessionname, p); + sb = strbuf_new(); + escape_registry_key(sessionname, sb); ret = RegCreateKey(HKEY_CURRENT_USER, puttystr, &subkey1); if (ret != ERROR_SUCCESS) { - sfree(p); + strbuf_free(sb); *errmsg = dupprintf("Unable to create registry key\n" "HKEY_CURRENT_USER\\%s", puttystr); return NULL; } - ret = RegCreateKey(subkey1, p, &sesskey); + ret = RegCreateKey(subkey1, sb->s, &sesskey); RegCloseKey(subkey1); if (ret != ERROR_SUCCESS) { *errmsg = dupprintf("Unable to create registry key\n" - "HKEY_CURRENT_USER\\%s\\%s", puttystr, p); - sfree(p); + "HKEY_CURRENT_USER\\%s\\%s", puttystr, sb->s); + strbuf_free(sb); return NULL; } - sfree(p); + strbuf_free(sb); settings_w *toret = snew(settings_w); toret->sesskey = sesskey; @@ -141,24 +94,24 @@ struct settings_r { settings_r *open_settings_r(const char *sessionname) { HKEY subkey1, sesskey; - char *p; + strbuf *sb; if (!sessionname || !*sessionname) sessionname = "Default Settings"; - p = snewn(3 * strlen(sessionname) + 1, char); - mungestr(sessionname, p); + sb = strbuf_new(); + escape_registry_key(sessionname, sb); if (RegOpenKey(HKEY_CURRENT_USER, puttystr, &subkey1) != ERROR_SUCCESS) { sesskey = NULL; } else { - if (RegOpenKey(subkey1, p, &sesskey) != ERROR_SUCCESS) { + if (RegOpenKey(subkey1, sb->s, &sesskey) != ERROR_SUCCESS) { sesskey = NULL; } RegCloseKey(subkey1); } - sfree(p); + strbuf_free(sb); settings_r *toret = snew(settings_r); toret->sesskey = sesskey; @@ -291,15 +244,15 @@ void close_settings_r(settings_r *handle) void del_settings(const char *sessionname) { HKEY subkey1; - char *p; + strbuf *sb; if (RegOpenKey(HKEY_CURRENT_USER, puttystr, &subkey1) != ERROR_SUCCESS) return; - p = snewn(3 * strlen(sessionname) + 1, char); - mungestr(sessionname, p); - RegDeleteKey(subkey1, p); - sfree(p); + sb = strbuf_new(); + escape_registry_key(sessionname, sb); + RegDeleteKey(subkey1, sb->s); + strbuf_free(sb); RegCloseKey(subkey1); @@ -328,18 +281,27 @@ settings_e *enum_settings_start(void) return ret; } -char *enum_settings_next(settings_e *e, char *buffer, int buflen) +bool enum_settings_next(settings_e *e, strbuf *sb) { - char *otherbuf; - otherbuf = snewn(3 * buflen, char); - if (RegEnumKey(e->key, e->i++, otherbuf, 3 * buflen) == ERROR_SUCCESS) { - unmungestr(otherbuf, buffer, buflen); - sfree(otherbuf); - return buffer; - } else { - sfree(otherbuf); - return NULL; + size_t regbuf_size = 256; + char *regbuf = snewn(regbuf_size, char); + bool success; + + while (1) { + DWORD retd = RegEnumKey(e->key, e->i++, regbuf, regbuf_size); + if (retd != ERROR_MORE_DATA) { + success = (retd == ERROR_SUCCESS); + break; + } + regbuf_size = regbuf_size * 5 / 4 + 256; + regbuf = sresize(regbuf, regbuf_size, char); } + + if (success) + unescape_registry_key(regbuf, sb); + + sfree(regbuf); + return success; } void enum_settings_finish(settings_e *e) @@ -348,21 +310,18 @@ void enum_settings_finish(settings_e *e) sfree(e); } -static void hostkey_regname(char *buffer, const char *hostname, +static void hostkey_regname(strbuf *sb, const char *hostname, int port, const char *keytype) { - int len; - strcpy(buffer, keytype); - strcat(buffer, "@"); - len = strlen(buffer); - len += sprintf(buffer + len, "%d:", port); - mungestr(hostname, buffer + strlen(buffer)); + strbuf_catf(sb, "%s@%d:", keytype, port); + escape_registry_key(hostname, sb); } int verify_host_key(const char *hostname, int port, const char *keytype, const char *key) { - char *otherstr, *regname; + char *otherstr; + strbuf *regname; int len; HKEY rkey; DWORD readlen; @@ -375,19 +334,18 @@ int verify_host_key(const char *hostname, int port, * Now read a saved key in from the registry and see what it * says. */ - regname = snewn(3 * (strlen(hostname) + strlen(keytype)) + 15, char); - + regname = strbuf_new(); hostkey_regname(regname, hostname, port, keytype); if (RegOpenKey(HKEY_CURRENT_USER, PUTTY_REG_POS "\\SshHostKeys", &rkey) != ERROR_SUCCESS) { - sfree(regname); + strbuf_free(regname); return 1; /* key does not exist in registry */ } readlen = len; otherstr = snewn(len, char); - ret = RegQueryValueEx(rkey, regname, NULL, + ret = RegQueryValueEx(rkey, regname->s, NULL, &type, (BYTE *)otherstr, &readlen); if (ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA && @@ -397,7 +355,7 @@ int verify_host_key(const char *hostname, int port, * another trick, which is to look up the _old_ key format * under just the hostname and translate that. */ - char *justhost = regname + 1 + strcspn(regname, ":"); + char *justhost = regname->s + 1 + strcspn(regname->s, ":"); char *oldstyle = snewn(len + 10, char); /* safety margin */ readlen = len; ret = RegQueryValueEx(rkey, justhost, NULL, &type, @@ -447,7 +405,7 @@ int verify_host_key(const char *hostname, int port, * wrong, and hyper-cautiously do nothing. */ if (!strcmp(otherstr, key)) - RegSetValueEx(rkey, regname, 0, REG_SZ, (BYTE *)otherstr, + RegSetValueEx(rkey, regname->s, 0, REG_SZ, (BYTE *)otherstr, strlen(otherstr) + 1); } @@ -459,7 +417,7 @@ int verify_host_key(const char *hostname, int port, compare = strcmp(otherstr, key); sfree(otherstr); - sfree(regname); + strbuf_free(regname); if (ret == ERROR_MORE_DATA || (ret == ERROR_SUCCESS && type == REG_SZ && compare)) @@ -483,16 +441,16 @@ bool have_ssh_host_key(const char *hostname, int port, void store_host_key(const char *hostname, int port, const char *keytype, const char *key) { - char *regname; + strbuf *regname; HKEY rkey; - regname = snewn(3 * (strlen(hostname) + strlen(keytype)) + 15, char); - + regname = strbuf_new(); hostkey_regname(regname, hostname, port, keytype); if (RegCreateKey(HKEY_CURRENT_USER, PUTTY_REG_POS "\\SshHostKeys", &rkey) == ERROR_SUCCESS) { - RegSetValueEx(rkey, regname, 0, REG_SZ, (BYTE *)key, strlen(key) + 1); + RegSetValueEx(rkey, regname->s, 0, REG_SZ, + (BYTE *)key, strlen(key) + 1); RegCloseKey(rkey); } /* else key does not exist in registry */ diff --git a/windows/winstuff.h b/windows/winstuff.h index c5d0ba24..4d735af1 100644 --- a/windows/winstuff.h +++ b/windows/winstuff.h @@ -544,6 +544,8 @@ HMODULE load_system32_dll(const char *libname); const char *win_strerror(int error); void restrict_process_acl(void); GLOBAL bool restricted_acl; +void escape_registry_key(const char *in, strbuf *out); +void unescape_registry_key(const char *in, strbuf *out); /* A few pieces of up-to-date Windows API definition needed for older * compilers. */ From 91d16881abf19592737ae31471b9540aeac24e8d Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 3 Nov 2018 08:25:28 +0000 Subject: [PATCH 595/607] Add missing 'static' on file-internal declarations. sk_startup and sk_nextaddr are entirely internal to winnet.c; nearly all of import.c and minibidi.c's internal routines should have been static and weren't; {read,write}_utf8 are internal to charset/utf8.c (and didn't even need separate declarations at all); do_sftp_cleanup is internal to psftp.c, and get_listitemheight to gtkdlg.c. While I was editing those prototypes anyway, I've also added missing 'const' to the 'char *' passphrase parameters in import,c. --- charset/utf8.c | 17 ++++------- import.c | 74 +++++++++++++++++++++++------------------------- minibidi.c | 32 ++++++++++++--------- psftp.c | 4 +-- unix/gtkdlg.c | 4 +-- windows/winnet.c | 4 +-- 6 files changed, 65 insertions(+), 70 deletions(-) diff --git a/charset/utf8.c b/charset/utf8.c index fe46cf98..13c5baa8 100644 --- a/charset/utf8.c +++ b/charset/utf8.c @@ -7,18 +7,13 @@ #include "charset.h" #include "internal.h" -void read_utf8(charset_spec const *, long int, charset_state *, - void (*)(void *, long int), void *); -void write_utf8(charset_spec const *, long int, - charset_state *, void (*)(void *, long int), void *); - /* * UTF-8 has no associated data, so `charset' may be ignored. */ -void read_utf8(charset_spec const *charset, long int input_chr, - charset_state *state, - void (*emit)(void *ctx, long int output), void *emitctx) +static void read_utf8(charset_spec const *charset, long int input_chr, + charset_state *state, + void (*emit)(void *ctx, long int output), void *emitctx) { UNUSEDARG(charset); @@ -186,9 +181,9 @@ void read_utf8(charset_spec const *charset, long int input_chr, * charset_state. */ -void write_utf8(charset_spec const *charset, long int input_chr, - charset_state *state, - void (*emit)(void *ctx, long int output), void *emitctx) +static void write_utf8(charset_spec const *charset, long int input_chr, + charset_state *state, + void (*emit)(void *ctx, long int output), void *emitctx) { UNUSEDARG(charset); UNUSEDARG(state); diff --git a/import.c b/import.c index d88ad2bb..e3ba53c4 100644 --- a/import.c +++ b/import.c @@ -12,26 +12,24 @@ #include "ssh.h" #include "misc.h" -bool openssh_pem_encrypted(const Filename *filename); -bool openssh_new_encrypted(const Filename *filename); -struct ssh2_userkey *openssh_pem_read(const Filename *filename, - char *passphrase, - const char **errmsg_p); -struct ssh2_userkey *openssh_new_read(const Filename *filename, - char *passphrase, - const char **errmsg_p); -bool openssh_auto_write(const Filename *filename, struct ssh2_userkey *key, - char *passphrase); -bool openssh_pem_write(const Filename *filename, struct ssh2_userkey *key, - char *passphrase); -bool openssh_new_write(const Filename *filename, struct ssh2_userkey *key, - char *passphrase); - -bool sshcom_encrypted(const Filename *filename, char **comment); -struct ssh2_userkey *sshcom_read(const Filename *filename, char *passphrase, - const char **errmsg_p); -bool sshcom_write(const Filename *filename, struct ssh2_userkey *key, - char *passphrase); +static bool openssh_pem_encrypted(const Filename *file); +static bool openssh_new_encrypted(const Filename *file); +static struct ssh2_userkey *openssh_pem_read( + const Filename *file, const char *passphrase, const char **errmsg_p); +static struct ssh2_userkey *openssh_new_read( + const Filename *file, const char *passphrase, const char **errmsg_p); +static bool openssh_auto_write( + const Filename *file, struct ssh2_userkey *key, const char *passphrase); +static bool openssh_pem_write( + const Filename *file, struct ssh2_userkey *key, const char *passphrase); +static bool openssh_new_write( + const Filename *file, struct ssh2_userkey *key, const char *passphrase); + +static bool sshcom_encrypted(const Filename *file, char **comment); +static struct ssh2_userkey *sshcom_read( + const Filename *file, const char *passphrase, const char **errmsg_p); +static bool sshcom_write( + const Filename *file, struct ssh2_userkey *key, const char *passphrase); /* * Given a key type, determine whether we know how to import it. @@ -482,7 +480,7 @@ static struct openssh_pem_key *load_openssh_pem_key(const Filename *filename, return NULL; } -bool openssh_pem_encrypted(const Filename *filename) +static bool openssh_pem_encrypted(const Filename *filename) { struct openssh_pem_key *key = load_openssh_pem_key(filename, NULL); bool ret; @@ -496,9 +494,8 @@ bool openssh_pem_encrypted(const Filename *filename) return ret; } -struct ssh2_userkey *openssh_pem_read(const Filename *filename, - char *passphrase, - const char **errmsg_p) +static struct ssh2_userkey *openssh_pem_read( + const Filename *filename, const char *passphrase, const char **errmsg_p) { struct openssh_pem_key *key = load_openssh_pem_key(filename, errmsg_p); struct ssh2_userkey *retkey; @@ -775,8 +772,8 @@ struct ssh2_userkey *openssh_pem_read(const Filename *filename, return retval; } -bool openssh_pem_write(const Filename *filename, struct ssh2_userkey *key, - char *passphrase) +static bool openssh_pem_write( + const Filename *filename, struct ssh2_userkey *key, const char *passphrase) { strbuf *pubblob, *privblob, *outblob; unsigned char *spareblob; @@ -1319,7 +1316,7 @@ static struct openssh_new_key *load_openssh_new_key(const Filename *filename, return NULL; } -bool openssh_new_encrypted(const Filename *filename) +static bool openssh_new_encrypted(const Filename *filename) { struct openssh_new_key *key = load_openssh_new_key(filename, NULL); bool ret; @@ -1334,9 +1331,8 @@ bool openssh_new_encrypted(const Filename *filename) return ret; } -struct ssh2_userkey *openssh_new_read(const Filename *filename, - char *passphrase, - const char **errmsg_p) +static struct ssh2_userkey *openssh_new_read( + const Filename *filename, const char *passphrase, const char **errmsg_p) { struct openssh_new_key *key = load_openssh_new_key(filename, errmsg_p); struct ssh2_userkey *retkey = NULL; @@ -1515,8 +1511,8 @@ struct ssh2_userkey *openssh_new_read(const Filename *filename, return retval; } -bool openssh_new_write(const Filename *filename, struct ssh2_userkey *key, - char *passphrase) +static bool openssh_new_write( + const Filename *filename, struct ssh2_userkey *key, const char *passphrase) { strbuf *pubblob, *privblob, *cblob; int padvalue, i; @@ -1644,8 +1640,8 @@ bool openssh_new_write(const Filename *filename, struct ssh2_userkey *key, * The switch function openssh_auto_write(), which chooses one of the * concrete OpenSSH output formats based on the key type. */ -bool openssh_auto_write(const Filename *filename, struct ssh2_userkey *key, - char *passphrase) +static bool openssh_auto_write( + const Filename *filename, struct ssh2_userkey *key, const char *passphrase) { /* * The old OpenSSH format supports a fixed list of key types. We @@ -1905,7 +1901,7 @@ static struct sshcom_key *load_sshcom_key(const Filename *filename, return NULL; } -bool sshcom_encrypted(const Filename *filename, char **comment) +static bool sshcom_encrypted(const Filename *filename, char **comment) { struct sshcom_key *key = load_sshcom_key(filename, NULL); BinarySource src[1]; @@ -1970,8 +1966,8 @@ static ptrlen BinarySource_get_mp_sshcom_as_string(BinarySource *src) #define get_mp_sshcom_as_string(bs) \ BinarySource_get_mp_sshcom_as_string(BinarySource_UPCAST(bs)) -struct ssh2_userkey *sshcom_read(const Filename *filename, char *passphrase, - const char **errmsg_p) +static struct ssh2_userkey *sshcom_read( + const Filename *filename, const char *passphrase, const char **errmsg_p) { struct sshcom_key *key = load_sshcom_key(filename, errmsg_p); const char *errmsg; @@ -2181,8 +2177,8 @@ struct ssh2_userkey *sshcom_read(const Filename *filename, char *passphrase, return ret; } -bool sshcom_write(const Filename *filename, struct ssh2_userkey *key, - char *passphrase) +static bool sshcom_write( + const Filename *filename, struct ssh2_userkey *key, const char *passphrase) { strbuf *pubblob, *privblob, *outblob; ptrlen numbers[6]; diff --git a/minibidi.c b/minibidi.c index 64f27a96..6838b440 100644 --- a/minibidi.c +++ b/minibidi.c @@ -55,14 +55,15 @@ typedef struct bidi_char { } bidi_char; /* function declarations */ -void flipThisRun(bidi_char *from, unsigned char* level, int max, int count); -int findIndexOfRun(unsigned char* level , int start, int count, int tlevel); -unsigned char getType(int ch); -unsigned char setOverrideBits(unsigned char level, unsigned char override); -int getPreviousLevel(unsigned char* level, int from); -int do_shape(bidi_char *line, bidi_char *to, int count); -int do_bidi(bidi_char *line, int count); -void doMirror(unsigned int *ch); +static void flipThisRun( + bidi_char *from, unsigned char *level, int max, int count); +static int findIndexOfRun( + unsigned char *level, int start, int count, int tlevel); +static unsigned char getType(int ch); +static unsigned char setOverrideBits( + unsigned char level, unsigned char override); +static int getPreviousLevel(unsigned char *level, int from); +static void doMirror(unsigned int *ch); /* character types */ enum { @@ -297,7 +298,8 @@ const shape_node shapetypes[] = { * max: the maximum level found in this line (should be unsigned char) * count: line size in bidi_char */ -void flipThisRun(bidi_char *from, unsigned char *level, int max, int count) +static void flipThisRun( + bidi_char *from, unsigned char *level, int max, int count) { int i, j, k, tlevel; bidi_char temp; @@ -323,7 +325,8 @@ void flipThisRun(bidi_char *from, unsigned char *level, int max, int count) /* * Finds the index of a run with level equals tlevel */ -int findIndexOfRun(unsigned char* level , int start, int count, int tlevel) +static int findIndexOfRun( + unsigned char *level , int start, int count, int tlevel) { int i; for (i=start; i 0) { unsigned char current = level[--from]; @@ -1630,7 +1634,7 @@ int do_bidi(bidi_char *line, int count) * takes a pointer to a character that is checked for * having a mirror glyph. */ -void doMirror(unsigned int *ch) +static void doMirror(unsigned int *ch) { if ((*ch & 0xFF00) == 0) { switch (*ch) { diff --git a/psftp.c b/psftp.c index 3fb8ffbe..d87fea21 100644 --- a/psftp.c +++ b/psftp.c @@ -26,7 +26,7 @@ const char *const appname = "PSFTP"; static int psftp_connect(char *userhost, char *user, int portnumber); static int do_sftp_init(void); -void do_sftp_cleanup(); +static void do_sftp_cleanup(void); /* ---------------------------------------------------------------------- * sftp client state. @@ -2383,7 +2383,7 @@ static int do_sftp_init(void) return 0; } -void do_sftp_cleanup() +static void do_sftp_cleanup(void) { char ch; if (backend) { diff --git a/unix/gtkdlg.c b/unix/gtkdlg.c index d2fd6f64..1d88d7fc 100644 --- a/unix/gtkdlg.c +++ b/unix/gtkdlg.c @@ -150,7 +150,7 @@ static void coloursel_ok(GtkButton *button, gpointer data); static void coloursel_cancel(GtkButton *button, gpointer data); #endif static void dlgparam_destroy(GtkWidget *widget, gpointer data); -int get_listitemheight(GtkWidget *widget); +static int get_listitemheight(GtkWidget *widget); static int uctrl_cmp_byctrl(void *av, void *bv) { @@ -2836,7 +2836,7 @@ void shortcut_add(struct Shortcuts *scs, GtkWidget *labelw, shortcut_highlight(labelw, chr); } -int get_listitemheight(GtkWidget *w) +static int get_listitemheight(GtkWidget *w) { #if !GTK_CHECK_VERSION(2,0,0) GtkWidget *listitem = gtk_list_item_new_with_label("foo"); diff --git a/windows/winnet.c b/windows/winnet.c index f26343be..459d584a 100644 --- a/windows/winnet.c +++ b/windows/winnet.c @@ -206,7 +206,7 @@ static HMODULE winsock2_module = NULL; static HMODULE wship6_module = NULL; #endif -bool sk_startup(int hi, int lo) +static bool sk_startup(int hi, int lo) { WORD winsock_ver; @@ -590,7 +590,7 @@ SockAddr *sk_namedpipe_addr(const char *pipename) return ret; } -bool sk_nextaddr(SockAddr *addr, SockAddrStep *step) +static bool sk_nextaddr(SockAddr *addr, SockAddrStep *step) { #ifndef NO_IPV6 if (step->ai) { From c5895ec2928948a04f59004b75c934a2d99ac508 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 3 Nov 2018 10:06:33 +0000 Subject: [PATCH 596/607] Move all extern declarations into header files. This is another cleanup I felt a need for while I was doing boolification. If you define a function or variable in one .c file and declare it extern in another, then nothing will check you haven't got the types of the two declarations mismatched - so when you're _changing_ the type, it's a pain to make sure you've caught all the copies of it. It's better to put all those extern declarations in header files, so that the declaration in the header is also in scope for the definition. Then the compiler will complain if they don't match, which is what I want. --- misc.c | 1 - putty.h | 4 +++ sercfg.c | 2 -- ssh.h | 8 +++++ ssh2connection.c | 7 ---- sshecdsag.c | 3 -- sshppl.h | 7 ++++ sshrand.c | 3 -- sshshare.c | 5 --- terminal.c | 1 - unix/gtkapp.c | 13 ++------ unix/gtkdlg.c | 12 +------ unix/gtkmain.c | 14 ++------ unix/gtkwin.c | 7 +--- unix/unix.h | 79 ++++++++++++++++++++++++++++++++++++++++++---- unix/uxpgnt.c | 4 --- unix/uxpterm.c | 2 -- unix/uxserver.c | 2 -- unix/uxshare.c | 6 ---- windows/windlg.c | 3 -- windows/window.c | 5 ++- windows/winnet.c | 4 +-- windows/winnpc.c | 3 -- windows/winnps.c | 9 ------ windows/winpgen.c | 2 -- windows/winpgnt.c | 2 -- windows/winplink.c | 1 - windows/winproxy.c | 3 -- windows/winsftp.c | 1 - windows/winshare.c | 3 -- windows/winstuff.h | 39 ++++++++++++++++++++--- 31 files changed, 136 insertions(+), 119 deletions(-) diff --git a/misc.c b/misc.c index 25ed8636..4e8764fb 100644 --- a/misc.c +++ b/misc.c @@ -1258,7 +1258,6 @@ bool strendswith(const char *s, const char *t) char *buildinfo(const char *newline) { strbuf *buf = strbuf_new(); - extern const char commitid[]; /* in commitid.c */ strbuf_catf(buf, "Build platform: %d-bit %s", (int)(CHAR_BIT * sizeof(void *)), diff --git a/putty.h b/putty.h index fdef2801..0f4ab6db 100644 --- a/putty.h +++ b/putty.h @@ -1709,6 +1709,7 @@ void ser_setup_config_box(struct controlbox *b, bool midsession, * Exports from version.c. */ extern const char ver[]; +extern const char commitid[]; /* * Exports from unicode.c. @@ -1853,6 +1854,9 @@ void conf_filesel_handler(union control *ctrl, dlgparam *dlg, void *data, int event); void conf_fontsel_handler(union control *ctrl, dlgparam *dlg, void *data, int event); +/* Much more special-purpose function needed by sercfg.c */ +void config_protocolbuttons_handler(union control *, dlgparam *, void *, int); + void setup_config_box(struct controlbox *b, bool midsession, int protocol, int protcfginfo); diff --git a/sercfg.c b/sercfg.c index 2c1682f5..a5a3e3f4 100644 --- a/sercfg.c +++ b/sercfg.c @@ -132,8 +132,6 @@ void ser_setup_config_box(struct controlbox *b, bool midsession, if (!midsession) { int i; - extern void config_protocolbuttons_handler(union control *, dlgparam *, - void *, int); /* * Add the serial back end to the protocols list at the diff --git a/ssh.h b/ssh.h index c657bca4..da98b7c8 100644 --- a/ssh.h +++ b/ssh.h @@ -185,6 +185,12 @@ void share_setup_x11_channel(ssh_sharing_connstate *cs, share_channel *chan, int protomajor, int protominor, const void *initial_data, int initial_len); +/* Per-application overrides for what roles we can take in connection + * sharing, regardless of user configuration (e.g. pscp will never be + * an upstream) */ +extern const bool share_can_be_downstream; +extern const bool share_can_be_upstream; + struct X11Display; struct X11FakeAuth; @@ -418,6 +424,8 @@ struct ec_point { bool infinity; }; +/* A couple of ECC functions exported for use outside sshecc.c */ +struct ec_point *ecp_mul(const struct ec_point *a, const Bignum b); void ec_point_free(struct ec_point *point); /* Weierstrass form curve */ diff --git a/ssh2connection.c b/ssh2connection.c index 0be08aa6..f1135309 100644 --- a/ssh2connection.c +++ b/ssh2connection.c @@ -325,13 +325,6 @@ static bool ssh2_connection_filter_queue(struct ssh2_connection_state *s) ChanopenResult chanopen_result; PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */ - /* Cross-reference to ssh2transport.c to handle the common packets - * between login and connection: DISCONNECT, DEBUG and IGNORE. If - * we have an instance of ssh2transport below us, then those - * messages won't come here anyway, but they could if we're - * running in bare ssh2-connection mode. */ - extern bool ssh2_common_filter_queue(PacketProtocolLayer *ppl); - while (1) { if (ssh2_common_filter_queue(&s->ppl)) return true; diff --git a/sshecdsag.c b/sshecdsag.c index 7523fa7a..09d2eba3 100644 --- a/sshecdsag.c +++ b/sshecdsag.c @@ -4,9 +4,6 @@ #include "ssh.h" -/* Forward reference from sshecc.c */ -struct ec_point *ecp_mul(const struct ec_point *a, const Bignum b); - int ec_generate(struct ec_key *key, int bits, progfn_t pfn, void *pfnparam) { diff --git a/sshppl.h b/sshppl.h index 5069f871..80be9d14 100644 --- a/sshppl.h +++ b/sshppl.h @@ -134,6 +134,13 @@ void ssh_ppl_user_output_string_and_free(PacketProtocolLayer *ppl, char *text); ptrlen ssh2_transport_get_session_id(PacketProtocolLayer *ssh2_transport_ptr); void ssh2_transport_notify_auth_done(PacketProtocolLayer *ssh2_transport_ptr); +/* Shared method between ssh2 layers (defined in ssh2transport.c) to + * handle the common packets between login and connection: DISCONNECT, + * DEBUG and IGNORE. Those messages are handled by the ssh2transport + * layer if we have one, but in bare ssh2-connection mode they have to + * be handled by ssh2connection. */ +bool ssh2_common_filter_queue(PacketProtocolLayer *ppl); + /* Methods for ssh1login to pass protocol flags to ssh1connection */ void ssh1_connection_set_protoflags( PacketProtocolLayer *ppl, int local, int remote); diff --git a/sshrand.c b/sshrand.c index 63211693..cde35eef 100644 --- a/sshrand.c +++ b/sshrand.c @@ -9,9 +9,6 @@ /* Collect environmental noise every 5 minutes */ #define NOISE_REGULAR_INTERVAL (5*60*TICKSPERSEC) -void noise_get_heavy(void (*func) (void *, int)); -void noise_get_light(void (*func) (void *, int)); - /* * `pool' itself is a pool of random data which we actually use: we * return bytes from `pool', at position `poolpos', until `poolpos' diff --git a/sshshare.c b/sshshare.c index 48a0ca36..664a622e 100644 --- a/sshshare.c +++ b/sshshare.c @@ -1968,11 +1968,6 @@ static int share_listen_accepting(Plug *plug, return 0; } -/* Per-application overrides for what roles we can take (e.g. pscp - * will never be an upstream) */ -extern const bool share_can_be_downstream; -extern const bool share_can_be_upstream; - /* * Decide on the string used to identify the connection point between * upstream and downstream (be it a Windows named pipe or a diff --git a/terminal.c b/terminal.c index ae0f3917..013fcbc2 100644 --- a/terminal.c +++ b/terminal.c @@ -1051,7 +1051,6 @@ static void null_line_error(Terminal *term, int y, int lineno, tree234 *whichtree, int treeindex, const char *varname) { - extern const char commitid[]; /* in version.c */ modalfatalbox("%s==NULL in terminal.c\n" "lineno=%d y=%d w=%d h=%d\n" "count(scrollback=%p)=%d\n" diff --git a/unix/gtkapp.c b/unix/gtkapp.c index 70dc7d3c..e7f49df5 100644 --- a/unix/gtkapp.c +++ b/unix/gtkapp.c @@ -107,8 +107,6 @@ void session_window_closed(void) {} void window_setup_error(const char *errmsg) {} #else /* GTK_CHECK_VERSION(3,0,0) */ -extern const bool use_event_log; - static void startup(GApplication *app, gpointer user_data) { GMenu *menubar, *menu, *section; @@ -216,7 +214,6 @@ GtkWidget *make_gtk_toplevel_window(GtkFrontend *frontend) void launch_duplicate_session(Conf *conf) { - extern const bool dup_check_launchable; assert(!dup_check_launchable || conf_launchable(conf)); g_application_hold(G_APPLICATION(app)); new_session_window(conf_copy(conf), NULL); @@ -315,15 +312,11 @@ int main(int argc, char **argv) { int status; - { - /* Call the function in ux{putty,pterm}.c to do app-type - * specific setup */ - extern void setup(bool); - setup(false); /* false means we are not a one-session process */ - } + /* Call the function in ux{putty,pterm}.c to do app-type + * specific setup */ + setup(false); /* false means we are not a one-session process */ if (argc > 1) { - extern char *pty_osx_envrestore_prefix; pty_osx_envrestore_prefix = argv[--argc]; } diff --git a/unix/gtkdlg.c b/unix/gtkdlg.c index 1d88d7fc..84f9774f 100644 --- a/unix/gtkdlg.c +++ b/unix/gtkdlg.c @@ -3189,15 +3189,7 @@ GtkWidget *create_config_box(const char *title, Conf *conf, dp->retval = -1; dp->window = window; - { - /* in gtkwin.c */ - extern void set_window_icon(GtkWidget *window, - const char *const *const *icon, - int n_icon); - extern const char *const *const cfg_icon[]; - extern const int n_cfg_icon; - set_window_icon(window, cfg_icon, n_cfg_icon); - } + set_window_icon(window, cfg_icon, n_cfg_icon); #if !GTK_CHECK_VERSION(2,0,0) gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(treescroll), @@ -3860,8 +3852,6 @@ static void eventlog_list_handler(union control *ctrl, dlgparam *dp, if (gtk_selection_owner_set(es->window, GDK_SELECTION_PRIMARY, GDK_CURRENT_TIME)) { - extern GdkAtom compound_text_atom; - gtk_selection_add_target(es->window, GDK_SELECTION_PRIMARY, GDK_SELECTION_TYPE_STRING, 1); gtk_selection_add_target(es->window, GDK_SELECTION_PRIMARY, diff --git a/unix/gtkmain.c b/unix/gtkmain.c index e51b5c43..6a3d25ed 100644 --- a/unix/gtkmain.c +++ b/unix/gtkmain.c @@ -47,9 +47,6 @@ static char *progname, **gtkargvstart; static int ngtkargs; -extern char **pty_argv; /* declared in pty.c */ -extern bool use_pty_argv; - static const char *app_name = "pterm"; char *x_get_default(const char *key) @@ -590,12 +587,9 @@ int main(int argc, char **argv) setlocale(LC_CTYPE, ""); - { - /* Call the function in ux{putty,pterm}.c to do app-type - * specific setup */ - extern void setup(bool); - setup(true); /* true means we are a one-session process */ - } + /* Call the function in ux{putty,pterm}.c to do app-type + * specific setup */ + setup(true); /* true means we are a one-session process */ progname = argv[0]; @@ -626,8 +620,6 @@ int main(int argc, char **argv) block_signal(SIGPIPE, true); if (argc > 1 && !strncmp(argv[1], "---", 3)) { - extern const bool dup_check_launchable; - read_dupsession_data(conf, argv[1]); /* Splatter this argument so it doesn't clutter a ps listing */ smemclr(argv[1], strlen(argv[1])); diff --git a/unix/gtkwin.c b/unix/gtkwin.c index c4269dd5..369e9942 100644 --- a/unix/gtkwin.c +++ b/unix/gtkwin.c @@ -5468,11 +5468,7 @@ void new_session_window(Conf *conf, const char *geometry_string) #endif ); - { - extern const char *const *const main_icon[]; - extern const int n_main_icon; - set_window_icon(inst->window, main_icon, n_main_icon); - } + set_window_icon(inst->window, main_icon, n_main_icon); gtk_widget_show(inst->window); @@ -5484,7 +5480,6 @@ void new_session_window(Conf *conf, const char *geometry_string) { GtkWidget *menuitem; char *s; - extern const bool use_event_log, new_session, saved_sessions; inst->menu = gtk_menu_new(); diff --git a/unix/unix.h b/unix/unix.h index 1ce587bd..1a74492a 100644 --- a/unix/unix.h +++ b/unix/unix.h @@ -189,7 +189,14 @@ enum MenuAction { }; void app_menu_action(GtkFrontend *frontend, enum MenuAction); -/* Things gtkdlg.c needs from pterm.c */ +/* Arrays of pixmap data used for GTK window icons. (main_icon is for + * the process's main window; cfg_icon is the modified icon used for + * its config box.) */ +extern const char *const *const main_icon[]; +extern const char *const *const cfg_icon[]; +extern const int n_main_icon, n_cfg_icon; + +/* Things gtkdlg.c needs from gtkwin.c */ #ifdef MAY_REFER_TO_GTK_IN_HEADERS enum DialogSlot { DIALOG_SLOT_RECONFIGURE, @@ -202,9 +209,12 @@ enum DialogSlot { GtkWidget *gtk_seat_get_window(Seat *seat); void register_dialog(Seat *seat, enum DialogSlot slot, GtkWidget *dialog); void unregister_dialog(Seat *seat, enum DialogSlot slot); +void set_window_icon(GtkWidget *window, const char *const *const *icon, + int n_icon); +extern GdkAtom compound_text_atom; #endif -/* Things pterm.c needs from gtkdlg.c */ +/* Things gtkwin.c needs from gtkdlg.c */ #ifdef MAY_REFER_TO_GTK_IN_HEADERS GtkWidget *create_config_box(const char *title, Conf *conf, bool midsession, int protcfginfo, @@ -247,18 +257,52 @@ GtkWidget *create_message_box( post_dialog_fn_t after, void *afterctx); #endif -/* Things pterm.c needs from {ptermm,uxputty}.c */ +/* Things gtkwin.c needs from {ptermm,uxputty}.c */ char *make_default_wintitle(char *hostname); -/* pterm.c needs this special function in xkeysym.c */ +/* gtkwin.c needs this special function in xkeysym.c */ int keysym_to_unicode(int keysym); -/* Things uxstore.c needs from pterm.c */ +/* Things uxstore.c needs from gtkwin.c */ char *x_get_default(const char *key); -/* Things uxstore.c provides to pterm.c */ +/* Things uxstore.c provides to gtkwin.c */ void provide_xrm_string(char *string); +/* Function that {gtkapp,gtkmain}.c needs from ux{pterm,putty}.c. Does + * early process setup that varies between applications (e.g. + * pty_pre_init or sk_init), and is passed a boolean by the caller + * indicating whether this is an OS X style multi-session monolithic + * process or an ordinary Unix one-shot. */ +void setup(bool single_session_in_this_process); + +/* + * Per-application constants that affect behaviour of shared modules. + */ +/* Do we need an Event Log menu item? (yes for PuTTY, no for pterm) */ +extern const bool use_event_log; +/* Do we need a New Session menu item? (yes for PuTTY, no for pterm) */ +extern const bool new_session; +/* Do we need a Saved Sessions menu item? (yes for PuTTY, no for pterm) */ +extern const bool saved_sessions; +/* When we Duplicate Session, do we need to double-check that the Conf + * is in a launchable state? (no for pterm, because conf_launchable + * returns an irrelevant answer, since we'll force use of the pty + * backend which ignores all the relevant settings) */ +extern const bool dup_check_launchable; +/* In the Duplicate Session serialised data, do we send/receive an + * argv array after the main Conf? (yes for pterm, no for PuTTY) */ +extern const bool use_pty_argv; + +/* + * OS X environment munging: this is the prefix we expect to find on + * environment variable names that were changed by osxlaunch. + * Extracted from the command line of the OS X pterm main binary, and + * used in uxpty.c to restore the original environment before + * launching its subprocess. + */ +extern char *pty_osx_envrestore_prefix; + /* Things provided by uxcons.c */ struct termios; void stderr_tty_init(void); @@ -360,4 +404,25 @@ Socket *make_fd_socket(int infd, int outfd, int inerrfd, Plug *plug); #define DEFAULT_GTK_FONT "server:fixed" #endif -#endif +/* + * uxpty.c. + */ +void pty_pre_init(void); /* pty+utmp setup before dropping privilege */ +/* Pass in the argv[] for an instance of the pty backend created by + * the standard vtable constructor. Only called from (non-OSX) pterm, + * which will construct exactly one such instance, and initialises + * this from the command line. */ +extern char **pty_argv; + +/* + * gtkask.c. + */ +char *gtk_askpass_main(const char *display, const char *wintitle, + const char *prompt, bool *success); + +/* + * uxsftpserver.c. + */ +extern const SftpServerVtable unix_live_sftpserver_vt; + +#endif /* PUTTY_UNIX_H */ diff --git a/unix/uxpgnt.c b/unix/uxpgnt.c index 42ce7ba5..907e69a4 100644 --- a/unix/uxpgnt.c +++ b/unix/uxpgnt.c @@ -349,10 +349,6 @@ static char *askpass_gui(const char *prompt) char *passphrase; bool success; - /* in gtkask.c */ - char *gtk_askpass_main(const char *display, const char *wintitle, - const char *prompt, bool *success); - passphrase = gtk_askpass_main( display, "Pageant passphrase prompt", prompt, &success); if (!success) { diff --git a/unix/uxpterm.c b/unix/uxpterm.c index 1be68f50..27738a3d 100644 --- a/unix/uxpterm.c +++ b/unix/uxpterm.c @@ -43,8 +43,6 @@ char *make_default_wintitle(char *hostname) void setup(bool single) { - extern void pty_pre_init(void); /* declared in pty.c */ - cmdline_tooltype = TOOLTYPE_NONNETWORK; default_protocol = -1; diff --git a/unix/uxserver.c b/unix/uxserver.c index 7b9ab0f0..470e34d6 100644 --- a/unix/uxserver.c +++ b/unix/uxserver.c @@ -355,8 +355,6 @@ static bool longoptarg(const char *arg, const char *expected, return false; } -extern const SftpServerVtable unix_live_sftpserver_vt; - int main(int argc, char **argv) { int *fdlist; diff --git a/unix/uxshare.c b/unix/uxshare.c index a7d7fc12..d11d6bb8 100644 --- a/unix/uxshare.c +++ b/unix/uxshare.c @@ -23,12 +23,6 @@ #define SALT_FILENAME "salt" #define SALT_SIZE 64 -/* - * Functions provided by uxnet.c to help connection sharing. - */ -SockAddr *unix_sock_addr(const char *path); -Socket *new_unix_listener(SockAddr *listenaddr, Plug *plug); - static char *make_parentdir_name(void) { char *username, *parent; diff --git a/windows/windlg.c b/windows/windlg.c index 4019b9a3..16abe3ff 100644 --- a/windows/windlg.c +++ b/windows/windlg.c @@ -49,8 +49,6 @@ static char *events_initial[LOGEVENT_INITIAL_MAX]; static char *events_circular[LOGEVENT_CIRCULAR_MAX]; static int ninitial = 0, ncircular = 0, circular_first = 0; -extern Conf *conf; /* defined in window.c */ - #define PRINTER_DISABLED_STRING "None (printing disabled)" void force_normal(HWND hwnd) @@ -799,7 +797,6 @@ static void win_gui_eventlog(LogPolicy *lp, const char *string) static void win_gui_logging_error(LogPolicy *lp, const char *event) { - extern Seat win_seat[1]; /* Send 'can't open log file' errors to the terminal window. * (Marked as stderr, although terminal.c won't care.) */ seat_stderr(win_seat, event, strlen(event)); diff --git a/windows/window.c b/windows/window.c index 31b1cbe5..913e453d 100644 --- a/windows/window.c +++ b/windows/window.c @@ -152,8 +152,6 @@ struct wm_netevent_params { LPARAM lParam; }; -Conf *conf; /* exported to windlg.c */ - static void conf_cache_data(void); int cursor_type; int vtmode; @@ -349,7 +347,8 @@ static const SeatVtable win_seat_vt = { nullseat_get_windowid, win_seat_get_window_pixel_size, }; -Seat win_seat[1] = {{ &win_seat_vt }}; +static Seat win_seat_impl = { &win_seat_vt }; +Seat *const win_seat = &win_seat_impl; static void start_backend(void) { diff --git a/windows/winnet.c b/windows/winnet.c index 459d584a..bf91634f 100644 --- a/windows/winnet.c +++ b/windows/winnet.c @@ -839,8 +839,6 @@ static void sk_net_set_frozen(Socket *s, bool is_frozen); static const char *sk_net_socket_error(Socket *s); static SocketPeerInfo *sk_net_peer_info(Socket *s); -extern char *do_select(SOCKET skt, bool startup); - static const SocketVtable NetSocket_sockvt = { sk_net_plug, sk_net_close, @@ -1790,7 +1788,7 @@ SOCKET next_socket(int *state) return s ? s->s : INVALID_SOCKET; } -extern bool socket_writable(SOCKET skt) +bool socket_writable(SOCKET skt) { NetSocket *s = find234(sktree, (void *)skt, cmpforsearch); diff --git a/windows/winnpc.c b/windows/winnpc.c index 31906e0d..4fcb9e26 100644 --- a/windows/winnpc.c +++ b/windows/winnpc.c @@ -15,9 +15,6 @@ #include "winsecur.h" -Socket *make_handle_socket(HANDLE send_H, HANDLE recv_H, HANDLE stderr_H, - Plug *plug, bool overlapped); - Socket *new_named_pipe_client(const char *pipename, Plug *plug) { HANDLE pipehandle; diff --git a/windows/winnps.c b/windows/winnps.c index d355a90a..fa1d804b 100644 --- a/windows/winnps.c +++ b/windows/winnps.c @@ -15,9 +15,6 @@ #include "winsecur.h" -Socket *make_handle_socket(HANDLE send_H, HANDLE recv_H, HANDLE stderr_H, - Plug *plug, bool overlapped); - typedef struct NamedPipeServerSocket { /* Parameters for (repeated) creation of named pipe objects */ PSECURITY_DESCRIPTOR psd; @@ -120,12 +117,6 @@ static Socket *named_pipe_accept(accept_ctx_t ctx, Plug *plug) return make_handle_socket(conn, conn, NULL, plug, true); } -/* - * Dummy SockAddr *type which just holds a named pipe address. Only - * used for calling plug_log from named_pipe_accept_loop() here. - */ -SockAddr *sk_namedpipe_addr(const char *pipename); - static void named_pipe_accept_loop(NamedPipeServerSocket *ps, bool got_one_already) { diff --git a/windows/winpgen.c b/windows/winpgen.c index 6d5c244b..833ef393 100644 --- a/windows/winpgen.c +++ b/windows/winpgen.c @@ -137,8 +137,6 @@ static void progress_update(void *param, int action, int phase, int iprogress) } } -extern const char ver[]; - struct PassphraseProcStruct { char **passphrase; char *comment; diff --git a/windows/winpgnt.c b/windows/winpgnt.c index f8320f4a..bf84e863 100644 --- a/windows/winpgnt.c +++ b/windows/winpgnt.c @@ -50,8 +50,6 @@ #define APPNAME "Pageant" -extern const char ver[]; - static HWND keylist; static HWND aboutbox; static HMENU systray_menu, session_menu; diff --git a/windows/winplink.c b/windows/winplink.c index 493db000..1f47dd9b 100644 --- a/windows/winplink.c +++ b/windows/winplink.c @@ -530,7 +530,6 @@ int main(int argc, char **argv) } else if (n == WAIT_OBJECT_0 + nhandles) { WSANETWORKEVENTS things; SOCKET socket; - extern SOCKET first_socket(int *), next_socket(int *); int i, socketstate; /* diff --git a/windows/winproxy.c b/windows/winproxy.c index 73b77d42..909af2f1 100644 --- a/windows/winproxy.c +++ b/windows/winproxy.c @@ -12,9 +12,6 @@ #include "network.h" #include "proxy.h" -Socket *make_handle_socket(HANDLE send_H, HANDLE recv_H, HANDLE stderr_H, - Plug *plug, bool overlapped); - Socket *platform_new_connection(SockAddr *addr, const char *hostname, int port, bool privport, bool oobinline, bool nodelay, bool keepalive, diff --git a/windows/winsftp.c b/windows/winsftp.c index 7d0adde5..f9f6222c 100644 --- a/windows/winsftp.c +++ b/windows/winsftp.c @@ -535,7 +535,6 @@ int do_eventsel_loop(HANDLE other_event) } else if (netindex >= 0 && n == WAIT_OBJECT_0 + netindex) { WSANETWORKEVENTS things; SOCKET socket; - extern SOCKET first_socket(int *), next_socket(int *); int i, socketstate; /* diff --git a/windows/winshare.c b/windows/winshare.c index 5d98cc17..6498cc4e 100644 --- a/windows/winshare.c +++ b/windows/winshare.c @@ -115,9 +115,6 @@ static char *make_name(const char *prefix, const char *name) return retname; } -Socket *new_named_pipe_client(const char *pipename, Plug *plug); -Socket *new_named_pipe_listener(const char *pipename, Plug *plug); - int platform_ssh_share(const char *pi_name, Conf *conf, Plug *downplug, Plug *upplug, Socket **sock, char **logtext, char **ds_err, char **us_err, diff --git a/windows/winstuff.h b/windows/winstuff.h index 4d735af1..cd128156 100644 --- a/windows/winstuff.h +++ b/windows/winstuff.h @@ -235,13 +235,16 @@ void quit_help(HWND hwnd); /* * The terminal and logging context are notionally local to the * Windows front end, but they must be shared between window.c and - * windlg.c. Likewise the Seat structure for the Windows GUI. + * windlg.c. Likewise the Seat structure for the Windows GUI, and the + * Conf for the main session.. */ GLOBAL Terminal *term; GLOBAL LogContext *logctx; +GLOBAL Conf *conf; /* - * GUI seat methods in windlg.c. + * GUI seat methods in windlg.c, so that the vtable definition in + * window.c can refer to them. */ int win_seat_verify_ssh_host_key( Seat *seat, const char *host, int port, @@ -254,6 +257,12 @@ int win_seat_confirm_weak_cached_hostkey( Seat *seat, const char *algname, const char *betteralgs, void (*callback)(void *ctx, int result), void *ctx); +/* + * The Windows GUI seat object itself, so that its methods can be + * called outside window.c. + */ +extern Seat *const win_seat; + /* * Windows-specific clipboard helper function shared with windlg.c, * which takes the data string in the system code page instead of @@ -303,7 +312,17 @@ void write_aclip(int clipboard, char *, int, bool); /* * Exports from winnet.c. */ -extern void select_result(WPARAM, LPARAM); +/* Report an event notification from WSA*Select */ +void select_result(WPARAM, LPARAM); +/* Enumerate all currently live OS-level SOCKETs */ +SOCKET first_socket(int *); +SOCKET next_socket(int *); +/* Ask winnet.c whether we currently want to try to write to a SOCKET */ +bool socket_writable(SOCKET skt); +/* Force a refresh of the SOCKET list by re-calling do_select for each one */ +void socket_reselect_all(void); +/* Make a SockAddr which just holds a named pipe address. */ +SockAddr *sk_namedpipe_addr(const char *pipename); /* * winnet.c dynamically loads WinSock 2 or WinSock 1 depending on @@ -331,9 +350,19 @@ DECL_WINDOWS_FUNCTION(GLOBAL, int, select, fd_set FAR *, const struct timeval FAR *)); #endif -extern bool socket_writable(SOCKET skt); +/* + * Provided by each client of winnet.c, and called by winnet.c to turn + * on or off WSA*Select for a given socket. + */ +char *do_select(SOCKET skt, bool startup); -extern void socket_reselect_all(void); +/* + * Network-subsystem-related functions provided in other Windows modules. + */ +Socket *make_handle_socket(HANDLE send_H, HANDLE recv_H, HANDLE stderr_H, + Plug *plug, bool overlapped); /* winhsock */ +Socket *new_named_pipe_client(const char *pipename, Plug *plug); /* winnpc */ +Socket *new_named_pipe_listener(const char *pipename, Plug *plug); /* winnps */ /* * Exports from winctrls.c. From 80db674648f649375eb40540a416fa2d15441d81 Mon Sep 17 00:00:00 2001 From: "Pavel I. Kryukov" Date: Sat, 3 Nov 2018 20:04:14 +0300 Subject: [PATCH 597/607] uxnet.c: initialize atmark variable GCC 5 does not trace control flow graph and claims that the variable may be used uninitialized. GCC 7 does not have this bug though. --- unix/uxnet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unix/uxnet.c b/unix/uxnet.c index 512ad835..ac3455fa 100644 --- a/unix/uxnet.c +++ b/unix/uxnet.c @@ -1268,7 +1268,7 @@ static void net_select_result(int fd, int event) int ret; char buf[20480]; /* nice big buffer for plenty of speed */ NetSocket *s; - bool atmark; + bool atmark = true; /* Find the Socket structure */ s = find234(sktree, &fd, cmpforsearch); From 506a0b1b77d2f8852e9542a79dde98ff82630b0b Mon Sep 17 00:00:00 2001 From: "Pavel I. Kryukov" Date: Sat, 3 Nov 2018 20:10:21 +0300 Subject: [PATCH 598/607] misc.c: use bool in debug_memdump signature --- misc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misc.c b/misc.c index 4e8764fb..7e3acd71 100644 --- a/misc.c +++ b/misc.c @@ -991,7 +991,7 @@ void debug_printf(const char *fmt, ...) } -void debug_memdump(const void *buf, int len, int L) +void debug_memdump(const void *buf, int len, bool L) { int i; const unsigned char *p = buf; From a4b5f66d931a43dda6aa00516f8d2d25cba607c3 Mon Sep 17 00:00:00 2001 From: "Pavel I. Kryukov" Date: Sat, 3 Nov 2018 21:20:40 +0300 Subject: [PATCH 599/607] Remove 'static' qualifier from Conf pointer Configuration pointer is globally visible from winstuff.h, so it cannot be 'static' any longer. --- pscp.c | 2 +- psftp.c | 2 +- unix/uxplink.c | 2 +- windows/winplink.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pscp.c b/pscp.c index a16825b9..592df7a9 100644 --- a/pscp.c +++ b/pscp.c @@ -43,7 +43,7 @@ static bool using_sftp = false; static bool uploading = false; static Backend *backend; -static Conf *conf; +Conf *conf; bool sent_eof = false; static void source(const char *src); diff --git a/psftp.c b/psftp.c index d87fea21..023a16e4 100644 --- a/psftp.c +++ b/psftp.c @@ -34,7 +34,7 @@ static void do_sftp_cleanup(void); char *pwd, *homedir; static Backend *backend; -static Conf *conf; +Conf *conf; bool sent_eof = false; /* ------------------------------------------------------------ diff --git a/unix/uxplink.c b/unix/uxplink.c index 35b07f92..9d080878 100644 --- a/unix/uxplink.c +++ b/unix/uxplink.c @@ -41,7 +41,7 @@ void cmdline_error(const char *fmt, ...) static bool local_tty = false; /* do we have a local tty? */ static Backend *backend; -static Conf *conf; +Conf *conf; /* * Default settings that are specific to Unix plink. diff --git a/windows/winplink.c b/windows/winplink.c index 1f47dd9b..fa6f4c98 100644 --- a/windows/winplink.c +++ b/windows/winplink.c @@ -38,7 +38,7 @@ DWORD orig_console_mode; WSAEVENT netevent; static Backend *backend; -static Conf *conf; +Conf *conf; bool term_ldisc(Terminal *term, int mode) { From 1a569fce092e01e85a540b905c51fef76605c8a8 Mon Sep 17 00:00:00 2001 From: Will Lauer Date: Wed, 19 Apr 2017 15:33:43 -0500 Subject: [PATCH 600/607] Adding RSA Cert support --- Recipe | 8 +- pageant.c | 1 + ssh.h | 26 ++++ sshpubk.c | 2 + sshrsacert.c | 332 +++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 365 insertions(+), 4 deletions(-) create mode 100644 sshrsacert.c diff --git a/Recipe b/Recipe index 0c4fd582..9e895a6d 100644 --- a/Recipe +++ b/Recipe @@ -251,7 +251,7 @@ NONSSH = telnet raw rlogin ldisc pinger # SSH back end (putty, plink, pscp, psftp). SSHCOMMON = sshcommon sshrand - + sshverstring sshcrc sshdes sshmd5 sshrsa sshsha sshblowf + + sshverstring sshcrc sshdes sshmd5 sshrsa sshrsacert sshsha sshblowf + sshdh sshcrcda sshpubk sshzlib sshdss ssharcf + sshaes sshccp sshsh256 sshsh512 sshbn sshmac marshal nullplug + sshgssc pgssapi sshecc wildcard ssh1censor ssh2censor ssh2bpp @@ -325,12 +325,12 @@ pscp : [C] pscp winsftp wincons WINSSH BE_SSH SFTP wildcard WINMISC psftp : [C] psftp winsftp wincons WINSSH BE_SSH SFTP wildcard WINMISC + psftp.res winnojmp LIBS -pageant : [G] winpgnt pageant sshrsa sshpubk sshdes sshbn sshmd5 version +pageant : [G] winpgnt pageant sshrsa sshrsacert sshpubk sshdes sshbn sshmd5 version + tree234 MISC sshaes sshsha winsecur winpgntc aqsync sshdss sshsh256 + sshsh512 winutils sshecc winmisc winhelp conf pageant.res LIBS puttygen : [G] winpgen sshrsag sshdssg sshprime sshdes sshbn sshmd5 version - + sshrand winnoise sshsha winstore MISC winctrls sshrsa sshdss winmisc + + sshrand winnoise sshsha winstore MISC winctrls sshrsa sshrsacert sshdss winmisc + sshpubk sshaes sshsh256 sshsh512 IMPORT winutils puttygen.res + tree234 notiming winhelp winnojmp CONF LIBS wintime sshecc + sshecdsag winsecur @@ -358,7 +358,7 @@ cgtest : [UT] cgtest PUTTYGEN_UNIX pscp : [U] pscp uxsftp uxcons UXSSH BE_SSH SFTP wildcard UXMISC uxnogtk psftp : [U] psftp uxsftp uxcons UXSSH BE_SSH SFTP wildcard UXMISC uxnogtk -pageant : [X] uxpgnt uxagentc aqsync pageant sshrsa sshpubk sshdes sshbn +pageant : [X] uxpgnt uxagentc aqsync pageant sshrsa sshrsacert sshpubk sshdes sshbn + sshmd5 version tree234 misc sshaes sshsha sshdss sshsh256 sshsh512 + sshecc CONF uxsignal nocproxy nogss be_none x11fwd ux_x11 uxcons + gtkask gtkmisc nullplug logging UXMISC uxagentsock diff --git a/pageant.c b/pageant.c index 8bdbe1f6..eb1fd534 100644 --- a/pageant.c +++ b/pageant.c @@ -409,6 +409,7 @@ void pageant_handle_msg(BinarySink *bs, } break; case SSH2_AGENTC_ADD_IDENTITY: + case SSH2_AGENTC_ADD_ID_CONSTRAINED: /* * Add to the list and return SSH_AGENT_SUCCESS, or * SSH_AGENT_FAILURE if the key was malformed. diff --git a/ssh.h b/ssh.h index da98b7c8..eb458237 100644 --- a/ssh.h +++ b/ssh.h @@ -410,6 +410,30 @@ struct RSAKey { ssh_key sshk; }; +struct RSACertKey { + ptrlen certificate; + char* nonce; + Bignum modulus; + Bignum exponent; + uint64_t serial; + uint32_t type; + char * keyid; + char * principals; + uint64_t valid_after; + uint64_t valid_before; + char * options; + char * extensions; + char * reserved; + ssh_key* sigkey; + char * signature; + Bignum private_exponent; + Bignum iqmp; + Bignum p; + Bignum q; + char *comment; + ssh_key sshk; +}; + struct dss_key { Bignum p, q, g, y, x; ssh_key sshk; @@ -872,6 +896,7 @@ extern const ssh_keyalg ssh_ecdsa_ed25519; extern const ssh_keyalg ssh_ecdsa_nistp256; extern const ssh_keyalg ssh_ecdsa_nistp384; extern const ssh_keyalg ssh_ecdsa_nistp521; +extern const ssh_keyalg ssh_cert_rsa; extern const struct ssh2_macalg ssh_hmac_md5; extern const struct ssh2_macalg ssh_hmac_sha1; extern const struct ssh2_macalg ssh_hmac_sha1_buggy; @@ -1402,6 +1427,7 @@ enum { #define SSH2_AGENTC_ADD_IDENTITY 17 #define SSH2_AGENTC_REMOVE_IDENTITY 18 #define SSH2_AGENTC_REMOVE_ALL_IDENTITIES 19 +#define SSH2_AGENTC_ADD_ID_CONSTRAINED 25 /* * Assorted other SSH-related enumerations. diff --git a/sshpubk.c b/sshpubk.c index 5072ff63..ab3a2b17 100644 --- a/sshpubk.c +++ b/sshpubk.c @@ -578,6 +578,8 @@ const ssh_keyalg *find_pubkey_alg_len(ptrlen name) return &ssh_ecdsa_nistp521; else if (ptrlen_eq_string(name, "ssh-ed25519")) return &ssh_ecdsa_ed25519; + else if (ptrlen_eq_string(name, "ssh-rsa-cert-v01@openssh.com")) + return &ssh_cert_rsa; else return NULL; } diff --git a/sshrsacert.c b/sshrsacert.c new file mode 100644 index 00000000..eb9a97a4 --- /dev/null +++ b/sshrsacert.c @@ -0,0 +1,332 @@ +/* + * RSA Certificate implementation for PuTTY. + */ + +#include +#include +#include +#include + +#include "ssh.h" +#include "misc.h" + +#define copy_string(field, src) field = mkstr(get_string(cert)) + +void freersacertkey(struct RSACertKey* key) +{ + if (key->certificate.ptr) + sfree((void*)(key->certificate.ptr)); + if (key->nonce) + sfree(key->nonce); + if (key->modulus) + freebn(key->modulus); + if (key->exponent) + freebn(key->exponent); + if (key->keyid) + sfree(key->keyid); + if (key->principals) + sfree(key->principals); + if (key->options) + sfree(key->options); + if (key->extensions) + sfree(key->extensions); + if (key->reserved) + sfree(key->reserved); + if (key->sigkey) + ssh_key_free(key->sigkey); + if (key->signature) + sfree(key->signature); + if (key->private_exponent) + freebn(key->private_exponent); + if (key->iqmp) + freebn(key->iqmp); + if (key->p) + freebn(key->p); + if (key->q) + freebn(key->q); + if (key->comment) + sfree(key->comment); +} + +/* ----------------------------------------------------------------------- + * Implementation of the ssh-rsa-cert-v01 key type + */ + +static void rsa2cert_freekey(ssh_key *key); /* forward reference */ + +static ssh_key *rsa2cert_new_pub(const ssh_keyalg *self, ptrlen data) +{ + BinarySource src[1]; + struct RSACertKey *certkey; + + BinarySource_BARE_INIT(src, data.ptr, data.len); + if (!ptrlen_eq_string(get_string(src), "ssh-rsa-cert-v01@openssh.com")) + return NULL; + + certkey = snew(struct RSACertKey); + certkey->sshk = &ssh_cert_rsa; + + ptrlen certdata = get_string(src); + certkey->certificate.ptr = snewn(certdata.len, char); + memcpy((void*)(certkey->certificate.ptr), certdata.ptr, certdata.len); + certkey->certificate.len = certdata.len; + + certkey->private_exponent = NULL; + certkey->p = certkey->q = certkey->iqmp = NULL; + certkey->comment = NULL; + certkey->modulus = certkey->exponent = NULL; + certkey->nonce = certkey->keyid = certkey->principals = NULL; + certkey->options = certkey->extensions = certkey->reserved = NULL; + certkey->sigkey = NULL; + certkey->signature = NULL; + + if (get_err(src)) { + rsa2cert_freekey(&certkey->sshk); + return NULL; + } + + BinarySource cert[1]; + BinarySource_BARE_INIT(cert, certkey->certificate.ptr, certkey->certificate.len); + ptrlen certtype = get_string(cert); + copy_string(certkey->nonce, cert); + certkey->exponent = get_mp_ssh2(cert); + certkey->modulus = get_mp_ssh2(cert); + certkey->serial = get_uint64(cert); + certkey->type = get_uint32(cert); + copy_string(certkey->keyid, cert); + copy_string(certkey->principals, cert); + certkey->valid_after = get_uint64(cert); + certkey->valid_before = get_uint64(cert); + copy_string(certkey->options, cert); + copy_string(certkey->extensions, cert); + copy_string(certkey->reserved, cert); + + ptrlen sigkey = get_string(cert); + + copy_string(certkey->signature, cert); + + if (get_err(cert) || !ptrlen_eq_string(certtype, ssh_cert_rsa.ssh_id)) { + rsa2cert_freekey(&certkey->sshk); + return NULL; + } + + BinarySource sk[1]; + BinarySource_BARE_INIT(sk, sigkey.ptr, sigkey.len); + ptrlen algname = get_string(sk); + ssh_key signature_key = find_pubkey_alg_len(algname); + if (signature_key != NULL) { + certkey->sigkey = ssh_key_new_pub(signature_key, get_data(sk, get_avail(sk))); + } + + if (get_err(sk)) { + rsa2cert_freekey(&certkey->sshk); + return NULL; + } + + return &certkey->sshk; +} + +static void rsa2cert_freekey(ssh_key *key) +{ + struct RSACertKey *certkey = container_of(key, struct RSACertKey, sshk); + freersacertkey(certkey); + sfree(certkey); +} + +static ssh_key *rsa2cert_new_priv(const ssh_keyalg *self, + ptrlen pub, ptrlen priv) +{ + BinarySource src[1]; + ssh_key *sshk; + struct RSACertKey *certkey; + + sshk = rsa2cert_new_pub(self, pub); + if (!sshk) { + return NULL; + } + + certkey = container_of(sshk, struct RSACertKey, sshk); + BinarySource_BARE_INIT(src, priv.ptr, priv.len); + certkey->private_exponent = get_mp_ssh2(src); + certkey->iqmp = get_mp_ssh2(src); + certkey->p = get_mp_ssh2(src); + certkey->q = get_mp_ssh2(src); + certkey->comment = NULL; + + if (get_err(src) || false /*rsa2cert_verify(certkey)*/) { + rsa2cert_freekey(&certkey->sshk); + return NULL; + } + + return &certkey->sshk; +} + +static ssh_key *rsa2cert_new_priv_openssh(const ssh_keyalg *self, + BinarySource *src) +{ + struct RSACertKey *certkey; + + certkey = snew(struct RSACertKey); + certkey->sshk = &ssh_cert_rsa; + certkey->comment = NULL; + + ptrlen certdata = get_string(src); + certkey->certificate.ptr = snewn(certdata.len, char); + memcpy((void*)(certkey->certificate.ptr), certdata.ptr, certdata.len); + certkey->certificate.len = certdata.len; + certkey->private_exponent = get_mp_ssh2(src); + certkey->iqmp = get_mp_ssh2(src); + certkey->p = get_mp_ssh2(src); + certkey->q = get_mp_ssh2(src); + + if (get_err(src) || false /*rsa2cert_verify(certkey)*/) { + rsa2cert_freekey(&certkey->sshk); + return NULL; + } + + BinarySource cert[1]; + BinarySource_BARE_INIT(cert, certkey->certificate.ptr, certkey->certificate.len); + ptrlen certtype = get_string(cert); + + copy_string(certkey->nonce, cert); + certkey->exponent = get_mp_ssh2(cert); + certkey->modulus = get_mp_ssh2(cert); + certkey->serial = get_uint64(cert); + certkey->type = get_uint32(cert); + copy_string(certkey->keyid, cert); + copy_string(certkey->principals, cert); + certkey->valid_after = get_uint64(cert); + certkey->valid_before = get_uint64(cert); + copy_string(certkey->options, cert); + copy_string(certkey->extensions, cert); + copy_string(certkey->reserved, cert); + + ptrlen sigkey = get_string(cert); + + copy_string(certkey->signature, cert); + + if (get_err(cert) || !ptrlen_eq_string(certtype, ssh_cert_rsa.ssh_id)) { + rsa2cert_freekey(&certkey->sshk); + return NULL; + } + + BinarySource sk[1]; + BinarySource_BARE_INIT(sk, sigkey.ptr, sigkey.len); + ptrlen algname = get_string(sk); + ssh_key signature_key = find_pubkey_alg_len(algname); + if (signature_key != NULL) { + certkey->sigkey = ssh_key_new_pub(signature_key, get_data(sk, get_avail(sk))); + } else { + certkey->sigkey = NULL; + } + + if (get_err(sk)) { + rsa2cert_freekey(&certkey->sshk); + return NULL; + } + + return &certkey->sshk; +} + +static void rsa2cert_sign(ssh_key *key, const void* data, int datalen, + BinarySink *bs) +{ + struct RSACertKey *certkey = container_of(key, struct RSACertKey, sshk); + struct RSAKey rsakey; + + rsakey.modulus = certkey->modulus; + rsakey.exponent = certkey->exponent; + rsakey.private_exponent = certkey->private_exponent; + rsakey.p = certkey->p; + rsakey.q = certkey->q; + rsakey.iqmp = certkey->iqmp; + rsakey.comment = ""; + rsakey.sshk = &ssh_rsa; + + return ssh_key_sign(&rsakey.sshk, data, datalen, bs); +} + +static bool rsa2cert_verify(ssh_key *key, ptrlen sig, ptrlen data) +{ + struct RSACertKey *certkey = container_of(key, struct RSACertKey, sshk); + struct RSAKey rsakey; + + rsakey.modulus = certkey->modulus; + rsakey.exponent = certkey->exponent; + rsakey.private_exponent = certkey->private_exponent; + rsakey.p = certkey->p; + rsakey.q = certkey->q; + rsakey.iqmp = certkey->iqmp; + rsakey.comment = ""; + rsakey.sshk = &ssh_rsa; + + return ssh_key_verify(&rsakey.sshk, sig, data); +} + +static void rsa2cert_public_blob(ssh_key *key, BinarySink *bs) +{ + struct RSACertKey *certkey = container_of(key, struct RSACertKey, sshk); + + // copy the certificate + put_data(bs, certkey->certificate.ptr, certkey->certificate.len); +} + +static void rsa2cert_private_blob(ssh_key *key, BinarySink *bs) +{ + struct RSACertKey *rsa = container_of(key, struct RSACertKey, sshk); + + put_mp_ssh2(bs, rsa->private_exponent); + put_mp_ssh2(bs, rsa->p); + put_mp_ssh2(bs, rsa->q); + put_mp_ssh2(bs, rsa->iqmp); +} + +static void rsa2cert_openssh_blob(ssh_key* key, BinarySink *bs) +{ + // don't return anything. USed only for export, and we don't export certs +} + +// Used just for looking up host keys for now, so skip +static char * rsa2cert_cache_str(ssh_key *key) +{ + char *p = snewn(1, char); + p[0] = '\0'; + return p; +} + +static int rsa2cert_pubkey_bits(const ssh_keyalg *self, ptrlen pub) +{ + ssh_key *sshk; + struct RSACertKey *certkey; + int ret; + + sshk = rsa2cert_new_pub(self, pub); + if (!sshk) + return -1; + + certkey = container_of(sshk, struct RSACertKey, sshk); + ret = bignum_bitcount(certkey->modulus); + rsa2cert_freekey(&certkey->sshk); + + return ret; +} + +const ssh_keyalg ssh_cert_rsa = { + rsa2cert_new_pub, + rsa2cert_new_priv, + rsa2cert_new_priv_openssh, + + rsa2cert_freekey, + rsa2cert_sign, + rsa2cert_verify, + rsa2cert_public_blob, + rsa2cert_private_blob, + rsa2cert_openssh_blob, + rsa2cert_cache_str, + + rsa2cert_pubkey_bits, + + "ssh-rsa-cert-v01@openssh.com", + "rsa2cert", + NULL, +}; From 00afd298cac17665299b0b3d28ae621ca546ece1 Mon Sep 17 00:00:00 2001 From: Will Lauer Date: Tue, 4 Dec 2018 16:49:03 -0600 Subject: [PATCH 601/607] Adding DSS Cert support --- Recipe | 8 +- ssh.h | 25 +++- sshdsscert.c | 316 +++++++++++++++++++++++++++++++++++++++++++++++++++ sshpubk.c | 2 + 4 files changed, 346 insertions(+), 5 deletions(-) create mode 100644 sshdsscert.c diff --git a/Recipe b/Recipe index 9e895a6d..7abcebb5 100644 --- a/Recipe +++ b/Recipe @@ -252,7 +252,7 @@ NONSSH = telnet raw rlogin ldisc pinger # SSH back end (putty, plink, pscp, psftp). SSHCOMMON = sshcommon sshrand + sshverstring sshcrc sshdes sshmd5 sshrsa sshrsacert sshsha sshblowf - + sshdh sshcrcda sshpubk sshzlib sshdss ssharcf + + sshdh sshcrcda sshpubk sshzlib sshdss sshdsscert ssharcf + sshaes sshccp sshsh256 sshsh512 sshbn sshmac marshal nullplug + sshgssc pgssapi sshecc wildcard ssh1censor ssh2censor ssh2bpp + ssh2transport ssh2transhk ssh2connection portfwd x11fwd @@ -326,11 +326,11 @@ psftp : [C] psftp winsftp wincons WINSSH BE_SSH SFTP wildcard WINMISC + psftp.res winnojmp LIBS pageant : [G] winpgnt pageant sshrsa sshrsacert sshpubk sshdes sshbn sshmd5 version - + tree234 MISC sshaes sshsha winsecur winpgntc aqsync sshdss sshsh256 + + tree234 MISC sshaes sshsha winsecur winpgntc aqsync sshdss sshdsscert sshsh256 + sshsh512 winutils sshecc winmisc winhelp conf pageant.res LIBS puttygen : [G] winpgen sshrsag sshdssg sshprime sshdes sshbn sshmd5 version - + sshrand winnoise sshsha winstore MISC winctrls sshrsa sshrsacert sshdss winmisc + + sshrand winnoise sshsha winstore MISC winctrls sshrsa sshrsacert sshdss sshdsscert winmisc + sshpubk sshaes sshsh256 sshsh512 IMPORT winutils puttygen.res + tree234 notiming winhelp winnojmp CONF LIBS wintime sshecc + sshecdsag winsecur @@ -359,7 +359,7 @@ pscp : [U] pscp uxsftp uxcons UXSSH BE_SSH SFTP wildcard UXMISC uxnogtk psftp : [U] psftp uxsftp uxcons UXSSH BE_SSH SFTP wildcard UXMISC uxnogtk pageant : [X] uxpgnt uxagentc aqsync pageant sshrsa sshrsacert sshpubk sshdes sshbn - + sshmd5 version tree234 misc sshaes sshsha sshdss sshsh256 sshsh512 + + sshmd5 version tree234 misc sshaes sshsha sshdss sshdsscert sshsh256 sshsh512 + sshecc CONF uxsignal nocproxy nogss be_none x11fwd ux_x11 uxcons + gtkask gtkmisc nullplug logging UXMISC uxagentsock diff --git a/ssh.h b/ssh.h index eb458237..7ae486dc 100644 --- a/ssh.h +++ b/ssh.h @@ -439,6 +439,28 @@ struct dss_key { ssh_key sshk; }; +struct dss_cert_key { + ptrlen certificate; + char* nonce; + Bignum p; + Bignum q; + Bignum g; + Bignum y; + uint64_t serial; + uint32_t type; + char * keyid; + char * principals; + uint64_t valid_after; + uint64_t valid_before; + char * options; + char * extensions; + char * reserved; + ssh_key* sigkey; + char * signature; + Bignum x; + ssh_key sshk; +}; + struct ec_curve; struct ec_point { @@ -459,7 +481,7 @@ struct ec_wcurve struct ec_point G; }; -/* Montgomery form curve */ +/* Montgomery form curvfe */ struct ec_mcurve { Bignum a, b; @@ -897,6 +919,7 @@ extern const ssh_keyalg ssh_ecdsa_nistp256; extern const ssh_keyalg ssh_ecdsa_nistp384; extern const ssh_keyalg ssh_ecdsa_nistp521; extern const ssh_keyalg ssh_cert_rsa; +extern const ssh_keyalg ssh_cert_dss; extern const struct ssh2_macalg ssh_hmac_md5; extern const struct ssh2_macalg ssh_hmac_sha1; extern const struct ssh2_macalg ssh_hmac_sha1_buggy; diff --git a/sshdsscert.c b/sshdsscert.c new file mode 100644 index 00000000..ac0432fa --- /dev/null +++ b/sshdsscert.c @@ -0,0 +1,316 @@ +/* + * DSS Certificate implementation for PuTTY. + */ + +#include +#include +#include +#include + +#include "ssh.h" +#include "misc.h" + +#define copy_string(field, src) field = mkstr(get_string(cert)) + +void freedsscertkey(struct dss_cert_key* key) +{ + if (key->certificate.ptr) + sfree((void*)(key->certificate.ptr)); + if (key->nonce) + sfree(key->nonce); + if (key->p) + freebn(key->p); + if (key->q) + freebn(key->q); + if (key->g) + freebn(key->g); + if (key->y) + freebn(key->y); + if (key->keyid) + sfree(key->keyid); + if (key->principals) + sfree(key->principals); + if (key->options) + sfree(key->options); + if (key->extensions) + sfree(key->extensions); + if (key->reserved) + sfree(key->reserved); + if (key->sigkey) + ssh_key_free(key->sigkey); + if (key->signature) + sfree(key->signature); + if (key->x) + freebn(key->x); +} + +/* ----------------------------------------------------------------------- + * Implementation of the ssh-dss-cert-v01@openssh.com key type + */ + +static void dsscert_freekey(ssh_key *key); /* forward reference */ + +static ssh_key *dsscert_new_pub(const ssh_keyalg *self, ptrlen data) +{ + BinarySource src[1]; + struct dss_cert_key *certkey; + + BinarySource_BARE_INIT(src, data.ptr, data.len); + if (!ptrlen_eq_string(get_string(src), "ssh-rsa-cert-v01@openssh.com")) + return NULL; + + certkey = snew(struct dss_cert_key); + certkey->sshk = &ssh_cert_dss; + + ptrlen certdata = get_string(src); + certkey->certificate.ptr = snewn(certdata.len, char); + memcpy((void*)(certkey->certificate.ptr), certdata.ptr, certdata.len); + certkey->certificate.len = certdata.len; + + certkey->x = NULL; + certkey->p = certkey->q = certkey->g = certkey->y = NULL; + certkey->nonce = certkey->keyid = certkey->principals = NULL; + certkey->options = certkey->extensions = certkey->reserved = NULL; + certkey->sigkey = NULL; + certkey->signature = NULL; + + if (get_err(src)) { + dsscert_freekey(&certkey->sshk); + return NULL; + } + + BinarySource cert[1]; + BinarySource_BARE_INIT(cert, certkey->certificate.ptr, certkey->certificate.len); + ptrlen certtype = get_string(cert); + copy_string(certkey->nonce, cert); + certkey->p = get_mp_ssh2(cert); + certkey->q = get_mp_ssh2(cert); + certkey->g = get_mp_ssh2(cert); + certkey->y = get_mp_ssh2(cert); + certkey->serial = get_uint64(cert); + certkey->type = get_uint32(cert); + copy_string(certkey->keyid, cert); + copy_string(certkey->principals, cert); + certkey->valid_after = get_uint64(cert); + certkey->valid_before = get_uint64(cert); + copy_string(certkey->options, cert); + copy_string(certkey->extensions, cert); + copy_string(certkey->reserved, cert); + + ptrlen sigkey = get_string(cert); + + copy_string(certkey->signature, cert); + + if (get_err(cert) || !ptrlen_eq_string(certtype, ssh_cert_dss.ssh_id)) { + dsscert_freekey(&certkey->sshk); + return NULL; + } + + BinarySource sk[1]; + BinarySource_BARE_INIT(sk, sigkey.ptr, sigkey.len); + ptrlen algname = get_string(sk); + ssh_key signature_key = find_pubkey_alg_len(algname); + if (signature_key != NULL) { + certkey->sigkey = ssh_key_new_pub(signature_key, get_data(sk, get_avail(sk))); + } + + if (get_err(sk)) { + dsscert_freekey(&certkey->sshk); + return NULL; + } + + return &certkey->sshk; +} + +static void dsscert_freekey(ssh_key *key) +{ + struct dss_cert_key *certkey = container_of(key, struct dss_cert_key, sshk); + freedsscertkey(certkey); + sfree(certkey); +} + +static ssh_key *dsscert_new_priv(const ssh_keyalg *self, + ptrlen pub, ptrlen priv) +{ + BinarySource src[1]; + ssh_key *sshk; + struct dss_cert_key *certkey; + + sshk = dsscert_new_pub(self, pub); + if (!sshk) { + return NULL; + } + + certkey = container_of(sshk, struct dss_cert_key, sshk); + BinarySource_BARE_INIT(src, priv.ptr, priv.len); + certkey->x = get_mp_ssh2(src); + + if (get_err(src) || false /*dsscert_verify(certkey)*/) { + dsscert_freekey(&certkey->sshk); + return NULL; + } + + return &certkey->sshk; +} + +static ssh_key *dsscert_new_priv_openssh(const ssh_keyalg *self, + BinarySource *src) +{ + struct dss_cert_key *certkey; + + certkey = snew(struct dss_cert_key); + certkey->sshk = &ssh_cert_dss; + + ptrlen certdata = get_string(src); + certkey->certificate.ptr = snewn(certdata.len, char); + memcpy((void*)(certkey->certificate.ptr), certdata.ptr, certdata.len); + certkey->certificate.len = certdata.len; + certkey->x = get_mp_ssh2(src); + + if (get_err(src) || false /*dsscert_verify(certkey)*/) { + dsscert_freekey(&certkey->sshk); + return NULL; + } + + BinarySource cert[1]; + BinarySource_BARE_INIT(cert, certkey->certificate.ptr, certkey->certificate.len); + ptrlen certtype = get_string(cert); + + copy_string(certkey->nonce, cert); + certkey->p = get_mp_ssh2(cert); + certkey->q = get_mp_ssh2(cert); + certkey->g = get_mp_ssh2(cert); + certkey->y = get_mp_ssh2(cert); + certkey->serial = get_uint64(cert); + certkey->type = get_uint32(cert); + copy_string(certkey->keyid, cert); + copy_string(certkey->principals, cert); + certkey->valid_after = get_uint64(cert); + certkey->valid_before = get_uint64(cert); + copy_string(certkey->options, cert); + copy_string(certkey->extensions, cert); + copy_string(certkey->reserved, cert); + + ptrlen sigkey = get_string(cert); + + copy_string(certkey->signature, cert); + + if (get_err(cert) || !ptrlen_eq_string(certtype, ssh_cert_dss.ssh_id)) { + dsscert_freekey(&certkey->sshk); + return NULL; + } + + BinarySource sk[1]; + BinarySource_BARE_INIT(sk, sigkey.ptr, sigkey.len); + ptrlen algname = get_string(sk); + ssh_key signature_key = find_pubkey_alg_len(algname); + if (signature_key != NULL) { + certkey->sigkey = ssh_key_new_pub(signature_key, get_data(sk, get_avail(sk))); + } else { + certkey->sigkey = NULL; + } + + if (get_err(sk)) { + dsscert_freekey(&certkey->sshk); + return NULL; + } + + return &certkey->sshk; +} + +static void dsscert_sign(ssh_key *key, const void* data, int datalen, + BinarySink *bs) +{ + struct dss_cert_key *certkey = container_of(key, struct dss_cert_key, sshk); + struct dss_key dsskey; + + dsskey.p = certkey->p; + dsskey.q = certkey->q; + dsskey.g = certkey->g; + dsskey.y = certkey->y; + dsskey.x = certkey->x; + dsskey.sshk = &ssh_dss; + + return ssh_key_sign(&dsskey.sshk, data, datalen, bs); +} + +static bool dsscert_verify(ssh_key *key, ptrlen sig, ptrlen data) +{ + struct dss_cert_key *certkey = container_of(key, struct dss_cert_key, sshk); + struct dss_key dsskey; + + dsskey.p = certkey->p; + dsskey.q = certkey->q; + dsskey.g = certkey->g; + dsskey.y = certkey->y; + dsskey.x = certkey->x; + + dsskey.sshk = &ssh_dss; + + return ssh_key_verify(&dsskey.sshk, sig, data); +} + +static void dsscert_public_blob(ssh_key *key, BinarySink *bs) +{ + struct dss_cert_key *certkey = container_of(key, struct dss_cert_key, sshk); + + // copy the certificate + put_data(bs, certkey->certificate.ptr, certkey->certificate.len); +} + +static void dsscert_private_blob(ssh_key *key, BinarySink *bs) +{ + struct dss_cert_key *dss = container_of(key, struct dss_cert_key, sshk); + + put_mp_ssh2(bs, dss->x); +} + +static void dsscert_openssh_blob(ssh_key* key, BinarySink *bs) +{ + // don't return anything. USed only for export, and we don't export certs +} + +// Used just for looking up host keys for now, so skip +static char * dsscert_cache_str(ssh_key *key) +{ + char *p = snewn(1, char); + p[0] = '\0'; + return p; +} + +static int dsscert_pubkey_bits(const ssh_keyalg *self, ptrlen pub) +{ + ssh_key *sshk; + struct dss_cert_key *certkey; + int ret; + + sshk = dsscert_new_pub(self, pub); + if (!sshk) + return -1; + + certkey = container_of(sshk, struct dss_cert_key, sshk); + ret = bignum_bitcount(certkey->p); + dsscert_freekey(&certkey->sshk); + + return ret; +} + +const ssh_keyalg ssh_cert_dss = { + dsscert_new_pub, + dsscert_new_priv, + dsscert_new_priv_openssh, + + dsscert_freekey, + dsscert_sign, + dsscert_verify, + dsscert_public_blob, + dsscert_private_blob, + dsscert_openssh_blob, + dsscert_cache_str, + + dsscert_pubkey_bits, + + "ssh-dss-cert-v01@openssh.com", + "dsscert", + NULL, +}; diff --git a/sshpubk.c b/sshpubk.c index ab3a2b17..ca68ac26 100644 --- a/sshpubk.c +++ b/sshpubk.c @@ -580,6 +580,8 @@ const ssh_keyalg *find_pubkey_alg_len(ptrlen name) return &ssh_ecdsa_ed25519; else if (ptrlen_eq_string(name, "ssh-rsa-cert-v01@openssh.com")) return &ssh_cert_rsa; + else if (ptrlen_eq_string(name, "ssh-dss-cert-v01@openssh.com")) + return &ssh_cert_dss; else return NULL; } From 050e35ded39e8f8860c94d0aaa6d0d0aa1e7d328 Mon Sep 17 00:00:00 2001 From: Will Lauer Date: Wed, 5 Dec 2018 14:30:17 -0600 Subject: [PATCH 602/607] RSA Cert cleanup --- sshrsacert.c | 161 ++++++++++++++++++++++++++++----------------------- 1 file changed, 88 insertions(+), 73 deletions(-) diff --git a/sshrsacert.c b/sshrsacert.c index eb9a97a4..b3683785 100644 --- a/sshrsacert.c +++ b/sshrsacert.c @@ -10,44 +10,6 @@ #include "ssh.h" #include "misc.h" -#define copy_string(field, src) field = mkstr(get_string(cert)) - -void freersacertkey(struct RSACertKey* key) -{ - if (key->certificate.ptr) - sfree((void*)(key->certificate.ptr)); - if (key->nonce) - sfree(key->nonce); - if (key->modulus) - freebn(key->modulus); - if (key->exponent) - freebn(key->exponent); - if (key->keyid) - sfree(key->keyid); - if (key->principals) - sfree(key->principals); - if (key->options) - sfree(key->options); - if (key->extensions) - sfree(key->extensions); - if (key->reserved) - sfree(key->reserved); - if (key->sigkey) - ssh_key_free(key->sigkey); - if (key->signature) - sfree(key->signature); - if (key->private_exponent) - freebn(key->private_exponent); - if (key->iqmp) - freebn(key->iqmp); - if (key->p) - freebn(key->p); - if (key->q) - freebn(key->q); - if (key->comment) - sfree(key->comment); -} - /* ----------------------------------------------------------------------- * Implementation of the ssh-rsa-cert-v01 key type */ @@ -60,16 +22,16 @@ static ssh_key *rsa2cert_new_pub(const ssh_keyalg *self, ptrlen data) struct RSACertKey *certkey; BinarySource_BARE_INIT(src, data.ptr, data.len); - if (!ptrlen_eq_string(get_string(src), "ssh-rsa-cert-v01@openssh.com")) + ptrlen certtype = get_string(src); + if (!ptrlen_eq_string(certtype, ssh_cert_rsa.ssh_id)) return NULL; certkey = snew(struct RSACertKey); certkey->sshk = &ssh_cert_rsa; - ptrlen certdata = get_string(src); - certkey->certificate.ptr = snewn(certdata.len, char); - memcpy((void*)(certkey->certificate.ptr), certdata.ptr, certdata.len); - certkey->certificate.len = certdata.len; + certkey->certificate.ptr = snewn(data.len, char); + memcpy((void*)(certkey->certificate.ptr), data.ptr, data.len); + certkey->certificate.len = data.len; certkey->private_exponent = NULL; certkey->p = certkey->q = certkey->iqmp = NULL; @@ -85,27 +47,24 @@ static ssh_key *rsa2cert_new_pub(const ssh_keyalg *self, ptrlen data) return NULL; } - BinarySource cert[1]; - BinarySource_BARE_INIT(cert, certkey->certificate.ptr, certkey->certificate.len); - ptrlen certtype = get_string(cert); - copy_string(certkey->nonce, cert); - certkey->exponent = get_mp_ssh2(cert); - certkey->modulus = get_mp_ssh2(cert); - certkey->serial = get_uint64(cert); - certkey->type = get_uint32(cert); - copy_string(certkey->keyid, cert); - copy_string(certkey->principals, cert); - certkey->valid_after = get_uint64(cert); - certkey->valid_before = get_uint64(cert); - copy_string(certkey->options, cert); - copy_string(certkey->extensions, cert); - copy_string(certkey->reserved, cert); + certkey->nonce = mkstr(get_string(src)); + certkey->exponent = get_mp_ssh2(src); + certkey->modulus = get_mp_ssh2(src); + certkey->serial = get_uint64(src); + certkey->type = get_uint32(src); + certkey->keyid = mkstr(get_string(src)); + certkey->principals = mkstr(get_string(src)); + certkey->valid_after = get_uint64(src); + certkey->valid_before = get_uint64(src); + certkey->options = mkstr(get_string(src)); + certkey->extensions = mkstr(get_string(src)); + certkey->reserved = mkstr(get_string(src)); - ptrlen sigkey = get_string(cert); + ptrlen sigkey = get_string(src); - copy_string(certkey->signature, cert); + certkey->signature = mkstr(get_string(src)); - if (get_err(cert) || !ptrlen_eq_string(certtype, ssh_cert_rsa.ssh_id)) { + if (get_err(src)) { rsa2cert_freekey(&certkey->sshk); return NULL; } @@ -129,7 +88,40 @@ static ssh_key *rsa2cert_new_pub(const ssh_keyalg *self, ptrlen data) static void rsa2cert_freekey(ssh_key *key) { struct RSACertKey *certkey = container_of(key, struct RSACertKey, sshk); - freersacertkey(certkey); + + if (certkey->certificate.ptr) + sfree((void*)(certkey->certificate.ptr)); + if (certkey->nonce) + sfree(certkey->nonce); + if (certkey->modulus) + freebn(certkey->modulus); + if (certkey->exponent) + freebn(certkey->exponent); + if (certkey->keyid) + sfree(certkey->keyid); + if (certkey->principals) + sfree(certkey->principals); + if (certkey->options) + sfree(certkey->options); + if (certkey->extensions) + sfree(certkey->extensions); + if (certkey->reserved) + sfree(certkey->reserved); + if (certkey->sigkey) + ssh_key_free(certkey->sigkey); + if (certkey->signature) + sfree(certkey->signature); + if (certkey->private_exponent) + freebn(certkey->private_exponent); + if (certkey->iqmp) + freebn(certkey->iqmp); + if (certkey->p) + freebn(certkey->p); + if (certkey->q) + freebn(certkey->q); + if (certkey->comment) + sfree(certkey->comment); + sfree(certkey); } @@ -148,12 +140,23 @@ static ssh_key *rsa2cert_new_priv(const ssh_keyalg *self, certkey = container_of(sshk, struct RSACertKey, sshk); BinarySource_BARE_INIT(src, priv.ptr, priv.len); certkey->private_exponent = get_mp_ssh2(src); - certkey->iqmp = get_mp_ssh2(src); certkey->p = get_mp_ssh2(src); certkey->q = get_mp_ssh2(src); + certkey->iqmp = get_mp_ssh2(src); certkey->comment = NULL; - if (get_err(src) || false /*rsa2cert_verify(certkey)*/) { + struct RSAKey rsakey; + + rsakey.modulus = certkey->modulus; + rsakey.exponent = certkey->exponent; + rsakey.private_exponent = certkey->private_exponent; + rsakey.p = certkey->p; + rsakey.q = certkey->q; + rsakey.iqmp = certkey->iqmp; + rsakey.comment = ""; + rsakey.sshk = &ssh_rsa; + + if (get_err(src) || !rsa_verify(&rsakey)) { rsa2cert_freekey(&certkey->sshk); return NULL; } @@ -179,7 +182,7 @@ static ssh_key *rsa2cert_new_priv_openssh(const ssh_keyalg *self, certkey->p = get_mp_ssh2(src); certkey->q = get_mp_ssh2(src); - if (get_err(src) || false /*rsa2cert_verify(certkey)*/) { + if (get_err(src)) { rsa2cert_freekey(&certkey->sshk); return NULL; } @@ -188,24 +191,36 @@ static ssh_key *rsa2cert_new_priv_openssh(const ssh_keyalg *self, BinarySource_BARE_INIT(cert, certkey->certificate.ptr, certkey->certificate.len); ptrlen certtype = get_string(cert); - copy_string(certkey->nonce, cert); + certkey->nonce = mkstr(get_string(cert)); certkey->exponent = get_mp_ssh2(cert); certkey->modulus = get_mp_ssh2(cert); certkey->serial = get_uint64(cert); certkey->type = get_uint32(cert); - copy_string(certkey->keyid, cert); - copy_string(certkey->principals, cert); + certkey->keyid = mkstr(get_string(cert)); + certkey->principals = mkstr(get_string(cert)); certkey->valid_after = get_uint64(cert); certkey->valid_before = get_uint64(cert); - copy_string(certkey->options, cert); - copy_string(certkey->extensions, cert); - copy_string(certkey->reserved, cert); + certkey->options = mkstr(get_string(cert)); + certkey->extensions = mkstr(get_string(cert)); + certkey->reserved = mkstr(get_string(cert)); ptrlen sigkey = get_string(cert); - copy_string(certkey->signature, cert); + certkey->signature = mkstr(get_string(cert)); + + struct RSAKey rsakey; + + rsakey.modulus = certkey->modulus; + rsakey.exponent = certkey->exponent; + rsakey.private_exponent = certkey->private_exponent; + rsakey.p = certkey->p; + rsakey.q = certkey->q; + rsakey.iqmp = certkey->iqmp; + rsakey.comment = ""; + rsakey.sshk = &ssh_rsa; - if (get_err(cert) || !ptrlen_eq_string(certtype, ssh_cert_rsa.ssh_id)) { + if (get_err(cert) || !ptrlen_eq_string(certtype, ssh_cert_rsa.ssh_id) + || !rsa_verify(&rsakey)) { rsa2cert_freekey(&certkey->sshk); return NULL; } From 31b788740ba671e0f1fa1c8e5f59120fc45d26e5 Mon Sep 17 00:00:00 2001 From: Will Lauer Date: Wed, 5 Dec 2018 14:30:38 -0600 Subject: [PATCH 603/607] DSS cert cleanup --- sshdsscert.c | 148 ++++++++++++++++++++++++++------------------------- 1 file changed, 76 insertions(+), 72 deletions(-) diff --git a/sshdsscert.c b/sshdsscert.c index ac0432fa..257b85df 100644 --- a/sshdsscert.c +++ b/sshdsscert.c @@ -10,40 +10,6 @@ #include "ssh.h" #include "misc.h" -#define copy_string(field, src) field = mkstr(get_string(cert)) - -void freedsscertkey(struct dss_cert_key* key) -{ - if (key->certificate.ptr) - sfree((void*)(key->certificate.ptr)); - if (key->nonce) - sfree(key->nonce); - if (key->p) - freebn(key->p); - if (key->q) - freebn(key->q); - if (key->g) - freebn(key->g); - if (key->y) - freebn(key->y); - if (key->keyid) - sfree(key->keyid); - if (key->principals) - sfree(key->principals); - if (key->options) - sfree(key->options); - if (key->extensions) - sfree(key->extensions); - if (key->reserved) - sfree(key->reserved); - if (key->sigkey) - ssh_key_free(key->sigkey); - if (key->signature) - sfree(key->signature); - if (key->x) - freebn(key->x); -} - /* ----------------------------------------------------------------------- * Implementation of the ssh-dss-cert-v01@openssh.com key type */ @@ -56,16 +22,16 @@ static ssh_key *dsscert_new_pub(const ssh_keyalg *self, ptrlen data) struct dss_cert_key *certkey; BinarySource_BARE_INIT(src, data.ptr, data.len); - if (!ptrlen_eq_string(get_string(src), "ssh-rsa-cert-v01@openssh.com")) + ptrlen certtype = get_string(src); + if (!ptrlen_eq_string(certtype, ssh_cert_dss.ssh_id)) return NULL; certkey = snew(struct dss_cert_key); certkey->sshk = &ssh_cert_dss; - ptrlen certdata = get_string(src); - certkey->certificate.ptr = snewn(certdata.len, char); - memcpy((void*)(certkey->certificate.ptr), certdata.ptr, certdata.len); - certkey->certificate.len = certdata.len; + certkey->certificate.ptr = snewn(data.len, char); + memcpy((void*)(certkey->certificate.ptr), data.ptr, data.len); + certkey->certificate.len = data.len; certkey->x = NULL; certkey->p = certkey->q = certkey->g = certkey->y = NULL; @@ -79,29 +45,26 @@ static ssh_key *dsscert_new_pub(const ssh_keyalg *self, ptrlen data) return NULL; } - BinarySource cert[1]; - BinarySource_BARE_INIT(cert, certkey->certificate.ptr, certkey->certificate.len); - ptrlen certtype = get_string(cert); - copy_string(certkey->nonce, cert); - certkey->p = get_mp_ssh2(cert); - certkey->q = get_mp_ssh2(cert); - certkey->g = get_mp_ssh2(cert); - certkey->y = get_mp_ssh2(cert); - certkey->serial = get_uint64(cert); - certkey->type = get_uint32(cert); - copy_string(certkey->keyid, cert); - copy_string(certkey->principals, cert); - certkey->valid_after = get_uint64(cert); - certkey->valid_before = get_uint64(cert); - copy_string(certkey->options, cert); - copy_string(certkey->extensions, cert); - copy_string(certkey->reserved, cert); - - ptrlen sigkey = get_string(cert); - - copy_string(certkey->signature, cert); + certkey->nonce = mkstr(get_string(src)); + certkey->p = get_mp_ssh2(src); + certkey->q = get_mp_ssh2(src); + certkey->g = get_mp_ssh2(src); + certkey->y = get_mp_ssh2(src); + certkey->serial = get_uint64(src); + certkey->type = get_uint32(src); + certkey->keyid = mkstr(get_string(src)); + certkey->principals = mkstr(get_string(src)); + certkey->valid_after = get_uint64(src); + certkey->valid_before = get_uint64(src); + certkey->options = mkstr(get_string(src)); + certkey->extensions = mkstr(get_string(src)); + certkey->reserved = mkstr(get_string(src)); + + ptrlen sigkey = get_string(src); + + certkey->signature = mkstr(get_string(src)); - if (get_err(cert) || !ptrlen_eq_string(certtype, ssh_cert_dss.ssh_id)) { + if (get_err(src)) { dsscert_freekey(&certkey->sshk); return NULL; } @@ -125,7 +88,36 @@ static ssh_key *dsscert_new_pub(const ssh_keyalg *self, ptrlen data) static void dsscert_freekey(ssh_key *key) { struct dss_cert_key *certkey = container_of(key, struct dss_cert_key, sshk); - freedsscertkey(certkey); + + if (certkey->certificate.ptr) + sfree((void*)(certkey->certificate.ptr)); + if (certkey->nonce) + sfree(certkey->nonce); + if (certkey->p) + freebn(certkey->p); + if (certkey->q) + freebn(certkey->q); + if (certkey->g) + freebn(certkey->g); + if (certkey->y) + freebn(certkey->y); + if (certkey->keyid) + sfree(certkey->keyid); + if (certkey->principals) + sfree(certkey->principals); + if (certkey->options) + sfree(certkey->options); + if (certkey->extensions) + sfree(certkey->extensions); + if (certkey->reserved) + sfree(certkey->reserved); + if (certkey->sigkey) + ssh_key_free(certkey->sigkey); + if (certkey->signature) + sfree(certkey->signature); + if (certkey->x) + freebn(certkey->x); + sfree(certkey); } @@ -135,6 +127,7 @@ static ssh_key *dsscert_new_priv(const ssh_keyalg *self, BinarySource src[1]; ssh_key *sshk; struct dss_cert_key *certkey; + Bignum ytest; sshk = dsscert_new_pub(self, pub); if (!sshk) { @@ -145,11 +138,20 @@ static ssh_key *dsscert_new_priv(const ssh_keyalg *self, BinarySource_BARE_INIT(src, priv.ptr, priv.len); certkey->x = get_mp_ssh2(src); - if (get_err(src) || false /*dsscert_verify(certkey)*/) { + if (get_err(src)) { dsscert_freekey(&certkey->sshk); return NULL; } + /* validate the key - from sshdss.c */ + ytest = modpow(certkey->g, certkey->x, certkey->p); + if (0 != bignum_cmp(ytest, certkey->y)) { + dsscert_freekey(&certkey->sshk); + freebn(ytest); + return NULL; + } + freebn(ytest); + return &certkey->sshk; } @@ -167,7 +169,7 @@ static ssh_key *dsscert_new_priv_openssh(const ssh_keyalg *self, certkey->certificate.len = certdata.len; certkey->x = get_mp_ssh2(src); - if (get_err(src) || false /*dsscert_verify(certkey)*/) { + if (get_err(src)) { dsscert_freekey(&certkey->sshk); return NULL; } @@ -176,26 +178,28 @@ static ssh_key *dsscert_new_priv_openssh(const ssh_keyalg *self, BinarySource_BARE_INIT(cert, certkey->certificate.ptr, certkey->certificate.len); ptrlen certtype = get_string(cert); - copy_string(certkey->nonce, cert); + certkey->nonce = mkstr(get_string(cert)); certkey->p = get_mp_ssh2(cert); certkey->q = get_mp_ssh2(cert); certkey->g = get_mp_ssh2(cert); certkey->y = get_mp_ssh2(cert); certkey->serial = get_uint64(cert); certkey->type = get_uint32(cert); - copy_string(certkey->keyid, cert); - copy_string(certkey->principals, cert); + certkey->keyid = mkstr(get_string(cert)); + certkey->principals = mkstr(get_string(cert)); certkey->valid_after = get_uint64(cert); certkey->valid_before = get_uint64(cert); - copy_string(certkey->options, cert); - copy_string(certkey->extensions, cert); - copy_string(certkey->reserved, cert); + certkey->options = mkstr(get_string(cert)); + certkey->extensions = mkstr(get_string(cert)); + certkey->reserved = mkstr(get_string(cert)); ptrlen sigkey = get_string(cert); - copy_string(certkey->signature, cert); + certkey->signature = mkstr(get_string(cert)); - if (get_err(cert) || !ptrlen_eq_string(certtype, ssh_cert_dss.ssh_id)) { + /* validate the key - from sshdss.c */ + if (get_err(cert) || !ptrlen_eq_string(certtype, ssh_cert_dss.ssh_id) + || !bignum_cmp(certkey->q, Zero) || !bignum_cmp(certkey->p, Zero)) { dsscert_freekey(&certkey->sshk); return NULL; } From 22ffd0b455b4561f54f56212995d82930cfa8396 Mon Sep 17 00:00:00 2001 From: Will Lauer Date: Wed, 5 Dec 2018 14:30:58 -0600 Subject: [PATCH 604/607] Load certs in pageant --- pageant.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- ssh.h | 3 +++ 2 files changed, 66 insertions(+), 2 deletions(-) diff --git a/pageant.c b/pageant.c index eb1fd534..db48f8be 100644 --- a/pageant.c +++ b/pageant.c @@ -999,6 +999,7 @@ int pageant_add_keyfile(Filename *filename, const char *passphrase, { struct RSAKey *rkey = NULL; struct ssh2_userkey *skey = NULL; + struct ssh2_userkey *ckey = NULL; bool needs_pass; int ret; int attempts; @@ -1213,6 +1214,36 @@ int pageant_add_keyfile(Filename *filename, const char *passphrase, * rkey/skey, but not yet added it to the agent. */ + /* + * attempt to load a certificate + */ + Filename certfilename; + certfilename.path = dupprintf("%s-cert", filename->path); + FILE* certfile = f_open(&certfilename, "rb", false); + sfree(certfilename.path); + + if (certfile) { + strbuf* certblob = strbuf_new(); + char* certalg = NULL; + char* comment = NULL; + const char* errstring = NULL; + if (openssh_loadpub(certfile, &certalg, BinarySink_UPCAST(certblob), &comment, &errstring)) { + strbuf* privblob = strbuf_new(); + ssh_key_private_blob(skey->key, BinarySink_UPCAST(privblob)); + const ssh_keyalg* alg = find_pubkey_alg(certalg); + ssh_key* cert = ssh_key_new_priv(alg, ptrlen_from_strbuf(certblob), ptrlen_from_strbuf(privblob)); + if (cert) { + ckey = snew(struct ssh2_userkey); + ckey->key = cert; + ckey->comment = comment; + } + strbuf_free(privblob); + } + strbuf_free(certblob); + fclose(certfile); + certfile = NULL; + } + /* * If the key was successfully decrypted, save the passphrase for * use with other keys we try to load. @@ -1291,11 +1322,41 @@ int pageant_add_keyfile(Filename *filename, const char *passphrase, } sfree(response); + + /* add cert here if it was found */ + + if (ckey != NULL) { + request = strbuf_new_for_agent_query(); + put_byte(request, SSH2_AGENTC_ADD_IDENTITY); + put_stringz(request, ssh_key_ssh_id(ckey->key)); + ssh_key_openssh_blob(ckey->key, BinarySink_UPCAST(request)); + put_stringz(request, ckey->comment); + agent_query_synchronous(request, &vresponse, &resplen); + strbuf_free(request); + + response = vresponse; + if (resplen < 5 || response[4] != SSH_AGENT_SUCCESS) { + *retstr = dupstr("The already running Pageant " + "refused to add the certificate."); + sfree(response); + return PAGEANT_ACTION_FAILURE; + } + + sfree(response); + } + } else { if (!pageant_add_ssh2_key(skey)) { - ssh_key_free(skey->key); - sfree(skey); /* already present, don't waste RAM */ + ssh_key_free(skey->key); + sfree(skey); /* already present, don't waste RAM */ } + + /* add cert here if it was found */ + if (ckey != NULL && !pageant_add_ssh2_key(ckey)) { + ssh_key_free(ckey->key); + sfree(ckey); /* already present, don't waste RAM */ + } + } } return PAGEANT_ACTION_OK; diff --git a/ssh.h b/ssh.h index 7ae486dc..32fc9937 100644 --- a/ssh.h +++ b/ssh.h @@ -1166,6 +1166,9 @@ bool ssh2_userkey_loadpub(const Filename *filename, char **algorithm, char **commentptr, const char **errorstr); bool ssh2_save_userkey(const Filename *filename, struct ssh2_userkey *key, char *passphrase); +bool openssh_loadpub(FILE *fp, char **algorithm, + BinarySink *bs, + char **commentptr, const char **errorstr); const ssh_keyalg *find_pubkey_alg(const char *name); const ssh_keyalg *find_pubkey_alg_len(ptrlen name); From 430824c245e77032303d03b1a8465e4c498d2c37 Mon Sep 17 00:00:00 2001 From: Will Lauer Date: Fri, 7 Dec 2018 13:23:51 -0600 Subject: [PATCH 605/607] Adding ecdsa certificate support and general cleanup --- Recipe | 10 +- pageant.c | 14 +- ssh.h | 33 +++++ sshdsscert.c | 19 +-- sshecc.c | 12 +- sshecccert.c | 398 +++++++++++++++++++++++++++++++++++++++++++++++++++ sshpubk.c | 6 + sshrsacert.c | 10 +- 8 files changed, 463 insertions(+), 39 deletions(-) create mode 100644 sshecccert.c diff --git a/Recipe b/Recipe index 7abcebb5..13d9d8f1 100644 --- a/Recipe +++ b/Recipe @@ -254,7 +254,7 @@ SSHCOMMON = sshcommon sshrand + sshverstring sshcrc sshdes sshmd5 sshrsa sshrsacert sshsha sshblowf + sshdh sshcrcda sshpubk sshzlib sshdss sshdsscert ssharcf + sshaes sshccp sshsh256 sshsh512 sshbn sshmac marshal nullplug - + sshgssc pgssapi sshecc wildcard ssh1censor ssh2censor ssh2bpp + + sshgssc pgssapi sshecc sshecccert wildcard ssh1censor ssh2censor ssh2bpp + ssh2transport ssh2transhk ssh2connection portfwd x11fwd + ssh1connection ssh1bpp SSH = SSHCOMMON ssh ssh2bpp-bare @@ -327,12 +327,12 @@ psftp : [C] psftp winsftp wincons WINSSH BE_SSH SFTP wildcard WINMISC pageant : [G] winpgnt pageant sshrsa sshrsacert sshpubk sshdes sshbn sshmd5 version + tree234 MISC sshaes sshsha winsecur winpgntc aqsync sshdss sshdsscert sshsh256 - + sshsh512 winutils sshecc winmisc winhelp conf pageant.res LIBS + + sshsh512 winutils sshecc sshecccert winmisc winhelp conf pageant.res LIBS puttygen : [G] winpgen sshrsag sshdssg sshprime sshdes sshbn sshmd5 version + sshrand winnoise sshsha winstore MISC winctrls sshrsa sshrsacert sshdss sshdsscert winmisc + sshpubk sshaes sshsh256 sshsh512 IMPORT winutils puttygen.res - + tree234 notiming winhelp winnojmp CONF LIBS wintime sshecc + + tree234 notiming winhelp winnojmp CONF LIBS wintime sshecc sshecccert + sshecdsag winsecur pterm : [X] GTKTERM uxmisc misc ldisc settings uxpty uxsel BE_NONE uxstore @@ -351,7 +351,7 @@ plink : [U] uxplink uxcons NONSSH UXSSH U_BE_ALL logging UXMISC uxsignal PUTTYGEN_UNIX = sshrsag sshdssg sshprime sshdes sshbn sshmd5 version + sshrand uxnoise sshsha MISC sshrsa sshdss uxcons uxstore uxmisc + sshpubk sshaes sshsh256 sshsh512 IMPORT puttygen.res time tree234 - + uxgen notiming CONF sshecc sshecdsag uxnogtk + + uxgen notiming CONF sshecc sshecccert sshecdsag uxnogtk puttygen : [U] cmdgen PUTTYGEN_UNIX cgtest : [UT] cgtest PUTTYGEN_UNIX @@ -360,7 +360,7 @@ psftp : [U] psftp uxsftp uxcons UXSSH BE_SSH SFTP wildcard UXMISC uxnogtk pageant : [X] uxpgnt uxagentc aqsync pageant sshrsa sshrsacert sshpubk sshdes sshbn + sshmd5 version tree234 misc sshaes sshsha sshdss sshdsscert sshsh256 sshsh512 - + sshecc CONF uxsignal nocproxy nogss be_none x11fwd ux_x11 uxcons + + sshecc sshecccert CONF uxsignal nocproxy nogss be_none x11fwd ux_x11 uxcons + gtkask gtkmisc nullplug logging UXMISC uxagentsock ptermapp : [XT] GTKTERM uxmisc misc ldisc settings uxpty uxsel BE_NONE uxstore diff --git a/pageant.c b/pageant.c index db48f8be..fb17a077 100644 --- a/pageant.c +++ b/pageant.c @@ -1231,13 +1231,15 @@ int pageant_add_keyfile(Filename *filename, const char *passphrase, strbuf* privblob = strbuf_new(); ssh_key_private_blob(skey->key, BinarySink_UPCAST(privblob)); const ssh_keyalg* alg = find_pubkey_alg(certalg); - ssh_key* cert = ssh_key_new_priv(alg, ptrlen_from_strbuf(certblob), ptrlen_from_strbuf(privblob)); - if (cert) { - ckey = snew(struct ssh2_userkey); - ckey->key = cert; - ckey->comment = comment; + if (alg) { + ssh_key* cert = ssh_key_new_priv(alg, ptrlen_from_strbuf(certblob), ptrlen_from_strbuf(privblob)); + if (cert) { + ckey = snew(struct ssh2_userkey); + ckey->key = cert; + ckey->comment = comment; + } + strbuf_free(privblob); } - strbuf_free(privblob); } strbuf_free(certblob); fclose(certfile); diff --git a/ssh.h b/ssh.h index 32fc9937..d245ad15 100644 --- a/ssh.h +++ b/ssh.h @@ -473,6 +473,8 @@ struct ec_point { /* A couple of ECC functions exported for use outside sshecc.c */ struct ec_point *ecp_mul(const struct ec_point *a, const Bignum b); void ec_point_free(struct ec_point *point); +bool BinarySource_get_point(BinarySource *src, struct ec_point *point); +#define get_point(src, pt) BinarySource_get_point(BinarySource_UPCAST(src), pt) /* Weierstrass form curve */ struct ec_wcurve @@ -514,6 +516,15 @@ struct ec_curve { }; }; +struct ecsign_extra { + struct ec_curve *(*curve)(void); + const struct ssh_hashalg *hash; + + /* These fields are used by the OpenSSH PEM format importer/exporter */ + const unsigned char *oid; + int oidlen; +}; + const ssh_keyalg *ec_alg_by_oid(int len, const void *oid, const struct ec_curve **curve); const unsigned char *ec_alg_oid(const ssh_keyalg *alg, int *oidlen); @@ -531,6 +542,25 @@ struct ec_key { ssh_key sshk; }; +struct ec_cert_key { + ptrlen certificate; + char* nonce; + struct ec_point publicKey; + uint64_t serial; + uint32_t type; + char * keyid; + char * principals; + uint64_t valid_after; + uint64_t valid_before; + char * options; + char * extensions; + char * reserved; + ssh_key* sigkey; + char * signature; + Bignum privateKey; + ssh_key sshk; +}; + struct ec_point *ec_public(const Bignum privateKey, const struct ec_curve *curve); /* @@ -920,6 +950,9 @@ extern const ssh_keyalg ssh_ecdsa_nistp384; extern const ssh_keyalg ssh_ecdsa_nistp521; extern const ssh_keyalg ssh_cert_rsa; extern const ssh_keyalg ssh_cert_dss; +extern const ssh_keyalg ssh_ecdsa_cert_nistp256; +extern const ssh_keyalg ssh_ecdsa_cert_nistp384; +extern const ssh_keyalg ssh_ecdsa_cert_nistp521; extern const struct ssh2_macalg ssh_hmac_md5; extern const struct ssh2_macalg ssh_hmac_sha1; extern const struct ssh2_macalg ssh_hmac_sha1_buggy; diff --git a/sshdsscert.c b/sshdsscert.c index 257b85df..6c5dd591 100644 --- a/sshdsscert.c +++ b/sshdsscert.c @@ -23,23 +23,17 @@ static ssh_key *dsscert_new_pub(const ssh_keyalg *self, ptrlen data) BinarySource_BARE_INIT(src, data.ptr, data.len); ptrlen certtype = get_string(src); - if (!ptrlen_eq_string(certtype, ssh_cert_dss.ssh_id)) + if (!ptrlen_eq_string(certtype, self->ssh_id)) return NULL; certkey = snew(struct dss_cert_key); - certkey->sshk = &ssh_cert_dss; + memset(certkey, 0, sizeof(struct dss_cert_key)); + certkey->sshk = self; certkey->certificate.ptr = snewn(data.len, char); memcpy((void*)(certkey->certificate.ptr), data.ptr, data.len); certkey->certificate.len = data.len; - certkey->x = NULL; - certkey->p = certkey->q = certkey->g = certkey->y = NULL; - certkey->nonce = certkey->keyid = certkey->principals = NULL; - certkey->options = certkey->extensions = certkey->reserved = NULL; - certkey->sigkey = NULL; - certkey->signature = NULL; - if (get_err(src)) { dsscert_freekey(&certkey->sshk); return NULL; @@ -161,7 +155,8 @@ static ssh_key *dsscert_new_priv_openssh(const ssh_keyalg *self, struct dss_cert_key *certkey; certkey = snew(struct dss_cert_key); - certkey->sshk = &ssh_cert_dss; + memset(certkey, 0, sizeof(struct dss_cert_key)); + certkey->sshk = self; ptrlen certdata = get_string(src); certkey->certificate.ptr = snewn(certdata.len, char); @@ -198,7 +193,7 @@ static ssh_key *dsscert_new_priv_openssh(const ssh_keyalg *self, certkey->signature = mkstr(get_string(cert)); /* validate the key - from sshdss.c */ - if (get_err(cert) || !ptrlen_eq_string(certtype, ssh_cert_dss.ssh_id) + if (get_err(cert) || !ptrlen_eq_string(certtype, self->ssh_id) || !bignum_cmp(certkey->q, Zero) || !bignum_cmp(certkey->p, Zero)) { dsscert_freekey(&certkey->sshk); return NULL; @@ -315,6 +310,6 @@ const ssh_keyalg ssh_cert_dss = { dsscert_pubkey_bits, "ssh-dss-cert-v01@openssh.com", - "dsscert", + "ssh-dss-cert-v01", NULL, }; diff --git a/sshecc.c b/sshecc.c index 947b64a9..c176d60c 100644 --- a/sshecc.c +++ b/sshecc.c @@ -1675,27 +1675,17 @@ static bool decodepoint(const char *p, int length, struct ec_point *point) return true; } -static bool BinarySource_get_point(BinarySource *src, struct ec_point *point) +bool BinarySource_get_point(BinarySource *src, struct ec_point *point) { ptrlen str = get_string(src); if (get_err(src)) return false; return decodepoint(str.ptr, str.len, point); } -#define get_point(src, pt) BinarySource_get_point(BinarySource_UPCAST(src), pt) /* ---------------------------------------------------------------------- * Exposed ECDSA interface */ -struct ecsign_extra { - struct ec_curve *(*curve)(void); - const struct ssh_hashalg *hash; - - /* These fields are used by the OpenSSH PEM format importer/exporter */ - const unsigned char *oid; - int oidlen; -}; - static void ecdsa_freekey(ssh_key *key) { struct ec_key *ec; diff --git a/sshecccert.c b/sshecccert.c new file mode 100644 index 00000000..b241b56b --- /dev/null +++ b/sshecccert.c @@ -0,0 +1,398 @@ +/* + * RSA Certificate implementation for PuTTY. + */ + +#include +#include +#include +#include + +#include "ssh.h" +#include "misc.h" + +/* ----------------------------------------------------------------------- + * Implementation of the ssh-rsa-cert-v01 key type + */ + +static void ecc_cert_freekey(ssh_key *key); /* forward reference */ + +static ssh_key *ecc_cert_new_pub(const ssh_keyalg *self, ptrlen data) +{ + const struct ecsign_extra *extra = + (const struct ecsign_extra *)((ssh_keyalg*)self->extra)->extra; + BinarySource src[1]; + struct ec_cert_key *certkey; + struct ec_curve *curve; + + curve = extra->curve(); + assert(curve->type == EC_WEIERSTRASS || curve->type == EC_EDWARDS); + + BinarySource_BARE_INIT(src, data.ptr, data.len); + ptrlen certtype = get_string(src); + if (!ptrlen_eq_string(certtype, self->ssh_id)) + return NULL; + + certkey = snew(struct ec_cert_key); + memset(certkey, 0, sizeof(struct ec_cert_key)); + certkey->sshk = self; + + certkey->certificate.ptr = snewn(data.len, char); + memcpy((void*)(certkey->certificate.ptr), data.ptr, data.len); + certkey->certificate.len = data.len; + + certkey->publicKey.curve = curve; + certkey->publicKey.infinity = false; + + if (get_err(src)) { + ecc_cert_freekey(&certkey->sshk); + return NULL; + } + + certkey->nonce = mkstr(get_string(src)); + + ptrlen curvename = get_string(src); + if (!get_point(src, &certkey->publicKey)) { + ecc_cert_freekey(&certkey->sshk); + return NULL; + } + + if (!ptrlen_eq_string(curvename, certkey->publicKey.curve->name) || + !certkey->publicKey.x || !certkey->publicKey.y || + bignum_cmp(certkey->publicKey.x, curve->p) >= 0 || + bignum_cmp(certkey->publicKey.y, curve->p) >= 0) + { + ecc_cert_freekey(&certkey->sshk); + certkey = NULL; + } + certkey->serial = get_uint64(src); + certkey->type = get_uint32(src); + certkey->keyid = mkstr(get_string(src)); + certkey->principals = mkstr(get_string(src)); + certkey->valid_after = get_uint64(src); + certkey->valid_before = get_uint64(src); + certkey->options = mkstr(get_string(src)); + certkey->extensions = mkstr(get_string(src)); + certkey->reserved = mkstr(get_string(src)); + + ptrlen sigkey = get_string(src); + + certkey->signature = mkstr(get_string(src)); + + if (get_err(src)) { + ecc_cert_freekey(&certkey->sshk); + return NULL; + } + + BinarySource sk[1]; + BinarySource_BARE_INIT(sk, sigkey.ptr, sigkey.len); + ptrlen algname = get_string(sk); + ssh_key signature_key = find_pubkey_alg_len(algname); + if (signature_key != NULL) { + certkey->sigkey = ssh_key_new_pub(signature_key, get_data(sk, get_avail(sk))); + } + + if (get_err(sk)) { + ecc_cert_freekey(&certkey->sshk); + return NULL; + } + + return &certkey->sshk; +} + +static void ecc_cert_freekey(ssh_key *key) +{ + struct ec_cert_key *certkey = container_of(key, struct ec_cert_key, sshk); + + if (certkey->certificate.ptr) + sfree((void*)(certkey->certificate.ptr)); + if (certkey->nonce) + sfree(certkey->nonce); + if (certkey->publicKey.x) + freebn(certkey->publicKey.x); + if (certkey->publicKey.y) + freebn(certkey->publicKey.y); + if (certkey->publicKey.z) + freebn(certkey->publicKey.z); + if (certkey->keyid) + sfree(certkey->keyid); + if (certkey->principals) + sfree(certkey->principals); + if (certkey->options) + sfree(certkey->options); + if (certkey->extensions) + sfree(certkey->extensions); + if (certkey->reserved) + sfree(certkey->reserved); + if (certkey->sigkey) + ssh_key_free(certkey->sigkey); + if (certkey->signature) + sfree(certkey->signature); + if (certkey->privateKey) + freebn(certkey->privateKey); + + sfree(certkey); +} + +static ssh_key *ecc_cert_new_priv(const ssh_keyalg *self, + ptrlen pub, ptrlen priv) +{ + BinarySource src[1]; + ssh_key *sshk; + struct ec_cert_key *certkey; + struct ec_point *publicKey; + + sshk = ecc_cert_new_pub(self, pub); + if (!sshk) { + return NULL; + } + + certkey = container_of(sshk, struct ec_cert_key, sshk); + BinarySource_BARE_INIT(src, priv.ptr, priv.len); + + if (certkey->publicKey.curve->type != EC_WEIERSTRASS + && certkey->publicKey.curve->type != EC_EDWARDS) { + ecc_cert_freekey(&certkey->sshk); + return NULL; + } + + certkey->privateKey = get_mp_ssh2(src); + if (!certkey->privateKey) { + ecc_cert_freekey(&certkey->sshk); + return NULL; + } + + /* Check that private key generates public key */ + publicKey = ec_public(certkey->privateKey, certkey->publicKey.curve); + + if (!publicKey || + bignum_cmp(publicKey->x, certkey->publicKey.x) || + bignum_cmp(publicKey->y, certkey->publicKey.y)) + { + ecc_cert_freekey(&certkey->sshk); + certkey = NULL; + } + ec_point_free(publicKey); + + if (get_err(src)) { + ecc_cert_freekey(&certkey->sshk); + return NULL; + } + + return &certkey->sshk; +} + +static ssh_key *ecc_cert_new_priv_openssh(const ssh_keyalg *self, + BinarySource *src) +{ + const struct ecsign_extra *extra = + (const struct ecsign_extra *)((ssh_keyalg*)self->extra)->extra; + struct ec_cert_key *certkey; + struct ec_curve *curve; + + curve = extra->curve(); + assert(curve->type == EC_WEIERSTRASS || curve->type == EC_EDWARDS); + + certkey = snew(struct ec_cert_key); + memset(certkey, 0, sizeof(struct ec_cert_key)); + certkey->sshk = self; + + ptrlen certdata = get_string(src); + certkey->certificate.ptr = snewn(certdata.len, char); + memcpy((void*)(certkey->certificate.ptr), certdata.ptr, certdata.len); + certkey->certificate.len = certdata.len; + + certkey->privateKey = get_mp_ssh2(src); + + if (get_err(src) || !certkey->privateKey) { + ecc_cert_freekey(&certkey->sshk); + return NULL; + } + + BinarySource cert[1]; + BinarySource_BARE_INIT(cert, certkey->certificate.ptr, certkey->certificate.len); + ptrlen certtype = get_string(cert); + + certkey->nonce = mkstr(get_string(cert)); + + ptrlen curvename = get_string(src); + bool gotPoint = get_point(cert, &certkey->publicKey); + + certkey->serial = get_uint64(cert); + certkey->type = get_uint32(cert); + certkey->keyid = mkstr(get_string(cert)); + certkey->principals = mkstr(get_string(cert)); + certkey->valid_after = get_uint64(cert); + certkey->valid_before = get_uint64(cert); + certkey->options = mkstr(get_string(cert)); + certkey->extensions = mkstr(get_string(cert)); + certkey->reserved = mkstr(get_string(cert)); + + ptrlen sigkey = get_string(cert); + + certkey->signature = mkstr(get_string(cert)); + + if (get_err(cert) || !ptrlen_eq_string(certtype, self->ssh_id) || + !ptrlen_eq_string(curvename, certkey->publicKey.curve->name) || !gotPoint || + !certkey->publicKey.x || !certkey->publicKey.y || + bignum_cmp(certkey->publicKey.x, curve->p) >= 0 || + bignum_cmp(certkey->publicKey.y, curve->p) >= 0) + { + ecc_cert_freekey(&certkey->sshk); + certkey = NULL; + } + + BinarySource sk[1]; + BinarySource_BARE_INIT(sk, sigkey.ptr, sigkey.len); + ptrlen algname = get_string(sk); + ssh_key signature_key = find_pubkey_alg_len(algname); + if (signature_key != NULL) { + certkey->sigkey = ssh_key_new_pub(signature_key, get_data(sk, get_avail(sk))); + } else { + certkey->sigkey = NULL; + } + + if (get_err(sk)) { + ecc_cert_freekey(&certkey->sshk); + return NULL; + } + + return &certkey->sshk; +} + +static void ecc_cert_sign(ssh_key *key, const void* data, int datalen, + BinarySink *bs) +{ + struct ec_cert_key *certkey = container_of(key, struct ec_cert_key, sshk); + struct ec_key eckey; + + eckey.publicKey.curve = certkey->publicKey.curve; + eckey.publicKey.x = certkey->publicKey.x; + eckey.publicKey.y = certkey->publicKey.y; + eckey.publicKey.z = certkey->publicKey.z; + eckey.publicKey.infinity = certkey->publicKey.infinity; + eckey.privateKey = certkey->privateKey; + eckey.sshk = (*key)->extra; + + return ssh_key_sign(&eckey.sshk, data, datalen, bs); +} + +static bool ecc_cert_verify(ssh_key *key, ptrlen sig, ptrlen data) +{ + struct ec_cert_key *certkey = container_of(key, struct ec_cert_key, sshk); + struct ec_key eckey; + + eckey.publicKey.curve = certkey->publicKey.curve; + eckey.publicKey.x = certkey->publicKey.x; + eckey.publicKey.y = certkey->publicKey.y; + eckey.publicKey.z = certkey->publicKey.z; + eckey.publicKey.infinity = certkey->publicKey.infinity; + eckey.privateKey = certkey->privateKey; + eckey.sshk = (*key)->extra; + + return ssh_key_verify(&eckey.sshk, sig, data); +} + +static void ecc_cert_public_blob(ssh_key *key, BinarySink *bs) +{ + struct ec_cert_key *certkey = container_of(key, struct ec_cert_key, sshk); + + // copy the certificate + put_data(bs, certkey->certificate.ptr, certkey->certificate.len); +} + +static void ecc_cert_private_blob(ssh_key *key, BinarySink *bs) +{ + struct ec_cert_key *certkey = container_of(key, struct ec_cert_key, sshk); + + put_mp_ssh2(bs, certkey->privateKey); +} + +static void ecc_cert_openssh_blob(ssh_key* key, BinarySink *bs) +{ + // don't return anything. USed only for export, and we don't export certs +} + +// Used just for looking up host keys for now, so skip +static char * ecc_cert_cache_str(ssh_key *key) +{ + char *p = snewn(1, char); + p[0] = '\0'; + return p; +} + +static int ecc_cert_pubkey_bits(const ssh_keyalg *self, ptrlen pub) +{ + ssh_key *sshk; + struct ec_cert_key *certkey; + int ret; + + sshk = ecc_cert_new_pub(self, pub); + if (!sshk) + return -1; + + certkey = container_of(sshk, struct ec_cert_key, sshk); + ret = certkey->publicKey.curve->fieldBits; + ecc_cert_freekey(&certkey->sshk); + + return ret; +} + +const ssh_keyalg ssh_ecdsa_cert_nistp256 = { + ecc_cert_new_pub, + ecc_cert_new_priv, + ecc_cert_new_priv_openssh, + + ecc_cert_freekey, + ecc_cert_sign, + ecc_cert_verify, + ecc_cert_public_blob, + ecc_cert_private_blob, + ecc_cert_openssh_blob, + ecc_cert_cache_str, + + ecc_cert_pubkey_bits, + + "ecdsa-sha2-nistp256-cert-v01@openssh.com", + "ecdsa-sha2-nistp256-cert-v01", + &ssh_ecdsa_nistp256 +}; + +const ssh_keyalg ssh_ecdsa_cert_nistp384 = { + ecc_cert_new_pub, + ecc_cert_new_priv, + ecc_cert_new_priv_openssh, + + ecc_cert_freekey, + ecc_cert_sign, + ecc_cert_verify, + ecc_cert_public_blob, + ecc_cert_private_blob, + ecc_cert_openssh_blob, + ecc_cert_cache_str, + + ecc_cert_pubkey_bits, + + "ecdsa-sha2-nistp384-cert-v01@openssh.com", + "ecdsa-sha2-nistp384-cert-v01", + &ssh_ecdsa_nistp384 +}; + +const ssh_keyalg ssh_ecdsa_cert_nistp521 = { + ecc_cert_new_pub, + ecc_cert_new_priv, + ecc_cert_new_priv_openssh, + + ecc_cert_freekey, + ecc_cert_sign, + ecc_cert_verify, + ecc_cert_public_blob, + ecc_cert_private_blob, + ecc_cert_openssh_blob, + ecc_cert_cache_str, + + ecc_cert_pubkey_bits, + + "ecdsa-sha2-nistp521-cert-v01@openssh.com", + "ecdsa-sha2-nistp521-cert-v01", + &ssh_ecdsa_nistp521 +}; diff --git a/sshpubk.c b/sshpubk.c index ca68ac26..41b94153 100644 --- a/sshpubk.c +++ b/sshpubk.c @@ -582,6 +582,12 @@ const ssh_keyalg *find_pubkey_alg_len(ptrlen name) return &ssh_cert_rsa; else if (ptrlen_eq_string(name, "ssh-dss-cert-v01@openssh.com")) return &ssh_cert_dss; + else if (ptrlen_eq_string(name, "ecdsa-sha2-nistp256-cert-v01@openssh.com")) + return &ssh_ecdsa_cert_nistp256; + else if (ptrlen_eq_string(name, "ecdsa-sha2-nistp384-cert-v01@openssh.com")) + return &ssh_ecdsa_cert_nistp384; + else if (ptrlen_eq_string(name, "ecdsa-sha2-nistp521-cert-v01@openssh.com")) + return &ssh_ecdsa_cert_nistp521; else return NULL; } diff --git a/sshrsacert.c b/sshrsacert.c index b3683785..b012447a 100644 --- a/sshrsacert.c +++ b/sshrsacert.c @@ -23,11 +23,11 @@ static ssh_key *rsa2cert_new_pub(const ssh_keyalg *self, ptrlen data) BinarySource_BARE_INIT(src, data.ptr, data.len); ptrlen certtype = get_string(src); - if (!ptrlen_eq_string(certtype, ssh_cert_rsa.ssh_id)) + if (!ptrlen_eq_string(certtype, self->ssh_id)) return NULL; certkey = snew(struct RSACertKey); - certkey->sshk = &ssh_cert_rsa; + certkey->sshk = self; certkey->certificate.ptr = snewn(data.len, char); memcpy((void*)(certkey->certificate.ptr), data.ptr, data.len); @@ -170,7 +170,7 @@ static ssh_key *rsa2cert_new_priv_openssh(const ssh_keyalg *self, struct RSACertKey *certkey; certkey = snew(struct RSACertKey); - certkey->sshk = &ssh_cert_rsa; + certkey->sshk = self; certkey->comment = NULL; ptrlen certdata = get_string(src); @@ -219,7 +219,7 @@ static ssh_key *rsa2cert_new_priv_openssh(const ssh_keyalg *self, rsakey.comment = ""; rsakey.sshk = &ssh_rsa; - if (get_err(cert) || !ptrlen_eq_string(certtype, ssh_cert_rsa.ssh_id) + if (get_err(cert) || !ptrlen_eq_string(certtype, self->ssh_id) || !rsa_verify(&rsakey)) { rsa2cert_freekey(&certkey->sshk); return NULL; @@ -342,6 +342,6 @@ const ssh_keyalg ssh_cert_rsa = { rsa2cert_pubkey_bits, "ssh-rsa-cert-v01@openssh.com", - "rsa2cert", + "ssh-rsa-cert-v01", NULL, }; From 11a229264029617d56edb9c7b9ba8ead80720c04 Mon Sep 17 00:00:00 2001 From: Will Lauer Date: Sun, 9 Dec 2018 06:24:51 -0600 Subject: [PATCH 606/607] Initial ED25519 support (not enabled) Unlike other certs, ED25519's cert isn't a simple concatenation of a cert blob with the ed25519 non-cert priv key. for some reason, the public key is duplicated, causing the cert to not parse correctly. --- ssh.h | 2 + sshdsscert.c | 4 +- sshecc.c | 2 +- sshecccert.c | 182 ++++++++++++++++++++++++++++++++++++++++++++++++++- sshpubk.c | 2 + sshrsacert.c | 4 +- 6 files changed, 189 insertions(+), 7 deletions(-) diff --git a/ssh.h b/ssh.h index d245ad15..4d0c16d0 100644 --- a/ssh.h +++ b/ssh.h @@ -475,6 +475,7 @@ struct ec_point *ecp_mul(const struct ec_point *a, const Bignum b); void ec_point_free(struct ec_point *point); bool BinarySource_get_point(BinarySource *src, struct ec_point *point); #define get_point(src, pt) BinarySource_get_point(BinarySource_UPCAST(src), pt) +bool decodepoint_ed(const char *p, int length, struct ec_point *point); /* Weierstrass form curve */ struct ec_wcurve @@ -953,6 +954,7 @@ extern const ssh_keyalg ssh_cert_dss; extern const ssh_keyalg ssh_ecdsa_cert_nistp256; extern const ssh_keyalg ssh_ecdsa_cert_nistp384; extern const ssh_keyalg ssh_ecdsa_cert_nistp521; +extern const ssh_keyalg ssh_ecdsa_cert_ed25519; extern const struct ssh2_macalg ssh_hmac_md5; extern const struct ssh2_macalg ssh_hmac_sha1; extern const struct ssh2_macalg ssh_hmac_sha1_buggy; diff --git a/sshdsscert.c b/sshdsscert.c index 6c5dd591..b8593ec5 100644 --- a/sshdsscert.c +++ b/sshdsscert.c @@ -123,7 +123,7 @@ static ssh_key *dsscert_new_priv(const ssh_keyalg *self, struct dss_cert_key *certkey; Bignum ytest; - sshk = dsscert_new_pub(self, pub); + sshk = ssh_key_new_pub(self, pub); if (!sshk) { return NULL; } @@ -283,7 +283,7 @@ static int dsscert_pubkey_bits(const ssh_keyalg *self, ptrlen pub) struct dss_cert_key *certkey; int ret; - sshk = dsscert_new_pub(self, pub); + sshk = ssh_key_new_pub(self, pub); if (!sshk) return -1; diff --git a/sshecc.c b/sshecc.c index c176d60c..2dd8f449 100644 --- a/sshecc.c +++ b/sshecc.c @@ -1598,7 +1598,7 @@ static Bignum BinarySource_get_mp_le(BinarySource *src) } #define get_mp_le(src) BinarySource_get_mp_le(BinarySource_UPCAST(src)) -static bool decodepoint_ed(const char *p, int length, struct ec_point *point) +bool decodepoint_ed(const char *p, int length, struct ec_point *point) { /* Got some conversion to do, first read in the y co-ord */ bool negative; diff --git a/sshecccert.c b/sshecccert.c index b241b56b..d82e6bf7 100644 --- a/sshecccert.c +++ b/sshecccert.c @@ -99,6 +99,85 @@ static ssh_key *ecc_cert_new_pub(const ssh_keyalg *self, ptrlen data) return &certkey->sshk; } +static ssh_key *ed_cert_new_pub(const ssh_keyalg *self, ptrlen data) +{ + const struct ecsign_extra *extra = + (const struct ecsign_extra *)((ssh_keyalg*)self->extra)->extra; + BinarySource src[1]; + struct ec_cert_key *certkey; + struct ec_curve *curve; + + curve = extra->curve(); + assert(curve->type == EC_WEIERSTRASS || curve->type == EC_EDWARDS); + + BinarySource_BARE_INIT(src, data.ptr, data.len); + ptrlen certtype = get_string(src); + if (!ptrlen_eq_string(certtype, self->ssh_id)) + return NULL; + + certkey = snew(struct ec_cert_key); + memset(certkey, 0, sizeof(struct ec_cert_key)); + certkey->sshk = self; + + certkey->certificate.ptr = snewn(data.len, char); + memcpy((void*)(certkey->certificate.ptr), data.ptr, data.len); + certkey->certificate.len = data.len; + + certkey->publicKey.curve = curve; + certkey->publicKey.infinity = false; + + if (get_err(src)) { + ecc_cert_freekey(&certkey->sshk); + return NULL; + } + + certkey->nonce = mkstr(get_string(src)); + + ptrlen pkstr = get_string(src); + bool gotPoint = decodepoint_ed(pkstr.ptr, pkstr.len, &certkey->publicKey); + + if (!gotPoint || !certkey->publicKey.x || !certkey->publicKey.y || + bignum_cmp(certkey->publicKey.x, curve->p) >= 0 || + bignum_cmp(certkey->publicKey.y, curve->p) >= 0) + { + ecc_cert_freekey(&certkey->sshk); + certkey = NULL; + } + certkey->serial = get_uint64(src); + certkey->type = get_uint32(src); + certkey->keyid = mkstr(get_string(src)); + certkey->principals = mkstr(get_string(src)); + certkey->valid_after = get_uint64(src); + certkey->valid_before = get_uint64(src); + certkey->options = mkstr(get_string(src)); + certkey->extensions = mkstr(get_string(src)); + certkey->reserved = mkstr(get_string(src)); + + ptrlen sigkey = get_string(src); + + certkey->signature = mkstr(get_string(src)); + + if (get_err(src)) { + ecc_cert_freekey(&certkey->sshk); + return NULL; + } + + BinarySource sk[1]; + BinarySource_BARE_INIT(sk, sigkey.ptr, sigkey.len); + ptrlen algname = get_string(sk); + ssh_key signature_key = find_pubkey_alg_len(algname); + if (signature_key != NULL) { + certkey->sigkey = ssh_key_new_pub(signature_key, get_data(sk, get_avail(sk))); + } + + if (get_err(sk)) { + ecc_cert_freekey(&certkey->sshk); + return NULL; + } + + return &certkey->sshk; +} + static void ecc_cert_freekey(ssh_key *key) { struct ec_cert_key *certkey = container_of(key, struct ec_cert_key, sshk); @@ -141,7 +220,7 @@ static ssh_key *ecc_cert_new_priv(const ssh_keyalg *self, struct ec_cert_key *certkey; struct ec_point *publicKey; - sshk = ecc_cert_new_pub(self, pub); + sshk = ssh_key_new_pub(self, pub); if (!sshk) { return NULL; } @@ -170,6 +249,7 @@ static ssh_key *ecc_cert_new_priv(const ssh_keyalg *self, { ecc_cert_freekey(&certkey->sshk); certkey = NULL; + return NULL; } ec_point_free(publicKey); @@ -259,6 +339,84 @@ static ssh_key *ecc_cert_new_priv_openssh(const ssh_keyalg *self, return &certkey->sshk; } +static ssh_key *ed_cert_new_priv_openssh(const ssh_keyalg *self, + BinarySource *src) +{ + const struct ecsign_extra *extra = + (const struct ecsign_extra *)((ssh_keyalg*)self->extra)->extra; + struct ec_cert_key *certkey; + struct ec_curve *curve; + + curve = extra->curve(); + assert(curve->type == EC_WEIERSTRASS || curve->type == EC_EDWARDS); + + certkey = snew(struct ec_cert_key); + memset(certkey, 0, sizeof(struct ec_cert_key)); + certkey->sshk = self; + + ptrlen certdata = get_string(src); + certkey->certificate.ptr = snewn(certdata.len, char); + memcpy((void*)(certkey->certificate.ptr), certdata.ptr, certdata.len); + certkey->certificate.len = certdata.len; + + certkey->privateKey = get_mp_ssh2(src); + + if (get_err(src) || !certkey->privateKey) { + ecc_cert_freekey(&certkey->sshk); + return NULL; + } + + BinarySource cert[1]; + BinarySource_BARE_INIT(cert, certkey->certificate.ptr, certkey->certificate.len); + ptrlen certtype = get_string(cert); + + certkey->nonce = mkstr(get_string(cert)); + + ptrlen pkstr = get_string(cert); + bool gotPoint = decodepoint_ed(pkstr.ptr, pkstr.len, &certkey->publicKey); + + certkey->serial = get_uint64(cert); + certkey->type = get_uint32(cert); + certkey->keyid = mkstr(get_string(cert)); + certkey->principals = mkstr(get_string(cert)); + certkey->valid_after = get_uint64(cert); + certkey->valid_before = get_uint64(cert); + certkey->options = mkstr(get_string(cert)); + certkey->extensions = mkstr(get_string(cert)); + certkey->reserved = mkstr(get_string(cert)); + + ptrlen sigkey = get_string(cert); + + certkey->signature = mkstr(get_string(cert)); + + if (get_err(cert) || !ptrlen_eq_string(certtype, self->ssh_id) || + !gotPoint || + !certkey->publicKey.x || !certkey->publicKey.y || + bignum_cmp(certkey->publicKey.x, curve->p) >= 0 || + bignum_cmp(certkey->publicKey.y, curve->p) >= 0) + { + ecc_cert_freekey(&certkey->sshk); + certkey = NULL; + } + + BinarySource sk[1]; + BinarySource_BARE_INIT(sk, sigkey.ptr, sigkey.len); + ptrlen algname = get_string(sk); + ssh_key signature_key = find_pubkey_alg_len(algname); + if (signature_key != NULL) { + certkey->sigkey = ssh_key_new_pub(signature_key, get_data(sk, get_avail(sk))); + } else { + certkey->sigkey = NULL; + } + + if (get_err(sk)) { + ecc_cert_freekey(&certkey->sshk); + return NULL; + } + + return &certkey->sshk; +} + static void ecc_cert_sign(ssh_key *key, const void* data, int datalen, BinarySink *bs) { @@ -326,7 +484,7 @@ static int ecc_cert_pubkey_bits(const ssh_keyalg *self, ptrlen pub) struct ec_cert_key *certkey; int ret; - sshk = ecc_cert_new_pub(self, pub); + sshk = ssh_key_new_pub(self, pub); if (!sshk) return -1; @@ -396,3 +554,23 @@ const ssh_keyalg ssh_ecdsa_cert_nistp521 = { "ecdsa-sha2-nistp521-cert-v01", &ssh_ecdsa_nistp521 }; + +const ssh_keyalg ssh_ecdsa_cert_ed25519 = { + ed_cert_new_pub, + ecc_cert_new_priv, + ed_cert_new_priv_openssh, + + ecc_cert_freekey, + ecc_cert_sign, + ecc_cert_verify, + ecc_cert_public_blob, + ecc_cert_private_blob, + ecc_cert_openssh_blob, + ecc_cert_cache_str, + + ecc_cert_pubkey_bits, + + "ssh-ed25519-cert-v01@openssh.com", + "ssh-ed25519-cert-v01", + &ssh_ecdsa_ed25519 +}; diff --git a/sshpubk.c b/sshpubk.c index 41b94153..3c1ac94a 100644 --- a/sshpubk.c +++ b/sshpubk.c @@ -588,6 +588,8 @@ const ssh_keyalg *find_pubkey_alg_len(ptrlen name) return &ssh_ecdsa_cert_nistp384; else if (ptrlen_eq_string(name, "ecdsa-sha2-nistp521-cert-v01@openssh.com")) return &ssh_ecdsa_cert_nistp521; +// else if (ptrlen_eq_string(name, "ssh-ed25519-cert-v01@openssh.com")) +// return &ssh_ecdsa_cert_ed25519; else return NULL; } diff --git a/sshrsacert.c b/sshrsacert.c index b012447a..f3d45f19 100644 --- a/sshrsacert.c +++ b/sshrsacert.c @@ -132,7 +132,7 @@ static ssh_key *rsa2cert_new_priv(const ssh_keyalg *self, ssh_key *sshk; struct RSACertKey *certkey; - sshk = rsa2cert_new_pub(self, pub); + sshk = ssh_key_new_pub(self, pub); if (!sshk) { return NULL; } @@ -315,7 +315,7 @@ static int rsa2cert_pubkey_bits(const ssh_keyalg *self, ptrlen pub) struct RSACertKey *certkey; int ret; - sshk = rsa2cert_new_pub(self, pub); + sshk = ssh_key_new_pub(self, pub); if (!sshk) return -1; From 25d1009341e90b1911f749b151ab8244efbc5cdf Mon Sep 17 00:00:00 2001 From: Will Lauer Date: Tue, 11 Dec 2018 01:20:53 -0600 Subject: [PATCH 607/607] Makind ed25519 work --- ssh.h | 2 ++ sshecc.c | 3 +-- sshecccert.c | 6 +++++- sshpubk.c | 4 ++-- 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/ssh.h b/ssh.h index 4d0c16d0..93461532 100644 --- a/ssh.h +++ b/ssh.h @@ -476,6 +476,8 @@ void ec_point_free(struct ec_point *point); bool BinarySource_get_point(BinarySource *src, struct ec_point *point); #define get_point(src, pt) BinarySource_get_point(BinarySource_UPCAST(src), pt) bool decodepoint_ed(const char *p, int length, struct ec_point *point); +#define get_mp_le(src) BinarySource_get_mp_le(BinarySource_UPCAST(src)) +Bignum BinarySource_get_mp_le(BinarySource *src); /* Weierstrass form curve */ struct ec_wcurve diff --git a/sshecc.c b/sshecc.c index 2dd8f449..d94d354f 100644 --- a/sshecc.c +++ b/sshecc.c @@ -1591,12 +1591,11 @@ static void _ecdsa_sign(const Bignum privateKey, const struct ec_curve *curve, * Misc functions */ -static Bignum BinarySource_get_mp_le(BinarySource *src) +Bignum BinarySource_get_mp_le(BinarySource *src) { ptrlen mp_str = get_string(src); return bignum_from_bytes_le(mp_str.ptr, mp_str.len); } -#define get_mp_le(src) BinarySource_get_mp_le(BinarySource_UPCAST(src)) bool decodepoint_ed(const char *p, int length, struct ec_point *point) { diff --git a/sshecccert.c b/sshecccert.c index d82e6bf7..81ace530 100644 --- a/sshecccert.c +++ b/sshecccert.c @@ -234,7 +234,11 @@ static ssh_key *ecc_cert_new_priv(const ssh_keyalg *self, return NULL; } - certkey->privateKey = get_mp_ssh2(src); + if (certkey->publicKey.curve->type == EC_EDWARDS) { + certkey->privateKey = get_mp_le(src); + } else { + certkey->privateKey = get_mp_ssh2(src); + } if (!certkey->privateKey) { ecc_cert_freekey(&certkey->sshk); return NULL; diff --git a/sshpubk.c b/sshpubk.c index 3c1ac94a..ecd1704f 100644 --- a/sshpubk.c +++ b/sshpubk.c @@ -588,8 +588,8 @@ const ssh_keyalg *find_pubkey_alg_len(ptrlen name) return &ssh_ecdsa_cert_nistp384; else if (ptrlen_eq_string(name, "ecdsa-sha2-nistp521-cert-v01@openssh.com")) return &ssh_ecdsa_cert_nistp521; -// else if (ptrlen_eq_string(name, "ssh-ed25519-cert-v01@openssh.com")) -// return &ssh_ecdsa_cert_ed25519; + else if (ptrlen_eq_string(name, "ssh-ed25519-cert-v01@openssh.com")) + return &ssh_ecdsa_cert_ed25519; else return NULL; }